/* codest7.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator SGS-Thomson ST7/STM8                                        */
/*                                                                           */
/*****************************************************************************/

#include "stdinc.h"

#include <ctype.h>
#include <string.h>
#include <assert.h>

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

#include "codest7.h"

typedef enum
{
  eModNone = -1,
  eModImm = 0,        /* #byte */
  eModAbs8,           /* shortmem */
  eModAbs16,          /* longmem */
  eModAbs24,          /* extmem */
  eModIX,             /* (X) */
  eModIX8,            /* (shortoff,X) */
  eModIX16,           /* (longoff,X) */
  eModIX24,           /* (extoff,X) */
  eModIY,             /* (Y) */
  eModIY8,            /* (shortoff,Y) */
  eModIY16,           /* (longoff,Y) */
  eModIY24,           /* (extoff,Y) */
  eModISP8,           /* (shortoff,SP) (STM8 only) */
  eModIAbs8,          /* [shortptr.b] (ST7 only) */
  eModIAbs16,         /* [shortptr.w] */
  eModI16Abs16,       /* [longptr.w] (STM8 only) */
  eModI16Abs24,       /* [longptr.e] (STM8 only) */
  eModIXAbs8,         /* ([shortptr.b],X) */
  eModIXAbs16,        /* ([<longptr.w],X) */
  eModI16XAbs16,      /* ([>longptr.w],X) (STM8 only) */
  eModI16XAbs24,      /* ([>longptr.e],X) (STM8 only) */
  eModIYAbs8,         /* ([shortptr.b],Y) */
  eModIYAbs16,        /* ([<longptr.w],Y) */
  eModI16YAbs24,      /* ([>longptr.e],Y) (STM8 only) */
  eModA,              /* A */
  eModX,              /* X */
  eModXL,             /* XL (STM8 only) */
  eModXH,             /* XH (STM8 only) */
  eModY,              /* Y */
  eModYL,             /* YL (STM8 only) */
  eModYH,             /* YH (STM8 only) */
  eModS               /* SP */
  /* bit mask is full, 32 modes! */
} tAdrMode;

#define MModImm (1ul << eModImm)
#define MModAbs8 (1ul << eModAbs8)
#define MModAbs16 (1ul << eModAbs16)
#define MModAbs24 (1ul << eModAbs24)
#define MModIX (1ul << eModIX)
#define MModIX8 (1ul << eModIX8)
#define MModIX16 (1ul << eModIX16)
#define MModIX24 (1ul << eModIX24)
#define MModIY (1ul << eModIY)
#define MModIY8 (1ul << eModIY8)
#define MModIY16 (1ul << eModIY16)
#define MModIY24 (1ul << eModIY24)
#define MModISP8 (1ul << eModISP8)
#define MModIAbs8 (1ul << eModIAbs8)
#define MModIAbs16 (1ul << eModIAbs16)
#define MModI16Abs16 (1ul << eModI16Abs16)
#define MModI16Abs24 (1ul << eModI16Abs24)
#define MModIXAbs8 (1ul << eModIXAbs8)
#define MModIXAbs16 (1ul << eModIXAbs16)
#define MModI16XAbs16 (1ul << eModI16XAbs16)
#define MModI16XAbs24 (1ul << eModI16XAbs24)
#define MModIYAbs8 (1ul << eModIYAbs8)
#define MModIYAbs16 (1ul << eModIYAbs16)
#define MModI16YAbs24 (1ul << eModI16YAbs24)
#define MModA (1ul << eModA)
#define MModX (1ul << eModX)
#define MModXL (1ul << eModXL)
#define MModXH (1ul << eModXH)
#define MModY (1ul << eModY)
#define MModYL (1ul << eModYL)
#define MModYH (1ul << eModYH)
#define MModS (1ul << eModS)

typedef enum
{
  eCoreST7,
  eCoreSTM8
} tCPUCore;

typedef struct
{
  const char *pName;
  IntType AddrIntType;
  tCPUCore Core;
} tCPUProps;

typedef struct
{
  tAdrMode Mode;
  Byte Part;
  unsigned Cnt;
  Byte Vals[3];
} tAdrVals;

static const tCPUProps *pCurrCPUProps;
static tSymbolSize OpSize;
static Byte PrefixCnt;

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

/*!------------------------------------------------------------------------
 * \fn     ResetAdrVals(tAdrVals *pAdrVals)
 * \brief  clear AdrVals structure
 * \param  pAdrVals struct to clear/reset
 * ------------------------------------------------------------------------ */

static void ResetAdrVals(tAdrVals *pAdrVals)
{
  pAdrVals->Mode = eModNone;
  pAdrVals->Part = 0;
  pAdrVals->Cnt = 0;
}

static void FillAdrVals(tAdrVals *pAdrVals, LongWord Value, tSymbolSize Size)
{
  pAdrVals->Cnt = 0;
  switch (Size)
  {
    case eSymbolSize24Bit:
      pAdrVals->Vals[pAdrVals->Cnt++] = (Value >> 16) & 255;
      /* fall-through */
    case eSymbolSize16Bit:
      pAdrVals->Vals[pAdrVals->Cnt++] = (Value >> 8) & 255;
      /* fall-through */
    case eSymbolSize8Bit:
      pAdrVals->Vals[pAdrVals->Cnt++] = Value & 255;
      /* fall-through */
    default:
      break;
  }
}

static void ExtendAdrVals(tAdrVals *pAdrVals)
{
  switch (pAdrVals->Mode)
  {
    case eModAbs8:
      pAdrVals->Mode = eModAbs16;
      pAdrVals->Vals[1] = pAdrVals->Vals[0];
      pAdrVals->Vals[0] = 0;
      pAdrVals->Cnt = 2;
      break;
    default:
      break;
  }
}

/*!------------------------------------------------------------------------
 * \fn     AddPrefix(Byte Pref)
 * \brief  add another prefix byte
 * \param  Pref prefix to add
 * ------------------------------------------------------------------------ */

static void AddPrefix(Byte Pref)
{
  BAsmCode[PrefixCnt++] = Pref;
}

/*!------------------------------------------------------------------------
 * \fn     ModeInMask(LongWord Mask, tAdrMode Mode)
 * \brief  check whether certain addressing mode is set in mask
 * \param  Mask list of allowed modes
 * \param  Mode addressing mode to check
 * \return True if allowed
 * ------------------------------------------------------------------------ */

static Boolean ModeInMask(LongWord Mask, tAdrMode Mode)
{
  return !!((Mask >> Mode) & 1);
}

/*!------------------------------------------------------------------------
 * \fn     mode_or_none(LongWord Mask, tAdrMode Mode)
 * \brief  wrapper to mute addressing mode
 * \param  Mask list of allowed modes
 * \param  Mode addressing mode to check
 * \return mode if allowed or none
 * ------------------------------------------------------------------------ */

static tAdrMode mode_or_none(LongWord Mask, tAdrMode Mode)
{
  return ModeInMask(Mask, Mode) ? Mode : eModNone;
}

/*!------------------------------------------------------------------------
 * \fn     CutSizeSuffix(tStrComp *pArg)
 * \brief  cut off possible size suffix (.b .w .e) from argument
 * \param  pArg argument
 * \return deduced size or unknown if no known suffix
 * ------------------------------------------------------------------------ */

static tSymbolSize CutSizeSuffix(const tStrComp *pArg)
{
  int l = strlen(pArg->str.p_str);

  if ((l >= 3) && (pArg->str.p_str[l - 2] == '.'))
  {
    switch (as_toupper(pArg->str.p_str[l - 1]))
    {
      case 'B':
        pArg->str.p_str[l - 2] = '\0';
        return eSymbolSize8Bit;
      case 'W':
        pArg->str.p_str[l - 2] = '\0';
        return eSymbolSize16Bit;
      case 'E':
        pArg->str.p_str[l - 2] = '\0';
        return eSymbolSize24Bit;
      default:
        break;
    }
  }
  return eSymbolSizeUnknown;
}

/*!------------------------------------------------------------------------
 * \fn     DecideSize(const tStrComp *pArg, tAdrMode Mode8, tAdrMode Mode16, tAdrMode Mode24, Byte Part8, Byte Part16, Byte Part24, Boolean IsCode, tAdrVals *pAdrVals)
 * \brief  decide about length of absolute or indexed operand
 * \param  pArg address argument
 * \param  Mode8 AdrMode for 8-bit address/displacement
 * \param  Mode16 AdrMode for 16-bit address/displacement
 * \param  Mode24 AdrMode for 24-bit address/displacement
 * \param  Part8 AdrPart for 8-bit address/displacement
 * \param  Part16 AdrPart for 16-bit address/displacement
 * \param  Part24 AdrPart for 24-bit address/displacement
 * \param  IsCode Address is in code space (check for same page)
 * \param  pAdrVals destination to fill out
 * ------------------------------------------------------------------------ */

