/* codeh8_3.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator H8/300(L/H)                                                 */
/*                                                                           */
/*****************************************************************************/

#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 "onoff_common.h"
#include "asmstructs.h"
#include "asmitree.h"
#include "codepseudo.h"
#include "motpseudo.h"
#include "codevars.h"
#include "errmsg.h"
#include "headids.h"

#include "codeh8_3.h"

#define ModNone (-1)
#define ModReg 0
#define MModReg (1 << ModReg)
#define ModImm 1
#define MModImm (1 << ModImm)
#define ModAbs8 2
#define MModAbs8 (1 << ModAbs8)
#define ModAbs16 3
#define MModAbs16 (1 << ModAbs16)
#define ModAbs24 4
#define MModAbs24 (1 << ModAbs24)
#define MModAbs (MModAbs8 | MModAbs16 | MModAbs24)
#define ModIReg 5
#define MModIReg (1 << ModIReg)
#define ModPreDec 6
#define MModPreDec (1 << ModPreDec)
#define ModPostInc 7
#define MModPostInc (1 << ModPostInc)
#define ModInd16 8
#define MModInd16 (1 << ModInd16)
#define ModInd24 9
#define MModInd24 (1 << ModInd24)
#define ModIIAbs 10
#define MModIIAbs (1 << ModIIAbs)
#define MModInd (MModInd16 | MModInd24)

/* keep in the same order as in registration */

#define M_CPUH8_300L  (1 << 0)
#define M_CPU6413308  (1 << 1)
#define M_CPUH8_300   (1 << 2)
#define M_CPU6413309  (1 << 3)
#define M_CPUH8_300H  (1 << 4)

#define REG_SP 7

static tSymbolSize OpSize, MomSize;
static ShortInt AdrMode;    /* Ergebnisadressmodus */
static Byte AdrPart;        /* Adressierungsmodusbits im Opcode */
static Word AdrVals[6];     /* Adressargument */

static CPUVar CPUH8_300L;
static CPUVar CPU6413308,CPUH8_300;
static CPUVar CPU6413309,CPUH8_300H;
static Boolean CPU16;       /* keine 32-Bit-Register */

/*-------------------------------------------------------------------------*/
/* Adressparsing */

static void SetOpSize(tSymbolSize Size)
{
  if (OpSize == eSymbolSizeUnknown)
    OpSize = Size;
  else if (Size != OpSize)
  {
    WrError(ErrNum_ConfOpSizes);
    AdrMode = ModNone;
    AdrCnt = 0;
  }
}

