Top secrets sources NedoPC pentevo

Rev

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

/* code68.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator fuer 68xx Prozessoren                                       */
/*                                                                           */
/*****************************************************************************/

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

#include "bpemu.h"
#include "strutil.h"
#include "asmdef.h"
#include "asmpars.h"
#include "asmallg.h"
#include "asmsub.h"
#include "errmsg.h"
#include "codepseudo.h"
#include "motpseudo.h"
#include "asmitree.h"
#include "codevars.h"
#include "cpu2phys.h"
#include "function.h"
#include "nlmessages.h"
#include "as.rsc"

#include "code68.h"

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

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

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

typedef struct
{
  Boolean MayImm;
  CPUVar MinCPU;    /* Shift  andere   ,Y   */
  Byte PageShift;   /* 0 :     nix    Pg 2  */
  Byte Code;        /* 1 :     Pg 3   Pg 4  */
} ALU16Order;       /* 2 :     nix    Pg 4  */
                    /* 3 :     Pg 2   Pg 3  */

enum
{
  ModNone = -1,
  ModAcc  = 0,
  ModDir  = 1,
  ModExt  = 2,
  ModInd  = 3,
  ModImm  = 4
};

#define MModAcc (1 << ModAcc)
#define MModDir (1 << ModDir)
#define MModExt (1 << ModExt)
#define MModInd (1 << ModInd)
#define MModImm (1 << ModImm)

#define Page2Prefix 0x18
#define Page3Prefix 0x1a
#define Page4Prefix 0xcd


static tSymbolSize OpSize;
static Byte PrefCnt;           /* Anzahl Befehlspraefixe */
static ShortInt AdrMode;       /* Ergebnisadressmodus */
static Byte AdrPart;           /* Adressierungsmodusbits im Opcode */
static Byte AdrVals[4];        /* Adressargument */

static FixedOrder *FixedOrders;
static RelOrder   *RelOrders;
static ALU16Order *ALU16Orders;

static LongInt Reg_MMSIZ, Reg_MMWBR, Reg_MM1CR, Reg_MM2CR, Reg_INIT, Reg_INIT2, Reg_CONFIG;

static CPUVar CPU6800, CPU6801, CPU6301, CPU6811, CPU68HC11K4;

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

/*!------------------------------------------------------------------------
 * \fn     compute_window(Byte w_size_code, Byte cpu_start_code, LongInt phys_start_code, LongWord phys_offset)
 * \brief  compute single window from MMU registers
 * \param  w_size_code MMSIZ bits (0..3)
 * \param  cpu_start_code Reg_MMWBR bits (0,2,4,6...14)
 * \param  phys_start_code Reg_MMxCR bits
 * \param  phys_offset offset in physical space
 * ------------------------------------------------------------------------ */


static void compute_window(Byte w_size_code, Byte cpu_start_code, LongInt phys_start_code, LongWord phys_offset)
{
  if (w_size_code)
  {
    Word size, cpu_start;
    LongWord phys_start;

    /* window size */

    size = 0x1000 << w_size_code;

    /* CPU space start address: assume 8K window, systematically clip out bits for
       larger windows */


    cpu_start = (Word)cpu_start_code << 12;
    if (w_size_code > 1)
      cpu_start &= ~0x2000;
    if (w_size_code > 2)
      cpu_start = (cpu_start == 0xc000) ? 0x8000 : cpu_start;

    /* physical space start: mask out lower bits according to window size */

    phys_start = ((phys_start_code & 0x7f & (~((1 << w_size_code) - 1))) << 12) + phys_offset;

    /* set addresses */

    cpu_2_phys_area_add(SegCode, cpu_start, phys_start, size);
  }
}

static void SetK4Ranges(void)
{
  Word ee_bank, io_bank, ram_bank;

  cpu_2_phys_area_clear(SegCode);

  /* Add window 1 after window 2, since it has higher priority and may partially overlap window 2 */

  compute_window((Reg_MMSIZ >> 4) & 0x3, (Reg_MMWBR >> 4) & 0x0e, Reg_MM2CR, 0x90000);
  compute_window(Reg_MMSIZ & 0x3, Reg_MMWBR & 0x0e, Reg_MM1CR, 0x10000);

  /* Internal registers, RAM and EEPROM (if enabled) have priority in CPU address space: */

  if (Reg_CONFIG & 1)
  {
    ee_bank = ((Reg_INIT & 15) << 12) + 0x0d80;
    cpu_2_phys_area_add(SegCode, ee_bank, ee_bank, 640);
  }

  io_bank = (Reg_INIT & 15) << 12;
  cpu_2_phys_area_add(SegCode, io_bank, io_bank, 128);

  /* If RAM position overlaps registers, 128 bytes of RAM get relocated to upper end: */

  ram_bank = ((Reg_INIT >> 4) & 15) << 12;
  if (ram_bank == io_bank)
    ram_bank += 128;
  cpu_2_phys_area_add(SegCode, ram_bank, ram_bank, 768);

  /* Fill the remainder of CPU address space with 1:1 mappings: */

  cpu_2_phys_area_fill(SegCode, 0x0000, 0xffff);
}

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

