/* code6809.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Code Generator 6809/6309                                                  */
/*                                                                           */
/*****************************************************************************/

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

#include "nls.h"
#include "strutil.h"
#include "bpemu.h"

#include "asmdef.h"
#include "asmpars.h"
#include "asmsub.h"
#include "asmallg.h"
#include "asmitree.h"
#include "asmcode.h"
#include "codepseudo.h"
#include "motpseudo.h"
#include "intpseudo.h"
#include "codevars.h"
#include "assume.h"
#include "errmsg.h"
#include "cmdarg.h"
#include "headids.h"

#include "code6809.h"

#define plain_base_mode_sym_name "PLAINBASE"
#define plain_base_mode_cmd_name "PLAINBASE"

typedef struct
{
  char *Name;
  Word Code;
  CPUVar MinCPU;
} BaseOrder;

typedef struct
{
  char *Name;
  Word Code;
  Boolean Inv;
  CPUVar MinCPU;
} FlagOrder;

typedef struct
{
  char *Name;
  Word Code8;
  Word Code16;
  CPUVar MinCPU;
} RelOrder;

typedef struct
{
  char *Name;
  Word Code;
  tSymbolSize OpSize;
  Boolean MayImm;
  CPUVar MinCPU;
} ALUOrder;

typedef enum
{
  e_adr_mode_none = -1,
  e_adr_mode_imm = 1,
  e_adr_mode_dir = 2,
  e_adr_mode_ind = 3,
  e_adr_mode_ext = 4
} adr_mode_t;

#define adr_mode_mask_imm (1 << e_adr_mode_imm)
#define adr_mode_mask_dir (1 << e_adr_mode_dir)
#define adr_mode_mask_ind (1 << e_adr_mode_ind)
#define adr_mode_mask_ext (1 << e_adr_mode_ext)
#define adr_mode_mask_no_imm (adr_mode_mask_dir | adr_mode_mask_ind | adr_mode_mask_ext)
#define adr_mode_mask_all (adr_mode_mask_imm | adr_mode_mask_no_imm)

typedef struct
{
  adr_mode_t mode;
  int cnt, guess_offset;
  Byte vals[5], guess_mask;
  tSymbolFlags symbol_flags;
} adr_vals_t;

#define StackRegCnt 12
static char StackRegNames[StackRegCnt][4] =
{
  "CCR",  "A",  "B","DPR",  "X",  "Y","S/U", "PC", "CC", "DP",  "S",  "D"
};
static Byte StackRegMasks[StackRegCnt] =
{
  0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x01, 0x08, 0x40, 0x06
};

static const char FlagChars[] = "CVZNIHFE";

static LongInt DPRValue;

static Boolean target_used,
               plain_base_mode,
               def_plain_base_mode,
               def_plain_base_mode_set;

static BaseOrder  *FixedOrders;
static RelOrder   *RelOrders;
static ALUOrder   *ALUOrders;
static BaseOrder *RMWOrders;
static FlagOrder *FlagOrders;
static BaseOrder *LEAOrders;
static BaseOrder *ImmOrders;

static CPUVar CPU6809,
              CPU6809UNDOC,
              CPU6309;

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

static Boolean CodeReg(char *ChIn, Byte *erg)
{
  static char Regs[5] = "XYUS", *p;

  if (strlen(ChIn) != 1)
    return False;
  else
  {
    p = strchr(Regs, as_toupper(*ChIn));
    if (!p)
      return False;
    *erg = p - Regs;
    return True;
  }
}

static unsigned ChkZero(const char *s, Byte *Erg)
{
  if (*s == '>')
  {
    *Erg = 1;
    return 1;
  }
  else if (*s == '<')
  {
    if (1[s] == '<')
    {
      *Erg = 3;
      return 2;
    }
    else
    {
      *Erg = 2;
      return 1;
    }
  }
  else
  {
    *Erg = 0;
    return 0;
  }
}

static Boolean MayShort(Integer Arg)
{
  return ((Arg >= -128) && (Arg <= 127));
}

static Boolean IsZeroOrEmpty(const tStrComp *pArg)
{
  Boolean OK;
  LongInt Value;

  if (!*pArg->str.p_str)
    return True;
  Value = EvalStrIntExpression(pArg, Int32, &OK);
  return OK && !Value;
}

static void reset_adr_vals(adr_vals_t *p_vals)
{
  p_vals->mode = e_adr_mode_none;
  p_vals->cnt = 0;
  p_vals->symbol_flags = eSymbolFlag_None;
  p_vals->guess_mask = 0xff;
  p_vals->guess_offset = 0;
}

static Boolean check_plain_base_arg(int adr_arg_cnt, const tStrComp *p_start_arg)
{
  switch (adr_arg_cnt)
  {
    case 1:
      if (!plain_base_mode)
        WrStrErrorPos(ErrNum_WrongArgCnt, p_start_arg);
      return plain_base_mode;
    case 2:
    {
      Boolean ret = IsZeroOrEmpty(p_start_arg);
      if (!ret)
        WrStrErrorPos(ErrNum_InvAddrMode, p_start_arg);
      return ret;
    }
    default:
      WrError(ErrNum_WrongArgCnt);
      return False;
  }
}