static Boolean IsNum(char Inp, Byte *Erg)
{
  if ((Inp < '0') || (Inp > '7'))
    return False;
  else
  {
    *Erg = Inp - AscOfs;
    return True;
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeRegCore(char *pArg, Byte *pResult, tSymbolSize *pSize)
 * \brief  check whether argument is a CPU register
 * \param  pArg source argument
 * \param  pResult register # if yes
 * \param  pSize register size if yes
 * \return True if it is a register
 * ------------------------------------------------------------------------ */

static Boolean DecodeRegCore(char *pArg, Byte *pResult, tSymbolSize *pSize)
{
  if (!as_strcasecmp(pArg, "SP"))
  {
    *pResult = REG_SP | REGSYM_FLAG_ALIAS;
    *pSize = MaxMode ? eSymbolSize32Bit : eSymbolSize16Bit;
    return True;
  }

  switch (strlen(pArg))
  {
    case 2:
      if (IsNum(pArg[1], pResult))
      {
        if (as_toupper(*pArg) == 'R')
        {
          *pSize = eSymbolSize16Bit;
          return True;
        }
        else if (as_toupper(*pArg) == 'E')
        {
          *pResult += 8;
          *pSize = eSymbolSize16Bit;
          return True;
        }
      }
      break;
    case 3:
      if ((as_toupper(*pArg) == 'R') && IsNum(pArg[1], pResult))
      {
        if (as_toupper(pArg[2]) == 'L')
        {
          *pResult += 8;
          *pSize = eSymbolSize8Bit;
          return True;
        }
        else if (as_toupper(pArg[2]) == 'H')
        {
          *pSize = eSymbolSize8Bit;
          return True;
        }
      }
      else if ((as_toupper(*pArg) == 'E') && (as_toupper(pArg[1]) == 'R') && IsNum(pArg[2], pResult))
      {
        *pSize = eSymbolSize32Bit;
        return True;
      }
  }

  *pSize = eSymbolSizeUnknown;
  return False;
}

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

static void DissectReg_H8_3(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
{
  switch (InpSize)
  {
    case eSymbolSize8Bit:
      as_snprintf(pDest, DestSize, "R%u%c", (unsigned)(Value & 7), "HL"[(Value >> 3) & 1]);
      break;
    case eSymbolSize16Bit:
      if (Value == (REG_SP | REGSYM_FLAG_ALIAS))
        as_snprintf(pDest, DestSize, "SP");
      else
        as_snprintf(pDest, DestSize, "%c%u", "RE"[(Value >> 3) & 1], (unsigned)(Value & 7));
      break;
    case eSymbolSize32Bit:
      if (Value == (REG_SP | REGSYM_FLAG_ALIAS))
        as_snprintf(pDest, DestSize, "SP");
      else
        as_snprintf(pDest, DestSize, "ER%u", (unsigned)Value);
      break;
    default:
      as_snprintf(pDest, DestSize, "%d-%u", (int)InpSize, (unsigned)Value);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeReg(const tStrComp *pArg, Byte *pResult, tSymbolSize ReqSize, tSymbolSize *pSize)
 * \brief  check whether argument is a CPU register or register alias
 * \param  pArg source argument
 * \param  pResult register # if yes
 * \param  SizeMask requested register size(s)
 * \param  pSize register size if yes
 * \return reg eval result
 * ------------------------------------------------------------------------ */

static tRegEvalResult DecodeReg(const tStrComp *pArg, Byte *pResult, unsigned SizeMask, tSymbolSize *pSize, Boolean MustBeReg)
{
  tRegDescr RegDescr;
  tEvalResult EvalResult;
  tRegEvalResult RegEvalResult;

  if (DecodeRegCore(pArg->str.p_str, pResult, pSize))
  {
    RegEvalResult = eIsReg;
    *pResult &= ~REGSYM_FLAG_ALIAS;
  }
  else
  {
    RegEvalResult = EvalStrRegExpressionAsOperand(pArg, &RegDescr, &EvalResult, eSymbolSizeUnknown, MustBeReg);
    *pSize = EvalResult.DataSize;
    *pResult = RegDescr.Reg & ~REGSYM_FLAG_ALIAS;
  }

  if ((RegEvalResult == eIsReg)
   && !((SizeMask >> *pSize) & 1))
  {
    WrStrErrorPos(ErrNum_InvOpSize, pArg);
    return MustBeReg ? eIsNoReg : eRegAbort;
  }

  return RegEvalResult;
}

static void CutSize(tStrComp *pArg)
{
  int ArgLen = strlen(pArg->str.p_str);

  if ((ArgLen >= 2) && !strcmp(pArg->str.p_str + ArgLen - 2, ":8"))
  {
    StrCompShorten(pArg, 2);
    MomSize = eSymbolSize8Bit;
  }
  else if ((ArgLen >= 3) && !strcmp(pArg->str.p_str + ArgLen - 3, ":16"))
  {
    StrCompShorten(pArg, 3);
    MomSize = eSymbolSize16Bit;
  }
  else if ((ArgLen >= 3) && !strcmp(pArg->str.p_str + ArgLen - 3, ":24"))
  {
    StrCompShorten(pArg, 3);
    MomSize = eSymbolSize24Bit;
  }
}

static Boolean ChkCPU32(tErrorNum ErrorNum)
{
  return ChkMinCPUExt(CPU6413309, ErrorNum);
}

static Byte DecodeBaseReg(const tStrComp *pArg, Byte *Erg, Boolean MustBeReg)
{
  tSymbolSize HSize;
  Word Mask;

  switch (DecodeReg(pArg, Erg, (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), &HSize, MustBeReg))
  {
    case eIsNoReg:
      return 0;
    case eRegAbort:
      return 1;
    default:
      break;
  }
  if ((HSize == eSymbolSize16Bit) && (*Erg > 7))
  {
    WrStrErrorPos(ErrNum_InvReg, pArg);
    return 1;
  }
  Mask = (HSize == eSymbolSize16Bit) ? (M_CPUH8_300L | M_CPU6413308 | M_CPUH8_300) : (M_CPU6413309 | M_CPUH8_300H);
  if (ChkExactCPUMaskExt(Mask, CPUH8_300L, ErrNum_AddrModeNotSupported) < 0)
    return 1;
  return 2;
}

static Boolean Is8(LongInt Address)
{
  if (CPU16)
    return (((Address >> 8) & 0xff) == 0xff);
  else
    return (((Address >> 8) & 0xffff) == 0xffff);
}

static Boolean Is16(LongInt Address)
{
  return (CPU16) ? (True) : (((Address >= 0) && (Address <= 0x7fff)) || ((Address >= 0xff8000) && (Address <= 0xffffff)));
}

static void DecideVAbsolute(LongInt Address, Word Mask)
{
  /* bei Automatik Operandengroesse festlegen */

  if (MomSize == eSymbolSizeUnknown)
  {
    if (Is8(Address))
      MomSize = eSymbolSize8Bit;
    else if (Is16(Address))
      MomSize = eSymbolSize16Bit;
    else
      MomSize = eSymbolSize24Bit;
  }

  /* wenn nicht vorhanden, eins rauf */

  if ((MomSize == eSymbolSize8Bit) && ((Mask & MModAbs8) == 0))
    MomSize = eSymbolSize16Bit;
  if ((MomSize == eSymbolSize16Bit) && ((Mask & MModAbs16) == 0))
    MomSize = eSymbolSize24Bit;

  /* entsprechend Modus Bytes ablegen */

  switch (MomSize)
  {
    case eSymbolSize8Bit:
      if (!Is8(Address)) WrError(ErrNum_AdrOverflow);
      else
      {
        AdrCnt = 2;
        AdrVals[0] = Address & 0xff;
        AdrMode = ModAbs8;
      }
      break;
    case eSymbolSize16Bit:
      if (!Is16(Address)) WrError(ErrNum_AdrOverflow);
      else
      {
        AdrCnt = 2;
        AdrVals[0] = Address & 0xffff;
        AdrMode = ModAbs16;
      }
      break;
    case eSymbolSize24Bit:
      AdrCnt = 4;
      AdrVals[1] = Address & 0xffff;
      AdrVals[0] = Lo(Address >> 16);
      AdrMode = ModAbs24;
      break;
    default:
      WrError(ErrNum_InternalError);
  }
}

static void DecideAbsolute(const tStrComp *pArg, Word Mask)
{
  LongInt Addr;
  Boolean OK;

  Addr = EvalStrIntExpression(pArg, Int32, &OK);
  if (OK)
    DecideVAbsolute(Addr, Mask);
}


static void DecodeAdr(tStrComp *pArg, Word Mask)
{
  tSymbolSize HSize;
  Byte HReg;
  LongInt HLong;
  Boolean OK;
  char *p;
  LongInt DispAcc;
  int ArgLen;

  AdrMode = ModNone;
  AdrCnt = 0;
  MomSize = eSymbolSizeUnknown;

  /* immediate ? */

  if (*pArg->str.p_str == '#')
  {
    switch (OpSize)
    {
      case eSymbolSizeUnknown:
        WrError(ErrNum_UndefOpSizes);
        break;
      case eSymbolSize8Bit:
        HReg = EvalStrIntExpressionOffs(pArg, 1, Int8, &OK);
        if (OK)
        {
          AdrCnt = 2;
          AdrVals[0] = HReg;
          AdrMode = ModImm;
        }
        break;
      case eSymbolSize16Bit:
        AdrVals[0] = EvalStrIntExpressionOffs(pArg, 1, Int16, &OK);
        if (OK)
        {
          AdrCnt = 2;
          AdrMode = ModImm;
        }
        break;
      case eSymbolSize32Bit:
        HLong = EvalStrIntExpressionOffs(pArg, 1, Int32, &OK);
        if (OK)
        {
          AdrCnt = 4;
          AdrVals[0] = HLong >> 16;
          AdrVals[1] = HLong & 0xffff;
          AdrMode = ModImm;
        }
        break;
      default:
        WrError(ErrNum_InvOpSize);
    }
    goto chk;
  }

  /* Register ? */

  switch (DecodeReg(pArg, &HReg, (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), &HSize, False))
  {
    case eIsReg:
      AdrMode = ModReg;
      AdrPart = HReg;
      SetOpSize(HSize);
      goto chk;
    case eRegAbort:
      return;
    case eIsNoReg:
      break;
  }

  /* indirekt ? */

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

    StrCompRefRight(&Arg, pArg, 1);

    if (*Arg.str.p_str == '@')
    {
      AdrVals[0] = EvalStrIntExpressionOffs(&Arg, 1, UInt8, &OK) & 0xff;
      if (OK)
      {
        AdrCnt = 1;
        AdrMode = ModIIAbs;
      }
      goto chk;
    }

    switch (DecodeBaseReg(&Arg, &AdrPart, False))
    {
      case 1:
        goto chk;
      case 2:
        AdrMode = ModIReg;
        goto chk;
    }

    if (*Arg.str.p_str == '-')
    {
      tStrComp Reg;

      StrCompRefRight(&Reg, &Arg, 1);
      switch (DecodeBaseReg(&Reg, &AdrPart, True))
      {
        case 1:
          goto chk;
        case 2:
          AdrMode = ModPreDec;
          goto chk;
      }
    }

    ArgLen = strlen(Arg.str.p_str);
    if (*Arg.str.p_str && (Arg.str.p_str[ArgLen - 1] == '+'))
    {
      StrCompShorten(&Arg, 1);
      switch (DecodeBaseReg(&Arg, &AdrPart, True))
      {
        case 1:
          goto chk;
        case 2:
         AdrMode = ModPostInc;
         goto chk;
      }
      Arg.str.p_str[ArgLen - 1] = '+'; Arg.Pos.Len++;
    }

    if (IsIndirect(Arg.str.p_str))
    {
      tStrComp Part, Remainder;

      StrCompRefRight(&Part, &Arg, 1);
      StrCompShorten(&Part, 1);

      AdrPart = 0xff;
      DispAcc = 0;
      do
      {
        p = QuotPos(Part.str.p_str, ',');
        if (p)
          StrCompSplitRef(&Part, &Remainder, &Part, p);
        switch (DecodeBaseReg(&Part, &HReg, False))
        {
          case 2:
            if (AdrPart != 0xff)
            {
              WrError(ErrNum_InvAddrMode);
              goto chk;
            }
            else
              AdrPart = HReg;
            break;
          case 1:
            goto chk;
          case 0:
            CutSize(&Part);
            DispAcc += EvalStrIntExpression(&Part, Int32, &OK);
            if (!OK)
            {
              goto chk;
            }
            break;
        }
        if (p)
          Part = Remainder;
      }
      while (p);

      if (AdrPart == 0xff)
        DecideVAbsolute(DispAcc, Mask);
      else
      {
        if ((CPU16) && ((DispAcc & 0xffff8000) == 0x8000))
          DispAcc += 0xffff0000;
        if (MomSize == eSymbolSizeUnknown)
          MomSize = ((DispAcc >= -32768) && (DispAcc <= 32767)) ? eSymbolSize16Bit : eSymbolSize24Bit;
        switch (MomSize)
        {
          case eSymbolSize8Bit:
            WrError(ErrNum_InvOpSize);
            break;
          case eSymbolSize16Bit:
            if (ChkRange(DispAcc, -32768, 32767))
            {
              AdrCnt = 2;
              AdrVals[0] = DispAcc & 0xffff;
              AdrMode = ModInd16;
            }
            break;
          case eSymbolSize24Bit:
            AdrVals[1] = DispAcc & 0xffff;
            AdrVals[0] = Lo(DispAcc >> 16);
            AdrCnt = 4;
            AdrMode = ModInd24;
            break;
          default:
            WrError(ErrNum_InternalError);
        }
      }
    }
    else
    {
      CutSize(&Arg);
      DecideAbsolute(&Arg, Mask);
    }
    goto chk;
  }

  CutSize(pArg);
  DecideAbsolute(pArg, Mask);

chk:
  if (((AdrMode == ModReg) && (OpSize == eSymbolSize32Bit))
   || ((AdrMode == ModReg) && (OpSize == eSymbolSize16Bit) && (AdrPart > 7))
   || (AdrMode == ModAbs24)
   || (AdrMode == ModInd24))
  {
    if (!ChkMinCPUExt(CPU6413309, ErrNum_AddrModeNotSupported))
    {
      AdrMode = ModNone;
      AdrCnt = 0;
    }
  }
  if ((AdrMode != ModNone) && ((Mask & (1 << AdrMode)) == 0))
  {
    WrError(ErrNum_InvAddrMode);
    AdrMode = ModNone;
    AdrCnt = 0;
  }
}

static LongInt ImmVal(void)
{
  switch (OpSize)
  {
    case eSymbolSize8Bit:
      return Lo(AdrVals[0]);
    case eSymbolSize16Bit:
      return AdrVals[0];
    case eSymbolSize32Bit:
      return (((LongInt)AdrVals[0]) << 16) + AdrVals[1];
    default:
      WrError(ErrNum_InternalError);
      return 0;
  }
}

/*--------------------------------------------------------------------------*/
/* Bit Symbol Handling */

/*
 * Compact representation of bits in symbol table:
 * Bits 10...3: Absolute address (8-bit value for range $FFxx or $FFFFxx)
 * Bits 0..2: Bit position
 */

/*!------------------------------------------------------------------------
 * \fn     EvalBitPosition(const tStrComp *pArg, Boolean *pOK)
 * \brief  evaluate bit position
 * \param  bit position argument (with or without #)
 * \param  pOK parsing OK?
 * \return numeric bit position
 * ------------------------------------------------------------------------ */

static LongWord EvalBitPosition(const tStrComp *pArg, Boolean *pOK)
{
  return EvalStrIntExpressionOffs(pArg, !!(*pArg->str.p_str == '#'), UInt3, pOK);
}

/*!------------------------------------------------------------------------
 * \fn     AssembleBitSymbol(Byte BitPos, LongWord Address)
 * \brief  build the compact internal representation of a bit symbol
 * \param  BitPos bit position in byte
 * \param  Address register address
 * \return compact representation
 * ------------------------------------------------------------------------ */

static LongWord AssembleBitSymbol(Byte BitPos, Word Address)
{
  return
    (Address << 3)
  | (BitPos << 0);
}

/*!------------------------------------------------------------------------
 * \fn     DecodeBitArg2(LongWord *pResult, const tStrComp *pBitArg, tStrComp *pRegArg)
 * \brief  encode a bit symbol, address & bit position separated
 * \param  pResult resulting encoded bit
 * \param  pRegArg register argument
 * \param  pBitArg bit argument
 * \return True if success
 * ------------------------------------------------------------------------ */

static Boolean DecodeBitArg2(LongWord *pResult, const tStrComp *pBitArg, tStrComp *pRegArg)
{
  Boolean OK;
  LongWord BitPos;

  BitPos = EvalBitPosition(pBitArg, &OK);
  if (!OK)
    return False;

  DecideAbsolute(pRegArg, MModAbs8);
  if (AdrMode != ModAbs8)
    return False;

  *pResult = AssembleBitSymbol(BitPos, AdrVals[0]);
  return True;
}

/*!------------------------------------------------------------------------
 * \fn     DecodeBitArg(LongWord *pResult, int Start, int Stop)
 * \brief  encode a bit symbol from instruction argument(s)
 * \param  pResult resulting encoded bit
 * \param  Start first argument
 * \param  Stop last argument
 * \return True if success
 * ------------------------------------------------------------------------ */

static Boolean DecodeBitArg(LongWord *pResult, int Start, int Stop)
{
  *pResult = 0;

  /* Just one argument -> parse as bit argument */

  if (Start == Stop)
  {
    tEvalResult EvalResult;

    *pResult = EvalStrIntExpressionWithResult(&ArgStr[Start], UInt32, &EvalResult);
    if (EvalResult.OK)
      ChkSpace(SegBData, EvalResult.AddrSpaceMask);
    return EvalResult.OK;
  }

  /* register & bit position are given as separate arguments */

  else if (Stop == Start + 1)
    return DecodeBitArg2(pResult, &ArgStr[Start], &ArgStr[Stop]);

  /* other # of arguments not allowed */

  else
  {
    WrError(ErrNum_WrongArgCnt);
    return False;
  }
}

/*!------------------------------------------------------------------------
 * \fn     DissectBitSymbol(LongWord BitSymbol, Word *pAddress, Byte *pBitPos)
 * \brief  transform compact representation of bit (field) symbol into components
 * \param  BitSymbol compact storage
 * \param  pAddress register address
 * \param  pBitPos bit position
 * \return constant True
 * ------------------------------------------------------------------------ */

static Boolean DissectBitSymbol(LongWord BitSymbol, LongWord *pAddress, Byte *pBitPos)
{
  *pAddress = (BitSymbol >> 3) & 0xfful;
  *pBitPos = BitSymbol & 7;
  return True;
}

/*!------------------------------------------------------------------------
 * \fn     DissectBit_H8_3(char *pDest, size_t DestSize, LargeWord Inp)
 * \brief  dissect compact storage of bit (field) into readable form for listing
 * \param  pDest destination for ASCII representation
 * \param  DestSize destination buffer size
 * \param  Inp compact storage
 * ------------------------------------------------------------------------ */

static void DissectBit_H8_3(char *pDest, size_t DestSize, LargeWord Inp)
{
  Byte BitPos;
  LongWord Address;

  DissectBitSymbol(Inp, &Address, &BitPos);

  as_snprintf(pDest, DestSize, "#%u,$%s%x", BitPos,
              (HexStartCharacter == 'A') ? (CPU16 ? "FF" : "FFFF") : (CPU16 ? "ff" : "ffff"),
              (unsigned)Address);
}

/*!------------------------------------------------------------------------
 * \fn     ExpandBit_H8_3(const tStrComp *pVarName, const struct sStructElem *pStructElem, LargeWord Base)
 * \brief  expands bit definition when a structure is instantiated
 * \param  pVarName desired symbol name
 * \param  pStructElem element definition
 * \param  Base base address of instantiated structure
 * ------------------------------------------------------------------------ */

static void ExpandBit_H8_3(const tStrComp *pVarName, const struct sStructElem *pStructElem, LargeWord Base)
{
  LongWord Address = Base + pStructElem->Offset;

  if (pInnermostNamedStruct)
  {
    PStructElem pElem = CloneStructElem(pVarName, pStructElem);

    if (!pElem)
      return;
    pElem->Offset = Address;
    AddStructElem(pInnermostNamedStruct->StructRec, pElem);
  }
  else
  {
    if (!ChkRange(Address, SegLimits[SegCode] - 0xff, SegLimits[SegCode])
     || !ChkRange(pStructElem->BitPos, 0, 7))
      return;

    PushLocHandle(-1);
    EnterIntSymbol(pVarName, AssembleBitSymbol(pStructElem->BitPos, Address), SegBData, False);
    PopLocHandle();
    /* TODO: MakeUseList? */
  }
}

/*-------------------------------------------------------------------------*/
/* Code Generators */

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

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

  if (OpSize == eSymbolSizeUnknown)
    OpSize = CPU16 ? eSymbolSize8Bit : eSymbolSize16Bit;
  if (OpSize > eSymbolSize16Bit) WrError(ErrNum_InvOpSize);
  else if (!ChkArgCnt(0, 0));
  else if ((OpSize == eSymbolSize16Bit) && !ChkCPU32(ErrNum_AddrModeNotSupported));
  else
  {
    CodeLen = 4;
    WAsmCode[0] = (OpSize == eSymbolSize8Bit) ? 0x7b5c : 0x7bd4;
    WAsmCode[1] = 0x598f;
  }
}

static void DecodeMOV(Word Code)
{
  Byte HReg;

  UNUSED(Code);

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[2], MModReg | MModIReg | MModPreDec | MModInd | MModAbs);
    switch (AdrMode)
    {
      case ModReg:
        HReg = AdrPart;
        DecodeAdr(&ArgStr[1], MModReg | MModIReg | MModPostInc | MModInd | MModImm | ((OpSize == eSymbolSize8Bit) ? MModAbs : (MModAbs16 | MModAbs24)));
        switch (AdrMode)
        {
          case ModReg:
          {
            int z = (OpSize == eSymbolSize32Bit) ? 3 : OpSize;

            CodeLen = 2;
            WAsmCode[0] = 0x0c00 + (z << 8) + (AdrPart << 4) + HReg;
            if (OpSize == eSymbolSize32Bit)
              WAsmCode[0] += 0x80;
            break;
          }
          case ModIReg:
            switch (OpSize)
            {
              case eSymbolSize8Bit:
                CodeLen = 2;
                WAsmCode[0] = 0x6800 + (AdrPart << 4) + HReg;
                break;
              case eSymbolSize16Bit:
                CodeLen = 2;
                WAsmCode[0] = 0x6900 + (AdrPart << 4) + HReg;
                break;
              case eSymbolSize32Bit:
                CodeLen = 4;
                WAsmCode[0] = 0x0100;
                WAsmCode[1] = 0x6900 + (AdrPart << 4) + HReg;
                break;
              default:
                break;
            }
            break;
          case ModPostInc:
            switch (OpSize)
            {
              case eSymbolSize8Bit:
                CodeLen = 2;
                WAsmCode[0] = 0x6c00 + (AdrPart << 4) + HReg;
                break;
              case eSymbolSize16Bit:
                CodeLen = 2;
                WAsmCode[0] = 0x6d00 + (AdrPart << 4) + HReg;
                break;
              case eSymbolSize32Bit:
                CodeLen = 4;
                WAsmCode[0] = 0x0100;
                WAsmCode[1] = 0x6d00 + (AdrPart << 4) + HReg;
                break;
              default:
                break;
            }
            break;
          case ModInd16:
            switch (OpSize)
            {
              case eSymbolSize8Bit:
                CodeLen = 4;
                WAsmCode[0] = 0x6e00 + (AdrPart << 4) + HReg;
                WAsmCode[1] = AdrVals[0];
                break;
              case eSymbolSize16Bit:
                CodeLen = 4;
                WAsmCode[0] = 0x6f00 + (AdrPart << 4) + HReg;
                WAsmCode[1] = AdrVals[0];
                break;
              case eSymbolSize32Bit:
                CodeLen = 6;
                WAsmCode[0] = 0x0100;
                WAsmCode[1] = 0x6f00 + (AdrPart << 4) + HReg;
                WAsmCode[2] = AdrVals[0];
                break;
              default:
                break;
            }
            break;
          case ModInd24:
            switch (OpSize)
            {
              case eSymbolSize8Bit:
                CodeLen = 8;
                WAsmCode[0] = 0x7800 + (AdrPart << 4);
                WAsmCode[1] = 0x6a20 + HReg;
                memcpy(WAsmCode + 2, AdrVals, AdrCnt);
                break;
              case eSymbolSize16Bit:
                CodeLen = 8;
                WAsmCode[0] = 0x7800 + (AdrPart << 4);
                WAsmCode[1] = 0x6b20 + HReg;
                memcpy(WAsmCode + 2, AdrVals, AdrCnt);
                break;
              case eSymbolSize32Bit:
                CodeLen = 10;
                WAsmCode[0] = 0x0100;
                WAsmCode[1] = 0x7800 + (AdrPart << 4);
                WAsmCode[2] = 0x6b20 + HReg;
                memcpy(WAsmCode + 3, AdrVals, AdrCnt);
                break;
              default:
                break;
            }
            break;
          case ModAbs8:
            CodeLen = 2;
            WAsmCode[0] = 0x2000 + (((Word)HReg) << 8) + Lo(AdrVals[0]);
            break;
          case ModAbs16:
            switch (OpSize)
            {
              case eSymbolSize8Bit:
                CodeLen = 4;
                WAsmCode[0] = 0x6a00 + HReg;
                WAsmCode[1] = AdrVals[0];
                break;
              case eSymbolSize16Bit:
                CodeLen = 4;
                WAsmCode[0] = 0x6b00 + HReg;
                WAsmCode[1] = AdrVals[0];
                break;
              case eSymbolSize32Bit:
                CodeLen = 6;
                WAsmCode[0] = 0x0100;
                WAsmCode[1] = 0x6b00 + HReg;
                WAsmCode[2] = AdrVals[0];
                break;
              default:
                break;
            }
            break;
          case ModAbs24:
            switch (OpSize)
            {
              case eSymbolSize8Bit:
                CodeLen = 6;
                WAsmCode[0] = 0x6a20 + HReg;
                memcpy(WAsmCode + 1, AdrVals, AdrCnt);
                break;
              case eSymbolSize16Bit:
                CodeLen = 6;
                WAsmCode[0] = 0x6b20 + HReg;
                memcpy(WAsmCode + 1, AdrVals, AdrCnt);
                break;
              case eSymbolSize32Bit:
                CodeLen = 8;
                WAsmCode[0] = 0x0100;
                WAsmCode[1] = 0x6b20 + HReg;
                memcpy(WAsmCode + 2, AdrVals, AdrCnt);
                break;
              default:
                break;
            }
            break;
          case ModImm:
            switch (OpSize)
            {
              case eSymbolSize8Bit:
                CodeLen = 2;
                WAsmCode[0] = 0xf000 + (((Word)HReg) << 8) + Lo(AdrVals[0]);
                break;
              case eSymbolSize16Bit:
                CodeLen = 4;
                WAsmCode[0] = 0x7900 + HReg;
                WAsmCode[1] = AdrVals[0];
                break;
              case eSymbolSize32Bit:
                CodeLen = 6;
                WAsmCode[0] = 0x7a00 + HReg;
                memcpy(WAsmCode + 1, AdrVals, AdrCnt);
                break;
              default:
                break;
            }
            break;
        }
        break;
      case ModIReg:
        HReg = AdrPart;
        DecodeAdr(&ArgStr[1], MModReg);
        if (AdrMode != ModNone)
        {
          switch (OpSize)
          {
            case eSymbolSize8Bit:
              CodeLen = 2;
              WAsmCode[0] = 0x6880 + (HReg << 4) + AdrPart;
              break;
            case eSymbolSize16Bit:
              CodeLen = 2;
              WAsmCode[0] = 0x6980 + (HReg << 4) + AdrPart;
              break;
            case eSymbolSize32Bit:
              CodeLen = 4;
              WAsmCode[0] = 0x0100;
              WAsmCode[1] = 0x6980 + (HReg << 4) + AdrPart;
              break;
            default:
              break;
          }
        }
        break;
      case ModPreDec:
        HReg = AdrPart;
        DecodeAdr(&ArgStr[1], MModReg);
        if (AdrMode != ModNone)
        {
          switch (OpSize)
          {
            case eSymbolSize8Bit:
              CodeLen=2; WAsmCode[0]=0x6c80+(HReg << 4)+AdrPart;
              break;
            case eSymbolSize16Bit:
              CodeLen=2; WAsmCode[0]=0x6d80+(HReg << 4)+AdrPart;
              break;
            case eSymbolSize32Bit:
              CodeLen=4; WAsmCode[0]=0x0100;
              WAsmCode[1]=0x6d80+(HReg << 4)+AdrPart;
              break;
            default:
              break;
          }
        }
        break;
      case ModInd16:
        HReg = AdrPart;
        WAsmCode[1] = AdrVals[0];
        DecodeAdr(&ArgStr[1], MModReg);
        if (AdrMode!=ModNone)
        {
          switch (OpSize)
          {
            case eSymbolSize8Bit:
              CodeLen = 4;
              WAsmCode[0] = 0x6e80 + (HReg << 4) + AdrPart;
              break;
            case eSymbolSize16Bit:
              CodeLen = 4;
              WAsmCode[0] = 0x6f80 + (HReg << 4) + AdrPart;
              break;
            case eSymbolSize32Bit:
              CodeLen = 6;
              WAsmCode[0] = 0x0100;
              WAsmCode[2] = WAsmCode[1];
              WAsmCode[1] = 0x6f80 + (HReg << 4) + AdrPart;
              break;
            default:
              break;
          }
        }
        break;
      case ModInd24:
        HReg = AdrPart;
        memcpy(WAsmCode + 2, AdrVals, 4);
        DecodeAdr(&ArgStr[1], MModReg);
        if (AdrMode != ModNone)
        {
          switch (OpSize)
          {
            case eSymbolSize8Bit:
              CodeLen = 8;
              WAsmCode[0] = 0x7800 + (HReg << 4);
              WAsmCode[1] = 0x6aa0 + AdrPart;
              break;
            case eSymbolSize16Bit:
              CodeLen = 8;
              WAsmCode[0] = 0x7800 + (HReg << 4);
              WAsmCode[1] = 0x6ba0 + AdrPart;
              break;
            case eSymbolSize32Bit:
              CodeLen = 10;
              WAsmCode[0] = 0x0100;
              WAsmCode[4] = WAsmCode[3];
              WAsmCode[3] = WAsmCode[2];
              WAsmCode[1] = 0x7800 + (HReg << 4);
              WAsmCode[2] = 0x6ba0 + AdrPart;
              break;
            default:
              break;
          }
        }
        break;
      case ModAbs8:
        HReg = Lo(AdrVals[0]);
        DecodeAdr(&ArgStr[1], MModReg);
        if (AdrMode != ModNone)
        {
          switch (OpSize)
          {
            case eSymbolSize8Bit:
              CodeLen = 2;
              WAsmCode[0] = 0x3000 + (((Word)AdrPart) << 8) + HReg;
              break;
            case eSymbolSize16Bit:
              CodeLen = 4;
              WAsmCode[0] = 0x6b80 + AdrPart;
              WAsmCode[1] = 0xff00 + HReg;
              break;
            case eSymbolSize32Bit:
              CodeLen = 6;
              WAsmCode[0] = 0x0100;
              WAsmCode[1] = 0x6b80 + AdrPart;
              WAsmCode[2] = 0xff00 + HReg;
              break;
            default:
              break;
          }
        }
        break;
      case ModAbs16:
        WAsmCode[1] = AdrVals[0];
        DecodeAdr(&ArgStr[1], MModReg);
        if (AdrMode != ModNone)
        {
          switch (OpSize)
          {
            case eSymbolSize8Bit:
              CodeLen = 4;
              WAsmCode[0] = 0x6a80 + AdrPart;
              break;
            case eSymbolSize16Bit:
              CodeLen = 4;
              WAsmCode[0] = 0x6b80 + AdrPart;
              break;
            case eSymbolSize32Bit:
              CodeLen = 6;
              WAsmCode[0] = 0x0100;
              WAsmCode[2] = WAsmCode[1];
              WAsmCode[1] = 0x6b80 + AdrPart;
              break;
            default:
              break;
          }
        }
        break;
      case ModAbs24:
        memcpy(WAsmCode + 1, AdrVals, 4);
        DecodeAdr(&ArgStr[1], MModReg);
        if (AdrMode != ModNone)
        {
          switch (OpSize)
          {
            case eSymbolSize8Bit:
              CodeLen = 6;
              WAsmCode[0] = 0x6aa0 + AdrPart;
              break;
            case eSymbolSize16Bit:
              CodeLen = 6;
              WAsmCode[0] = 0x6ba0 + AdrPart;
              break;
            case eSymbolSize32Bit:
              CodeLen = 8;
              WAsmCode[0] = 0x0100;
              WAsmCode[3] = WAsmCode[2];
              WAsmCode[2] = WAsmCode[1];
              WAsmCode[1] = 0x6ba0 + AdrPart;
              break;
            default:
              break;
          }
        }
        break;
    }
  }
}

static void DecodeMOVTPE_MOVFPE(Word CodeTPE)
{
  if (ChkArgCnt(2, 2)
   && ChkMinCPU(CPU6413308))
  {
    tStrComp *pRegArg = CodeTPE ? &ArgStr[1] : &ArgStr[2],
             *pMemArg = CodeTPE ? &ArgStr[2] : &ArgStr[1];

    DecodeAdr(pRegArg, MModReg);
    if (AdrMode != ModNone)
    {
      if (OpSize != eSymbolSize8Bit) WrError(ErrNum_InvOpSize);
      else
      {
        Byte HReg = AdrPart;
        DecodeAdr(pMemArg, MModAbs16);
        if (AdrMode != ModNone)
        {
          CodeLen = 4;
          WAsmCode[0] = 0x6a40 + CodeTPE + HReg;
          WAsmCode[1] = AdrVals[0];
        }
      }
    }
  }
}

static void DecodePUSH_POP(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    if (AdrMode != ModNone)
    {
      if (OpSize == eSymbolSize8Bit) WrError(ErrNum_InvOpSize);
      else if ((OpSize != eSymbolSize32Bit) || ChkCPU32(ErrNum_AddrModeNotSupported))
      {
        if (OpSize == eSymbolSize32Bit)
          WAsmCode[0] = 0x0100;
        CodeLen = 2 * OpSize;
        WAsmCode[(CodeLen - 2) >> 1] = Code + AdrPart;
      }
    }
  }
}