static Boolean DecodeAcc(const char *pArg, Byte *pReg)
{
  static const char Regs[] = "AB";

  if (strlen(pArg) == 1)
  {
    const char *pPos = strchr(Regs, as_toupper(*pArg));

    if (pPos)
    {
      *pReg = pPos - Regs;
      return True;
    }
  }
  return False;
}

static void DecodeAdr(int StartInd, int StopInd, Byte Erl)
{
  tStrComp *pStartArg = &ArgStr[StartInd];
  Boolean OK, ErrOcc;
  tSymbolFlags Flags;
  Word AdrWord;
  Byte Bit8;

  AdrMode = ModNone;
  AdrPart = 0;
  ErrOcc = False;

  /* eine Komponente ? */

  if (StartInd == StopInd)
  {
    /* Akkumulatoren ? */

    if (DecodeAcc(pStartArg->str.p_str, &AdrPart))
    {
      if (MModAcc & Erl)
        AdrMode = ModAcc;
    }

    /* immediate ? */

    else if ((strlen(pStartArg->str.p_str) > 1) && (*pStartArg->str.p_str == '#'))
    {
      if (MModImm & Erl)
      {
        if (OpSize == eSymbolSize16Bit)
        {
          AdrWord = EvalStrIntExpressionOffs(pStartArg, 1, Int16, &OK);
          if (OK)
          {
            AdrMode = ModImm;
            AdrVals[AdrCnt++] = Hi(AdrWord);
            AdrVals[AdrCnt++] = Lo(AdrWord);
          }
          else
            ErrOcc = True;
        }
        else
        {
          AdrVals[AdrCnt] = EvalStrIntExpressionOffs(pStartArg, 1, Int8, &OK);
          if (OK)
          {
            AdrMode = ModImm;
            AdrCnt++;
          }
          else
            ErrOcc = True;
        }
      }
    }

    /* absolut ? */

    else
    {
      unsigned Offset = 0;

      Bit8 = 0;
      if (pStartArg->str.p_str[Offset] == '<')
      {
        Bit8 = 2;
        Offset++;
      }
      else if (pStartArg->str.p_str[Offset] == '>')
      {
        Bit8 = 1;
        Offset++;
      }
      if (MomCPU == CPU68HC11K4)
      {
        LargeWord AdrLWord = EvalStrIntExpressionOffsWithFlags(pStartArg, Offset, UInt21, &OK, &Flags);
        if (OK)
        {
          if (!def_phys_2_cpu(SegCode, &AdrLWord))
          {
            WrError(ErrNum_InAccPage);
            AdrWord = AdrLWord & 0xffffu;
          }
          else
            AdrWord = AdrLWord;
        }
      }
      else
        AdrWord = EvalStrIntExpressionOffsWithFlags(pStartArg, Offset, UInt16, &OK, &Flags);
      if (OK)
      {
        if ((MModDir & Erl) && (Bit8 != 1) && ((Bit8 == 2) || (!(MModExt & Erl)) || (Hi(AdrWord) == 0)))
        {
          if ((Hi(AdrWord) != 0) && !mFirstPassUnknown(Flags))
          {
            WrError(ErrNum_NoShortAddr);
            ErrOcc = True;
          }
          else
          {
            AdrMode = ModDir;
            AdrPart = 1;
            AdrVals[AdrCnt++] = Lo(AdrWord);
          }
        }
        else if ((MModExt & Erl)!=0)
        {
          AdrMode = ModExt;
          AdrPart = 3;
          AdrVals[AdrCnt++] = Hi(AdrWord);
          AdrVals[AdrCnt++] = Lo(AdrWord);
        }
      }
      else
        ErrOcc = True;
    }
  }

  /* zwei Komponenten ? */

  else if (StartInd + 1 == StopInd)
  {
    Boolean IsX = !as_strcasecmp(ArgStr[StopInd].str.p_str, "X"),
            IsY = !as_strcasecmp(ArgStr[StopInd].str.p_str, "Y");

    /* indiziert ? */

    if (IsX || IsY)
    {
      if (MModInd & Erl)
      {
        AdrWord = EvalStrIntExpression(pStartArg, UInt8, &OK);
        if (OK)
        {
          if (IsY && !ChkMinCPUExt(CPU6811, ErrNum_AddrModeNotSupported))
            ErrOcc = True;
          else
          {
            AdrVals[AdrCnt++] = Lo(AdrWord);
            AdrMode = ModInd;
            AdrPart = 2;
            if (IsY)
            {
              BAsmCode[PrefCnt++] = 0x18;
            }
          }
        }
        else
          ErrOcc = True;
      }
    }
    else
    {
      WrStrErrorPos(ErrNum_InvReg, &ArgStr[StopInd]);
      ErrOcc = True;
    }
  }

  else
  {
    char Str[100];

    as_snprintf(Str, sizeof(Str), getmessage(Num_ErrMsgAddrArgCnt), 1, 2, StopInd - StartInd + 1);
    WrXError(ErrNum_WrongArgCnt, Str);
    ErrOcc = True;
  }

  if ((!ErrOcc) && (AdrMode == ModNone))
    WrError(ErrNum_InvAddrMode);
}