static adr_mode_t DecodeAdr(int ArgStartIdx, int ArgEndIdx,
                            unsigned OpcodeLen, tSymbolSize op_size,
                            unsigned mode_mask, adr_vals_t *p_vals)
{
  tStrComp *pStartArg, *pEndArg, IndirComps[2];
  String temp;
  LongInt AdrLong;
  Word AdrWord;
  Boolean IndFlag, OK;
  Byte EReg, ZeroMode;
  char *p;
  unsigned Offset;
  Integer AdrInt;
  int AdrArgCnt = ArgEndIdx - ArgStartIdx + 1;
  const Boolean allow_6309 = (MomCPU >= CPU6309);

  reset_adr_vals(p_vals);
  pStartArg = &ArgStr[ArgStartIdx];
  pEndArg = &ArgStr[ArgEndIdx];

  /* immediate */

  if ((*pStartArg->str.p_str == '#') && (AdrArgCnt == 1))
  {
    switch (op_size)
    {
      case eSymbolSize32Bit:
        AdrLong = EvalStrIntExpressionOffsWithFlags(pStartArg, 1, Int32, &OK, &p_vals->symbol_flags);
        if (OK)
        {
          p_vals->vals[0] = Lo(AdrLong >> 24);
          p_vals->vals[1] = Lo(AdrLong >> 16);
          p_vals->vals[2] = Lo(AdrLong >>  8);
          p_vals->vals[3] = Lo(AdrLong);
          p_vals->cnt = 4;
        }
        break;
      case eSymbolSize16Bit:
        AdrWord = EvalStrIntExpressionOffsWithFlags(pStartArg, 1, Int16, &OK, &p_vals->symbol_flags);
        if (OK)
        {
          p_vals->vals[0] = Hi(AdrWord);
          p_vals->vals[1] = Lo(AdrWord);
          p_vals->cnt = 2;
        }
        break;
      case eSymbolSize8Bit:
        p_vals->vals[0] = EvalStrIntExpressionOffsWithFlags(pStartArg, 1, Int8, &OK, &p_vals->symbol_flags);
        if (OK)
          p_vals->cnt = 1;
        break;
      case eSymbolSizeUnknown:
        WrStrErrorPos(ErrNum_InvAddrMode, pStartArg);
        OK = False;
        break;
      default:
        WrStrErrorPos(ErrNum_InvOpSize, pStartArg);
        OK = False;
        break;
    }
    if (OK)
      p_vals->mode = e_adr_mode_imm;
    goto chk_mode;
  }

  /* indirekter Ausdruck ? */

  if ((*pStartArg->str.p_str == '[') && (pStartArg->str.p_str[strlen(pStartArg->str.p_str) - 1] == ']'))
  {
    tStrComp Arg, Remainder;

    IndFlag = True;
    StrCompRefRight(&Arg, pStartArg, 1);
    StrCompShorten(&Arg, 1);
    AdrArgCnt = 0;
    do
    {
      p = QuotPos(Arg.str.p_str, ',');
      if (p)
        StrCompSplitRef(&IndirComps[AdrArgCnt], &Remainder, &Arg, p);
      else
        IndirComps[AdrArgCnt] = Arg;
      KillPrefBlanksStrCompRef(&IndirComps[AdrArgCnt]);
      KillPostBlanksStrComp(&IndirComps[AdrArgCnt]);
      AdrArgCnt++;
      if (p)
        Arg = Remainder;
    }
    while (p && (AdrArgCnt < 2));
    pStartArg = &IndirComps[0];
    pEndArg = &IndirComps[AdrArgCnt - 1];
  }
  else
    IndFlag = False;

  /* Predekrement ? */

  if ((AdrArgCnt >= 1) && (AdrArgCnt <= 2) && (strlen(pEndArg->str.p_str) == 2) && (*pEndArg->str.p_str == '-') && (CodeReg(pEndArg->str.p_str + 1, &EReg)))
  {
    if (check_plain_base_arg(AdrArgCnt, pStartArg))
    {
      p_vals->cnt = 1;
      p_vals->vals[0] = 0x82 + (EReg << 5) + (Ord(IndFlag) << 4);
      p_vals->mode = e_adr_mode_ind;
    }
    goto chk_mode;
  }

  if ((AdrArgCnt >= 1) && (AdrArgCnt <= 2) && (strlen(pEndArg->str.p_str) == 3) && (!strncmp(pEndArg->str.p_str, "--", 2)) && (CodeReg(pEndArg->str.p_str + 2, &EReg)))
  {
    if (check_plain_base_arg(AdrArgCnt, pStartArg))
    {
      p_vals->cnt = 1;
      p_vals->vals[0] = 0x83 + (EReg << 5) + (Ord(IndFlag) << 4);
      p_vals->mode = e_adr_mode_ind;
    }
    goto chk_mode;
  }

  if ((AdrArgCnt >= 1) && (AdrArgCnt <= 2) && (!as_strcasecmp(pEndArg->str.p_str, "--W")))
  {
    if (!check_plain_base_arg(AdrArgCnt, pStartArg));
    else if (!allow_6309) WrError(ErrNum_AddrModeNotSupported);
    else
    {
      p_vals->cnt = 1;
      p_vals->vals[0] = 0xef + Ord(IndFlag);
      p_vals->mode = e_adr_mode_ind;
    }
    goto chk_mode;
  }

  /* Postinkrement ? */

  if ((AdrArgCnt >= 1) && (AdrArgCnt <= 2) && (strlen(pEndArg->str.p_str) == 2) && (pEndArg->str.p_str[1] == '+'))
  {
    temp[0] = *pEndArg->str.p_str;
    temp[1] = '\0';
    if (CodeReg(temp, &EReg))
    {
      if (check_plain_base_arg(AdrArgCnt, pStartArg))
      {
        p_vals->cnt = 1;
        p_vals->vals[0] = 0x80 + (EReg << 5) + (Ord(IndFlag) << 4);
        p_vals->mode = e_adr_mode_ind;
      }
      goto chk_mode;
    }
  }

  if ((AdrArgCnt >= 1) && (AdrArgCnt <= 2) && (strlen(pEndArg->str.p_str) == 3) && (!strncmp(pEndArg->str.p_str + 1, "++", 2)))
  {
    temp[0] = *pEndArg->str.p_str;
    temp[1] = '\0';
    if (CodeReg(temp, &EReg))
    {
      if (check_plain_base_arg(AdrArgCnt, pStartArg))
      {
        p_vals->cnt = 1;
        p_vals->vals[0] = 0x81 + (EReg << 5) + (Ord(IndFlag) << 4);
        p_vals->mode = e_adr_mode_ind;
      }
      goto chk_mode;
    }
  }

  if ((AdrArgCnt >= 1) && (AdrArgCnt <= 2) && (!as_strcasecmp(pEndArg->str.p_str, "W++")))
  {
    if (!check_plain_base_arg(AdrArgCnt, pStartArg));
    else if (!allow_6309) WrError(ErrNum_AddrModeNotSupported);
    else
    {
      p_vals->cnt = 1;
      p_vals->vals[0] = 0xcf + Ord(IndFlag);
      p_vals->mode = e_adr_mode_ind;
    }
    goto chk_mode;
  }

  /* 16-Bit-Register (mit Index) ? */

  if ((AdrArgCnt <= 2) && (AdrArgCnt >= 1) && (CodeReg(pEndArg->str.p_str, &EReg)))
  {
    p_vals->vals[0] = (EReg << 5) + (Ord(IndFlag) << 4);

    /* nur 16-Bit-Register */

    if (AdrArgCnt == 1)
    {
      if (!plain_base_mode) WrStrErrorPos(ErrNum_WrongArgCnt, pEndArg);
      else
      {
        p_vals->cnt = 1;
        p_vals->vals[0] += 0x84;
        p_vals->mode = e_adr_mode_ind;
      }
      goto chk_mode;
    }

    /* mit Index */

    if (!as_strcasecmp(pStartArg->str.p_str, "A"))
    {
      p_vals->cnt = 1;
      p_vals->vals[0] += 0x86;
      p_vals->mode = e_adr_mode_ind;
      goto chk_mode;
    }
    if (!as_strcasecmp(pStartArg->str.p_str, "B"))
    {
      p_vals->cnt = 1;
      p_vals->vals[0] += 0x85;
      p_vals->mode = e_adr_mode_ind;
      goto chk_mode;
    }
    if (!as_strcasecmp(pStartArg->str.p_str, "D"))
    {
      p_vals->cnt = 1;
      p_vals->vals[0] += 0x8b;
      p_vals->mode = e_adr_mode_ind;
      goto chk_mode;
    }
    if ((!as_strcasecmp(pStartArg->str.p_str, "E")) && allow_6309)
    {
      p_vals->cnt = 1;
      p_vals->vals[0] += 0x87;
      p_vals->mode = e_adr_mode_ind;
      goto chk_mode;
    }
    if ((!as_strcasecmp(pStartArg->str.p_str, "F")) && allow_6309)
    {
      p_vals->cnt = 1;
      p_vals->vals[0] += 0x8a;
      p_vals->mode = e_adr_mode_ind;
      goto chk_mode;
    }
    if ((!as_strcasecmp(pStartArg->str.p_str, "W")) && allow_6309)
    {
      p_vals->cnt = 1;
      p_vals->vals[0] += 0x8e;
      p_vals->mode = e_adr_mode_ind;
      goto chk_mode;
    }

    /* Displacement auswerten */

    Offset = ChkZero(pStartArg->str.p_str, &ZeroMode);
    if (!pStartArg->str.p_str[0])
    {
      AdrInt = 0;
      OK = True;
    }
    else if (ZeroMode > 1)
    {
      AdrInt = EvalStrIntExpressionOffsWithFlags(pStartArg, Offset, Int8, &OK, &p_vals->symbol_flags);
      if (mFirstPassUnknown(p_vals->symbol_flags) && (ZeroMode == 3))
        AdrInt &= 0x0f;
    }
    else
      AdrInt = EvalStrIntExpressionOffsWithFlags(pStartArg, Offset, Int16, &OK, &p_vals->symbol_flags);
    if (!OK)
      goto chk_mode;

    /* Displacement 0 ? */

    if ((ZeroMode == 0) && (AdrInt == 0))
    {
      p_vals->cnt = 1;
      p_vals->vals[0] += 0x84;
      p_vals->mode = e_adr_mode_ind;
      goto chk_mode;
    }

    /* 5-Bit-Displacement */

    else if ((ZeroMode == 3) || ((ZeroMode == 0) && (!IndFlag) && (AdrInt >= -16) && (AdrInt <= 15)))
    {
      if ((AdrInt < -16) || (AdrInt > 15)) WrError(ErrNum_NoShortAddr);
      else if (IndFlag) WrError(ErrNum_InvAddrMode);
      else
      {
        p_vals->mode = e_adr_mode_ind;
        p_vals->cnt = 1;
        p_vals->vals[0] += AdrInt & 0x1f;
        p_vals->guess_mask = 0x1f;
      }
      goto chk_mode;
    }

    /* 8-Bit-Displacement */

    else if ((ZeroMode == 2) || ((ZeroMode == 0) && (MayShort(AdrInt))))
    {
      if (!MayShort(AdrInt)) WrError(ErrNum_NoShortAddr);
      else
      {
        p_vals->mode = e_adr_mode_ind;
        p_vals->cnt = 2;
        p_vals->vals[0] += 0x88;
        p_vals->guess_offset = 1;
        p_vals->vals[1] = Lo(AdrInt);
      }
      goto chk_mode;
    }

    /* 16-Bit-Displacement */

    else
    {
      p_vals->mode = e_adr_mode_ind;
      p_vals->cnt = 3;
      p_vals->vals[0] += 0x89;
      p_vals->guess_offset = 1;
      p_vals->vals[1] = Hi(AdrInt);
      p_vals->vals[2] = Lo(AdrInt);
      goto chk_mode;
    }
  }

  if ((AdrArgCnt <= 2) && (AdrArgCnt >= 1) && allow_6309 && (!as_strcasecmp(pEndArg->str.p_str, "W")))
  {
    p_vals->vals[0] = 0x8f + Ord(IndFlag);

    /* nur W-Register */

    if (AdrArgCnt == 1)
    {
      if (!plain_base_mode) WrStrErrorPos(ErrNum_WrongArgCnt, pEndArg);
      else
      {
        p_vals->cnt = 1;
        p_vals->mode = e_adr_mode_ind;
      }
      goto chk_mode;
    }

    /* Displacement auswerten */

    Offset = ChkZero(pStartArg->str.p_str, &ZeroMode);
    if (pStartArg->str.p_str[0])
      AdrInt = EvalStrIntExpressionOffsWithFlags(pStartArg, Offset, Int16, &OK, &p_vals->symbol_flags);
    else
    {
      AdrInt = 0;
      OK = True;
    }

    /* Displacement 0 ? */

    if ((ZeroMode == 0) && (AdrInt == 0))
    {
      p_vals->cnt = 1;
      p_vals->mode = e_adr_mode_ind;
      goto chk_mode;
    }

    /* 16-Bit-Displacement */

    else
    {
      p_vals->mode = e_adr_mode_ind;
      p_vals->cnt = 3;
      p_vals->vals[0] += 0x20;
      p_vals->guess_offset = 1;
      p_vals->vals[1] = Hi(AdrInt);
      p_vals->vals[2] = Lo(AdrInt);
      goto chk_mode;
    }
  }

  /* PC-relativ ? */

  if ((AdrArgCnt == 2) && (!as_strcasecmp(pEndArg->str.p_str, "PCR") || !as_strcasecmp(pEndArg->str.p_str, "PC")))
  {
    p_vals->vals[0] = Ord(IndFlag) << 4;
    Offset = ChkZero(pStartArg->str.p_str, &ZeroMode);
    AdrInt = EvalStrIntExpressionOffsWithFlags(pStartArg, Offset, Int16, &OK, &p_vals->symbol_flags);
    if (OK)
    {
      AdrInt -= EProgCounter() + 2 + OpcodeLen;

      if (ZeroMode == 3) WrError(ErrNum_InvAddrMode);

      else if ((ZeroMode == 2) || ((ZeroMode == 0) && MayShort(AdrInt)))
      {
        if (!MayShort(AdrInt)) WrError(ErrNum_OverRange);
        else
        {
          p_vals->cnt = 2;
          p_vals->vals[0] += 0x8c;
          p_vals->guess_offset = 1;
          p_vals->vals[1] = Lo(AdrInt);
          p_vals->mode = e_adr_mode_ind;
        }
      }

      else
      {
        AdrInt--;
        p_vals->cnt = 3;
        p_vals->vals[0] += 0x8d;
        p_vals->guess_offset = 1;
        p_vals->vals[1] = Hi(AdrInt);
        p_vals->vals[2] = Lo(AdrInt);
        p_vals->mode = e_adr_mode_ind;
      }
    }
    goto chk_mode;
  }

  if (AdrArgCnt == 1)
  {
    Offset = ChkZero(pStartArg->str.p_str, &ZeroMode);
    AdrInt = EvalStrIntExpressionOffsWithFlags(pStartArg, Offset, Int16, &OK, &p_vals->symbol_flags);
    if (mFirstPassUnknown(p_vals->symbol_flags) && (ZeroMode == 2))
      AdrInt = (AdrInt & 0xff) | (DPRValue << 8);

    if (OK)
    {
      if (ZeroMode == 3) WrError(ErrNum_InvAddrMode);

      else if ((ZeroMode == 2) || ((ZeroMode == 0) && (Hi(AdrInt) == DPRValue) && (!IndFlag)))
      {
        if (IndFlag) WrError(ErrNum_NoIndir);
        else if (Hi(AdrInt) != DPRValue) WrError(ErrNum_NoShortAddr);
        else
        {
          p_vals->cnt = 1;
          p_vals->mode = e_adr_mode_dir;
          p_vals->vals[0] = Lo(AdrInt);
        }
      }

      else
      {
        if (IndFlag)
        {
          p_vals->mode = e_adr_mode_ind;
          p_vals->cnt = 3;
          p_vals->vals[0] = 0x9f;
          p_vals->vals[1] = Hi(AdrInt);
          p_vals->vals[2] = Lo(AdrInt);
        }
        else
        {
          p_vals->mode = e_adr_mode_ext;
          p_vals->cnt = 2;
          p_vals->vals[0] = Hi(AdrInt);
          p_vals->vals[1] = Lo(AdrInt);
        }
      }
    }
    goto chk_mode;
  }

  if (p_vals->mode == e_adr_mode_none)
    WrError(ErrNum_InvAddrMode);

chk_mode:
  if ((p_vals->mode != e_adr_mode_none) && !((mode_mask >> p_vals->mode) & 1))
  {
    WrError(ErrNum_InvAddrMode);
    reset_adr_vals(p_vals);
  }
  return p_vals->mode;
}