static void DecodeLDC_STC(Word CodeIsSTC)
{
  if (ChkArgCnt(2, 2))
  {
    tStrComp *pRegArg = CodeIsSTC ? &ArgStr[1] : &ArgStr[2],
             *pMemArg = CodeIsSTC ? &ArgStr[2] : &ArgStr[1];

    if (as_strcasecmp(pRegArg->str.p_str, "CCR")) WrError(ErrNum_InvAddrMode);
    else
    {
       SetOpSize(eSymbolSize8Bit);
       DecodeAdr(pMemArg, MModReg | MModIReg | MModInd | MModAbs16 | MModAbs24 | (CodeIsSTC ? MModPreDec : (MModImm | MModPostInc)));
       switch (AdrMode)
       {
         case ModReg:
           CodeLen = 2;
           WAsmCode[0] = 0x0300 + AdrPart - (CodeIsSTC << 1);
           break;
         case ModIReg:
           CodeLen = 4;
           WAsmCode[0] = 0x0140;
           WAsmCode[1] = 0x6900 + CodeIsSTC + (AdrPart << 4);
           break;
         case ModPostInc:
         case ModPreDec:
           CodeLen = 4;
           WAsmCode[0] = 0x0140;
           WAsmCode[1] = 0x6d00 + CodeIsSTC + (AdrPart << 4);
           break;
         case ModInd16:
           CodeLen = 6;
           WAsmCode[0] = 0x0140;
           WAsmCode[2] = AdrVals[0];
           WAsmCode[1] = 0x6f00 + CodeIsSTC + (AdrPart << 4);
           break;
         case ModInd24:
           CodeLen = 10;
           WAsmCode[0] = 0x0140;
           WAsmCode[1] = 0x7800 + (AdrPart << 4);
           WAsmCode[2] = 0x6b20 + CodeIsSTC;
           memcpy(WAsmCode + 3, AdrVals, AdrCnt);
           break;
         case ModAbs16:
           CodeLen = 6;
           WAsmCode[0] = 0x0140;
           WAsmCode[2] = AdrVals[0];
           WAsmCode[1] = 0x6b00 + CodeIsSTC;
           break;
         case ModAbs24:
           CodeLen = 8;
           WAsmCode[0] = 0x0140;
           WAsmCode[1] = 0x6b20 + CodeIsSTC;
           memcpy(WAsmCode + 2, AdrVals, AdrCnt);
           break;
         case ModImm:
           CodeLen = 2;
           WAsmCode[0] = 0x0700 + Lo(AdrVals[0]);
           break;
       }
    }
  }
}