static void AddPrefix(Byte Prefix)
{
  BAsmCode[PrefCnt++] = Prefix;
}

static void Try2Split(int Src)
{
  char *p;
  size_t SrcLen;

  KillPrefBlanksStrComp(&ArgStr[Src]);
  KillPostBlanksStrComp(&ArgStr[Src]);
  SrcLen = strlen(ArgStr[Src].str.p_str);
  p = ArgStr[Src].str.p_str + SrcLen - 1;
  while ((p > ArgStr[Src].str.p_str) && !as_isspace(*p))
    p--;
  if (p > ArgStr[Src].str.p_str)
  {
    InsertArg(Src + 1, SrcLen);
    StrCompSplitRight(&ArgStr[Src], &ArgStr[Src + 1], p);
    KillPostBlanksStrComp(&ArgStr[Src]);
    KillPrefBlanksStrComp(&ArgStr[Src + 1]);
  }
}

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

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

  if (!ChkArgCnt(0, 0));
  else if (!ChkRangeCPU(forder->MinCPU, forder->MaxCPU));
  else if (Hi(forder->Code) != 0)
  {
    CodeLen = 2;
    BAsmCode[0] = Hi(forder->Code);
    BAsmCode[1] = Lo(forder->Code);
  }
  else
  {
    CodeLen = 1;
    BAsmCode[0] = Lo(forder->Code);
  }
}

static void DecodeRel(Word Index)
{
  const RelOrder *pOrder = &RelOrders[Index];
  Integer AdrInt;
  Boolean OK;
  tSymbolFlags Flags;

  if (ChkArgCnt(1, 1)
   && ChkMinCPU(pOrder->MinCPU))
  {
    AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[1], Int16, &OK, &Flags);
    if (OK)
    {
      AdrInt -= EProgCounter() + 2;
      if (((AdrInt < -128) || (AdrInt > 127)) && !mSymbolQuestionable(Flags)) WrError(ErrNum_JmpDistTooBig);
      else
      {
        CodeLen = 2;
        BAsmCode[0] = pOrder->Code;
        BAsmCode[1] = Lo(AdrInt);
      }
    }
  }
}

static void DecodeALU16(Word Index)
{
  const ALU16Order *forder = ALU16Orders + Index;

  OpSize = eSymbolSize16Bit;
  if (ChkArgCnt(1, 2)
   && ChkMinCPU(forder->MinCPU))
  {
    DecodeAdr(1, ArgCnt, (forder->MayImm ? MModImm : 0) | MModInd | MModExt | MModDir);
    if (AdrMode != ModNone)
    {
      switch (forder->PageShift)
      {
        case 1:
          if (PrefCnt == 1)
            BAsmCode[PrefCnt - 1] = Page4Prefix;
          else
            AddPrefix(Page3Prefix);
          break;
        case 2:
          if (PrefCnt == 1)
            BAsmCode[PrefCnt - 1] = Page4Prefix;
          break;
        case 3:
          if (PrefCnt == 0)
            AddPrefix((AdrMode == ModInd) ? Page3Prefix : Page2Prefix);
          break;
      }
      BAsmCode[PrefCnt] = forder->Code + (AdrPart << 4);
      CodeLen = PrefCnt + 1 + AdrCnt;
      memcpy(BAsmCode + 1 + PrefCnt, AdrVals, AdrCnt);
    }
  }
}