static Boolean CodeCPUReg(const char *Asc, Byte *Erg)
{
#define RegCnt (sizeof(RegNames) / sizeof(*RegNames))
  static const char RegNames[][4] =
  {
    "D", "X", "Y", "U", "S", "SP", "PC", "W", "V", "A", "B", "CCR", "DPR", "CC", "DP", "Z", "E", "F"
  };
  static const Byte RegVals[RegCnt] =
  {
    0  , 1  , 2  , 3  , 4  , 4   , 5   , 6  , 7  , 8  , 9  , 10   , 11   , 10  , 11  , 13 , 14 , 15
   };

  unsigned z;
  String Asc_N;

  strmaxcpy(Asc_N, Asc, STRINGSIZE); NLS_UpString(Asc_N); Asc = Asc_N;

  for (z = 0; z < RegCnt; z++)
    if (!strcmp(Asc, RegNames[z]))
    {
      if (((RegVals[z] & 6) == 6) && !ChkMinCPUExt(CPU6309, ErrNum_AddrModeNotSupported));
      else
      {
        *Erg = RegVals[z];
        return True;
      }
    }
  return False;
}

static void SplitIncDec(char *s, int *Erg)
{
  int l = strlen(s);

  if (l == 0)
    *Erg = 0;
  else if (s[l - 1] == '+')
  {
    s[l - 1] = '\0';
    *Erg = 1;
  }
  else if (s[l - 1] == '-')
  {
    s[l - 1] = '\0';
    *Erg = -1;
  }
  else
    *Erg = 0;
}

static Boolean SplitBit(tStrComp *pArg, int *Erg, tSymbolFlags *p_bit_flags)
{
  char *p;
  Boolean OK;
  tStrComp BitArg;

  p = QuotPos(pArg->str.p_str, '.');
  if (!p)
  {
    WrError(ErrNum_InvBitPos);
    return False;
  }
  StrCompSplitRef(pArg, &BitArg, pArg, p);
  *Erg = EvalStrIntExpressionWithFlags(&BitArg, UInt3, &OK, p_bit_flags);
  if (!OK)
    return False;
  *p = '\0';
  return True;
}