static void DecodeADD_SUB(Word IsSUB)
{
  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[2], MModReg);
    if (AdrMode != ModNone)
    {
      Byte HReg = AdrPart;
      DecodeAdr(&ArgStr[1], MModReg | MModImm);
      if (AdrMode != ModNone)
      {
        if (((OpSize > eSymbolSize16Bit) || ((OpSize == eSymbolSize16Bit) && (AdrMode == ModImm))) && !ChkCPU32(ErrNum_AddrModeNotSupported));
        else
        {
          switch (AdrMode)
          {
            case ModImm:
              switch (OpSize)
              {
                case eSymbolSize8Bit:
                  if (IsSUB) WrError(ErrNum_InvAddrMode);
                  else
                  {
                    CodeLen = 2;
                    WAsmCode[0] = 0x8000 + (((Word)HReg) << 8) + Lo(AdrVals[0]);
                  }
                  break;
                case eSymbolSize16Bit:
                  CodeLen = 4;
                  WAsmCode[1] = AdrVals[0];
                  WAsmCode[0] = 0x7910 + (IsSUB << 5) + HReg;
                  break;
                case eSymbolSize32Bit:
                  CodeLen = 6;
                  memcpy(WAsmCode + 1, AdrVals, 4);
                  WAsmCode[0] = 0x7a10 + (IsSUB << 5) + HReg;
                  break;
                default:
                  break;
              }
              break;
            case ModReg:
              switch (OpSize)
              {
                case eSymbolSize8Bit:
                  CodeLen = 2;
                  WAsmCode[0] = 0x0800 + (IsSUB << 12) + (AdrPart << 4) + HReg;
                  break;
                case eSymbolSize16Bit:
                  CodeLen = 2;
                  WAsmCode[0] = 0x0900 + (IsSUB << 12) + (AdrPart << 4) + HReg;
                  break;
                case eSymbolSize32Bit:
                  CodeLen = 2;
                  WAsmCode[0] = 0x0a00 + (IsSUB << 12) + 0x80 + (AdrPart << 4) + HReg;
                  break;
                default:
                  break;
              }
              break;
          }
        }
      }
    }
  }
}

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

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[2], MModReg);
    if (AdrMode != ModNone)
    {
      Byte HReg = AdrPart;
      DecodeAdr(&ArgStr[1], MModReg | MModImm);
      if (AdrMode != ModNone)
      {
        if (((OpSize > eSymbolSize16Bit) || ((OpSize == eSymbolSize16Bit) && (AdrMode == ModImm))) && !ChkCPU32(ErrNum_AddrModeNotSupported));
        else
        {
          switch (AdrMode)
          {
            case ModImm:
              switch (OpSize)
              {
                case eSymbolSize8Bit:
                  CodeLen = 2;
                  WAsmCode[0] = 0xa000 + (((Word)HReg) << 8) + Lo(AdrVals[0]);
                  break;
                case eSymbolSize16Bit:
                  CodeLen = 4;
                  WAsmCode[1] = AdrVals[0];
                  WAsmCode[0] = 0x7920 + HReg;
                  break;
                case eSymbolSize32Bit:
                  CodeLen = 6;
                  memcpy(WAsmCode + 1, AdrVals, 4);
                  WAsmCode[0] = 0x7a20 + HReg;
                default:
                  break;
              }
              break;
            case ModReg:
              switch (OpSize)
              {
                case eSymbolSize8Bit:
                  CodeLen = 2;
                  WAsmCode[0] = 0x1c00 + (AdrPart << 4) + HReg;
                  break;
                case eSymbolSize16Bit:
                  CodeLen = 2;
                  WAsmCode[0] = 0x1d00 + (AdrPart << 4) + HReg;
                  break;
                case eSymbolSize32Bit:
                  CodeLen = 2;
                  WAsmCode[0] = 0x1f80 + (AdrPart << 4) + HReg;
                  break;
                default:
                  break;
              }
              break;
          }
        }
      }
    }
  }
}