static void DecideSize(const tStrComp *pArg, tAdrMode Mode8, tAdrMode Mode16, tAdrMode Mode24, Byte Part8, Byte Part16, Byte Part24, Boolean IsCode, tAdrVals *pAdrVals)
{
  tSymbolSize Size = eSymbolSizeUnknown;
  IntType SizeType;
  LongWord Value;
  Boolean OK;
  tSymbolFlags Flags;

  Size = CutSizeSuffix(pArg);
  switch (Size)
  {
    case eSymbolSize8Bit:
      if (Mode8 == eModNone)
        goto InvSize;
      break;
    case eSymbolSize16Bit:
      if (Mode16 == eModNone)
        goto InvSize;
      break;
    case eSymbolSize24Bit:
      if (Mode24 == eModNone)
        goto InvSize;
      break;
    default:
      break;
    InvSize:
      WrStrErrorPos(ErrNum_InvAddrMode, pArg);
      return;
  }

  if (IsCode)
    SizeType = pCurrCPUProps->AddrIntType;
  else switch (Size)
  {
    case eSymbolSize24Bit:
      SizeType = Int24;
      break;
    case eSymbolSize16Bit:
      SizeType = Int16;
      break;
    case eSymbolSize8Bit:
      SizeType = Int8;
      break;
    default:
      if (Mode24 != eModNone)
        SizeType = Int24;
      else if (Mode16 != eModNone)
        SizeType = Int16;
      else
        SizeType = Int8;
      break;
  }
  Value = EvalStrIntExpressionWithFlags(pArg, SizeType, &OK, &Flags);

  if (OK)
  {
    LongWord SrcAddress = IsCode ? EProgCounter() + 3 : 0;

    if (Size == eSymbolSizeUnknown)
    {
      if ((Value <= 0xff) && (Mode8 != eModNone))
        Size = eSymbolSize8Bit;
      else if (((Value >> 16) == (SrcAddress >> 16)) && (Mode16 != eModNone))
        Size = eSymbolSize16Bit;
      else
        Size = eSymbolSize24Bit;
    }

    /* this may only happen if SizeTypes was forced to 24 Bit because of code addessing: */

    if ((Size == eSymbolSize24Bit) && (Mode24 == eModNone) && !mSymbolQuestionable(Flags))
    {
      WrStrErrorPos(ErrNum_TargOnDiffSection, pArg);
      return;
    }

    FillAdrVals(pAdrVals, Value, Size);
    switch (Size)
    {
      case eSymbolSize8Bit:
        pAdrVals->Part = Part8;
        pAdrVals->Mode = Mode8;
        break;
      case eSymbolSize16Bit:
        pAdrVals->Part = Part16;
        pAdrVals->Mode = Mode16;
        break;
      case eSymbolSize24Bit:
        pAdrVals->Part = Part24;
        pAdrVals->Mode = Mode24;
        break;
      default:
        assert(0);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecideIndirectSize(const tStrComp *pArg,
                              tAdrMode Mode8_8, tAdrMode Mode8_16, tAdrMode Mode16_16, tAdrMode Mode16_24,
                              Byte Part8_8, Byte Part8_16, Byte Part16_16, Byte Part16_24,
                              tAdrVals *pAdrVals)
 * \brief  address mode decision for indirect operands []
 * \param  pArg expression
 * \param  Mode8_8 requested mode for 8-bit pointer on 8-bit address
 * \param  Mode8_16 requested mode for 16-bit pointer on 8-bit address
 * \param  Mode16_16 requested mode for 16-bit pointer on 16-bit address
 * \param  Mode16_24 requested mode for 24-bit pointer on 16-bit address
 * \param  Part8_8 Address part for 8-bit pointer on 8-bit address
 * \param  Part8_16 Address part for 16-bit pointer on 8-bit address
 * \param  Part16_16 Address part for 16-bit pointer on 16-bit address
 * \param  Part16_24 Address part for 24-bit pointer on 16-bit address
 * \param  pAdrVals destination to fill out
 * \return True if successfully parsed
 * ------------------------------------------------------------------------ */

static Boolean DecideIndirectSize(const tStrComp *pArg,
                                  tAdrMode Mode8_8, tAdrMode Mode8_16, tAdrMode Mode16_16, tAdrMode Mode16_24,
                                  Byte Part8_8, Byte Part8_16, Byte Part16_16, Byte Part16_24,
                                  tAdrVals *pAdrVals)
{
  Boolean OK;
  int Offset;
  tSymbolSize AddrSize = eSymbolSizeUnknown,
              PtrSize = eSymbolSizeUnknown;
  IntType SizeType;
  Word Address;
  tSymbolFlags Flags;

  /* Cut off address byte size, signified by leading '<' or '>': */

  switch (*pArg->str.p_str)
  {
    case '>':
      Offset = 1;
      AddrSize = eSymbolSize16Bit;
      break;
    case '<':
      Offset = 1;
      AddrSize = eSymbolSize8Bit;
      break;
    default:
      Offset = 0;
      AddrSize = eSymbolSizeUnknown;
  }

  /* Cut off pointer size, signified by trailing '.w/.e' if 16/24 bit: */

  PtrSize = CutSizeSuffix(pArg);

  /* if no pointer size given, assume the smallest possible one: */

  if (PtrSize == eSymbolSizeUnknown)
  {
    if (Mode8_8 != eModNone)
      PtrSize = eSymbolSize8Bit;
    else if ((Mode8_16 != eModNone) || (Mode16_16 != eModNone))
      PtrSize = eSymbolSize16Bit;
    else
      PtrSize = eSymbolSize24Bit;
  }

  switch (AddrSize)
  {
    case eSymbolSize16Bit:
      SizeType = Int16;
      break;
    case eSymbolSize8Bit:
      SizeType = Int8;
      break;
    default:
      if ((Mode16_16 != eModNone) || (Mode16_24 != eModNone))
        SizeType = Int16;
      else
        SizeType = Int8;
      break;
  }

  Address = EvalStrIntExpressionOffsWithFlags(pArg, Offset, SizeType, &OK, &Flags);
  if (mFirstPassUnknown(Flags) && (Mode16_16 == eModNone) && (Mode16_24 == eModNone))
    Address &= 0xff;

  if (OK)
  {
    /* Finally decide about address size: */

    if (eSymbolSizeUnknown == AddrSize)
    {
      if ((Address <= 0xff) && (PtrSize == eSymbolSize8Bit) && (Mode8_8 != eModNone))
        AddrSize = eSymbolSize8Bit;
      else if ((Address <= 0xff) && (PtrSize == eSymbolSize16Bit) && (Mode8_16 != eModNone))
        AddrSize = eSymbolSize8Bit;
      else
        AddrSize = eSymbolSize16Bit;
    }

    FillAdrVals(pAdrVals, Address, AddrSize);
    if (eSymbolSize16Bit == AddrSize)
    {
      if (PtrSize == eSymbolSize24Bit)
      {
        pAdrVals->Part = Part16_24;
        pAdrVals->Mode = Mode16_24;
      }
      else
      {
        pAdrVals->Part = Part16_16;
        pAdrVals->Mode = Mode16_16;
      }
    }
    else
    {
      if (PtrSize == eSymbolSize16Bit)
      {
        pAdrVals->Part = Part8_16;
        pAdrVals->Mode = Mode8_16;
      }
      else
      {
        pAdrVals->Part = Part8_8;
        pAdrVals->Mode = Mode8_8;
      }
    }
  }
  return OK;
}

/*!------------------------------------------------------------------------
 * \fn     ChkAdrMode(tAdrMode *pAdrMode, LongWord Mask, tErrorNum ErrorNum, const tStrComp *pArg)
 * \brief  check for allowed addressing mode
 * \param  pAdrMode parsed addressing mode (in/out)
 * \param  Mask list of allowed modes
 * \param  ErrorNum error message to emit if not allowed
 * \param  pArg offending arg
 * \return True if mode is OK
 * ------------------------------------------------------------------------ */

static Boolean ChkAdrMode(tAdrMode *pAdrMode, LongWord Mask, tErrorNum ErrorNum, const tStrComp *pArg)
{
  if ((*pAdrMode != eModNone) && (!(Mask & (1ul << *pAdrMode))))
  {
    WrStrErrorPos(ErrorNum, pArg);
    *pAdrMode = eModNone;
    return False;
  }
  return True;
}

/*!------------------------------------------------------------------------
 * \fn     ChkAdrValsMode(tAdrVals *pAdrVals, LongWord Mask, tErrorNum ErrorNum, const tStrComp *pArg)
 * \brief  check for allowed addressing mode
 * \param  pAdrVals parsed addressing mode (in/out)
 * \param  Mask list of allowed modes
 * \param  ErrorNum error message to emit if not allowed
 * \param  pArg offending arg
 * \return True if mode is OK
 * ------------------------------------------------------------------------ */

static Boolean ChkAdrValsMode(tAdrVals *pAdrVals, LongWord Mask, tErrorNum ErrorNum, const tStrComp *pArg)
{
  if (!ChkAdrMode(&pAdrVals->Mode, Mask, ErrorNum, pArg))
  {
    pAdrVals->Cnt = 0;
    return False;
  }
  return True;
}

/*!------------------------------------------------------------------------
 * \fn     DecodeRegCore(const tStrComp *pArg, tAdrMode *pResult)
 * \brief  check whether argument is a CPU register
 * \param  pArg argument to check
 * \param  pResult resulting mode if it is a register
 * \return True if argument is a register
 * ------------------------------------------------------------------------ */

static Boolean DecodeRegCore(const tStrComp *pArg, tAdrMode *pResult)
{
  *pResult = eModNone;

  if (!as_strcasecmp(pArg->str.p_str, "A"))
  {
    *pResult = eModA;
    return True;
  }

  if (!as_strcasecmp(pArg->str.p_str, "X"))
  {
    *pResult = eModX;
    return True;
  }
  if (!as_strcasecmp(pArg->str.p_str, "XL"))
  {
    *pResult = eModXL;
    return True;
  }
  if (!as_strcasecmp(pArg->str.p_str, "XH"))
  {
    *pResult = eModXH;
    return True;
  }

  if (!as_strcasecmp(pArg->str.p_str, "Y"))
  {
    *pResult = eModY;
    return True;
  }
  if (!as_strcasecmp(pArg->str.p_str, "YL"))
  {
    *pResult = eModYL;
    return True;
  }
  if (!as_strcasecmp(pArg->str.p_str, "YH"))
  {
    *pResult = eModYH;
    return True;
  }

  if ((!as_strcasecmp(pArg->str.p_str, "S"))
   || ((pCurrCPUProps->Core == eCoreSTM8) && !as_strcasecmp(pArg->str.p_str, "SP")))
  {
    *pResult = eModS;
    return True;
  }

  return False;
}

/*!------------------------------------------------------------------------
 * \fn     DecodeReg(const tStrComp *pArg, tAdrMode *pResult, LongWord Mask)
 * \brief  decode addressing expression, registers-only
 * \param  pArg argument
 * \param  pResult resulting mode
 * \param  Mask list of allowed modes
 * \return True if argument is a CPU register
 * ------------------------------------------------------------------------ */

static Boolean DecodeReg(const tStrComp *pArg, tAdrMode *pResult, LongWord Mask)
{
  return DecodeRegCore(pArg, pResult)
      && ChkAdrMode(pResult, Mask, ErrNum_InvReg, pArg);
}

/*!------------------------------------------------------------------------
 * \fn     DecodeAdr(const tStrComp *pArg, LongWord Mask, Boolean IsCode, tAdrVals *pAdrVals)
 * \brief  decode addressing expression
 * \param  pArg argument
 * \param  Mask list of allowed masks
 * \param  IsCode is expression a jump/call address?
 * \param  pAdrVals destination to fill out
 * \return True if successfully parsed
 * ------------------------------------------------------------------------ */

static Boolean DecodeAdr(const tStrComp *pArg, LongWord Mask, Boolean IsCode, tAdrVals *pAdrVals)
{
  Boolean OK;
  int ArgLen;

  ArgLen = strlen(pArg->str.p_str);

  ResetAdrVals(pAdrVals);

  /* Register ? */

  if (DecodeRegCore(pArg, &pAdrVals->Mode))
  {
    switch (pAdrVals->Mode)
    {
      case eModY:
      case eModYL:
      case eModYH:
        AddPrefix(0x90);
        break;
      default:
        break;
    }
    goto chk;
  }

  /* immediate ? */

  if (*pArg->str.p_str == '#')
  {
    Word Value = EvalStrIntExpressionOffs(pArg, 1, (OpSize == eSymbolSize16Bit) ? Int16 : Int8, &OK);
    if (OK)
    {
      pAdrVals->Mode = eModImm;
      pAdrVals->Part = 0xa;
      FillAdrVals(pAdrVals, Value, OpSize);
    }
    goto chk;
  }

  /* speicherindirekt ? */

  if ((*pArg->str.p_str == '[') && (pArg->str.p_str[ArgLen - 1] == ']'))
  {
    tStrComp Comp;
    Boolean OK;

    StrCompRefRight(&Comp, pArg, 1);
    Comp.str.p_str[ArgLen - 2] = '\0'; Comp.Pos.Len--;
    OK = DecideIndirectSize(&Comp,
                            mode_or_none(Mask, eModIAbs8),
                            mode_or_none(Mask, eModIAbs16),
                            mode_or_none(Mask, eModI16Abs16),
                            mode_or_none(Mask, eModI16Abs24),
                            0xb, 0xc, 0xc, 0xb, pAdrVals);
    Comp.str.p_str[ArgLen - 2] = ']';
    if (OK)
      AddPrefix((pAdrVals->Mode == eModI16Abs16) ? 0x72: 0x92);
    goto chk;
  }

  /* sonstwie indirekt ? */

  if (IsIndirect(pArg->str.p_str))
  {
    tStrComp Comp, Left, Right;
    Boolean YReg = False, SPReg = False;
    char *p;

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

    /* ein oder zwei Argumente ? */

    p = QuotPos(Comp.str.p_str, ',');
    if (!p)
    {
      pAdrVals->Part = 0xf;
      if (!as_strcasecmp(Comp.str.p_str, "X")) pAdrVals->Mode = eModIX;
      else if (!as_strcasecmp(Comp.str.p_str, "Y"))
      {
        pAdrVals->Mode = eModIY;
        AddPrefix(0x90);
      }
      else WrStrErrorPos(ErrNum_InvReg, &Comp);
      goto chk;
    }

    StrCompSplitRef(&Left, &Right, &Comp, p);

    if (!as_strcasecmp(Left.str.p_str, "X"))
      Left = Right;
    else if (!as_strcasecmp(Right.str.p_str, "X"));
    else if (!as_strcasecmp(Left.str.p_str, "Y"))
    {
      Left = Right;
      YReg = True;
    }
    else if (!as_strcasecmp(Right.str.p_str, "Y"))
      YReg = True;
    else if (!as_strcasecmp(Left.str.p_str, "SP"))
    {
      Left = Right;
      SPReg = True;
    }
    else if (!as_strcasecmp(Right.str.p_str, "SP"))
      SPReg = True;
    else
    {
      WrStrErrorPos(ErrNum_InvAddrMode, &Comp);
      return False;
    }

    /* speicherindirekt ? */

    ArgLen = strlen(Left.str.p_str);
    if ((*Left.str.p_str == '[') && (Left.str.p_str[ArgLen - 1] == ']'))
    {
      StrCompRefRight(&Right, &Left, 1);
      StrCompShorten(&Right, 1);
      if (YReg)
      {
        if (DecideIndirectSize(&Right,
                               mode_or_none(Mask, eModIYAbs8),
                               mode_or_none(Mask, eModIYAbs16),
                               eModNone,
                               mode_or_none(Mask, eModI16YAbs24),
                               0xe, 0xd, 0x0, 0xa, pAdrVals))
          AddPrefix(0x91);
      }
      else
      {
        if (DecideIndirectSize(&Right,
                               mode_or_none(Mask, eModIXAbs8),
                               mode_or_none(Mask, eModIXAbs16),
                               mode_or_none(Mask, eModI16XAbs16),
                               mode_or_none(Mask, eModI16YAbs24),
                               0xe, 0xd, 0xd, 0xa, pAdrVals))
          AddPrefix((pAdrVals->Mode == eModI16XAbs16) ? 0x72 : 0x92);
      }
    }
    else
    {
      if (YReg) DecideSize(&Left,
                           mode_or_none(Mask, eModIY8),
                           mode_or_none(Mask, eModIY16),
                           mode_or_none(Mask, eModIY24),
                           0xe, 0xd, 0xa, IsCode, pAdrVals);
      else if (SPReg) DecideSize(&Left,
                                 mode_or_none(Mask, eModISP8),
                                 eModNone,
                                 eModNone,
                                 0x1, 0x0, 0x0, IsCode, pAdrVals);
      else DecideSize(&Left,
                      mode_or_none(Mask, eModIX8),
                      mode_or_none(Mask, eModIX16),
                      mode_or_none(Mask, eModIX24),
                      0xe, 0xd, 0xa, IsCode, pAdrVals);
      if ((pAdrVals->Mode != eModNone) && YReg) AddPrefix(0x90);
    }

    goto chk;
  }

  /* dann absolut */

  DecideSize(pArg,
             mode_or_none(Mask, eModAbs8),
             mode_or_none(Mask, eModAbs16),
             mode_or_none(Mask, eModAbs24),
             0xb, 0xc, 0xb, IsCode, pAdrVals);

chk:
  return ChkAdrValsMode(pAdrVals, Mask, ErrNum_InvAddrMode, pArg);
}

/*!------------------------------------------------------------------------
 * \fn     ConstructMask(LongWord TotMask, tSymbolSize OpSize)
 * \brief  construct actual bit mask of allowed addressing modes from overall list
 * \param  TotMask overall list
 * \param  OpSize operand size in use (8/16/unknown)
 * \return actual mask
 * ------------------------------------------------------------------------ */

static LongWord ConstructMask(LongWord TotMask, tSymbolSize OpSize)
{
  if (pCurrCPUProps->Core == eCoreST7)
  {
    /* not present on ST7 */

    TotMask &= ~(MModISP8 | MModI16Abs16 | MModI16XAbs16 | MModXL | MModYL | MModXH | MModYH);

    /* SP/X/Y are 8 bits wide on ST7 */

    if (OpSize == eSymbolSize16Bit)
      TotMask &= ~(MModX | MModY | MModS);
  }

  if (pCurrCPUProps->Core == eCoreSTM8)
  {
    /* removed on STM8 */

    TotMask &= ~(MModIAbs8 | MModIXAbs8 | MModIYAbs8);

    /* SP/X/Y changed to 16 bits on STM8 */

    if (OpSize == eSymbolSize8Bit)
      TotMask &= ~(MModX | MModY | MModS);
  }

  return TotMask;
}

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

/*
 * Compact representation of bits in symbol table:
 * bits 0..2: bit position
 * bits 3...10/18: register address in memory space (first 256/64K)
 */

/*!------------------------------------------------------------------------
 * \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, Word Address)
 * \brief  build the compact internal representation of a bit symbol
 * \param  BitPos bit position in word
 * \param  Address register address
 * \return compact representation
 * ------------------------------------------------------------------------ */

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

/*!------------------------------------------------------------------------
 * \fn     DecodeBitArg2(LongWord *pResult, const tStrComp *pRegArg, const tStrComp *pBitArg)
 * \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 *pRegArg, const tStrComp *pBitArg)
{
  Boolean OK;
  LongWord Addr;
  Byte BitPos;

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

  Addr = EvalStrIntExpression(pRegArg, (pCurrCPUProps->Core == eCoreSTM8) ? UInt16 : UInt8, &OK);
  if (!OK)
    return False;

  *pResult = AssembleBitSymbol(BitPos, Addr);

  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], (pCurrCPUProps->Core == eCoreSTM8) ? UInt19 : UInt11, &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 (I/O) register address
 * \param  pBitPos (start) bit position
 * \return constant True
 * ------------------------------------------------------------------------ */

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

/*!------------------------------------------------------------------------
 * \fn     DissectBit_ST7(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_ST7(char *pDest, size_t DestSize, LargeWord Inp)
{
  Byte BitPos;
  Word Address;

  DissectBitSymbol(Inp, &Address, &BitPos);

  as_snprintf(pDest, DestSize, "$%x.%u", (unsigned)Address, (unsigned)BitPos);
}

/*!------------------------------------------------------------------------
 * \fn     ExpandST7Bit(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 ExpandST7Bit(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, 0, (pCurrCPUProps->Core == eCoreSTM8) ? 0xffff : 0xff)
     || !ChkRange(pStructElem->BitPos, 0, 7))
      return;

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

/*!------------------------------------------------------------------------
 * \fn     DecodeBitAdrWithIndir(int Start, int Stop, Byte *pBitPos, tAdrVals *pAdrVals)
 * \brief  decode bit expression, regarding indirect mode on ST7
 * \param  Start 1st argument of bit expression
 * \param  Stop 2nd argument of bit expression
 * \param  pAdrVals result to fill
 * \return True if parsing OK
 * ------------------------------------------------------------------------ */

static Boolean DecodeBitAdrWithIndir(int Start, int Stop, Byte *pBitPos, tAdrVals *pAdrVals)
{
  Boolean OK;

  if (Start == Stop)
  {
    LongWord BitSym;
    Word Address;

    if (!DecodeBitArg(&BitSym, Start, Stop))
      return False;
    DissectBitSymbol(BitSym, &Address, pBitPos);
    if (pCurrCPUProps->Core == eCoreSTM8)
    {
      FillAdrVals(pAdrVals, Address, eSymbolSize16Bit);
      pAdrVals->Mode = eModAbs16;
    }
    else
    {
      FillAdrVals(pAdrVals, Address, eSymbolSize8Bit);
      pAdrVals->Mode = eModAbs8;
    }
    PrefixCnt = 0;
    return True;
  }
  else if (Start + 1 == Stop)
  {
    *pBitPos = EvalBitPosition(&ArgStr[Stop], &OK);
    if (!OK)
      return False;
    return DecodeAdr(&ArgStr[Start], (pCurrCPUProps->Core == eCoreSTM8) ? MModAbs16 : (MModAbs8 | MModIAbs8), False, pAdrVals);
  }
  else
    return False;
}

/*!------------------------------------------------------------------------
 * \fn     CompleteCode(const tAdrVals *pAdrVals)
 * \brief  assemble instruction from prefixes, opcode and address values
 * \param  pAdrVals values to append to code
 * ------------------------------------------------------------------------ */

static void CompleteCode(const tAdrVals *pAdrVals)
{
  memcpy(BAsmCode + PrefixCnt + 1, pAdrVals->Vals, pAdrVals->Cnt);
  CodeLen = PrefixCnt + 1 + pAdrVals->Cnt;
}

/*!------------------------------------------------------------------------
 * \fn     WriteMOV(tAdrVals *pDestAdrVals, tAdrVals *pSrcAdrVals)
 * \brief  core of writing code of MOV instruction
 * \param  pDestAdrVals parsed destination operand
 * \param  pSrcAdrVals parsed source operand
 * ------------------------------------------------------------------------ */

static void WriteMOV(tAdrVals *pDestAdrVals, tAdrVals *pSrcAdrVals)
{
  if ((pDestAdrVals->Mode == eModAbs16)
   || (pSrcAdrVals->Mode == eModAbs16)
   || (pSrcAdrVals->Mode == eModImm))
  {
    ExtendAdrVals(pSrcAdrVals);
    ExtendAdrVals(pDestAdrVals);
  }
  switch (pSrcAdrVals->Mode)
  {
    case eModImm:
      BAsmCode[0] = 0x35;
      break;
    case eModAbs8:
      BAsmCode[0] = 0x45;
      break;
    case eModAbs16:
      BAsmCode[0] = 0x55;
      break;
    default:
      break;
  }
  memcpy(&BAsmCode[1], pSrcAdrVals->Vals, pSrcAdrVals->Cnt);
  memcpy(&BAsmCode[1 + pSrcAdrVals->Cnt], pDestAdrVals->Vals, pDestAdrVals->Cnt);
  CodeLen = 1 + pSrcAdrVals->Cnt + pDestAdrVals->Cnt;
}

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

/*!------------------------------------------------------------------------
 * \fn     DecodeFixed(Word Code)
 * \brief  decode instructions without argument
 * \param  per-instruction context
 * ------------------------------------------------------------------------ */

static void DecodeFixed(Word Code)
{
  if (!ChkArgCnt(0, 0));
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else if (Hi(Code) && (pCurrCPUProps->Core != eCoreSTM8)) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else
  {
    if (Hi(Code) >= 2)
      AddPrefix(Hi(Code));
    BAsmCode[PrefixCnt] = Lo(Code);
    CodeLen = PrefixCnt + 1;
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeLD(Word Code)
 * \brief  decode LD instruction
 * ------------------------------------------------------------------------ */

static void DecodeLD(Word Code)
{
  LongWord Mask;
  tAdrVals DestAdrVals, SrcAdrVals;

  UNUSED(Code);

  if (!ChkArgCnt(2, 2));
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else
  {
    /* NOTE: Set eSymbolSizeUnknown so we get X/Y/S also in STM8 mode.
             LD will work like LDW in thi case. */

    Mask = ConstructMask(MModA | MModX | MModY | MModS |  MModXL | MModYL | MModXH | MModYH
                       | MModImm | MModAbs8 | MModAbs16
                       | MModIX | MModIX8 | MModIX16 | MModIY | MModIY8 | MModIY16 | MModISP8
                       | MModIAbs8 | MModIAbs16 | MModI16Abs16
                       | MModIXAbs8 | MModIXAbs16 | MModI16XAbs16 | MModIYAbs8 | MModIYAbs16, eSymbolSizeUnknown);
    if (DecodeAdr(&ArgStr[1], Mask, False, &DestAdrVals))
    switch (DestAdrVals.Mode)
    {
      case eModA:
        Mask = ConstructMask(MModImm | MModX | MModY | MModS | MModXL | MModYL | MModXH | MModYH | MModAbs8 | MModAbs16
             | MModIX | MModIX8 | MModIX16 | MModIY | MModIY8 | MModIY16 | MModISP8
             | MModIAbs8 | MModIAbs16 | MModI16Abs16
             | MModIXAbs8 | MModIXAbs16 | MModI16XAbs16 | MModIYAbs8 | MModIYAbs16, eSymbolSize8Bit);
        if (DecodeAdr(&ArgStr[2], Mask, False, &SrcAdrVals))
        switch (SrcAdrVals.Mode)
        {
          case eModX: case eModXL:
          case eModY: case eModYL:
            BAsmCode[PrefixCnt] = 0x9f;
            CodeLen = PrefixCnt + 1;
            break;
          case eModXH: case eModYH:
            BAsmCode[PrefixCnt] = 0x9e;
            CodeLen = PrefixCnt + 1;
            break;
          case eModS:
            BAsmCode[PrefixCnt] = 0x9e;
            CodeLen = PrefixCnt + 1;
            break;
          case eModISP8: /* irregular, cannot use default case */
            BAsmCode[PrefixCnt] = 0x7b;
            CompleteCode(&SrcAdrVals);
            break;
          default:
            BAsmCode[PrefixCnt] = 0x06 + (SrcAdrVals.Part << 4);
            CompleteCode(&SrcAdrVals);
        }
        break;
      case eModX:
        if (pCurrCPUProps->Core == eCoreSTM8)
          OpSize = eSymbolSize16Bit;
        Mask = ConstructMask(MModA | MModY | MModS | MModImm
                           | MModAbs8 | MModAbs16
                           | MModIX | MModIX8 | MModIX16 | MModISP8
                           | MModIAbs8 | MModIAbs16 | MModI16Abs16
                           | MModIXAbs8 | MModIXAbs16 | MModI16XAbs16, OpSize);
        if (DecodeAdr(&ArgStr[2], Mask, False, &SrcAdrVals))
        switch (SrcAdrVals.Mode)
        {
          case eModA:
            BAsmCode[PrefixCnt] = 0x97;
            CodeLen = PrefixCnt + 1;
            break;
          case eModY:
            BAsmCode[0] = 0x93;
            CodeLen = 1;
            break;
          case eModS:
            BAsmCode[PrefixCnt] = 0x96;
            CodeLen = PrefixCnt + 1;
            break;
          default:
            BAsmCode[PrefixCnt] = 0x0e + (SrcAdrVals.Part << 4); /* ANSI :-O */
            CompleteCode(&SrcAdrVals);
        }
        break;
      case eModXL:
      case eModYL:
        if (DecodeAdr(&ArgStr[2], MModA, False, &SrcAdrVals))
        {
          BAsmCode[PrefixCnt] = 0x97;
          CodeLen = PrefixCnt + 1;
        }
        break;
      case eModXH:
      case eModYH:
        if (DecodeAdr(&ArgStr[2], MModA, False, &SrcAdrVals))
        {
          BAsmCode[PrefixCnt] = 0x95;
          CodeLen = PrefixCnt + 1;
        }
        break;
      case eModY:
        PrefixCnt = 0;
        if (pCurrCPUProps->Core == eCoreSTM8)
          OpSize = eSymbolSize16Bit;
        Mask = ConstructMask(MModA | MModX | MModS | MModImm
                           | MModAbs8 | MModAbs16
                           | MModIY | MModIY8 | MModIY16 | MModISP8
                           | MModIAbs8 | MModIAbs16 | MModIYAbs8 | MModIYAbs16, OpSize);
        if (DecodeAdr(&ArgStr[2], Mask, False, &SrcAdrVals))
        switch (SrcAdrVals.Mode)
        {
          case eModA:
            AddPrefix(0x90);
            BAsmCode[PrefixCnt] = 0x97;
            CodeLen = PrefixCnt + 1;
            break;
          case eModX:
            AddPrefix(0x90);
            BAsmCode[PrefixCnt] = 0x93;
            CodeLen = PrefixCnt + 1;
            break;
          case eModS:
            AddPrefix(0x90);
            BAsmCode[PrefixCnt] = 0x96;
            CodeLen = PrefixCnt + 1;
            break;
          case eModISP8:
            BAsmCode[PrefixCnt] = 0x16;
            goto common;
          default:
            if (PrefixCnt == 0) AddPrefix(0x90);
            if (BAsmCode[0] == 0x92) BAsmCode[0]--;
            BAsmCode[PrefixCnt] = 0x0e + (SrcAdrVals.Part << 4); /* ANSI :-O */
          common:
            CompleteCode(&SrcAdrVals);
        }
        break;
      case eModS:
        if (DecodeAdr(&ArgStr[2], MModA | MModX | MModY, False, &SrcAdrVals))
        switch (SrcAdrVals.Mode)
        {
          case eModA:
            BAsmCode[PrefixCnt] = 0x95;
            CodeLen = PrefixCnt + 1;
            break;
          case eModX:
          case eModY:
            BAsmCode[PrefixCnt] = 0x94;
            CodeLen = PrefixCnt + 1;
            break;
          default:
            break;
        }
        break;
      default:
      {
        Boolean Result;
        unsigned SavePrefixCnt = PrefixCnt;

        /* set unknown size to allow X&Y also on STM8 if LD is written instead of LDW */
        Mask = ConstructMask(MModA | MModX | MModY, eSymbolSizeUnknown);
        /* aliases for MOV */
        if (pCurrCPUProps->Core == eCoreSTM8)
          switch (DestAdrVals.Mode)
          {
            case eModAbs16:
              Mask |= MModAbs16 | MModImm;
              break;
            case eModAbs8:
              Mask |= MModAbs8 | MModAbs16 | MModImm;
              break;
            default:
              break;
          }
        Result = DecodeAdr(&ArgStr[2], Mask, False, &SrcAdrVals);
        PrefixCnt = SavePrefixCnt;
        if (Result)
        switch (SrcAdrVals.Mode)
        {
          case eModA:
            Mask = ConstructMask(MModAbs8 | MModAbs16
                               | MModIX | MModIX8 | MModIX16 | MModIY | MModIY8 | MModIY16 | MModISP8
                               | MModIAbs8 | MModIAbs16 | MModI16Abs16 | MModIXAbs8 | MModIXAbs16 | MModI16XAbs16 | MModIYAbs8 | MModIYAbs16, eSymbolSize8Bit);
            if (ChkAdrValsMode(&DestAdrVals, Mask, ErrNum_InvAddrMode, &ArgStr[1]))
            {
              BAsmCode[PrefixCnt] = (DestAdrVals.Mode == eModISP8) ? 0x6b : (0x07 + (DestAdrVals.Part << 4));
              CompleteCode(&DestAdrVals);
            }
            break;
          case eModX:
            Mask = MModAbs8 | MModAbs16 | MModIAbs16;
            if (pCurrCPUProps->Core == eCoreST7)
              Mask |= MModIX | MModIX8 | MModIX16 | MModIAbs8 | MModIXAbs8 | MModIXAbs16;
            if (pCurrCPUProps->Core == eCoreSTM8)
              Mask |= MModIY | MModIY8 | MModIY16 | MModIYAbs16 | MModISP8 | MModI16Abs16;
            if (ChkAdrValsMode(&DestAdrVals, Mask, ErrNum_InvAddrMode, &ArgStr[1]))
            {
              BAsmCode[PrefixCnt] = 0x0f + (DestAdrVals.Part << 4);
              CompleteCode(&DestAdrVals);
            }
            break;
          case eModY:
            Mask = MModAbs8 | MModAbs16 | MModIAbs16;
            if (pCurrCPUProps->Core == eCoreST7)
              Mask |= MModIY | MModIY8 | MModIY16 | MModIAbs8 | MModIYAbs8 | MModIYAbs16;
            if (pCurrCPUProps->Core == eCoreSTM8)
              Mask |= MModIX | MModIX8 | MModIX16 | MModIXAbs16 | MModI16XAbs16 | MModISP8;
            if (ChkAdrValsMode(&DestAdrVals, Mask, ErrNum_InvAddrMode, &ArgStr[1]))
            switch (DestAdrVals.Mode)
            {
              case eModISP8:
                PrefixCnt = 0;
                BAsmCode[PrefixCnt] = 0x07 + (DestAdrVals.Part << 4);
                goto common_ysrc2;
              case eModIX:
              case eModIX8:
              case eModIX16:
                PrefixCnt = 0;
                goto common_ysrc;
              case eModIXAbs16:
                goto common_ysrc;
              default:
                if (PrefixCnt == 0) AddPrefix(0x90);
                if (BAsmCode[0] == 0x92) BAsmCode[0]--;
              common_ysrc:
                BAsmCode[PrefixCnt] = 0x0f + (DestAdrVals.Part << 4);
              common_ysrc2:
                CompleteCode(&DestAdrVals);
            }
            break;
          case eModImm: /* MOV aliases: only possible if Dest = Abs8/16 */
          case eModAbs8:
          case eModAbs16:
            WriteMOV(&DestAdrVals, &SrcAdrVals);
            break;
          default:
            break;
        }
      }
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeLDW(Word Code)
 * \brief  decode LDW instruction
 * ------------------------------------------------------------------------ */

static void DecodeLDW(Word Code)
{
  tAdrVals DestAdrVals, SrcAdrVals;
  LongWord Mask;

  UNUSED(Code);
  if (!ChkArgCnt(2, 2));
  else if (pCurrCPUProps->Core != eCoreSTM8) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else
  {
    Mask = ConstructMask(MModX | MModY | MModS
                       | MModAbs8 | MModAbs16
                       | MModIX | MModIX8 | MModIX16 | MModIY | MModIY8 | MModIY16 | MModISP8
                       | MModIAbs16 | MModI16Abs16 | MModIXAbs16 | MModI16XAbs16 | MModIYAbs16, OpSize = eSymbolSize16Bit);
    if (DecodeAdr(&ArgStr[1], Mask, False, &DestAdrVals))
    switch (DestAdrVals.Mode)
    {
      case eModX:
        Mask = ConstructMask(MModY | MModS | MModImm
                           | MModAbs8 | MModAbs16
                           | MModIX | MModIX8 | MModIX16 | MModISP8
                           | MModIAbs16 | MModI16Abs16 | MModIXAbs16 | MModI16XAbs16, eSymbolSize16Bit);
        if (DecodeAdr(&ArgStr[2], Mask, False, &SrcAdrVals))
        switch (SrcAdrVals.Mode)
        {
          case eModY:
            PrefixCnt = 0;
            BAsmCode[PrefixCnt] = 0x93;
            CodeLen = PrefixCnt + 1;
            break;
          case eModS:
            BAsmCode[PrefixCnt] = 0x96;
            CodeLen = PrefixCnt + 1;
            break;
          default:
            BAsmCode[PrefixCnt] = 0x0e | (SrcAdrVals.Part << 4);
            CompleteCode(&SrcAdrVals);
            break;
        }
        break;
      case eModY:
        PrefixCnt = 0;
        Mask = ConstructMask(MModX | MModS | MModImm
                           | MModAbs8 | MModAbs16
                           | MModIY | MModIY8 | MModIY16 | MModISP8
                           | MModIAbs16 | MModIYAbs16, eSymbolSize16Bit);
        DecodeAdr(&ArgStr[2], Mask, False, &SrcAdrVals);
        if (!PrefixCnt)
          AddPrefix(0x90);
        if (SrcAdrVals.Mode != eModNone)
        switch (SrcAdrVals.Mode)
        {
          case eModX:
            BAsmCode[PrefixCnt] = 0x93;
            CodeLen = PrefixCnt + 1;
            break;
          case eModS:
            BAsmCode[PrefixCnt] = 0x96;
            CodeLen = PrefixCnt + 1;
            break;
          case eModISP8:
            PrefixCnt = 0;
            BAsmCode[PrefixCnt] = 0x16;
            goto common_x;
          case eModIAbs16:
            PrefixCnt = 0;
            AddPrefix(0x91);
            /* fall-through */
          default:
            BAsmCode[PrefixCnt] = 0x0e | (SrcAdrVals.Part << 4);
          common_x:
            CompleteCode(&SrcAdrVals);
            break;
        }
        break;
      case eModS:
        Mask = ConstructMask(MModX | MModY, eSymbolSize16Bit);
        if (DecodeAdr(&ArgStr[2], Mask, False, &SrcAdrVals))
        {
          BAsmCode[PrefixCnt] = 0x94;
          CodeLen = PrefixCnt + 1;
        }
        break;
      default:
      {
        Mask = ConstructMask(MModX | MModY, eSymbolSize16Bit);
        if (DecodeReg(&ArgStr[2], &SrcAdrVals.Mode, Mask))
        switch (DestAdrVals.Mode)
        {
          case eModIAbs16:
            if (eModY == SrcAdrVals.Mode)
            {
              PrefixCnt = 0;
              AddPrefix(0x91);
            }
            goto common_y2;
          case eModISP8:
            BAsmCode[PrefixCnt] = (eModY == SrcAdrVals.Mode) ? 0x17 : 0x1f;
            goto common_y;
          case eModAbs8:
          case eModAbs16:
            if (eModY == SrcAdrVals.Mode)
              AddPrefix(0x90);
            /* fall-through */
          default:
          common_y2:
            BAsmCode[PrefixCnt] = 0x0f | (DestAdrVals.Part << 4);
          common_y:
            CompleteCode(&DestAdrVals);
            break;
        }
        break;
      }
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeLDF(Word Code)
 * \brief  decode LDF instruction
 * ------------------------------------------------------------------------ */

static void DecodeLDF(Word Code)
{
  tAdrVals AdrVals;

  UNUSED(Code);
  if (!ChkArgCnt(2, 2));
  else if (pCurrCPUProps->Core != eCoreSTM8) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else if (DecodeAdr(&ArgStr[1], MModA | MModAbs24 | MModIX24 | MModIY24 | MModI16XAbs24 | MModI16YAbs24 | MModI16Abs24, False, &AdrVals))
  switch (AdrVals.Mode)
  {
    case eModA:
      if (DecodeAdr(&ArgStr[2], MModAbs24 | MModIX24 | MModIY24 | MModI16XAbs24 | MModI16YAbs24 | MModI16Abs24, False, &AdrVals))
      {
        switch (AdrVals.Mode)
        {
          case eModAbs24:
          case eModI16Abs24:
            BAsmCode[PrefixCnt] = 0x0c | (AdrVals.Part << 4);
            break;
          case eModIX24:
          case eModIY24:
          case eModI16XAbs24:
          case eModI16YAbs24:
            BAsmCode[PrefixCnt] = 0x0f | (AdrVals.Part << 4);
            break;
          default:
            break;
        }
        CompleteCode(&AdrVals);
      }
      break;
    default:
    {
      tAdrMode RegMode;

      if (DecodeReg(&ArgStr[2], &RegMode, MModA))
      {
        switch (AdrVals.Mode)
        {
          case eModAbs24:
          case eModI16Abs24:
            BAsmCode[PrefixCnt] = 0x0d | (AdrVals.Part << 4);
            break;
          case eModIX24:
          case eModIY24:
          case eModI16XAbs24:
          case eModI16YAbs24:
            BAsmCode[PrefixCnt] = 0x07 | (AdrVals.Part << 4);
            break;
          default:
            break;
        }
        CompleteCode(&AdrVals);
      }
      break;
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeMOV(Word Code)
 * \brief  decode MOV instruction
 * ------------------------------------------------------------------------ */

static void DecodeMOV(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;

  UNUSED(Code);
  if (!ChkArgCnt(2, 2));
  else if (pCurrCPUProps->Core != eCoreSTM8) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else if (DecodeAdr(&ArgStr[2], MModImm | MModAbs8 | MModAbs16, False, &SrcAdrVals))
  {
    if (DecodeAdr(&ArgStr[1], ((SrcAdrVals.Mode == eModAbs8) ? MModAbs8 : 0) | MModAbs16, False, &DestAdrVals))
      WriteMOV(&DestAdrVals, &SrcAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodePUSH_POP(Word Code)
 * \brief  decode PUSH(W)/POP(W) instructions
 * \param  Code instruction context
 * ------------------------------------------------------------------------ */

static void DecodePUSH_POP(Word Code)
{
  if (!ChkArgCnt(1, 1));
  else if (Hi(Code) && (pCurrCPUProps->Core != eCoreSTM8)) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else
  {
    LongWord Mask;
    tAdrVals AdrVals;

    Mask = MModX | MModY | (Hi(Code) ? 0 : MModA);
    if (pCurrCPUProps->Core == eCoreSTM8)
    {
      Mask |= MModAbs16;
      if (Lo(Code))
        Mask |= MModImm;
    }
    if (!as_strcasecmp(ArgStr[1].str.p_str, "CC"))
    {
      BAsmCode[PrefixCnt] = 0x86 + Lo(Code);
      CodeLen = PrefixCnt + 1;
    }
    else if (DecodeAdr(&ArgStr[1], Mask, False, &AdrVals))
    {
      switch (AdrVals.Mode)
      {
        case eModA:
          BAsmCode[PrefixCnt] = 0x84 + Lo(Code);
          break;
        case eModX:
        case eModY:
          BAsmCode[PrefixCnt] = 0x85 + Lo(Code);
          break;
        case eModAbs16:
          BAsmCode[PrefixCnt] = Lo(Code) ? 0x4b : 0x32;
          break;
        case eModImm:
          BAsmCode[PrefixCnt] = 0x4b;
          break;
        default:
          break;
      }
      CompleteCode(&AdrVals);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeCP(Word Code)
 * \brief  decode CP(W) instructions
 * \param  IsCPW 1 if CPW
 * ------------------------------------------------------------------------ */

static void DecodeCP(Word IsCPW)
{
  LongWord Mask;

  if (!ChkArgCnt(2, 2));
  else if (IsCPW && (pCurrCPUProps->Core != eCoreSTM8)) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else
  {
    tAdrVals SrcAdrVals;
    tAdrMode DestMode;

    if (DecodeReg(&ArgStr[1], &DestMode, (IsCPW ? 0 : MModA) | MModX | MModY))
    switch (DestMode)
    {
      case eModA:
        Mask = ConstructMask(MModImm | MModAbs8 | MModAbs16
                           | MModIX | MModIX8 | MModIX16 | MModIY | MModIY8 | MModIY16 | MModISP8
                           | MModIAbs8 | MModIAbs16 | MModI16Abs16
                           | MModIXAbs8 | MModIXAbs16 | MModI16XAbs16 | MModIYAbs8 | MModIYAbs16, eSymbolSize8Bit);
        if (DecodeAdr(&ArgStr[2], Mask, False, &SrcAdrVals))
        {
          BAsmCode[PrefixCnt] = 0x01 + (SrcAdrVals.Part << 4);
          CompleteCode(&SrcAdrVals);
        }
        break;
      case eModX:
        Mask = MModImm | MModAbs8 | MModAbs16 | MModIAbs16;
        if (pCurrCPUProps->Core == eCoreST7)
          Mask |= MModIAbs8 | MModIXAbs8 | MModIX | MModIX8 | MModIX16 | MModIXAbs16;
        if (pCurrCPUProps->Core == eCoreSTM8)
        {
          Mask |= MModIY | MModIY8 | MModIY16 | MModISP8 | MModI16Abs16 | MModIYAbs16;
          OpSize = eSymbolSize16Bit;
        }
        if (DecodeAdr(&ArgStr[2], Mask, False, &SrcAdrVals))
        {
          BAsmCode[PrefixCnt] = 0x03 + (SrcAdrVals.Part << 4);
          CompleteCode(&SrcAdrVals);
        }
        break;
      case eModY:
        PrefixCnt = 0;
        Mask = MModImm | MModAbs8 | MModAbs16 | MModIAbs16;
        if (pCurrCPUProps->Core == eCoreST7)
          Mask |= MModIAbs8 | MModIYAbs8 | MModIY | MModIY8 | MModIY16 | MModIYAbs16;
        if (pCurrCPUProps->Core == eCoreSTM8)
        {
          Mask |= MModIX | MModIX8 | MModIX16 | MModIXAbs16 | MModI16XAbs16;
          OpSize = eSymbolSize16Bit;
        }
        if (DecodeAdr(&ArgStr[2], Mask, False, &SrcAdrVals))
        switch (SrcAdrVals.Mode)
        {
          case eModIXAbs16:
          case eModIX:
          case eModIX8:
          case eModIX16:
            goto common;
          default:
            if (PrefixCnt == 0) AddPrefix(0x90);
            if (BAsmCode[0] == 0x92) BAsmCode[0]--;
          common:
            BAsmCode[PrefixCnt] = 0x03 + (SrcAdrVals.Part << 4);
            CompleteCode(&SrcAdrVals);
        }
        break;
      default:
        break;
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeAri16(Word Code)
 * \brief  decode 16-bit arithmetic/logic instructions with two operands
 * \param  Code instruction code
 * ------------------------------------------------------------------------ */

static void DecodeAri16(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;

  if (!ChkArgCnt(2, 2));
  else if (pCurrCPUProps->Core != eCoreSTM8) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else if (DecodeAdr(&ArgStr[1], MModX | MModY | MModS, False, &DestAdrVals))
  switch (DestAdrVals.Mode)
  {
    case eModX:
    case eModY:
      OpSize = eSymbolSize16Bit;
      if (DecodeAdr(&ArgStr[2], MModImm | MModAbs16 | MModISP8, False, &SrcAdrVals))
      switch (SrcAdrVals.Mode)
      {
        case eModImm:
          if (PrefixCnt)
          {
            BAsmCode[PrefixCnt - 1] = 0x72;
            BAsmCode[PrefixCnt] = 0xa0 | Hi(Code);
          }
          else
            BAsmCode[PrefixCnt] = 0x1d - !!Lo(Code);
          goto common;
        case eModAbs16:
          if (PrefixCnt)
          {
            BAsmCode[PrefixCnt - 1] = 0x72;
            BAsmCode[PrefixCnt] = 0xb0 | Hi(Code);
          }
          else
          {
            BAsmCode[PrefixCnt++] = 0x72;
            BAsmCode[PrefixCnt] = 0xb0 | Lo(Code);
          }
          goto common;
        case eModISP8:
          if (PrefixCnt)
          {
            BAsmCode[PrefixCnt - 1] = 0x72;
            BAsmCode[PrefixCnt] = 0xf0 | Hi(Code);
          }
          else
          {
            BAsmCode[PrefixCnt++] = 0x72;
            BAsmCode[PrefixCnt] = 0xf0 | Lo(Code);
          }
          goto common;
        common:
          CompleteCode(&SrcAdrVals);
          break;
        default:
          break;
      }
      break;
    case eModS:
      OpSize = eSymbolSize8Bit;
      if (DecodeAdr(&ArgStr[2], MModImm, False, &SrcAdrVals))
      {
        BAsmCode[0] = 0x52 | Lo(Code);
        BAsmCode[1] = SrcAdrVals.Vals[0];
        CodeLen = 2;
      }
      break;
    default:
      break;
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeAri(Word Code)
 * \brief  decode 8-bit arithmetic/logic instructions with two operands
 * \param  Code instruction code
 * ------------------------------------------------------------------------ */

static void DecodeAri(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;
  LongWord Mask;
  Word Code16 = 0;

  if (!ChkArgCnt(2, 2));
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else
  {
    Mask = MModA;
    if (pCurrCPUProps->Core == eCoreSTM8)
      switch (Lo(Code))
      {
        case 0x00: /* SUB->SUBW */
          Code16 = 0x0200;
          Mask |= MModS | MModX | MModY;
          break;
        case 0x0b: /* ADD->ADDW */
          Code16 = 0x090b;
          Mask |= MModS | MModX | MModY;
          break;
      }
    if (DecodeAdr(&ArgStr[1], Mask, False, &DestAdrVals))
    switch (DestAdrVals.Mode)
    {
      case eModA:
        Mask = MModAbs8 | MModAbs16 | MModIX | MModIX8 | MModIX16 | MModIY |
               MModIY8 | MModIY16 | MModIAbs16 | MModIXAbs16 | MModIYAbs16;
        if (pCurrCPUProps->Core == eCoreST7)
          Mask |= MModIAbs8 | MModIXAbs8 | MModIYAbs8;
        if (pCurrCPUProps->Core == eCoreSTM8)
          Mask |= MModISP8 | MModI16Abs16 | MModI16XAbs16;
        if (Hi(Code)) Mask |= MModImm;
        if (DecodeAdr(&ArgStr[2], Mask, False, &SrcAdrVals))
        {
          BAsmCode[PrefixCnt] = Lo(Code) + (SrcAdrVals.Part << 4);
          CompleteCode(&SrcAdrVals);
        }
        break;
      case eModS:
      case eModX:
      case eModY:
        PrefixCnt = 0;
        DecodeAri16(Code16);
      default:
        break;
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeRMW(Word Code)
 * \brief  decode 8-bit read/modify/write instructions with one operand
 * \param  Code instruction code
 * ------------------------------------------------------------------------ */

static void DecodeRMW(Word Code)
{
  Boolean IsW = Hi(Code);

  Code = Lo(Code);
  if (!ChkArgCnt(1, 1));
  else if (IsW && (pCurrCPUProps->Core != eCoreSTM8)) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else
  {
    LongWord Mask;
    tAdrVals AdrVals;

    Mask = MModX | MModY;
    if (!IsW)
    {
      Mask |= MModA |  MModAbs8
            | MModIX | MModIX8 | MModIY | MModIY8;
      if (pCurrCPUProps->Core == eCoreST7)
        Mask |= MModIAbs8 | MModIXAbs8 | MModIYAbs8;
      if (pCurrCPUProps->Core == eCoreSTM8)
        Mask |= MModAbs16 | MModIX16 | MModIY16 | MModISP8
              | MModIAbs16 | MModI16Abs16 | MModIXAbs16 | MModI16XAbs16 | MModIYAbs16;
    }
    if (DecodeAdr(&ArgStr[1], Mask, False, &AdrVals))
    switch (AdrVals.Mode)
    {
      case eModA:
        BAsmCode[PrefixCnt] = 0x40 + Code;
        CodeLen = PrefixCnt + 1;
        break;
      case eModX:
      case eModY:
        BAsmCode[PrefixCnt] = 0x50 + Code;
        CodeLen = PrefixCnt + 1;
        break;
      case eModAbs16:
        BAsmCode[PrefixCnt++] = 0x72;
        BAsmCode[PrefixCnt] = 0x50 | Code;
        goto common;
      case eModIX16:
        BAsmCode[PrefixCnt++] = 0x72;
        BAsmCode[PrefixCnt] = 0x40 | Code;
        goto common;
      case eModIY16:
        BAsmCode[PrefixCnt] = 0x40 | Code;
        goto common;
      case eModISP8:
        BAsmCode[PrefixCnt] = 0x00 | Code;
        goto common;
      case eModIAbs16:
      case eModI16Abs16:
        BAsmCode[PrefixCnt] = 0x30 | Code;
        goto common;
      case eModIXAbs16:
      case eModI16XAbs16:
      case eModIYAbs16:
        BAsmCode[PrefixCnt] = 0x60 | Code;
        goto common;
      default:
        BAsmCode[PrefixCnt] = Code + ((AdrVals.Part - 8) << 4);
        /* fall-through */
      common:
        CompleteCode(&AdrVals);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeMUL(Word Code)
 * \brief  decode MUL instruction
 * ------------------------------------------------------------------------ */

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

  if (!ChkArgCnt(2, 2));
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else
  {
    tAdrMode SrcMode;
    tAdrVals DestVals;

    if (DecodeReg(&ArgStr[2], &SrcMode, MModA)
     && DecodeAdr(&ArgStr[1], MModX | MModY, False, &DestVals))
    {
      BAsmCode[PrefixCnt] = 0x42;
      CodeLen = PrefixCnt + 1;
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeDIV(Word Code)
 * \brief  decode DIV(W) instructions
 * \param  IsW True if DIVW
 * ------------------------------------------------------------------------ */

static void DecodeDIV(Word IsW)
{
  tAdrVals DestAdrVals, SrcAdrVals;

  if (!ChkArgCnt(2, 2));
  else if (pCurrCPUProps->Core != eCoreSTM8) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else if (DecodeAdr(&ArgStr[1], MModX | (IsW ? 0 : MModY), False, &DestAdrVals)
        && DecodeAdr(&ArgStr[2], MModY | (IsW ? 0 : MModA), False, &SrcAdrVals))
  {
    BAsmCode[PrefixCnt] = (SrcAdrVals.Mode == eModA) ? 0x62 : 0x65;
    CodeLen = PrefixCnt + 1;
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeEXG(Word Code)
 * \brief  decode EXG(W) instructions
 * \param  IsW True if EXGW
 * ------------------------------------------------------------------------ */

static void DecodeEXG(Word IsW)
{
  tAdrVals DestAdrVals, SrcAdrVals;

  if (!ChkArgCnt(2, 2));
  else if (pCurrCPUProps->Core != eCoreSTM8) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else if (DecodeAdr(&ArgStr[1], (IsW ? 0 : (MModA | MModXL | MModYL | MModAbs16)) | MModX | MModY, False, &DestAdrVals))
  switch (DestAdrVals.Mode)
  {
    case eModA:
      if (DecodeAdr(&ArgStr[2], MModXL | MModYL | MModAbs16, False, &SrcAdrVals))
      switch (SrcAdrVals.Mode)
      {
        case eModXL:
          BAsmCode[0] = 0x41;
          CodeLen = 1;
          break;
        case eModYL:
          BAsmCode[0] = 0x61;
          CodeLen = 1;
          break;
        case eModAbs16:
          BAsmCode[0] = 0x31;
          CompleteCode(&SrcAdrVals);
          break;
        default:
          break;
      }
      break;
    case eModXL:
      if (DecodeAdr(&ArgStr[2], MModA, False, &SrcAdrVals))
      {
        BAsmCode[0] = 0x41;
        CodeLen = 1;
      }
      break;
    case eModYL:
      if (DecodeAdr(&ArgStr[2], MModA, False, &SrcAdrVals))
      {
        BAsmCode[0] = 0x61;
        CodeLen = 1;
      }
      break;
    case eModAbs16:
      if (DecodeAdr(&ArgStr[2], MModA, False, &SrcAdrVals))
      {
        BAsmCode[0] = 0x31;
        memcpy(&BAsmCode[1], SrcAdrVals.Vals, SrcAdrVals.Cnt);
        CodeLen = 3;
      }
      break;
    case eModX:
      if (DecodeAdr(&ArgStr[2], MModY, False, &SrcAdrVals))
      {
        BAsmCode[0] = 0x51;
        CodeLen = 1;
      }
      break;
    case eModY:
      if (DecodeAdr(&ArgStr[2], MModX, False, &SrcAdrVals))
      {
        BAsmCode[0] = 0x51;
        CodeLen = 1;
      }
      break;
    default:
      break;
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeBitOp(Word Code)
 * \brief  decode bit operation instructions
 * \param  Code instruction code
 * ------------------------------------------------------------------------ */

static void DecodeBitOp(Word Code)
{
  Byte BitPos;
  tAdrVals AdrVals;

  if (!ChkArgCnt(1, 2));
  else if ((Hi(Code == 0x90)) && (pCurrCPUProps->Core != eCoreSTM8)) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else if (DecodeBitAdrWithIndir(1, ArgCnt, &BitPos, &AdrVals))
  {
    if (pCurrCPUProps->Core == eCoreSTM8)
    {
      PrefixCnt = 0;
      AddPrefix(Hi(Code));
      BAsmCode[PrefixCnt] = 0x10 | (BitPos << 1) | (Code & 1);
    }
    else
      BAsmCode[PrefixCnt] = Lo(Code) + (BitPos << 1);
    CompleteCode(&AdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeBTJF_BTJT(Word Code)
 * \brief  decode BTJF/BTJT instructions
 * \param  Code instruction code
 * ------------------------------------------------------------------------ */

static void DecodeBTJF_BTJT(Word Code)
{
  Byte BitPos;
  tAdrVals AdrVals;

  if (!ChkArgCnt(2, 3));
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else if (DecodeBitAdrWithIndir(1, ArgCnt - 1, &BitPos, &AdrVals))
  {
    Integer AdrInt;
    Boolean OK;
    tSymbolFlags Flags;

    if (pCurrCPUProps->Core == eCoreSTM8)
    {
      PrefixCnt = 0;
      AddPrefix(0x72);
    }
    BAsmCode[PrefixCnt] = Code + (BitPos << 1);
    memcpy(BAsmCode + 1 + PrefixCnt, AdrVals.Vals, AdrVals.Cnt);
    AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[3], pCurrCPUProps->AddrIntType, &OK, &Flags) - (EProgCounter() + PrefixCnt + 1 + AdrVals.Cnt + 1);
    if (OK)
    {
      if (!mSymbolQuestionable(Flags) && ((AdrInt < -128) || (AdrInt > 127))) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[3]);
      else
      {
        BAsmCode[PrefixCnt + 1 + AdrVals.Cnt] = AdrInt & 0xff;
        CodeLen = PrefixCnt + 1 + AdrVals.Cnt + 1;
      }
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeJP_CALL(Word Code)
 * \brief  decode JP/CALL instructions
 * \param  Code instruction code
 * ------------------------------------------------------------------------ */

static void DecodeJP_CALL(Word Code)
{
  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else
  {
    LongWord Mask;
    tAdrVals AdrVals;

    Mask = ConstructMask(MModAbs8 | MModAbs16 | MModIX | MModIX8 | MModIX16 | MModIY
                       | MModIY8 | MModIY16 | MModIAbs8 | MModIAbs16 | MModI16Abs16
                       | MModIXAbs8 | MModIXAbs16 | MModI16XAbs16 | MModIYAbs8 | MModIYAbs16,
                         eSymbolSizeUnknown);
    if (DecodeAdr(&ArgStr[1], Mask, True, &AdrVals))
    {
      BAsmCode[PrefixCnt] = Code + (AdrVals.Part << 4);
      CompleteCode(&AdrVals);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeJPF_CALLF(Word Code)
 * \brief  decode JPF/CALLF instructions
 * \param  Code instruction code
 * ------------------------------------------------------------------------ */

static void DecodeJPF_CALLF(Word Code)
{
  tAdrVals AdrVals;

  if (!ChkArgCnt(1, 1));
  else if (pCurrCPUProps->Core != eCoreSTM8) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else if (DecodeAdr(&ArgStr[1], MModAbs24 | MModI16Abs24, True, &AdrVals))
  {
    BAsmCode[PrefixCnt] = Code;
    CompleteCode(&AdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeRel(Word Code)
 * \brief  decode relative branch instructions
 * \param  instruction code
 * ------------------------------------------------------------------------ */

static void DecodeRel(Word Code)
{
  if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else if (!Code) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else if (!ChkArgCnt(1, 1));
  else if (*ArgStr[1].str.p_str == '[')
  {
    if (pCurrCPUProps->Core != eCoreST7) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
    else
    {
      tAdrVals AdrVals;

      if (DecodeAdr(&ArgStr[1], MModIAbs8, False, &AdrVals))
      {
        BAsmCode[PrefixCnt] = Lo(Code);
        CompleteCode(&AdrVals);
      }
    }
  }
  else
  {
    Boolean OK;
    Integer AdrInt;
    tSymbolFlags Flags;

    if (Hi(Code))
      BAsmCode[PrefixCnt++] = Hi(Code);
    AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[1], pCurrCPUProps->AddrIntType, &OK, &Flags) - (EProgCounter() + 2 + PrefixCnt);
    if (OK)
    {
      if (!mSymbolQuestionable(Flags) && ((AdrInt < -128) || (AdrInt > 127))) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
      else
      {
        BAsmCode[PrefixCnt] = Lo(Code);
        BAsmCode[PrefixCnt + 1] = AdrInt & 0xff;
        CodeLen = PrefixCnt + 2;
      }
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeRxWA(Word Code)
 * \brief  decode RLWA/RRWA instructions
 * \param  Code instruction code
 * ------------------------------------------------------------------------ */

static void DecodeRxWA(Word Code)
{
  tAdrMode SrcMode;
  tAdrVals DestAdrVals;

  if (*AttrPart.str.p_str) WrStrErrorPos(ErrNum_UseLessAttr, &AttrPart);
  else if (!ChkArgCnt(1, 2));
  else if (pCurrCPUProps->Core != eCoreSTM8) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  else if (((ArgCnt == 1) || DecodeReg(&ArgStr[2], &SrcMode, MModA)) && DecodeAdr(&ArgStr[1], MModX | MModY, False, &DestAdrVals))
  {
    BAsmCode[PrefixCnt] = Code;
    CodeLen = PrefixCnt + 1;
  }
}

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

static void DecodeBIT(Word Code)
{
  LongWord BitSpec;

  UNUSED(Code);

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

  if (ActPC == StructSeg)
  {
    Boolean OK;
    Byte BitPos;
    PStructElem pElement;

    if (!ChkArgCnt(2, 2))
      return;
    BitPos = EvalBitPosition(&ArgStr[2], &OK);
    if (!OK)
      return;
    pElement = CreateStructElem(&LabPart);
    if (!pElement)
      return;
    pElement->pRefElemName = as_strdup(ArgStr[1].str.p_str);
    pElement->OpSize = eSymbolSize8Bit;
    pElement->BitPos = BitPos;
    pElement->ExpandFnc = ExpandST7Bit;
    AddStructElem(pInnermostNamedStruct->StructRec, pElement);
  }
  else
  {
    if (DecodeBitArg(&BitSpec, 1, ArgCnt))
    {
      *ListLine = '=';
      DissectBit_ST7(ListLine + 1, STRINGSIZE - 3, BitSpec);
      PushLocHandle(-1);
      EnterIntSymbol(&LabPart, BitSpec, SegBData, False);
      PopLocHandle();
      /* TODO: MakeUseList? */
    }
  }
}

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

/*!------------------------------------------------------------------------
 * \fn     InitFields(void)
 * \brief  build up hash table of instructions
 * ------------------------------------------------------------------------ */

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

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

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

static void AddRMW(const char *NName, Byte NCode)
{
  char WName[10];

  AddInstTable(InstTable, NName, NCode, DecodeRMW);
  as_snprintf(WName, sizeof(WName), "%sW", NName);
  AddInstTable(InstTable, WName, NCode | 0x100, DecodeRMW);
}

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

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

  AddInstTable(InstTable, "LD", 0, DecodeLD);
  AddInstTable(InstTable, "LDF", 0, DecodeLDF);
  AddInstTable(InstTable, "LDW", 0, DecodeLDW);
  AddInstTable(InstTable, "MOV", 0, DecodeMOV);
  AddInstTable(InstTable, "PUSH", 0x0004, DecodePUSH_POP);
  AddInstTable(InstTable, "POP", 0x0000, DecodePUSH_POP);
  AddInstTable(InstTable, "PUSHW", 0x0104, DecodePUSH_POP);
  AddInstTable(InstTable, "POPW", 0x0100, DecodePUSH_POP);
  AddInstTable(InstTable, "CP", 0, DecodeCP);
  AddInstTable(InstTable, "CPW", 1, DecodeCP);
  AddInstTable(InstTable, "MUL", 0, DecodeMUL);
  AddInstTable(InstTable, "DIV", 0, DecodeDIV);
  AddInstTable(InstTable, "DIVW", 1, DecodeDIV);
  AddInstTable(InstTable, "EXG", 0, DecodeEXG);
  AddInstTable(InstTable, "EXGW", 1, DecodeEXG);
  AddInstTable(InstTable, "RLWA", 0x02, DecodeRxWA);
  AddInstTable(InstTable, "RRWA", 0x01, DecodeRxWA);
  AddInstTable(InstTable, "BCCM", 0x9001, DecodeBitOp);
  AddInstTable(InstTable, "BCPL", 0x9000, DecodeBitOp);
  AddInstTable(InstTable, "BRES", 0x7211, DecodeBitOp);
  AddInstTable(InstTable, "BSET", 0x7210, DecodeBitOp);
  AddInstTable(InstTable, "BTJF", 0x01, DecodeBTJF_BTJT);
  AddInstTable(InstTable, "BTJT", 0x00, DecodeBTJF_BTJT);
  AddInstTable(InstTable, "JP", 0x0c, DecodeJP_CALL);
  AddInstTable(InstTable, "CALL", 0x0d, DecodeJP_CALL);
  AddInstTable(InstTable, "JPF", 0xac, DecodeJPF_CALLF);
  AddInstTable(InstTable, "CALLF", 0x8d, DecodeJPF_CALLF);
  AddInstTable(InstTable, "BIT", 0, DecodeBIT);

  AddFixed("HALT" , 0x8e); AddFixed("IRET" , 0x80); AddFixed("NOP"  , 0x9d);
  AddFixed("RCF"  , 0x98); AddFixed("RET"  , 0x81); AddFixed("RIM"  , 0x9a);
  AddFixed("RSP"  , 0x9c); AddFixed("SCF"  , 0x99); AddFixed("SIM"  , 0x9b);
  AddFixed("TRAP" , 0x83); AddFixed("WFI"  , 0x8f); AddFixed("BREAK", 0x018b);
  AddFixed("WFE"  , 0x728f); AddFixed("RVF"  , 0x019c); AddFixed("RETF", 0x0187);
  AddFixed("CCF"  , 0x018c);

  AddAri("ADC" , 0x09, True ); AddAri("ADD" , 0x0b, True ); AddAri("AND" , 0x04, True );
  AddAri("BCP" , 0x05, True ); AddAri("OR"  , 0x0a, True ); AddAri("SBC" , 0x02, True );
  AddAri("SUB" , 0x00, True ); AddAri("XOR" , 0x08, True );

  AddAri16("ADDW", 0x090b); AddAri16("SUBW", 0x0200);

  AddRMW("CLR" , 0x0f); AddRMW("CPL" , 0x03); AddRMW("DEC" , 0x0a);
  AddRMW("INC" , 0x0c); AddRMW("NEG" , 0x00); AddRMW("RLC" , 0x09);
  AddRMW("RRC" , 0x06); AddRMW("SLA" , 0x08); AddRMW("SLL" , 0x08);
  AddRMW("SRA" , 0x07); AddRMW("SRL" , 0x04); AddRMW("SWAP", 0x0e);
  AddRMW("TNZ" , 0x0d);

  AddRel("CALLR", 0xad);
  AddRel("JRA"  , 0x20);
  AddRel("JRC"  , 0x25);
  AddRel("JREQ" , 0x27);
  AddRel("JRF"  , 0x21);
  AddRel("JRH"  , (pCurrCPUProps->Core == eCoreSTM8) ? 0x9029 : 0x29);
  AddRel("JRIH" , (pCurrCPUProps->Core == eCoreSTM8) ? 0x902f : 0x2f);
  AddRel("JRIL" , (pCurrCPUProps->Core == eCoreSTM8) ? 0x902e : 0x2e);
  AddRel("JRM"  , (pCurrCPUProps->Core == eCoreSTM8) ? 0x902d : 0x2d);
  AddRel("JRMI" , 0x2b);
  AddRel("JRNC" , 0x24);
  AddRel("JRNE" , 0x26);
  AddRel("JRNH" , (pCurrCPUProps->Core == eCoreSTM8) ? 0x9028 : 0x28);
  AddRel("JRNM" , (pCurrCPUProps->Core == eCoreSTM8) ? 0x902c : 0x2c);
  AddRel("JRNV" , (pCurrCPUProps->Core == eCoreSTM8) ? 0x28 : 0x00);
  AddRel("JRPL" , 0x2a);
  AddRel("JRSGE", (pCurrCPUProps->Core == eCoreSTM8) ? 0x2e : 0x00);
  AddRel("JRSGT", (pCurrCPUProps->Core == eCoreSTM8) ? 0x2c : 0x00);
  AddRel("JRSLE", (pCurrCPUProps->Core == eCoreSTM8) ? 0x2d : 0x00);
  AddRel("JRSLT", (pCurrCPUProps->Core == eCoreSTM8) ? 0x2f : 0x00);
  AddRel("JRT"  , 0x20);
  AddRel("JRUGE", 0x24);
  AddRel("JRUGT", 0x22);
  AddRel("JRULE", 0x23);
  AddRel("JRULT", 0x25);
  AddRel("JRV"  , (pCurrCPUProps->Core == eCoreSTM8) ? 0x29 : 0x00);

  add_moto8_pseudo(InstTable, e_moto_pseudo_flags_be);
  AddMoto16Pseudo(InstTable, e_moto_pseudo_flags_be);
}

/*!------------------------------------------------------------------------
 * \fn     DeinitFields(void)
 * \brief  tear down instruction hash table
 * ------------------------------------------------------------------------ */

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

/*!------------------------------------------------------------------------
 * \fn     MakeCode_ST7(void)
 * \brief  entry point to decode machine instructions
 * ------------------------------------------------------------------------ */

static Boolean DecodeAttrPart_ST7(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_ST7(void)
{
  if (AttrPartOpSize[0] == eSymbolSizeUnknown)
    AttrPartOpSize[0] = eSymbolSize8Bit;
  OpSize = AttrPartOpSize[0];
  PrefixCnt = 0;

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

/*!------------------------------------------------------------------------
 * \fn     IsDef_ST7(void)
 * \brief  does instruction consume label field?
 * \return true if to be consumed
 * ------------------------------------------------------------------------ */

static Boolean IsDef_ST7(void)
{
  return Memo("BIT");
}

/*!------------------------------------------------------------------------
 * \fn     SwitchTo_ST7(void)
 * \brief  switch to target
 * ------------------------------------------------------------------------ */

static void SwitchTo_ST7(void *pUser)
{
  const TFamilyDescr *p_descr = FindFamilyByName("ST7");

  pCurrCPUProps = (const tCPUProps*)pUser;
  TurnWords = False;
  SetIntConstMode(eIntConstModeMoto);

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

  ValidSegs = 1 << SegCode;
  Grans[SegCode] = 1; ListGrans[SegCode] = 1; SegInits[SegCode] = 0;
  SegLimits[SegCode] = IntTypeDefs[pCurrCPUProps->AddrIntType].Max;

  DecodeAttrPart = DecodeAttrPart_ST7;
  MakeCode = MakeCode_ST7;
  IsDef = IsDef_ST7;
  SwitchFrom = DeinitFields;
  DissectBit = DissectBit_ST7;
  InitFields();
  AddMoto16PseudoONOFF(False);
}

/*!------------------------------------------------------------------------
 * \fn     codest7_init(void)
 * \brief  register ST7/STM8 target
 * ------------------------------------------------------------------------ */

static const tCPUProps CPUProps[] =
{
  { "ST7"         ,  Int16, eCoreST7  },
  { "ST7232AK1"   ,  Int16, eCoreST7  },
  { "ST7232AK2"   ,  Int16, eCoreST7  },
  { "ST7232AJ1"   ,  Int16, eCoreST7  },
  { "ST7232AJ2"   ,  Int16, eCoreST7  },
  { "ST72251G1"   ,  Int16, eCoreST7  },
  { "ST72251G2"   ,  Int16, eCoreST7  },
  { "ST72311J2"   ,  Int16, eCoreST7  },
  { "ST72311J4"   ,  Int16, eCoreST7  },
  { "ST72321BR6"  ,  Int16, eCoreST7  },
  { "ST72321BR7"  ,  Int16, eCoreST7  },
  { "ST72321BR9"  ,  Int16, eCoreST7  },
  { "ST72324J6"   ,  Int16, eCoreST7  },
  { "ST72324K6"   ,  Int16, eCoreST7  },
  { "ST72324J4"   ,  Int16, eCoreST7  },
  { "ST72324K4"   ,  Int16, eCoreST7  },
  { "ST72324J2"   ,  Int16, eCoreST7  },
  { "ST72324K2"   ,  Int16, eCoreST7  },
  { "ST72325S4"   ,  Int16, eCoreST7  },
  { "ST72325S6"   ,  Int16, eCoreST7  },
  { "ST72325J7"   ,  Int16, eCoreST7  },
  { "ST72325R9"   ,  Int16, eCoreST7  },
  { "ST72344K2"   ,  Int16, eCoreST7  },
  { "ST72344K4"   ,  Int16, eCoreST7  },
  { "ST72345C4"   ,  Int16, eCoreST7  },
  { "ST72521BR6"  ,  Int16, eCoreST7  },
  { "ST72521BM9"  ,  Int16, eCoreST7  },
  { "ST72361AR4"  ,  Int16, eCoreST7  },
  { "ST72361AR6"  ,  Int16, eCoreST7  },
  { "ST72361AR7"  ,  Int16, eCoreST7  },
  { "ST72361AR9"  ,  Int16, eCoreST7  },
  { "ST7FOXK1"    ,  Int16, eCoreST7  },
  { "ST7FOXK2"    ,  Int16, eCoreST7  },
  { "ST7LITES2Y0" ,  Int16, eCoreST7  },
  { "ST7LITES5Y0" ,  Int16, eCoreST7  },
  { "ST7LITE02Y0" ,  Int16, eCoreST7  },
  { "ST7LITE05Y0" ,  Int16, eCoreST7  },
  { "ST7LITE09Y0" ,  Int16, eCoreST7  },
  { "ST7LITE10F1" ,  Int16, eCoreST7  },
  { "ST7LITE15F1" ,  Int16, eCoreST7  },
  { "ST7LITE19F1" ,  Int16, eCoreST7  },
  { "ST7LITE10BF0",  Int16, eCoreST7  },
  { "ST7LITE15BF0",  Int16, eCoreST7  },
  { "ST7LITE15BF1",  Int16, eCoreST7  },
  { "ST7LITE19BF0",  Int16, eCoreST7  },
  { "ST7LITE19BF1",  Int16, eCoreST7  },
  { "ST7LITE20F2" ,  Int16, eCoreST7  },
  { "ST7LITE25F2" ,  Int16, eCoreST7  },
  { "ST7LITE29F2" ,  Int16, eCoreST7  },
  { "ST7LITE30F2" ,  Int16, eCoreST7  },
  { "ST7LITE35F2" ,  Int16, eCoreST7  },
  { "ST7LITE39F2" ,  Int16, eCoreST7  },
  { "ST7LITE49K2" ,  Int16, eCoreST7  },
  { "ST7MC1K2"    ,  Int16, eCoreST7  },
  { "ST7MC1K4"    ,  Int16, eCoreST7  },
  { "ST7MC2N6"    ,  Int16, eCoreST7  },
  { "ST7MC2S4"    ,  Int16, eCoreST7  },
  { "ST7MC2S6"    ,  Int16, eCoreST7  },
  { "ST7MC2S7"    ,  Int16, eCoreST7  },
  { "ST7MC2S9"    ,  Int16, eCoreST7  },
  { "ST7MC2R6"    ,  Int16, eCoreST7  },
  { "ST7MC2R7"    ,  Int16, eCoreST7  },
  { "ST7MC2R9"    ,  Int16, eCoreST7  },
  { "ST7MC2M9"    ,  Int16, eCoreST7  },

  { "STM8"        ,  Int24, eCoreSTM8 },
  { "STM8S001J3"  ,  Int16, eCoreSTM8 },
  { "STM8S003F3"  ,  Int16, eCoreSTM8 },
  { "STM8S003K3"  ,  Int16, eCoreSTM8 },
  { "STM8S005C6"  ,  Int16, eCoreSTM8 },
  { "STM8S005K6"  ,  Int16, eCoreSTM8 },
  { "STM8S007C8"  ,  Int24, eCoreSTM8 },
  { "STM8S103F2"  ,  Int16, eCoreSTM8 },
  { "STM8S103F3"  ,  Int16, eCoreSTM8 },
  { "STM8S103K3"  ,  Int16, eCoreSTM8 },
  { "STM8S105C4"  ,  Int16, eCoreSTM8 },
  { "STM8S105C6"  ,  Int16, eCoreSTM8 },
  { "STM8S105K4"  ,  Int16, eCoreSTM8 },
  { "STM8S105K6"  ,  Int16, eCoreSTM8 },
  { "STM8S105S4"  ,  Int16, eCoreSTM8 },
  { "STM8S105S6"  ,  Int16, eCoreSTM8 },
  { "STM8S207MB"  ,  Int24, eCoreSTM8 },
  { "STM8S207M8"  ,  Int24, eCoreSTM8 },
  { "STM8S207RB"  ,  Int24, eCoreSTM8 },
  { "STM8S207R8"  ,  Int24, eCoreSTM8 },
  { "STM8S207R6"  ,  Int16, eCoreSTM8 },
  { "STM8S207CB"  ,  Int24, eCoreSTM8 },
  { "STM8S207C8"  ,  Int24, eCoreSTM8 },
  { "STM8S207C6"  ,  Int16, eCoreSTM8 },
  { "STM8S207SB"  ,  Int24, eCoreSTM8 },
  { "STM8S207S8"  ,  Int24, eCoreSTM8 },
  { "STM8S207S6"  ,  Int16, eCoreSTM8 },
  { "STM8S207K8"  ,  Int24, eCoreSTM8 },
  { "STM8S207K6"  ,  Int16, eCoreSTM8 },
  { "STM8S208MB"  ,  Int24, eCoreSTM8 },
  { "STM8S208RB"  ,  Int24, eCoreSTM8 },
  { "STM8S208R8"  ,  Int24, eCoreSTM8 },
  { "STM8S208R6"  ,  Int24, eCoreSTM8 },
  { "STM8S208CB"  ,  Int24, eCoreSTM8 },
  { "STM8S208C8"  ,  Int24, eCoreSTM8 },
  { "STM8S208C6"  ,  Int16, eCoreSTM8 },
  { "STM8S208SB"  ,  Int24, eCoreSTM8 },
  { "STM8S208S8"  ,  Int24, eCoreSTM8 },
  { "STM8S208S6"  ,  Int16, eCoreSTM8 },
  { "STM8S903K3"  ,  Int16, eCoreSTM8 },
  { "STM8S903F3"  ,  Int16, eCoreSTM8 },
  { "STM8L050J3"  ,  Int16, eCoreSTM8 },
  { "STM8L051F3"  ,  Int16, eCoreSTM8 },
  { "STM8L052C6"  ,  Int16, eCoreSTM8 },
  { "STM8L052R8"  ,  Int24, eCoreSTM8 },
  { "STM8L001J3"  ,  Int16, eCoreSTM8 },
  { "STM8L101F1"  ,  Int16, eCoreSTM8 },
  { "STM8L101F2"  ,  Int16, eCoreSTM8 },
  { "STM8L101G2"  ,  Int16, eCoreSTM8 },
  { "STM8L101F3"  ,  Int16, eCoreSTM8 },
  { "STM8L101G3"  ,  Int16, eCoreSTM8 },
  { "STM8L101K3"  ,  Int16, eCoreSTM8 },
  { "STM8L151C2"  ,  Int16, eCoreSTM8 },
  { "STM8L151K2"  ,  Int16, eCoreSTM8 },
  { "STM8L151G2"  ,  Int16, eCoreSTM8 },
  { "STM8L151F2"  ,  Int16, eCoreSTM8 },
  { "STM8L151C3"  ,  Int16, eCoreSTM8 },
  { "STM8L151K3"  ,  Int16, eCoreSTM8 },
  { "STM8L151G3"  ,  Int16, eCoreSTM8 },
  { "STM8L151F3"  ,  Int16, eCoreSTM8 },
  { "STM8L151C4"  ,  Int16, eCoreSTM8 },
  { "STM8L151C6"  ,  Int16, eCoreSTM8 },
  { "STM8L151K4"  ,  Int16, eCoreSTM8 },
  { "STM8L151K6"  ,  Int16, eCoreSTM8 },
  { "STM8L151G4"  ,  Int16, eCoreSTM8 },
  { "STM8L151G6"  ,  Int16, eCoreSTM8 },
  { "STM8L152C4"  ,  Int16, eCoreSTM8 },
  { "STM8L152C6"  ,  Int16, eCoreSTM8 },
  { "STM8L152K4"  ,  Int16, eCoreSTM8 },
  { "STM8L152K6"  ,  Int16, eCoreSTM8 },
  { "STM8L151R6"  ,  Int16, eCoreSTM8 },
  { "STM8L151C8"  ,  Int24, eCoreSTM8 },
  { "STM8L151M8"  ,  Int16, eCoreSTM8 },
  { "STM8L151R8"  ,  Int24, eCoreSTM8 },
  { "STM8L152R6"  ,  Int16, eCoreSTM8 },
  { "STM8L152C8"  ,  Int24, eCoreSTM8 },
  { "STM8L152K8"  ,  Int24, eCoreSTM8 },
  { "STM8L152M8"  ,  Int24, eCoreSTM8 },
  { "STM8L152R8"  ,  Int24, eCoreSTM8 },
  { "STM8L162M8"  ,  Int24, eCoreSTM8 },
  { "STM8L162R8"  ,  Int24, eCoreSTM8 },
  { "STM8AF6366"  ,  Int16, eCoreSTM8 },
  { "STM8AF6388"  ,  Int24, eCoreSTM8 },
  { "STM8AF6213"  ,  Int16, eCoreSTM8 },
  { "STM8AF6223"  ,  Int16, eCoreSTM8 },
  { "STM8AF6226"  ,  Int16, eCoreSTM8 },
  { "STM8AF6246"  ,  Int16, eCoreSTM8 },
  { "STM8AF6248"  ,  Int16, eCoreSTM8 },
  { "STM8AF6266"  ,  Int16, eCoreSTM8 },
  { "STM8AF6268"  ,  Int16, eCoreSTM8 },
  { "STM8AF6269"  ,  Int16, eCoreSTM8 },
  { "STM8AF6286"  ,  Int24, eCoreSTM8 },
  { "STM8AF6288"  ,  Int24, eCoreSTM8 },
  { "STM8AF6289"  ,  Int24, eCoreSTM8 },
  { "STM8AF628A"  ,  Int24, eCoreSTM8 },
  { "STM8AF62A6"  ,  Int24, eCoreSTM8 },
  { "STM8AF62A8"  ,  Int24, eCoreSTM8 },
  { "STM8AF62A9"  ,  Int24, eCoreSTM8 },
  { "STM8AF62AA"  ,  Int24, eCoreSTM8 },
  { "STM8AF5268"  ,  Int16, eCoreSTM8 },
  { "STM8AF5269"  ,  Int16, eCoreSTM8 },
  { "STM8AF5286"  ,  Int24, eCoreSTM8 },
  { "STM8AF5288"  ,  Int24, eCoreSTM8 },
  { "STM8AF5289"  ,  Int24, eCoreSTM8 },
  { "STM8AF528A"  ,  Int24, eCoreSTM8 },
  { "STM8AF52A6"  ,  Int24, eCoreSTM8 },
  { "STM8AF52A8"  ,  Int24, eCoreSTM8 },
  { "STM8AF52A9"  ,  Int24, eCoreSTM8 },
  { "STM8AF52AA"  ,  Int24, eCoreSTM8 },
  { "STM8AL3136"  ,  Int16, eCoreSTM8 },
  { "STM8AL3138"  ,  Int16, eCoreSTM8 },
  { "STM8AL3146"  ,  Int16, eCoreSTM8 },
  { "STM8AL3148"  ,  Int16, eCoreSTM8 },
  { "STM8AL3166"  ,  Int16, eCoreSTM8 },
  { "STM8AL3168"  ,  Int16, eCoreSTM8 },
  { "STM8AL3L46"  ,  Int16, eCoreSTM8 },
  { "STM8AL3L48"  ,  Int16, eCoreSTM8 },
  { "STM8AL3L66"  ,  Int16, eCoreSTM8 },
  { "STM8AL3L68"  ,  Int16, eCoreSTM8 },
  { "STM8AL3188"  ,  Int24, eCoreSTM8 },
  { "STM8AL3189"  ,  Int24, eCoreSTM8 },
  { "STM8AL318A"  ,  Int24, eCoreSTM8 },
  { "STM8AL3L88"  ,  Int24, eCoreSTM8 },
  { "STM8AL3L89"  ,  Int24, eCoreSTM8 },
  { "STM8AL3L8A"  ,  Int24, eCoreSTM8 },
  { "STM8TL52F4"  ,  Int16, eCoreSTM8 },
  { "STM8TL52G4"  ,  Int16, eCoreSTM8 },
  { "STM8TL53C4"  ,  Int16, eCoreSTM8 },
  { "STM8TL53F4"  ,  Int16, eCoreSTM8 },
  { "STM8TL53G4"  ,  Int16, eCoreSTM8 },
  { NULL          ,  UInt1, eCoreST7  },
};

void codest7_init(void)
{
  const tCPUProps *pProp;

  for (pProp = CPUProps; pProp->pName; pProp++)
    (void)AddCPUUser(pProp->pName, SwitchTo_ST7, (void*)pProp, NULL);
}