static void append_adr_vals(const adr_vals_t *p_vals)
{
  set_b_guessed(p_vals->symbol_flags, CodeLen + p_vals->guess_offset, p_vals->cnt - p_vals->guess_offset, p_vals->guess_mask);
  memcpy(&BAsmCode[CodeLen], p_vals->vals, p_vals->cnt);
  CodeLen += p_vals->cnt;
}

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

/* Anweisungen ohne Argument */

static void DecodeFixed(Word Index)
{
  const BaseOrder *pOrder = FixedOrders + Index;

  if (!moto8_chk_no_args());
  else if (!ChkMinCPU(pOrder->MinCPU));
  else if (Hi(pOrder->Code) == 0)
  {
    BAsmCode[0] = Lo(pOrder->Code);
    CodeLen = 1;
  }
  else
  {
    BAsmCode[0] = Hi(pOrder->Code);
    BAsmCode[1] = Lo(pOrder->Code);
    CodeLen = 2;
  }
}

/* Specials... */

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

  if (ArgCnt == 0)
  {
    BAsmCode[0] = 0x3f;
    CodeLen = 1;
  }
  else if (ChkArgCnt(1, 1))
  {
    Boolean OK;
    tSymbolFlags Flags;
    Byte Num;

    Num = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt2, &OK, &Flags);
    if (OK && mFirstPassUnknown(Flags) && (Num < 2))
      Num = 2;
    if (OK && ChkRange(Num, 2, 3))
    {
      set_b_guessed(Flags, 0, 1, 0x01);
      BAsmCode[0] = 0x10 | (Num & 1);
      BAsmCode[1] = 0x3f;
      CodeLen = 2;
    }
  }
}

/* relative Spruenge */

static void DecodeRel(Word Index)
{
  Boolean LongFlag = (Index & 0x8000) || False;
  const RelOrder *pOrder = RelOrders + (Index & 0x7fff);

  if (ChkArgCnt(1, 1))
  {
    Boolean ExtFlag = (LongFlag) && (Hi(pOrder->Code16) != 0), OK;
    tSymbolFlags Flags;
    Integer AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt16, &OK, &Flags);

    if (OK)
    {
      AdrInt -= EProgCounter() + 2 + Ord(LongFlag) + Ord(ExtFlag);
      if (!mSymbolQuestionable(Flags) && !LongFlag && ((AdrInt < -128) || (AdrInt > 127))) WrError(ErrNum_JmpDistTooBig);
      else
      {
        CodeLen = 1 + Ord(ExtFlag);
        if (LongFlag)
        {
          if (ExtFlag)
          {
            BAsmCode[0] = Hi(pOrder->Code16);
            BAsmCode[1] = Lo(pOrder->Code16);
          }
          else
            BAsmCode[0] = Lo(pOrder->Code16);
        }
        else
          BAsmCode[0] = Lo(pOrder->Code8);
        if (LongFlag)
        {
          set_b_guessed(Flags, CodeLen, 2, 0xff);
          BAsmCode[CodeLen] = Hi(AdrInt);
          BAsmCode[CodeLen + 1] = Lo(AdrInt);
          CodeLen += 2;
        }
        else
        {
          set_b_guessed(Flags, CodeLen, 1, 0xff);
          BAsmCode[CodeLen] = Lo(AdrInt);
          CodeLen++;
        }
      }
    }
  }
}

/* ALU-Operationen */

static void DecodeALU(Word Index)
{
  const ALUOrder *pOrder = ALUOrders + Index;

  if (ChkArgCnt(1, 2)
   && ChkMinCPU(pOrder->MinCPU))
  {
    adr_vals_t vals;

    if (DecodeAdr(1, ArgCnt, 1 + !!Hi(pOrder->Code), pOrder->OpSize, pOrder->MayImm ? adr_mode_mask_all : adr_mode_mask_no_imm, &vals) != e_adr_mode_none)
    {
      if (Hi(pOrder->Code))
        BAsmCode[CodeLen++] = Hi(pOrder->Code);
      BAsmCode[CodeLen++] = Lo(pOrder->Code) + ((vals.mode - 1) << 4);
      append_adr_vals(&vals);
    }
  }
}

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

  if (ChkArgCnt(1, 2)
   && ChkMinCPU(CPU6309))
  {
    adr_vals_t vals;

    if (DecodeAdr(1, ArgCnt, 2, eSymbolSize32Bit, adr_mode_mask_all, &vals) == e_adr_mode_imm)
    {
      BAsmCode[CodeLen++] = 0xcd;
      append_adr_vals(&vals);
    }
    else
    {
      BAsmCode[CodeLen++] = 0x10;
      BAsmCode[CodeLen++] = 0xcc + ((vals.mode - 1) << 4);
      append_adr_vals(&vals);
    }
  }
}

/* Read-Modify-Write-Operationen */

static void DecodeRMW(Word Index)
{
  const BaseOrder *pOrder = RMWOrders + Index;

  if (ChkArgCnt(1, 2)
   && ChkMinCPU(pOrder->MinCPU))
  {
    adr_vals_t vals;

    switch (DecodeAdr(1, ArgCnt, 1, eSymbolSizeUnknown, adr_mode_mask_no_imm, &vals))
    {
      case e_adr_mode_dir:
        BAsmCode[CodeLen++] = pOrder->Code;
        goto append;
      case e_adr_mode_ind:
        BAsmCode[CodeLen++] = pOrder->Code + 0x60;
        goto append;
      case e_adr_mode_ext:
        BAsmCode[CodeLen++] = pOrder->Code + 0x70;
        goto append;
      append:
        append_adr_vals(&vals);
        break;
      default:
        return;
    }
  }
}

/* Anweisungen mit Flag-Operand */

static void DecodeFlag(Word Index)
{
  const FlagOrder *pOrder = FlagOrders + Index;
  Boolean OK;
  const char *p;
  int z2, z3;

  if (ChkArgCnt(1, ArgCntMax))
  {
    OK = True;
    BAsmCode[1] = (pOrder->Inv) ? 0xff : 0x00;
    for (z2 = 1; z2 <= ArgCnt; z2++)
      if (OK)
      {
        p = (strlen(ArgStr[z2].str.p_str) == 1) ? strchr(FlagChars, as_toupper(*ArgStr[z2].str.p_str)) : NULL;
        if (p)
        {
          z3 = p - FlagChars;
          if (pOrder->Inv)
            BAsmCode[1] &= (0xff ^ (1 << z3));
          else
            BAsmCode[1] |= (1 << z3);
        }
        else if (*ArgStr[z2].str.p_str != '#')
        {
          WrError(ErrNum_OnlyImmAddr);
          OK = False;
        }
        else
        {
          tSymbolFlags flags;

          BAsmCode[2] = EvalStrIntExpressionOffsWithFlags(&ArgStr[z2], 1, Int8, &OK, &flags);
          if (OK)
          {
            set_b_guessed(flags, 1, 1, 0xff);
            if (pOrder->Inv)
              BAsmCode[1] &= BAsmCode[2];
            else
              BAsmCode[1] |= BAsmCode[2];
          }
        }
      }
    if (OK)
    {
      CodeLen = 2;
      BAsmCode[0] = pOrder->Code;
    }
  }
}

/* Bit-Befehle */

static void DecodeImm(Word Index)
{
  const BaseOrder *pOrder = ImmOrders + Index;

  if (!ChkArgCnt(2, 3));
  else if (!ChkMinCPU(pOrder->MinCPU));
  else if (*ArgStr[1].str.p_str != '#') WrError(ErrNum_OnlyImmAddr);
  else
  {
    Boolean OK;
    tSymbolFlags flags;

    BAsmCode[1] = EvalStrIntExpressionOffsWithFlags(&ArgStr[1], 1, Int8, &OK, &flags);
    if (OK)
    {
      adr_vals_t vals;

      switch (DecodeAdr(2, ArgCnt, 2, eSymbolSizeUnknown, adr_mode_mask_no_imm, &vals))
      {
        case e_adr_mode_dir:
          BAsmCode[0] = pOrder->Code;
          goto append;
        case e_adr_mode_ext:
          BAsmCode[0] = pOrder->Code + 0x70;
          goto append;
        case e_adr_mode_ind:
          BAsmCode[0] = pOrder->Code + 0x60;
          goto append;
        append:
          set_b_guessed(flags, 1, 1, 0xff);
          CodeLen = 2;
          append_adr_vals(&vals);
          break;
        default:
          return;
      }
    }
  }
}