static void DecodeLogic(Word Code)
{
  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[2], MModReg);
    if (AdrMode != ModNone)
    {
      if ((OpSize <= eSymbolSize8Bit) || ChkCPU32(ErrNum_AddrModeNotSupported))
      {
        Byte HReg = AdrPart;
        DecodeAdr(&ArgStr[1], MModImm | MModReg);
        switch (AdrMode)
        {
          case ModImm:
            switch (OpSize)
            {
              case eSymbolSize8Bit:
                CodeLen = 2;
                WAsmCode[0] = 0xc000 + (Code << 12) + (((Word)HReg) << 8) + Lo(AdrVals[0]);
                break;
              case eSymbolSize16Bit:
                CodeLen = 4;
                WAsmCode[1] = AdrVals[0];
                WAsmCode[0] = 0x7940 + (Code << 4) + HReg;
                break;
              case eSymbolSize32Bit:
                CodeLen = 6;
                memcpy(WAsmCode + 1, AdrVals, AdrCnt);
                WAsmCode[0] = 0x7a40 + (Code << 4) + HReg;
                break;
              default:
                break;
            }
            break;
          case ModReg:
            switch (OpSize)
            {
              case eSymbolSize8Bit:
                CodeLen = 2;
                WAsmCode[0] = 0x1400 + (Code << 8) + (AdrPart << 4) + HReg;
                break;
              case eSymbolSize16Bit:
                CodeLen = 2;
                WAsmCode[0] = 0x6400 + (Code << 8) + (AdrPart << 4) + HReg;
                break;
              case eSymbolSize32Bit:
                CodeLen = 4;
                WAsmCode[0] = 0x01f0;
                WAsmCode[1] = 0x6400 + (Code << 8) + (AdrPart << 4) + HReg;
                break;
              default:
                break;
            }
            break;
        }
      }
    }
  }
}