static void DecodeBit63(Word Code)
{
  if (ChkArgCnt(2, 3)
   && ChkExactCPU(CPU6301))
  {
    DecodeAdr(1, 1, MModImm);
    if (AdrMode != ModNone)
    {
      DecodeAdr(2, ArgCnt, MModDir | MModInd);
      if (AdrMode != ModNone)
      {
        BAsmCode[PrefCnt] = Code;
        if (AdrMode == ModDir)
          BAsmCode[PrefCnt] |= 0x10;
        CodeLen = PrefCnt + 1 + AdrCnt;
        memcpy(BAsmCode + 1 + PrefCnt, AdrVals, AdrCnt);
      }
    }
  }
}

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

  if (ChkArgCnt(1, 2))
  {
    DecodeAdr(1, ArgCnt, MModExt | MModInd);
    if (AdrMode != ModImm)
    {
      CodeLen = PrefCnt + 1 + AdrCnt;
      BAsmCode[PrefCnt] = 0x4e + (AdrPart << 4);
      memcpy(BAsmCode + 1 + PrefCnt, AdrVals, AdrCnt);
    }
  }
}

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

  if (ChkArgCnt(1, 2))
  {
    DecodeAdr(1, ArgCnt, MModExt | MModInd | ((MomCPU >= CPU6801) ? MModDir : 0));
    if (AdrMode != ModImm)
    {
      CodeLen=PrefCnt + 1 + AdrCnt;
      BAsmCode[PrefCnt] = 0x8d + (AdrPart << 4);
      memcpy(BAsmCode + 1 + PrefCnt, AdrVals, AdrCnt);
    }
  }
}

static void DecodeBRxx(Word Index)
{
  Boolean OK;
  Byte Mask;
  Integer AdrInt;

  if (ArgCnt == 1)
  {
    Try2Split(1);
    Try2Split(1);
  }
  else if (ArgCnt == 2)
  {
    Try2Split(ArgCnt);
    Try2Split(2);
  }
  if (ChkArgCnt(3, 4)
   && ChkMinCPU(CPU6811))
  {
    Mask = EvalStrIntExpressionOffs(&ArgStr[ArgCnt - 1], !!(*ArgStr[ArgCnt - 1].str.p_str == '#'), Int8, &OK);
    if (OK)
    {
      DecodeAdr(1, ArgCnt - 2, MModDir | MModInd);
      if (AdrMode != ModNone)
      {
        AdrInt = EvalStrIntExpression(&ArgStr[ArgCnt], Int16, &OK);
        if (OK)
        {
          AdrInt -= EProgCounter() + 3 + PrefCnt + AdrCnt;
          if ((AdrInt < -128) || (AdrInt > 127)) WrError(ErrNum_JmpDistTooBig);
          else
          {
            CodeLen = PrefCnt + 3 + AdrCnt;
            BAsmCode[PrefCnt] = 0x12 + Index;
            if (AdrMode == ModInd)
              BAsmCode[PrefCnt] += 12;
            memcpy(BAsmCode + PrefCnt + 1, AdrVals, AdrCnt);
            BAsmCode[PrefCnt + 1 + AdrCnt] = Mask;
            BAsmCode[PrefCnt + 2 + AdrCnt] = Lo(AdrInt);
          }
        }
      }
    }
  }
}

static void DecodeBxx(Word Index)
{
  Byte Mask;
  Boolean OK;
  int AddrStart, AddrEnd;
  tStrComp *pMaskArg;

  if (MomCPU == CPU6301)
  {
    pMaskArg = &ArgStr[1];
    AddrStart = 2;
    AddrEnd = ArgCnt;
  }
  else
  {
    if ((ArgCnt >= 1) && (ArgCnt <= 2)) Try2Split(ArgCnt);
    pMaskArg = &ArgStr[ArgCnt];
    AddrStart = 1;
    AddrEnd = ArgCnt - 1;
  }
  if (ChkArgCnt(2, 3)
   && ChkMinCPU(CPU6301))
  {
    Mask = EvalStrIntExpressionOffs(pMaskArg, !!(*pMaskArg->str.p_str == '#'),
                                    (MomCPU == CPU6301) ? UInt3 : Int8, &OK);
    if (OK && (MomCPU == CPU6301))
    {
      Mask = 1 << Mask;
      if (Index == 1) Mask = 0xff - Mask;
    }
    if (OK)
    {
      DecodeAdr(AddrStart, AddrEnd, MModDir | MModInd);
      if (AdrMode != ModNone)
      {
        CodeLen = PrefCnt + 2 + AdrCnt;
        if (MomCPU == CPU6301)
        {
          BAsmCode[PrefCnt] = 0x62 - Index;
          if (AdrMode == ModDir)
            BAsmCode[PrefCnt] += 0x10;
          BAsmCode[1 + PrefCnt] = Mask;
          memcpy(BAsmCode + 2 + PrefCnt, AdrVals, AdrCnt);
        }
        else
        {
          BAsmCode[PrefCnt] = 0x14 + Index;
          if (AdrMode == ModInd)
            BAsmCode[PrefCnt] += 8;
          memcpy(BAsmCode + 1 + PrefCnt, AdrVals, AdrCnt);
          BAsmCode[1 + PrefCnt + AdrCnt] = Mask;
        }
      }
    }
  }
}

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

  if (ChkArgCnt(2, 3)
   && ChkExactCPU(CPU6301))
  {
    AdrByte = EvalStrIntExpressionOffs(&ArgStr[1], !!(*ArgStr[1].str.p_str == '#'), UInt3, &OK);
    if (OK)
    {
      DecodeAdr(2, ArgCnt, MModDir | MModInd);
      if (AdrMode != ModNone)
      {
        CodeLen = PrefCnt + 2 + AdrCnt;
        BAsmCode[1 + PrefCnt] = 1 << AdrByte;
        memcpy(BAsmCode + 2 + PrefCnt, AdrVals, AdrCnt);
        BAsmCode[PrefCnt] = 0x65 + Index;
        if (AdrMode == ModDir)
          BAsmCode[PrefCnt] += 0x10;
      }
    }
  }
}