static void DecodeBit(Word Code)
{
  int bit_num_1, bit_num_2;
  tSymbolFlags bit_flags_1, bit_flags_2;

  if (ChkArgCnt(2, 2)
   && ChkMinCPU(CPU6309)
   && SplitBit(&ArgStr[1], &bit_num_1, &bit_flags_1) && SplitBit(&ArgStr[2], &bit_num_2, &bit_flags_2))
  {
    if (!CodeCPUReg(ArgStr[1].str.p_str, BAsmCode + 2)) WrError(ErrNum_InvRegName);
    else if ((BAsmCode[2] < 8) || (BAsmCode[2] > 11)) WrError(ErrNum_InvRegName);
    else
    {
      adr_vals_t vals;

      if (DecodeAdr(2, 2, 3, eSymbolSizeUnknown, adr_mode_mask_dir, &vals) != e_adr_mode_none)
      {
        BAsmCode[2] -= 7;
        if (BAsmCode[2] == 3)
          BAsmCode[2] = 0;
        BAsmCode[0] = 0x11;
        BAsmCode[1] = 0x30 + Code;
        set_basmcode_guessed(2, 1,
                             (mFirstPassUnknownOrQuestionable(bit_flags_1) ? 0x07 : 0x00)
                           | (mFirstPassUnknownOrQuestionable(bit_flags_2) ? 0x38 : 0x00));
        BAsmCode[2] = (BAsmCode[2] << 6) + (bit_num_2 << 3) + bit_num_1;
        BAsmCode[3] = vals.vals[0];
        CodeLen = 4;
      }
    }
  }
}

/* Register-Register-Operationen */