static void DecodeLogicBit(Word Code)
{
  SetOpSize(eSymbolSize8Bit);
  if (!ChkArgCnt(2, 2));
  else if (as_strcasecmp(ArgStr[2].str.p_str, "CCR")) WrError(ErrNum_InvAddrMode);
  else
  {
    DecodeAdr(&ArgStr[1], MModImm);
    if (AdrMode != ModNone)
    {
      CodeLen = 2;
      WAsmCode[0] = 0x0400 + (Code << 8) + Lo(AdrVals[0]);
    }
  }
}

static void DecodeADDX_SUBX(Word IsSUBX)
{
  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[2], MModReg);
    if (AdrMode != ModNone)
    {
      if (OpSize != eSymbolSize8Bit) WrError(ErrNum_InvOpSize);
      else
      {
        Byte HReg = AdrPart;
        DecodeAdr(&ArgStr[1], MModImm | MModReg);
        switch (AdrMode)
        {
          case ModImm:
            CodeLen = 2;
            WAsmCode[0] = 0x9000 + (((Word)HReg) << 8) + Lo(AdrVals[0]) + (IsSUBX << 13);
            break;
          case ModReg:
            CodeLen = 2;
            WAsmCode[0] = 0x0e00 + (AdrPart << 4) + HReg + (IsSUBX << 12);
            break;
        }
      }
    }
  }
}

static void DecodeADDS_SUBS(Word IsSUBS)
{
  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[2], MModReg);
    if (AdrMode != ModNone)
    {
      if (((CPU16) && (OpSize != eSymbolSize16Bit)) || ((!CPU16) && (OpSize != eSymbolSize32Bit))) WrError(ErrNum_InvOpSize);
      else
      {
        Byte HReg = AdrPart;
        DecodeAdr(&ArgStr[1], MModImm);
        if (AdrMode != ModNone)
        {
          LongInt AdrLong = ImmVal();
          if ((AdrLong != 1) && (AdrLong != 2) && (AdrLong != 4)) WrError(ErrNum_OverRange);
          else
          {
            switch (AdrLong)
            {
              case 1: WAsmCode[0] = 0x0b00; break;
              case 2: WAsmCode[0] = 0x0b80; break;
              case 4: WAsmCode[0] = 0x0b90; break;
            }
            CodeLen = 2;
            WAsmCode[0] += HReg + IsSUBS;
          }
        }
      }
    }
  }
}

static void DecodeMul(Word Code)
{
  if (ChkArgCnt(2, 2))
  {
    if (OpSize != eSymbolSizeUnknown) OpSize++;
    DecodeAdr(&ArgStr[2], MModReg);
    if (AdrMode != ModNone)
    {
      if (OpSize == eSymbolSize8Bit) WrError(ErrNum_InvOpSize);
      else if ((OpSize != eSymbolSize32Bit) || ChkCPU32(ErrNum_AddrModeNotSupported))
      {
        Byte HReg = AdrPart;
        OpSize--;
        DecodeAdr(&ArgStr[1], MModReg);
        if (AdrMode != ModNone)
        {
          if ((Code & 2) == 2)
          {
            CodeLen = 4;
            WAsmCode[0] = 0x01c0;
            if ((Code & 1) == 1)
              WAsmCode[0] += 0x10;
          }
          else
            CodeLen=2;
          WAsmCode[CodeLen >> 2] = 0x5000
                                 + (((Word)OpSize) << 9)
                                 + ((Code & 1) << 8)
                                 + (AdrPart << 4) + HReg;
        }
      }
    }
  }
}

static void DecodeBit1(Word Code)
{
  Word OpCode = 0x60 + (Code & 0x7f);
  Byte BitPos;

  switch (ArgCnt)
  {
    case 1:
    {
      LongWord BitSpec;

      if (DecodeBitArg(&BitSpec, 1, 1))
      {
        LongWord Addr;

        DissectBitSymbol(BitSpec, &Addr, &BitPos);
        AdrMode = ModAbs8;
        AdrVals[0] = Addr & 0xff;
        AdrCnt = 2;
        goto common;
      }
      break;
    }
    case 2:
    {
      Boolean OK;

      BitPos = EvalBitPosition(&ArgStr[1], &OK);
      if (OK)
      {
        DecodeAdr(&ArgStr[2], MModReg | MModIReg | MModAbs8);
        if (AdrMode != ModNone)
          goto common;
      }
      break;
    }
    common:
      if (OpSize > eSymbolSize8Bit) WrError(ErrNum_InvOpSize);
      else switch (AdrMode)
      {
        case ModReg:
          CodeLen = 2;
          WAsmCode[0] = (OpCode << 8) + (Code & 0x80) + (BitPos << 4) + AdrPart;
          break;
        case ModIReg:
          CodeLen = 4;
          WAsmCode[0] = 0x7c00 + (AdrPart << 4);
          WAsmCode[1] = (OpCode << 8) + (Code & 0x80) + (BitPos << 4);
          if (OpCode < 0x70)
            WAsmCode[0] += 0x100;
          break;
        case ModAbs8:
          CodeLen = 4;
          WAsmCode[0] = 0x7e00 + Lo(AdrVals[0]);
          WAsmCode[1] = (OpCode << 8) + (Code & 0x80) + (BitPos << 4);
          if (OpCode < 0x70)
            WAsmCode[0] += 0x100;
          break;
      }
      break;
    default:
      (void)ChkArgCnt(1, 2);
  }
}

static void DecodeBit2(Word Code)
{
  Word OpCode;
  Byte Bit;
  Boolean OK;
  tSymbolSize HSize;

  switch (ArgCnt)
  {
    case 1:
    {
      LongWord BitSpec;

      if (DecodeBitArg(&BitSpec, 1, 1))
      {
        LongWord Addr;

        DissectBitSymbol(BitSpec, &Addr, &Bit);
        OpCode = Code + 0x70;
        AdrMode = ModAbs8;
        AdrVals[0] = Addr & 0xff;
        AdrCnt = 2;
        goto common;
      }
      break;
    }
    case 2:
      switch (DecodeReg(&ArgStr[1], &Bit, 1 << eSymbolSize8Bit, &HSize, False))
      {
        case eIsReg:
          OpCode = Code + 0x60;
          OK = True;
          break;
        case eIsNoReg:
          OpCode = Code + 0x70;
          Bit = EvalBitPosition(&ArgStr[1], &OK);
          break;
        default: /* eRegAbort */
          return;
      }
      if (OK)
      {
        DecodeAdr(&ArgStr[2], MModReg | MModIReg | MModAbs8);
        if (AdrMode != ModNone)
          goto common;
        break;
      }
    common:
      if (OpSize > eSymbolSize8Bit) WrError(ErrNum_InvOpSize);
      else
      {
        switch (AdrMode)
        {
          case ModReg:
            CodeLen = 2;
            WAsmCode[0] = (OpCode << 8) + (Bit << 4) + AdrPart;
            break;
          case ModIReg:
            CodeLen = 4;
            WAsmCode[0] = 0x7d00 + (AdrPart << 4);
            WAsmCode[1] = (OpCode << 8) + (Bit << 4);
            if (Code == 3)
              WAsmCode[0] -= 0x100;
            break;
          case ModAbs8:
            CodeLen = 4;
            WAsmCode[0] = 0x7f00 + Lo(AdrVals[0]);
            WAsmCode[1] = (OpCode << 8) + (Bit << 4);
            if (Code == 3)
              WAsmCode[0] -= 0x100;
            break;
        }
      }
      break;
    default:
      (void)ChkArgCnt(1, 2);
  }
}