static void DecodeALU8(Word Code)
{
  Byte Reg;
  int MinArgCnt = Hi(Code) & 3;

  /* dirty hack: LDA/STA/ORA, and first arg is not A or B, treat like LDAA/STAA/ORAA: */

  if ((MinArgCnt == 2)
   && (as_toupper(OpPart.str.p_str[2]) == 'A')
   && (ArgCnt >= 1)
   && !DecodeAcc(ArgStr[1].str.p_str, &Reg))
    MinArgCnt = 1;

  if (ChkArgCnt(MinArgCnt, MinArgCnt + 1))
  {
    DecodeAdr(MinArgCnt , ArgCnt, ((Code & 0x8000) ? MModImm : 0) | MModInd | MModExt | MModDir);
    if (AdrMode != ModNone)
    {
      BAsmCode[PrefCnt] = Lo(Code) | (AdrPart << 4);
      if (MinArgCnt == 1)
      {
        AdrMode = ModAcc;
        AdrPart = (Code & 0x4000) >> 14;
      }
      else
        DecodeAdr(1, 1, MModAcc);
      if (AdrMode != ModNone)
      {
        BAsmCode[PrefCnt] |= AdrPart << 6;
        CodeLen = PrefCnt + 1 + AdrCnt;
        memcpy(BAsmCode + 1 + PrefCnt, AdrVals, AdrCnt);
      }
    }
  }
}

static void DecodeSing8(Word Code)
{
  if (ChkArgCnt(1, 2))
  {
    DecodeAdr(1, ArgCnt, MModAcc | MModExt | MModInd);
    if (AdrMode!=ModNone)
    {
      CodeLen = PrefCnt + 1 + AdrCnt;
      BAsmCode[PrefCnt] = Code | (AdrPart << 4);
      memcpy(BAsmCode + 1 + PrefCnt, AdrVals, AdrCnt);
    }
  }
}

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

static void DecodePSH_PUL(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    DecodeAdr(1, 1, MModAcc);
    if (AdrMode != ModNone)
    {
      CodeLen = 1;
      BAsmCode[0]=Code | AdrPart;
    }
  }
}

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

  if (ChkExactCPU(CPU68HC11K4))
  {
    printf("\nMMSIZ $%02x MMWBR $%02x MM1CR $%02x MM2CR $%02x INIT $%02x INIT2 $%02x CONFIG $%02x\n",
           (unsigned)Reg_MMSIZ, (unsigned)Reg_MMWBR, (unsigned)Reg_MM1CR, (unsigned)Reg_MM2CR,
           (unsigned)Reg_INIT, (unsigned)Reg_INIT2, (unsigned)Reg_CONFIG);
    cpu_2_phys_area_dump(SegCode, stdout);
  }
}

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

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

static void AddRel(const char *NName, CPUVar NMin, Word NCode)
{
  order_array_rsv_end(RelOrders, RelOrder);
  RelOrders[InstrZ].MinCPU = NMin;
  RelOrders[InstrZ].Code = NCode;
  AddInstTable(InstTable, NName, InstrZ++, DecodeRel);
}

static void AddALU8(const char *NamePlain, const char *NameA, const char *NameB, const char *NameB2, Boolean MayImm, Byte NCode)
{
  Word BaseCode = NCode | (MayImm ? 0x8000 : 0);

  AddInstTable(InstTable, NamePlain, BaseCode | (2 << 8), DecodeALU8);
  AddInstTable(InstTable, NameA, BaseCode | (1 << 8), DecodeALU8);
  AddInstTable(InstTable, NameB, BaseCode | (1 << 8) | 0x4000, DecodeALU8);
  if (NameB2)
    AddInstTable(InstTable, NameB2, BaseCode | (1 << 8) | 0x4000, DecodeALU8);
}

static void AddALU16(const char *NName, Boolean NMay, CPUVar NMin, Byte NShift, Byte NCode)
{
  order_array_rsv_end(ALU16Orders, ALU16Order);
  ALU16Orders[InstrZ].MayImm = NMay;
  ALU16Orders[InstrZ].MinCPU = NMin;
  ALU16Orders[InstrZ].PageShift = NShift;
  ALU16Orders[InstrZ].Code = NCode;
  AddInstTable(InstTable, NName, InstrZ++, DecodeALU16);
}