void DecodeTFR_TFM_EXG_6809(Word code, Boolean allow_inc_dec, reg_decoder_6809_t reg_decoder, Boolean reverse)
{
  if (ChkArgCnt(2, 2))
  {
    int Inc1, Inc2;

    SplitIncDec(ArgStr[1].str.p_str, &Inc1);
    SplitIncDec(ArgStr[2].str.p_str, &Inc2);
    if ((Inc1 != 0) || (Inc2 != 0))
    {
      if (!allow_inc_dec) WrError(ErrNum_InvAddrMode);
      else if (!reg_decoder(ArgStr[1].str.p_str, BAsmCode + 3) || (BAsmCode[3] > 4)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
      else if (!reg_decoder(ArgStr[2].str.p_str, BAsmCode + 2) || (BAsmCode[2] > 4)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[2]);
      else
      {
        BAsmCode[0] = 0x11;
        BAsmCode[1] = 0;
        if (reverse)
          BAsmCode[2] = (BAsmCode[2] << 4) | (BAsmCode[3] & 0x0f);
        else
          BAsmCode[2] |= BAsmCode[3] << 4;
        if ((Inc1 == 1) && (Inc2 == 1))
          BAsmCode[1] = 0x38;
        else if ((Inc1 == -1) && (Inc2 == -1))
          BAsmCode[1] = 0x39;
        else if ((Inc1 ==  1) && (Inc2 ==  0))
          BAsmCode[1] = 0x3a;
        else if ((Inc1 ==  0) && (Inc2 ==  1))
          BAsmCode[1] = 0x3b;
        if (BAsmCode[1] == 0) WrError(ErrNum_InvAddrMode);
        else
          CodeLen = 3;
      }
    }
    else if (Memo("TFM")) WrError(ErrNum_InvAddrMode);
    else if (!reg_decoder(ArgStr[1].str.p_str, BAsmCode + 2)) WrError(ErrNum_InvRegName);
    else if (!reg_decoder(ArgStr[2].str.p_str, BAsmCode + 1)) WrError(ErrNum_InvRegName);
    else if ((BAsmCode[1] != 13) && (BAsmCode[2] != 13) /* Z Register compatible to all other registers */
          && (((BAsmCode[1] ^ BAsmCode[2]) & 0x08) != 0)) WrError(ErrNum_ConfOpSizes);
    else
    {
      CodeLen = 2;
      BAsmCode[0] = code;
      if (reverse)
        BAsmCode[1] = (BAsmCode[1] << 4) | (BAsmCode[2] & 0x0f);
      else
        BAsmCode[1] |= BAsmCode[2] << 4;
    }
  }
}

static void DecodeTFR_TFM(Word code)
{
  DecodeTFR_TFM_EXG_6809(code, MomCPU == CPU6309, CodeCPUReg, False);
}

static void DecodeEXG(Word code)
{
  DecodeTFR_TFM_EXG_6809(code, False, CodeCPUReg, False);
}

static void DecodeALU2(Word Code)
{
  if (!ChkArgCnt(2, 2));
  else if (!CodeCPUReg(ArgStr[1].str.p_str, &BAsmCode[3])) WrError(ErrNum_InvRegName);
  else if (!CodeCPUReg(ArgStr[2].str.p_str, &BAsmCode[2])) WrError(ErrNum_InvRegName);
  else if ((BAsmCode[2] != 13) && (BAsmCode[3] != 13) /* Z Register compatible to all other registers */
        && (((BAsmCode[2] ^ BAsmCode[3]) & 0x08) != 0)) WrError(ErrNum_ConfOpSizes);
  else
  {
    CodeLen = 3;
    BAsmCode[0] = 0x10;
    BAsmCode[1] = 0x30 + Code;
    BAsmCode[2] += BAsmCode[3] << 4;
  }
}

/* Berechnung effektiver Adressen */

static void DecodeLEA(Word Index)
{
  const BaseOrder *pOrder = LEAOrders + Index;

  if (ChkArgCnt(1, 2))
  {
    adr_vals_t vals;

    if (DecodeAdr(1, ArgCnt, 1, eSymbolSizeUnknown, adr_mode_mask_ind, &vals) != e_adr_mode_none)
    {
      BAsmCode[CodeLen++] = pOrder->Code;
      append_adr_vals(&vals);
    }
  }
}

/* Push/Pull */

void DecodeStack_6809(Word code)
{
  Boolean OK = True, Extent = False;
  int z2, z3;
  Boolean has_w = !!Hi(code);

  BAsmCode[1] = 0;

  /* S oder U einsetzen, entsprechend Opcode */

  *StackRegNames[StackRegCnt - 2] = OpPart.str.p_str[strlen(OpPart.str.p_str) - 1] ^ ('S' ^ 'U');
  for (z2 = 1; z2 <= ArgCnt; z2++)
    if (OK)
    {
      if (!as_strcasecmp(ArgStr[z2].str.p_str, "W"))
      {
        if (!has_w)
          OK = False;
        else if (ArgCnt != 1)
        {
          WrError(ErrNum_InAccReg);
          OK = False;
        }
        else
          Extent = True;
      }
      else
      {
        for (z3 = 0; z3 < StackRegCnt; z3++)
          if (!as_strcasecmp(ArgStr[z2].str.p_str, StackRegNames[z3]))
          {
            BAsmCode[1] |= StackRegMasks[z3];
            break;
          }
        if (z3 >= StackRegCnt)
        {
          if (!as_strcasecmp(ArgStr[z2].str.p_str, "ALL"))
            BAsmCode[1] = 0xff;
          else if (*ArgStr[z2].str.p_str != '#') OK = False;
          else
          {
            tSymbolFlags flags;

            BAsmCode[2] = EvalStrIntExpressionOffsWithFlags(&ArgStr[z2], 1, Int8, &OK, &flags);
            if (OK)
            {
              set_b_guessed(flags, 1, 1, 0xff);
              BAsmCode[1] |= BAsmCode[2];
            }
          }
        }
      }
    }
  if (OK)
  {
    if (Extent)
    {
      CodeLen = 2;
      BAsmCode[0] = 0x10;
      BAsmCode[1] = Lo(code) + 4;
    }
    else
    {
      CodeLen = 2;
      BAsmCode[0] = code;
    }
  }
  else
    WrStrErrorPos(ErrNum_InvRegName, &ArgStr[z2 - 1]);
}

static void DecodeBITMD_LDMD(Word Code)
{
  if (!ChkArgCnt(1, 1));
  else if (!ChkMinCPU(CPU6309));
  else if (*ArgStr[1].str.p_str != '#') WrError(ErrNum_OnlyImmAddr);
  else
  {
    Boolean OK;
    tSymbolFlags flags;

    BAsmCode[2] = EvalStrIntExpressionOffsWithFlags(&ArgStr[1], 1,Int8, &OK, &flags);
    if (OK)
    {
      BAsmCode[0] = 0x11;
      BAsmCode[1] = Code;
      set_b_guessed(flags, 2, 1, 0xff);
      CodeLen = 3;
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeHCF(Word Code)
 * \brief  handle HCF instruction
 * \param  Code default machine code
 * ------------------------------------------------------------------------ */

static void DecodeHCF(Word Code)
{
  if (MomCPU != CPU6809UNDOC)
  {
    WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
    return;
  }
  switch (ArgCnt)
  {
    case 0:
      BAsmCode[0] = Code;
      CodeLen = 1;
      break;
    case 1:
    {
      Boolean ok;
      tSymbolFlags flags;

      BAsmCode[0] = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt8, &ok, &flags);
      if (ok && mSymbolQuestionable(flags))
        BAsmCode[0] = 0x14;
      if ((BAsmCode[0] != 0x14) && (BAsmCode[0] != 0x15) && (BAsmCode[0] != 0xcd))
      {
        WrStrErrorPos(ErrNum_InvArg, &ArgStr[1]);
        return;
      }
      set_b_guessed(flags, 0, 1, 0xff);
      CodeLen = 1;
      break;
    }
    default:
      (void)ChkArgCnt(0, 1);
  }
}

/*-------------------------------------------------------------------------*/
/* Erzeugung/Aufloesung Codetabellen */

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

static void AddRel(const char *NName, Word NCode8, Word NCode16)
{
  char LongName[30];

  order_array_rsv_end(RelOrders, RelOrder);
  RelOrders[InstrZ].Code8 = NCode8;
  RelOrders[InstrZ].Code16 = NCode16;
  AddInstTable(InstTable, NName, InstrZ, DecodeRel);
  as_snprintf(LongName, sizeof(LongName), "L%s", NName);
  AddInstTable(InstTable, LongName, InstrZ | 0x8000, DecodeRel);
  InstrZ++;
}

static void AddALU(const char *NName, Word NCode, tSymbolSize NSize, Boolean NImm, CPUVar NCPU)
{
  order_array_rsv_end(ALUOrders, ALUOrder);
  ALUOrders[InstrZ].Code = NCode;
  ALUOrders[InstrZ].OpSize = NSize;
  ALUOrders[InstrZ].MayImm = NImm;
  ALUOrders[InstrZ].MinCPU = NCPU;
  AddInstTable(InstTable, NName, InstrZ++, DecodeALU);
}

static void AddALU2(const char *NName)
{
  char RName[30];

  AddInstTable(InstTable, NName, InstrZ, DecodeALU2);
  as_snprintf(RName, sizeof(RName), "%sR", NName);
  AddInstTable(InstTable, RName, InstrZ, DecodeALU2);
  InstrZ++;
}

static void AddRMW(const char *NName, Word NCode, CPUVar NCPU)
{
  order_array_rsv_end(RMWOrders, BaseOrder);
  RMWOrders[InstrZ].Code = NCode;
  RMWOrders[InstrZ].MinCPU = NCPU;
  AddInstTable(InstTable, NName, InstrZ++, DecodeRMW);
}

static void AddFlag(const char *NName, Word NCode, Boolean NInv, CPUVar NCPU)
{
  order_array_rsv_end(FlagOrders, FlagOrder);
  FlagOrders[InstrZ].Code = NCode;
  FlagOrders[InstrZ].Inv = NInv;
  FlagOrders[InstrZ].MinCPU = NCPU;
  AddInstTable(InstTable, NName, InstrZ++, DecodeFlag);
}

static void AddLEA(const char *NName, Word NCode, CPUVar NCPU)
{
  order_array_rsv_end(LEAOrders, BaseOrder);
  LEAOrders[InstrZ].Code = NCode;
  LEAOrders[InstrZ].MinCPU = NCPU;
  AddInstTable(InstTable, NName, InstrZ++, DecodeLEA);
}

static void AddImm(const char *NName, Word NCode, CPUVar NCPU)
{
  order_array_rsv_end(ImmOrders, BaseOrder);
  ImmOrders[InstrZ].Code = NCode;
  ImmOrders[InstrZ].MinCPU = NCPU;
  AddInstTable(InstTable, NName, InstrZ++, DecodeImm);
}

static void InitFields(void)
{
  InstTable = CreateInstTable(307);
  SetDynamicInstTable(InstTable);

  add_null_pseudo(InstTable);

  AddInstTable(InstTable, "SWI", 0, DecodeSWI);
  AddInstTable(InstTable, "LDQ", 0, DecodeLDQ);
  AddInstTable(InstTable, "TFR", 0x1f, DecodeTFR_TFM);
  AddInstTable(InstTable, "TFM", 0x1138, DecodeTFR_TFM);
  AddInstTable(InstTable, "EXG", 0x1e, DecodeEXG);
  AddInstTable(InstTable, "BITMD", 0x3c, DecodeBITMD_LDMD);
  AddInstTable(InstTable, "LDMD", 0x3d, DecodeBITMD_LDMD);

  InstrZ = 0;
  AddFixed("NOP"  , 0x0012, CPU6809); AddFixed("SYNC" , 0x0013, CPU6809);
  AddFixed("DAA"  , 0x0019, CPU6809); AddFixed("SEX"  , 0x001d, CPU6809);
  AddFixed("RTS"  , 0x0039, CPU6809); AddFixed("ABX"  , 0x003a, CPU6809);
  AddFixed("RTI"  , 0x003b, CPU6809); AddFixed("MUL"  , 0x003d, CPU6809);
  AddFixed("SWI2" , 0x103f, CPU6809); AddFixed("SWI3" , 0x113f, CPU6809);
  AddFixed("NEGA" , 0x0040, CPU6809); AddFixed("COMA" , 0x0043, CPU6809);
  AddFixed("LSRA" , 0x0044, CPU6809); AddFixed("RORA" , 0x0046, CPU6809);
  AddFixed("ASRA" , 0x0047, CPU6809); AddFixed("ASLA" , 0x0048, CPU6809);
  AddFixed("LSLA" , 0x0048, CPU6809); AddFixed("ROLA" , 0x0049, CPU6809);
  AddFixed("DECA" , 0x004a, CPU6809); AddFixed("INCA" , 0x004c, CPU6809);
  AddFixed("TSTA" , 0x004d, CPU6809); AddFixed("CLRA" , 0x004f, CPU6809);
  AddFixed("NEGB" , 0x0050, CPU6809); AddFixed("COMB" , 0x0053, CPU6809);
  AddFixed("LSRB" , 0x0054, CPU6809); AddFixed("RORB" , 0x0056, CPU6809);
  AddFixed("ASRB" , 0x0057, CPU6809); AddFixed("ASLB" , 0x0058, CPU6809);
  AddFixed("LSLB" , 0x0058, CPU6809); AddFixed("ROLB" , 0x0059, CPU6809);
  AddFixed("DECB" , 0x005a, CPU6809); AddFixed("INCB" , 0x005c, CPU6809);
  AddFixed("TSTB" , 0x005d, CPU6809); AddFixed("CLRB" , 0x005f, CPU6809);
  AddFixed("PSHSW", 0x1038, CPU6309); AddFixed("PULSW", 0x1039, CPU6309);
  AddFixed("PSHUW", 0x103a, CPU6309); AddFixed("PULUW", 0x103b, CPU6309);
  AddFixed("SEXW" , 0x0014, CPU6309); AddFixed("NEGD" , 0x1040, CPU6309);
  AddFixed("COMD" , 0x1043, CPU6309); AddFixed("LSRD" , 0x1044, CPU6309);
  AddFixed("RORD" , 0x1046, CPU6309); AddFixed("ASRD" , 0x1047, CPU6309);
  AddFixed("ASLD" , 0x1048, CPU6309); AddFixed("LSLD" , 0x1048, CPU6309);
  AddFixed("ROLD" , 0x1049, CPU6309); AddFixed("DECD" , 0x104a, CPU6309);
  AddFixed("INCD" , 0x104c, CPU6309); AddFixed("TSTD" , 0x104d, CPU6309);
  AddFixed("CLRD" , 0x104f, CPU6309); AddFixed("COMW" , 0x1053, CPU6309);
  AddFixed("LSRW" , 0x1054, CPU6309); AddFixed("RORW" , 0x1056, CPU6309);
  AddFixed("ROLW" , 0x1059, CPU6309); AddFixed("DECW" , 0x105a, CPU6309);
  AddFixed("INCW" , 0x105c, CPU6309); AddFixed("TSTW" , 0x105d, CPU6309);
  AddFixed("CLRW" , 0x105f, CPU6309); AddFixed("COME" , 0x1143, CPU6309);
  AddFixed("DECE" , 0x114a, CPU6309); AddFixed("INCE" , 0x114c, CPU6309);
  AddFixed("TSTE" , 0x114d, CPU6309); AddFixed("CLRE" , 0x114f, CPU6309);
  AddFixed("COMF" , 0x1153, CPU6309); AddFixed("DECF" , 0x115a, CPU6309);
  AddFixed("INCF" , 0x115c, CPU6309); AddFixed("TSTF" , 0x115d, CPU6309);
  AddFixed("CLRF" , 0x115f, CPU6309); AddFixed("CLRS" , 0x1fd4, CPU6309);
  AddFixed("CLRV" , 0x1fd7, CPU6309); AddFixed("CLRX" , 0x1fd1, CPU6309);
  AddFixed("CLRY" , 0x1fd2, CPU6309);

  AddInstTable(InstTable, "HCF", 0x14, DecodeHCF);

  InstrZ = 0;
  AddRel("BRA", 0x0020, 0x0016); AddRel("BRN", 0x0021, 0x1021);
  AddRel("BHI", 0x0022, 0x1022); AddRel("BLS", 0x0023, 0x1023);
  AddRel("BHS", 0x0024, 0x1024); AddRel("BCC", 0x0024, 0x1024);
  AddRel("BLO", 0x0025, 0x1025); AddRel("BCS", 0x0025, 0x1025);
  AddRel("BNE", 0x0026, 0x1026); AddRel("BEQ", 0x0027, 0x1027);
  AddRel("BVC", 0x0028, 0x1028); AddRel("BVS", 0x0029, 0x1029);
  AddRel("BPL", 0x002a, 0x102a); AddRel("BMI", 0x002b, 0x102b);
  AddRel("BGE", 0x002c, 0x102c); AddRel("BLT", 0x002d, 0x102d);
  AddRel("BGT", 0x002e, 0x102e); AddRel("BLE", 0x002f, 0x102f);
  AddRel("BSR", 0x008d, 0x0017);

  InstrZ = 0;
  AddALU("LDA" , 0x0086, eSymbolSize8Bit , True , CPU6809);
  AddALU("STA" , 0x0087, eSymbolSize8Bit , False, CPU6809);
  AddALU("CMPA", 0x0081, eSymbolSize8Bit , True , CPU6809);
  AddALU("ADDA", 0x008b, eSymbolSize8Bit , True , CPU6809);
  AddALU("ADCA", 0x0089, eSymbolSize8Bit , True , CPU6809);
  AddALU("SUBA", 0x0080, eSymbolSize8Bit , True , CPU6809);
  AddALU("SBCA", 0x0082, eSymbolSize8Bit , True , CPU6809);
  AddALU("ANDA", 0x0084, eSymbolSize8Bit , True , CPU6809);
  AddALU("ORA" , 0x008a, eSymbolSize8Bit , True , CPU6809);
  AddALU("EORA", 0x0088, eSymbolSize8Bit , True , CPU6809);
  AddALU("BITA", 0x0085, eSymbolSize8Bit , True , CPU6809);

  AddALU("LDB" , 0x00c6, eSymbolSize8Bit , True , CPU6809);
  AddALU("STB" , 0x00c7, eSymbolSize8Bit , False, CPU6809);
  AddALU("CMPB", 0x00c1, eSymbolSize8Bit , True , CPU6809);
  AddALU("ADDB", 0x00cb, eSymbolSize8Bit , True , CPU6809);
  AddALU("ADCB", 0x00c9, eSymbolSize8Bit , True , CPU6809);
  AddALU("SUBB", 0x00c0, eSymbolSize8Bit , True , CPU6809);
  AddALU("SBCB", 0x00c2, eSymbolSize8Bit , True , CPU6809);
  AddALU("ANDB", 0x00c4, eSymbolSize8Bit , True , CPU6809);
  AddALU("ORB" , 0x00ca, eSymbolSize8Bit , True , CPU6809);
  AddALU("EORB", 0x00c8, eSymbolSize8Bit , True , CPU6809);
  AddALU("BITB", 0x00c5, eSymbolSize8Bit , True , CPU6809);

  AddALU("LDD" , 0x00cc, eSymbolSize16Bit, True , CPU6809);
  AddALU("STD" , 0x00cd, eSymbolSize16Bit, False, CPU6809);
  AddALU("CMPD", 0x1083, eSymbolSize16Bit, True , CPU6809);
  AddALU("ADDD", 0x00c3, eSymbolSize16Bit, True , CPU6809);
  AddALU("ADCD", 0x1089, eSymbolSize16Bit, True , CPU6309);
  AddALU("SUBD", 0x0083, eSymbolSize16Bit, True , CPU6809);
  AddALU("SBCD", 0x1082, eSymbolSize16Bit, True , CPU6309);
  AddALU("MULD", 0x118f, eSymbolSize16Bit, True , CPU6309);
  AddALU("DIVD", 0x118d, eSymbolSize8Bit , True , CPU6309);
  AddALU("ANDD", 0x1084, eSymbolSize16Bit, True , CPU6309);
  AddALU("ORD" , 0x108a, eSymbolSize16Bit, True , CPU6309);
  AddALU("EORD", 0x1088, eSymbolSize16Bit, True , CPU6309);
  AddALU("BITD", 0x1085, eSymbolSize16Bit, True , CPU6309);

  AddALU("LDW" , 0x1086, eSymbolSize16Bit, True , CPU6309);
  AddALU("STW" , 0x1087, eSymbolSize16Bit, False, CPU6309);
  AddALU("CMPW", 0x1081, eSymbolSize16Bit, True , CPU6309);
  AddALU("ADDW", 0x108b, eSymbolSize16Bit, True , CPU6309);
  AddALU("SUBW", 0x1080, eSymbolSize16Bit, True , CPU6309);

  AddALU("STQ" , 0x10cd, eSymbolSize16Bit, True , CPU6309);
  AddALU("DIVQ", 0x118e, eSymbolSize16Bit, True , CPU6309);

  AddALU("LDE" , 0x1186, eSymbolSize8Bit , True , CPU6309);
  AddALU("STE" , 0x1187, eSymbolSize8Bit , False, CPU6309);
  AddALU("CMPE", 0x1181, eSymbolSize8Bit , True , CPU6309);
  AddALU("ADDE", 0x118b, eSymbolSize8Bit , True , CPU6309);
  AddALU("SUBE", 0x1180, eSymbolSize8Bit , True , CPU6309);

  AddALU("LDF" , 0x11c6, eSymbolSize8Bit , True , CPU6309);
  AddALU("STF" , 0x11c7, eSymbolSize8Bit , False, CPU6309);
  AddALU("CMPF", 0x11c1, eSymbolSize8Bit , True , CPU6309);
  AddALU("ADDF", 0x11cb, eSymbolSize8Bit , True , CPU6309);
  AddALU("SUBF", 0x11c0, eSymbolSize8Bit , True , CPU6309);

  AddALU("LDX" , 0x008e, eSymbolSize16Bit, True , CPU6809);
  AddALU("STX" , 0x008f, eSymbolSize16Bit, False, CPU6809);
  AddALU("CMPX", 0x008c, eSymbolSize16Bit, True , CPU6809);

  AddALU("LDY" , 0x108e, eSymbolSize16Bit, True , CPU6809);
  AddALU("STY" , 0x108f, eSymbolSize16Bit, False, CPU6809);
  AddALU("CMPY", 0x108c, eSymbolSize16Bit, True , CPU6809);

  AddALU("LDU" , 0x00ce, eSymbolSize16Bit, True , CPU6809);
  AddALU("STU" , 0x00cf, eSymbolSize16Bit, False, CPU6809);
  AddALU("CMPU", 0x1183, eSymbolSize16Bit, True , CPU6809);

  AddALU("LDS" , 0x10ce, eSymbolSize16Bit, True , CPU6809);
  AddALU("STS" , 0x10cf, eSymbolSize16Bit, False, CPU6809);
  AddALU("CMPS", 0x118c, eSymbolSize16Bit, True , CPU6809);

  AddALU("JSR" , 0x008d, eSymbolSize16Bit, False, CPU6809);

  InstrZ = 0;
  AddALU2("ADD"); AddALU2("ADC");
  AddALU2("SUB"); AddALU2("SBC");
  AddALU2("AND"); AddALU2("OR" );
  AddALU2("EOR"); AddALU2("CMP");

  InstrZ = 0;
  AddRMW("NEG", 0x00, CPU6809);
  AddRMW("COM", 0x03, CPU6809);
  AddRMW("LSR", 0x04, CPU6809);
  AddRMW("ROR", 0x06, CPU6809);
  AddRMW("ASR", 0x07, CPU6809);
  AddRMW("ASL", 0x08, CPU6809);
  AddRMW("LSL", 0x08, CPU6809);
  AddRMW("ROL", 0x09, CPU6809);
  AddRMW("DEC", 0x0a, CPU6809);
  AddRMW("INC", 0x0c, CPU6809);
  AddRMW("TST", 0x0d, CPU6809);
  AddRMW("JMP", 0x0e, CPU6809);
  AddRMW("CLR", 0x0f, CPU6809);

  InstrZ = 0;
  AddFlag("CWAI" , 0x3c, True , CPU6809);
  AddFlag("ANDCC", 0x1c, True , CPU6809);
  AddFlag("ORCC" , 0x1a, False, CPU6809);

  InstrZ = 0;
  AddLEA("LEAX", 0x30, CPU6809);
  AddLEA("LEAY", 0x31, CPU6809);
  AddLEA("LEAS", 0x32, CPU6809);
  AddLEA("LEAU", 0x33, CPU6809);

  InstrZ = 0;
  AddImm("AIM", 0x02, CPU6309);
  AddImm("OIM", 0x01, CPU6309);
  AddImm("EIM", 0x05, CPU6309);
  AddImm("TIM", 0x0b, CPU6309);

  AddInstTable(InstTable, "PSHS", 0x34 | ((MomCPU == CPU6309) ? 0x100 : 0), DecodeStack_6809);
  AddInstTable(InstTable, "PULS", 0x35 | ((MomCPU == CPU6309) ? 0x100 : 0), DecodeStack_6809);
  AddInstTable(InstTable, "PSHU", 0x36 | ((MomCPU == CPU6309) ? 0x100 : 0), DecodeStack_6809);
  AddInstTable(InstTable, "PULU", 0x37 | ((MomCPU == CPU6309) ? 0x100 : 0), DecodeStack_6809);

  InstrZ = 0;
  AddInstTable(InstTable, "BAND" , InstrZ++, DecodeBit);
  AddInstTable(InstTable, "BIAND", InstrZ++, DecodeBit);
  AddInstTable(InstTable, "BOR"  , InstrZ++, DecodeBit);
  AddInstTable(InstTable, "BIOR" , InstrZ++, DecodeBit);
  AddInstTable(InstTable, "BEOR" , InstrZ++, DecodeBit);
  AddInstTable(InstTable, "BIEOR", InstrZ++, DecodeBit);
  AddInstTable(InstTable, "LDBT" , InstrZ++, DecodeBit);
  AddInstTable(InstTable, "STBT" , InstrZ++, DecodeBit);

  add_moto8_pseudo(InstTable, e_moto_pseudo_flags_be);
  add_moto8_comment_onoff();
  AddMoto16Pseudo(InstTable, e_moto_pseudo_flags_be);
  AddInstTable(InstTable, "DB", eIntPseudoFlag_BigEndian | eIntPseudoFlag_AllowInt | eIntPseudoFlag_AllowString | eIntPseudoFlag_MotoRep, DecodeIntelDB);
  AddInstTable(InstTable, "DW", eIntPseudoFlag_BigEndian | eIntPseudoFlag_AllowInt | eIntPseudoFlag_AllowString | eIntPseudoFlag_MotoRep, DecodeIntelDW);
}

static void DeinitFields(void)
{
  DestroyInstTable(InstTable);
  order_array_free(FixedOrders);
  order_array_free(RelOrders);
  order_array_free(ALUOrders);
  order_array_free(RMWOrders);
  order_array_free(FlagOrders);
  order_array_free(LEAOrders);
  order_array_free(ImmOrders);
}

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

static Boolean DecodeAttrPart_6809(void)
{
  if (strlen(AttrPart.str.p_str) > 1)
  {
    WrStrErrorPos(ErrNum_UndefAttr, &AttrPart);
    return False;
  }

  /* deduce operand size No size is zero-length string -> '\0' */

  return DecodeMoto16AttrSize(*AttrPart.str.p_str, &AttrPartOpSize[0], False);
}

static void MakeCode_6809(void)
{
  if (AttrPartOpSize[0] == eSymbolSizeUnknown)
    AttrPartOpSize[0] = eSymbolSize8Bit;

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

static void InitCode_6809(void)
{
  DPRValue = 0;
  target_used = False;
}

static Boolean IsDef_6809(void)
{
  return False;
}

static void SwitchTo_6809(void)
{
  static const as_assume_rec_t ASSUME09s[] =
  {
    { "DPR", &DPRValue, 0, 0xff, 0x100, NULL }
  };
  const TFamilyDescr *p_descr = FindFamilyByName("6809");

  TurnWords = False;
  SetIntConstMode(eIntConstModeMoto);

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

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

  DecodeAttrPart = DecodeAttrPart_6809;
  MakeCode = MakeCode_6809;
  IsDef = IsDef_6809;

  SwitchFrom = DeinitFields;
  InitFields();
  AddMoto16PseudoONOFF(False);
  if (!target_used)
    SetFlag(&plain_base_mode, plain_base_mode_sym_name, def_plain_base_mode_set ? def_plain_base_mode : False);
  AddONOFF(plain_base_mode_cmd_name, &plain_base_mode, plain_base_mode_sym_name, False);
  target_used = True;

  assume_set(ASSUME09s, as_array_size(ASSUME09s));
}

static as_cmd_result_t cmd_plain_base(Boolean negate, const char *p_arg)
{
  UNUSED(p_arg);
  def_plain_base_mode = !negate;
  def_plain_base_mode_set = True;
  return e_cmd_ok;
}

static const as_cmd_rec_t onoff_params[] =
{
  { plain_base_mode_cmd_name, cmd_plain_base }
};

void code6809_init(void)
{
  CPU6809      = AddCPU("6809"     , SwitchTo_6809);
  CPU6809UNDOC = AddCPU("6809UNDOC", SwitchTo_6809);
  CPU6309      = AddCPU("6309"     , SwitchTo_6809);

  as_cmd_register(onoff_params, as_array_size(onoff_params));
  AddInitPassProc(InitCode_6809);
}