static void DecodeINC_DEC(Word Code)
{
  Boolean OK;
  int z;
  Byte HReg;

  if (ChkArgCnt(1, 2))
  {
    DecodeAdr(&ArgStr[ArgCnt], MModReg);
    if (AdrMode != ModNone)
    {
      if ((OpSize <= eSymbolSize8Bit) || ChkCPU32(ErrNum_AddrModeNotSupported))
      {
        HReg = AdrPart;
        if (ArgCnt == 1)
        {
          OK = True;
          z = 1;
        }
        else
        {
          DecodeAdr(&ArgStr[1], MModImm);
          OK = (AdrMode == ModImm);
          if (OK)
          {
            z = ImmVal();
            if (z < 1)
            {
              WrError(ErrNum_UnderRange);
              OK = False;
            }
            else if (((OpSize == eSymbolSize8Bit) && (z > 1)) || (z > 2))
            {
              WrError(ErrNum_OverRange);
              OK = False;
            }
          }
        }
        if (OK)
        {
          CodeLen = 2;
          z--;
          switch (OpSize)
          {
            case eSymbolSize8Bit:
              WAsmCode[0] = Code + 0x0a00 + HReg;
              break;
            case eSymbolSize16Bit:
              WAsmCode[0] = Code + 0x0b50 + HReg + (z << 7);
              break;
            case eSymbolSize32Bit:
              WAsmCode[0] = Code + 0x0b70 + HReg + (z << 7);
              break;
            default:
              break;
          }
        }
      }
    }
  }
}

static void DecodeShift(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    if (AdrMode != ModNone)
    {
      if ((OpSize <= eSymbolSize8Bit) || ChkCPU32(ErrNum_AddrModeNotSupported))
      {
        CodeLen = 2;
        switch (OpSize)
        {
          case eSymbolSize8Bit:
            WAsmCode[0] = Code + AdrPart;
            break;
          case eSymbolSize16Bit:
            WAsmCode[0] = Code + AdrPart + 0x10;
            break;
          case eSymbolSize32Bit:
            WAsmCode[0] = Code + AdrPart + 0x30;
            break;
          default:
            break;
        }
      }
    }
  }
}

static void DecodeNEG_NOT(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    if (AdrMode != ModNone)
    {
      if ((OpSize <= eSymbolSize8Bit) || ChkCPU32(ErrNum_AddrModeNotSupported))
      {
        CodeLen = 2;
        switch (OpSize)
        {
          case eSymbolSize8Bit:
            WAsmCode[0] = Code + 0x1700 + AdrPart;
            break;
          case eSymbolSize16Bit:
            WAsmCode[0] = Code + 0x1710 + AdrPart;
            break;
          case eSymbolSize32Bit:
            WAsmCode[0] = Code + 0x1730 + AdrPart;
            break;
          default:
            break;
        }
      }
    }
  }
}

static void DecodeEXTS_EXTU(Word IsEXTS)
{
  if (ChkArgCnt(1, 1)
   && ChkCPU32(ErrNum_InstructionNotSupported))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    if (AdrMode != ModNone)
    {
      if ((OpSize != eSymbolSize16Bit) && (OpSize != 2)) WrError(ErrNum_InvOpSize);
      else
      {
        CodeLen = 2;
        switch (OpSize)
        {
          case eSymbolSize16Bit:
            WAsmCode[0] = IsEXTS ? 0x17d0 : 0x1750;
            break;
          case eSymbolSize32Bit:
            WAsmCode[0] = IsEXTS ? 0x17f0 : 0x1770;
            break;
          default:
            break;
        }
        WAsmCode[0] += AdrPart;
      }
    }
  }
}

static void DecodeDAA_DAS(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    if (AdrMode != ModNone)
    {
      if (OpSize != eSymbolSize8Bit) WrError(ErrNum_InvOpSize);
      else
      {
        CodeLen = 2;
        WAsmCode[0] = Code + AdrPart;
      }
    }
  }
}

static void DecodeCond(Word Code)
{
  if (!ChkArgCnt(1, 1));
  else if ((OpSize != eSymbolSizeUnknown) && (OpSize != eSymbolSizeFloat32Bit) && (OpSize != eSymbolSize32Bit)) WrError(ErrNum_InvOpSize);
  else
  {
    Boolean OK;
    tSymbolFlags Flags;
    LongInt AdrLong = EvalStrIntExpressionWithFlags(&ArgStr[1], Int24, &OK, &Flags) - (EProgCounter() + 2);

    if (OK)
    {
      if (OpSize == eSymbolSizeUnknown)
      {
        if ((AdrLong >= -128) && (AdrLong <= 127))
          OpSize = eSymbolSizeFloat32Bit;
        else
        {
          OpSize = eSymbolSize32Bit;
          AdrLong -= 2;
        }
      }
      else if (OpSize == eSymbolSize32Bit)
        AdrLong -= 2;
      if (OpSize == eSymbolSize32Bit)
      {
        if (!mSymbolQuestionable(Flags) && ((AdrLong < -32768) || (AdrLong > 32767))) WrError(ErrNum_JmpDistTooBig);
        else if (ChkCPU32(ErrNum_AddrModeNotSupported))
        {
          CodeLen = 4;
          WAsmCode[0] = 0x5800 + (Code << 4);
          WAsmCode[1] = AdrLong & 0xffff;
        }
      }
      else
      {
        if (!mSymbolQuestionable(Flags) && ((AdrLong < -128) || (AdrLong > 127))) WrError(ErrNum_JmpDistTooBig);
        else
        {
          CodeLen = 2;
          WAsmCode[0] = 0x4000 + (Code << 8) + (AdrLong & 0xff);
        }
      }
    }
  }
}

static void DecodeJMP_JSR(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    DecodeAdr(&ArgStr[1], MModIReg | ((CPU16) ? MModAbs16 : MModAbs24) | MModIIAbs);
    switch (AdrMode)
    {
      case ModIReg:
        CodeLen = 2;
        WAsmCode[0] = 0x5900 + Code + (AdrPart << 4);
        break;
      case ModAbs16:
        CodeLen = 4;
        WAsmCode[0] = 0x5a00 + Code;
        WAsmCode[1] = AdrVals[0];
        break;
      case ModAbs24:
        CodeLen = 4;
        WAsmCode[0] = 0x5a00 + Code + Lo(AdrVals[0]);
        WAsmCode[1] = AdrVals[1];
        break;
      case ModIIAbs:
        CodeLen = 2;
        WAsmCode[0] = 0x5b00 + Code + Lo(AdrVals[0]);
        break;
    }
  }
}

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

  if (!ChkArgCnt(1, 1));
  else if ((OpSize != eSymbolSizeUnknown) && (OpSize != eSymbolSizeFloat32Bit) && (OpSize != eSymbolSize32Bit)) WrError(ErrNum_InvOpSize);
  else
  {
    Boolean OK;
    tSymbolFlags Flags;
    LongInt AdrLong = EvalStrIntExpressionWithFlags(&ArgStr[1], Int24, &OK, &Flags) - (EProgCounter() + 2);

    if (OK)
    {
      if (OpSize == eSymbolSizeUnknown)
      {
        if ((AdrLong >= -128) && (AdrLong <= 127))
          OpSize = eSymbolSizeFloat32Bit;
        else
        {
          OpSize = eSymbolSize32Bit;
          AdrLong -= 2;
        }
      }
      else
      {
        if (OpSize == eSymbolSize32Bit)
          AdrLong -= 2;
      }
      if (OpSize == eSymbolSize32Bit)
      {
        if (!mSymbolQuestionable(Flags) && ((AdrLong < -32768) || (AdrLong > 32767))) WrError(ErrNum_JmpDistTooBig);
        else if (ChkCPU32(ErrNum_AddrModeNotSupported))
        {
          CodeLen = 4;
          WAsmCode[0] = 0x5c00;
          WAsmCode[1] = AdrLong & 0xffff;
        }
      }
      else
      {
        if ((AdrLong < -128) || (AdrLong > 127)) WrError(ErrNum_JmpDistTooBig);
        else
        {
          CodeLen = 2;
          WAsmCode[0] = 0x5500 + (AdrLong & 0xff);
        }
      }
    }
  }
}

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

  if (ChkArgCnt(1, 1)
   && ChkMinCPU(CPU6413309))
  {
    Boolean OK;

    WAsmCode[0] = EvalStrIntExpressionOffs(&ArgStr[1], !!(*ArgStr[1].str.p_str == '#'), UInt2, &OK) << 4;
    if (OK)
    {
      WAsmCode[0] += 0x5700;
      CodeLen = 2;
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeBIT(Word Code)
 * \brief  handle BIT instruction
 * ------------------------------------------------------------------------ */

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

  /* if in structure definition, add special element to structure */

  if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSizeUnknown))
  {
    WrError(ErrNum_InvOpSize);
    return;
  }
  if (ActPC == StructSeg)
  {
    Boolean OK;
    Byte BitPos;
    PStructElem pElement;

    if (!ChkArgCnt(2, 2))
      return;
    BitPos = EvalBitPosition(&ArgStr[1], &OK);
    if (!OK)
      return;
    pElement = CreateStructElem(&LabPart);
    if (!pElement)
      return;
    pElement->pRefElemName = as_strdup(ArgStr[2].str.p_str);
    pElement->OpSize = eSymbolSize8Bit;
    pElement->BitPos = BitPos;
    pElement->ExpandFnc = ExpandBit_H8_3;
    AddStructElem(pInnermostNamedStruct->StructRec, pElement);
  }
  else
  {
    LongWord BitSpec;

    if (DecodeBitArg(&BitSpec, 1, ArgCnt))
    {
      *ListLine = '=';
      DissectBit_H8_3(ListLine + 1, STRINGSIZE - 3, BitSpec);
      PushLocHandle(-1);
      EnterIntSymbol(&LabPart, BitSpec, SegBData, False);
      PopLocHandle();
      /* TODO: MakeUseList? */
    }
  }
}