static void AddSing8(const char *NamePlain, const char *NameA, const char *NameB, Byte NCode)
{
  AddInstTable(InstTable, NamePlain, NCode, DecodeSing8);
  AddInstTable(InstTable, NameA, NCode | 0, DecodeSing8_Acc);
  AddInstTable(InstTable, NameB, NCode | 0x10, DecodeSing8_Acc);
}

static void InitFields(void)
{
  InstTable = CreateInstTable(317);
  AddInstTable(InstTable, "JMP"  , 0, DecodeJMP);
  AddInstTable(InstTable, "JSR"  , 0, DecodeJSR);
  AddInstTable(InstTable, "BRCLR", 1, DecodeBRxx);
  AddInstTable(InstTable, "BRSET", 0, DecodeBRxx);
  AddInstTable(InstTable, "BCLR" , 1, DecodeBxx);
  AddInstTable(InstTable, "BSET" , 0, DecodeBxx);
  AddInstTable(InstTable, "BTST" , 6, DecodeBTxx);
  AddInstTable(InstTable, "BTGL" , 0, DecodeBTxx);

  InstrZ = 0;
  AddFixed("ABA"  ,CPU6800, CPU68HC11K4, 0x001b); AddFixed("ABX"  ,CPU6801, CPU68HC11K4, 0x003a);
  AddFixed("ABY"  ,CPU6811, CPU68HC11K4, 0x183a); AddFixed("ASLD" ,CPU6801, CPU68HC11K4, 0x0005);
  AddFixed("CBA"  ,CPU6800, CPU68HC11K4, 0x0011); AddFixed("CLC"  ,CPU6800, CPU68HC11K4, 0x000c);
  AddFixed("CLI"  ,CPU6800, CPU68HC11K4, 0x000e); AddFixed("CLV"  ,CPU6800, CPU68HC11K4, 0x000a);
  AddFixed("DAA"  ,CPU6800, CPU68HC11K4, 0x0019); AddFixed("DES"  ,CPU6800, CPU68HC11K4, 0x0034);
  AddFixed("DEX"  ,CPU6800, CPU68HC11K4, 0x0009); AddFixed("DEY"  ,CPU6811, CPU68HC11K4, 0x1809);
  AddFixed("FDIV" ,CPU6811, CPU68HC11K4, 0x0003); AddFixed("IDIV" ,CPU6811, CPU68HC11K4, 0x0002);
  AddFixed("INS"  ,CPU6800, CPU68HC11K4, 0x0031); AddFixed("INX"  ,CPU6800, CPU68HC11K4, 0x0008);
  AddFixed("INY"  ,CPU6811, CPU68HC11K4, 0x1808); AddFixed("LSLD" ,CPU6801, CPU68HC11K4, 0x0005);
  AddFixed("LSRD" ,CPU6801, CPU68HC11K4, 0x0004); AddFixed("MUL"  ,CPU6801, CPU68HC11K4, 0x003d);
  AddFixed("NOP"  ,CPU6800, CPU68HC11K4, 0x0001); AddFixed("PSHX" ,CPU6801, CPU68HC11K4, 0x003c);
  AddFixed("PSHY" ,CPU6811, CPU68HC11K4, 0x183c); AddFixed("PULX" ,CPU6801, CPU68HC11K4, 0x0038);
  AddFixed("PULY" ,CPU6811, CPU68HC11K4, 0x1838); AddFixed("RTI"  ,CPU6800, CPU68HC11K4, 0x003b);
  AddFixed("RTS"  ,CPU6800, CPU68HC11K4, 0x0039); AddFixed("SBA"  ,CPU6800, CPU68HC11K4, 0x0010);
  AddFixed("SEC"  ,CPU6800, CPU68HC11K4, 0x000d); AddFixed("SEI"  ,CPU6800, CPU68HC11K4, 0x000f);
  AddFixed("SEV"  ,CPU6800, CPU68HC11K4, 0x000b); AddFixed("SLP"  ,CPU6301, CPU6301    , 0x001a);
  AddFixed("STOP" ,CPU6811, CPU68HC11K4, 0x00cf); AddFixed("SWI"  ,CPU6800, CPU68HC11K4, 0x003f);
  AddFixed("TAB"  ,CPU6800, CPU68HC11K4, 0x0016); AddFixed("TAP"  ,CPU6800, CPU68HC11K4, 0x0006);
  AddFixed("TBA"  ,CPU6800, CPU68HC11K4, 0x0017); AddFixed("TPA"  ,CPU6800, CPU68HC11K4, 0x0007);
  AddFixed("TSX"  ,CPU6800, CPU68HC11K4, 0x0030); AddFixed("TSY"  ,CPU6811, CPU68HC11K4, 0x1830);
  AddFixed("TXS"  ,CPU6800, CPU68HC11K4, 0x0035); AddFixed("TYS"  ,CPU6811, CPU68HC11K4, 0x1835);
  AddFixed("WAI"  ,CPU6800, CPU68HC11K4, 0x003e);
  AddFixed("XGDX" ,CPU6301, CPU68HC11K4, (MomCPU == CPU6301) ? 0x0018 : 0x008f);
  AddFixed("XGDY" ,CPU6811, CPU68HC11K4, 0x188f);

  InstrZ = 0;
  AddRel("BCC", CPU6800, 0x24);
  AddRel("BCS", CPU6800, 0x25);
  AddRel("BEQ", CPU6800, 0x27);
  AddRel("BGE", CPU6800, 0x2c);
  AddRel("BGT", CPU6800, 0x2e);
  AddRel("BHI", CPU6800, 0x22);
  AddRel("BHS", CPU6800, 0x24);
  AddRel("BLE", CPU6800, 0x2f);
  AddRel("BLO", CPU6800, 0x25);
  AddRel("BLS", CPU6800, 0x23);
  AddRel("BLT", CPU6800, 0x2d);
  AddRel("BMI", CPU6800, 0x2b);
  AddRel("BNE", CPU6800, 0x26);
  AddRel("BPL", CPU6800, 0x2a);
  AddRel("BRA", CPU6800, 0x20);
  AddRel("BRN", CPU6801, 0x21);
  AddRel("BSR", CPU6800, 0x8d);
  AddRel("BVC", CPU6800, 0x28);
  AddRel("BVS", CPU6800, 0x29);

  AddALU8("ADC", "ADCA", "ADCB", NULL , True , 0x89);
  AddALU8("ADD", "ADDA", "ADDB", NULL , True , 0x8b);
  AddALU8("AND", "ANDA", "ANDB", NULL , True , 0x84);
  AddALU8("BIT", "BITA", "BITB", NULL , True , 0x85);
  AddALU8("CMP", "CMPA", "CMPB", NULL , True , 0x81);
  AddALU8("EOR", "EORA", "EORB", NULL , True , 0x88);
  AddALU8("LDA", "LDAA", "LDAB", "LDB", True , 0x86);
  AddALU8("ORA", "ORAA", "ORAB", "ORB", True , 0x8a);
  AddALU8("SBC", "SBCA", "SBCB", NULL , True , 0x82);
  AddALU8("STA", "STAA", "STAB", "STB", False, 0x87);
  AddALU8("SUB", "SUBA", "SUBB", NULL , True , 0x80);

  InstrZ = 0;
  AddALU16("ADDD", True , CPU6801, 0, 0xc3);
  AddALU16("CPD" , True , CPU6811, 1, 0x83);
  AddALU16("CMPD", True , CPU6811, 1, 0x83);
  AddALU16("CPX" , True , CPU6800, 2, 0x8c);
  AddALU16("CMPX", True , CPU6800, 2, 0x8c);
  AddALU16("CPY" , True , CPU6811, 3, 0x8c);
  AddALU16("CMPY", True , CPU6811, 3, 0x8c);
  AddALU16("LDD" , True , CPU6801, 0, 0xcc);
  AddALU16("LDS" , True , CPU6800, 0, 0x8e);
  AddALU16("LDX" , True , CPU6800, 2, 0xce);
  AddALU16("LDY" , True , CPU6811, 3, 0xce);
  AddALU16("STD" , False, CPU6801, 0, 0xcd);
  AddALU16("STS" , False, CPU6800, 0, 0x8f);
  AddALU16("STX" , False, CPU6800, 2, 0xcf);
  AddALU16("STY" , False, CPU6811, 3, 0xcf);
  AddALU16("SUBD", True , CPU6801, 0, 0x83);

  AddSing8("ASL", "ASLA", "ASLB", 0x48);
  AddSing8("ASR", "ASRA", "ASRB", 0x47);
  AddSing8("CLR", "CLRA", "CLRB", 0x4f);
  AddSing8("COM", "COMA", "COMB", 0x43);
  AddSing8("DEC", "DECA", "DECB", 0x4a);
  AddSing8("INC", "INCA", "INCB", 0x4c);
  AddSing8("LSL", "LSLA", "LSLB", 0x48);
  AddSing8("LSR", "LSRA", "LSRB", 0x44);
  AddSing8("NEG", "NEGA", "NEGB", 0x40);
  AddSing8("ROL", "ROLA", "ROLB", 0x49);
  AddSing8("ROR", "RORA", "RORB", 0x46);
  AddSing8("TST", "TSTA", "TSTB", 0x4d);

  AddInstTable(InstTable, "PSH" , 0x36, DecodePSH_PUL);
  AddInstTable(InstTable, "PSHA", 0x36, DecodeSing8_Acc);
  AddInstTable(InstTable, "PSHB", 0x37, DecodeSing8_Acc);
  AddInstTable(InstTable, "PUL" , 0x32, DecodePSH_PUL);
  AddInstTable(InstTable, "PULA", 0x32, DecodeSing8_Acc);
  AddInstTable(InstTable, "PULB", 0x33, DecodeSing8_Acc);

  AddInstTable(InstTable, "AIM", 0x61, DecodeBit63);
  AddInstTable(InstTable, "EIM", 0x65, DecodeBit63);
  AddInstTable(InstTable, "OIM", 0x62, DecodeBit63);
  AddInstTable(InstTable, "TIM", 0x6b, DecodeBit63);

  AddInstTable(InstTable, "PRWINS", 0, DecodePRWINS);

  init_moto8_pseudo(InstTable, e_moto_8_be | e_moto_8_db | e_moto_8_dw);
}

static void DeinitFields(void)
{
  DestroyInstTable(InstTable);
  order_array_free(FixedOrders);
  order_array_free(RelOrders);
  order_array_free(ALU16Orders);
}

static Boolean DecodeAttrPart_68(void)
{
  if (strlen(AttrPart.str.p_str) > 1)
  {
    WrStrErrorPos(ErrNum_UndefAttr, &AttrPart);
    return False;
  }
  return DecodeMoto16AttrSize(*AttrPart.str.p_str, &AttrPartOpSize[0], False);
}

static void MakeCode_68(void)
{
  CodeLen = 0;
  DontPrint = False;
  PrefCnt = 0;
  AdrCnt = 0;

  /* Operandengroesse festlegen */

  OpSize = (AttrPartOpSize[0] != eSymbolSizeUnknown) ? AttrPartOpSize[0] : eSymbolSize8Bit;

  /* zu ignorierendes */

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

  /* Pseudoanweisungen */

  if (DecodeMoto16Pseudo(OpSize, True))
    return;

  /* gehashtes */

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

static void InitCode_68(void)
{
  Reg_MMSIZ = Reg_MMWBR = Reg_MM1CR = Reg_MM2CR = 0;
}

static Boolean IsDef_68(void)
{
  return False;
}

static void SwitchTo_68(void)
{
  TurnWords = False;
  SetIntConstMode(eIntConstModeMoto);

  PCSymbol = "*";
  HeaderID = 0x61;
  NOPCode = 0x01;
  DivideChars = ",";
  HasAttrs = True;
  AttrChars = ".";

  ValidSegs = 1 << SegCode;
  Grans[SegCode] = 1; ListGrans[SegCode] = 1; SegInits[SegCode] = 0;
  SegLimits[SegCode] = (MomCPU == CPU68HC11K4) ? 0x10ffffl : 0xffff;

  DecodeAttrPart = DecodeAttrPart_68;
  MakeCode = MakeCode_68;
  IsDef = IsDef_68;
  SwitchFrom = DeinitFields;
  InitFields();
  AddMoto16PseudoONOFF(False);

  if (MomCPU == CPU68HC11K4)
  {
    static const ASSUMERec ASSUMEHC11s[] =
    {
      {"MMSIZ" , &Reg_MMSIZ , 0, 0xff, 0, SetK4Ranges},
      {"MMWBR" , &Reg_MMWBR , 0, 0xff, 0, SetK4Ranges},
      {"MM1CR" , &Reg_MM1CR , 0, 0xff, 0, SetK4Ranges},
      {"MM2CR" , &Reg_MM2CR , 0, 0xff, 0, SetK4Ranges},
      {"INIT"  , &Reg_INIT  , 0, 0xff, 0, SetK4Ranges},
      {"INIT2" , &Reg_INIT2 , 0, 0xff, 0, SetK4Ranges},
      {"CONFIG", &Reg_CONFIG, 0, 0xff, 0, SetK4Ranges},
    };

    pASSUMERecs = ASSUMEHC11s;
    ASSUMERecCnt = as_array_size(ASSUMEHC11s);

    SetK4Ranges();
  }
  else
    cpu_2_phys_area_clear(SegCode);
}

void code68_init(void)
{
  CPU6800 = AddCPU("6800", SwitchTo_68);
  CPU6801 = AddCPU("6801", SwitchTo_68);
  CPU6301 = AddCPU("6301", SwitchTo_68);
  CPU6811 = AddCPU("6811", SwitchTo_68);
  CPU68HC11K4 = AddCPU("68HC11K4", SwitchTo_68);

  AddInitPassProc(InitCode_68);
}