/*-------------------------------------------------------------------------*/
/* dynamische Belegung/Freigabe Codetabellen */

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

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

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

static void AddLogic(const char *NName, const char *NNameBit, Word NCode)
{
  AddInstTable(InstTable, NName, NCode, DecodeLogic);
  AddInstTable(InstTable, NNameBit, NCode, DecodeLogicBit);
}

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

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

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

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

  add_null_pseudo(InstTable);

  AddInstTable(InstTable, "EEPMOV", 0, DecodeEEPMOV);
  AddInstTable(InstTable, "MOV", 0, DecodeMOV);
  AddInstTable(InstTable, "MOVTPE", 0x80, DecodeMOVTPE_MOVFPE);
  AddInstTable(InstTable, "MOVFPE", 0x00, DecodeMOVTPE_MOVFPE);
  AddInstTable(InstTable, "PUSH", 0x6df0, DecodePUSH_POP);
  AddInstTable(InstTable, "POP", 0x6d70, DecodePUSH_POP);
  AddInstTable(InstTable, "LDC", 0x00, DecodeLDC_STC);
  AddInstTable(InstTable, "STC", 0x80, DecodeLDC_STC);
  AddInstTable(InstTable, "ADD", 0, DecodeADD_SUB);
  AddInstTable(InstTable, "SUB", 1, DecodeADD_SUB);
  AddInstTable(InstTable, "CMP", 0, DecodeCMP);
  AddInstTable(InstTable, "ADDX", 0, DecodeADDX_SUBX);
  AddInstTable(InstTable, "SUBX", 1, DecodeADDX_SUBX);
  AddInstTable(InstTable, "ADDS", 0x0000, DecodeADDS_SUBS);
  AddInstTable(InstTable, "SUBS", 0x1000, DecodeADDS_SUBS);
  AddInstTable(InstTable, "INC", 0x0000, DecodeINC_DEC);
  AddInstTable(InstTable, "DEC", 0x1000, DecodeINC_DEC);
  AddInstTable(InstTable, "NEG", 0x80, DecodeNEG_NOT);
  AddInstTable(InstTable, "NOT", 0x00, DecodeNEG_NOT);
  AddInstTable(InstTable, "EXTS", 1, DecodeEXTS_EXTU);
  AddInstTable(InstTable, "EXTU", 0, DecodeEXTS_EXTU);
  AddInstTable(InstTable, "DAA", 0x0f00, DecodeDAA_DAS);
  AddInstTable(InstTable, "DAS", 0x1f00, DecodeDAA_DAS);
  AddInstTable(InstTable, "JMP", 0x0000, DecodeJMP_JSR);
  AddInstTable(InstTable, "JSR", 0x0400, DecodeJMP_JSR);
  AddInstTable(InstTable, "BSR", 0, DecodeBSR);
  AddInstTable(InstTable, "TRAPA", 0, DecodeTRAPA);

  AddFixed("NOP", 0x0000); AddFixed("RTE"  , 0x5670);
  AddFixed("RTS", 0x5470); AddFixed("SLEEP", 0x0180);

  AddCond("BRA", 0x0); AddCond("BT" , 0x0);
  AddCond("BRN", 0x1); AddCond("BF" , 0x1);
  AddCond("BHI", 0x2); AddCond("BLS", 0x3);
  AddCond("BCC", 0x4); AddCond("BHS", 0x4);
  AddCond("BCS", 0x5); AddCond("BLO", 0x5);
  AddCond("BNE", 0x6); AddCond("BEQ", 0x7);
  AddCond("BVC", 0x8); AddCond("BVS", 0x9);
  AddCond("BPL", 0xa); AddCond("BMI", 0xb);
  AddCond("BGE", 0xc); AddCond("BLT", 0xd);
  AddCond("BGT", 0xe); AddCond("BLE", 0xf);

  AddShift("ROTL" , 0x1280); AddShift("ROTR" , 0x1380);
  AddShift("ROTXL", 0x1200); AddShift("ROTXR", 0x1300);
  AddShift("SHAL" , 0x1080); AddShift("SHAR" , 0x1180);
  AddShift("SHLL" , 0x1000); AddShift("SHLR" , 0x1100);

  AddLogic("OR", "ORC", 0);
  AddLogic("XOR", "XORC", 1);
  AddLogic("AND", "ANDC", 2);

  AddMul("DIVXS", 3);
  AddMul("DIVXU", 1);
  AddMul("MULXS", 2);
  AddMul("MULXU", 0);

  AddBit1("BAND", 0x16); AddBit1("BIAND", 0x96);
  AddBit1("BOR" , 0x14); AddBit1("BIOR" , 0x94);
  AddBit1("BXOR", 0x15); AddBit1("BIXOR", 0x95);
  AddBit1("BLD" , 0x17); AddBit1("BILD" , 0x97);
  AddBit1("BST" , 0x07); AddBit1("BIST" , 0x87);

  AddBit2("BCLR", 2);
  AddBit2("BNOT", 1);
  AddBit2("BSET", 0);
  AddBit2("BTST", 3);

  AddInstTable(InstTable, "REG", 0, CodeREG);
  AddInstTable(InstTable, "BIT", 0, DecodeBIT);
  AddMoto16Pseudo(InstTable, e_moto_pseudo_flags_be);
}

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

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

/*!------------------------------------------------------------------------
 * \fn     InternSymbol_H8_3(char *pArg, TempResult *pResult)
 * \brief  handle built-in symbols on H8/300
 * \param  pArg source argument
 * \param  pResult result buffer
 * ------------------------------------------------------------------------ */

static void InternSymbol_H8_3(char *pArg, TempResult *pResult)
{
  Byte Result;
  tSymbolSize Size;

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

static Boolean DecodeAttrPart_H8_3(void)
{
  if (*AttrPart.str.p_str)
  {
    if (strlen(AttrPart.str.p_str) != 1)
    {
      WrStrErrorPos(ErrNum_TooLongAttr, &AttrPart);
      return False;
    }
    if (!DecodeMoto16AttrSize(*AttrPart.str.p_str, &AttrPartOpSize[0], False))
      return False;
  }
  return True;
}

static void MakeCode_H8_3(void)
{
  OpSize = eSymbolSizeUnknown;
  if (AttrPartOpSize[0] != eSymbolSizeUnknown)
    SetOpSize(AttrPartOpSize[0]);

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

static Boolean IsDef_H8_3(void)
{
  return Memo("REG")
      || Memo("BIT");
}

static void SwitchTo_H8_3(void)
{
  const TFamilyDescr *p_descr = FindFamilyByName("H8/300(H)");

  TurnWords = True;
  SetIntConstMode(eIntConstModeMoto);

  PCSymbol = "*";
  HeaderID = p_descr->Id;
  NOPCode = 0x0000;
  DivideChars = ",";
  HasAttrs = True;
  AttrChars = ".";

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

  DecodeAttrPart = DecodeAttrPart_H8_3;
  MakeCode = MakeCode_H8_3;
  IsDef = IsDef_H8_3;
  InternSymbol = InternSymbol_H8_3;
  DissectReg = DissectReg_H8_3;
  DissectBit = DissectBit_H8_3;
  QualifyQuote = QualifyQuote_SingleQuoteConstant;
  IntConstModeIBMNoTerm = True;
  SwitchFrom = DeinitFields;
  InitFields();
  onoff_maxmode_add();
  AddMoto16PseudoONOFF(False);

  CPU16 = (MomCPU <= CPUH8_300);
}

void codeh8_3_init(void)
{
  CPUH8_300L = AddCPU("H8/300L"   , SwitchTo_H8_3);
  CPU6413308 = AddCPU("HD6413308" , SwitchTo_H8_3);
  CPUH8_300  = AddCPU("H8/300"    , SwitchTo_H8_3);
  CPU6413309 = AddCPU("HD6413309" , SwitchTo_H8_3);
  CPUH8_300H = AddCPU("H8/300H"   , SwitchTo_H8_3);
}
