/* code7000.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator SH7x00                                                      */
/*                                                                           */
/*****************************************************************************/

#include "stdinc.h"

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

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

#include "code7000.h"

enum
{
  ModNone = -1,
  ModReg = 0,
  ModIReg = 1,
  ModPreDec = 2,
  ModPostInc = 3,
  ModIndReg = 4,
  ModR0Base = 5,
  ModGBRBase = 6,
  ModGBRR0 = 7,
  ModPCRel = 8,
  ModImm = 9
};

#define MModReg (1 << ModReg)
#define MModIReg (1 << ModIReg)
#define MModPreDec (1 << ModPreDec)
#define MModPostInc (1 << ModPostInc)
#define MModIndReg (1 << ModIndReg)
#define MModR0Base (1 << ModR0Base)
#define MModGBRBase (1 << ModGBRBase)
#define MModGBRR0 (1 << ModGBRR0)
#define MModPCRel (1 << ModPCRel)
#define MModImm (1 << ModImm)

#define REG_SP 15
#define RegNone (-1)
#define RegPC (-2)
#define RegGBR (-3)

#define CompLiteralsName "COMPRESSEDLITERALS"

typedef struct
{
  CPUVar MinCPU;
  Boolean Priv;
  Word Code;
} FixedOrder;

typedef struct
{
  CPUVar MinCPU;
  Boolean Priv;
  Word Code;
  Boolean Delayed;
} OneRegOrder;

typedef struct
{
  CPUVar MinCPU;
  Boolean Priv;
  Word Code;
  ShortInt DefSize;
} TwoRegOrder;

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

typedef struct
{
   const char *Name;
   Word Code;
   CPUVar MinCPU;
   Boolean NeedsDSP;
} TRegDef;

static tSymbolSize OpSize;  /* Groesse=8*(2^OpSize) */
static ShortInt AdrMode;    /* Ergebnisadressmodus */
static Word AdrPart;        /* Adressierungsmodusbits im Opcode */

static CPUVar CPU7000, CPU7600, CPU7700;

static FixedOrder *FixedOrders;
static OneRegOrder *OneRegOrders;
static TwoRegOrder *TwoRegOrders;
static FixedMinOrder *MulRegOrders;
static FixedOrder *BWOrders;
static TRegDef *RegDefs;

static Boolean CurrDelayed, PrevDelayed, CompLiterals, DSPAvail;
static LongInt DelayedAdr;

/*-------------------------------------------------------------------------*/
/* die PC-relative Adresse: direkt nach verzoegerten Spruengen = Sprungziel+2 */

static LongInt PCRelAdr(void)
{
  if (PrevDelayed) return DelayedAdr + 2;
  else return EProgCounter() + 4;
}

static void ChkDelayed(void)
{
  if (PrevDelayed) WrError(ErrNum_Pipeline);
}

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

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

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

static Boolean DecodeRegCore(const char *pArg, Word *pResult)
{
  size_t l;
  char *p_end;

  if (!as_strcasecmp(pArg, "SP"))
  {
    *pResult = REG_SP | REGSYM_FLAG_ALIAS;
    return True;
  }

  l = strlen(pArg);
  if ((l < 2) || (l > 3) || (as_toupper(*pArg) != 'R'))
    return False;

  *pResult = strtoul(pArg + 1, &p_end, 10);
  return !*p_end && (*pResult <= 15);
}

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

static void DissectReg_7000(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
{
  switch (InpSize)
  {
    case eSymbolSize32Bit:
      if (Value == (REG_SP | REGSYM_FLAG_ALIAS))
        as_snprintf(pDest, DestSize, "SP");
      else
        as_snprintf(pDest, DestSize, "R%u", (unsigned)Value);
      break;
    default:
      as_snprintf(pDest, DestSize, "%d-%u", (int)InpSize, (unsigned)Value);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeReg(const tStrComp *pArg, Word *pResult, Boolean MustBeReg)
 * \brief  check whether argument is a CPU register or register alias
 * \param  pArg source argument
 * \param  pResult register # if yes
 * \return eval result
 * ------------------------------------------------------------------------ */

static tRegEvalResult DecodeReg(const tStrComp *pArg, Word *pResult, Boolean MustBeReg)
{
  tRegEvalResult RegEvalResult;
  tEvalResult EvalResult;
  tRegDescr RegDescr;

  if (DecodeRegCore(pArg->str.p_str, pResult))
  {
    *pResult &= ~REGSYM_FLAG_ALIAS;
    return eIsReg;
  }

  RegEvalResult = EvalStrRegExpressionAsOperand(pArg, &RegDescr, &EvalResult, eSymbolSize32Bit, MustBeReg);
  *pResult = RegDescr.Reg & ~REGSYM_FLAG_ALIAS;
  return RegEvalResult;
}

static Boolean DecodeCtrlReg(char *Asc, Word *Erg)
{
  CPUVar MinCPU = CPU7000;

  *Erg = 0xff;
  if (!as_strcasecmp(Asc, "SR")) *Erg = 0;
  else if (!as_strcasecmp(Asc, "GBR")) *Erg = 1;
  else if (!as_strcasecmp(Asc, "VBR")) *Erg = 2;
  else if (!as_strcasecmp(Asc, "SSR"))
  {
    *Erg = 3; MinCPU = CPU7700;
  }
  else if (!as_strcasecmp(Asc, "SPC"))
  {
    *Erg = 4; MinCPU = CPU7700;
  }
  else if ((strlen(Asc) == 7) && (as_toupper(*Asc) == 'R')
      && (!as_strcasecmp(Asc + 2, "_BANK"))
      && (Asc[1] >= '0') && (Asc[1] <= '7'))
  {
    *Erg = Asc[1] - '0' + 8; MinCPU = CPU7700;
  }
  if ((*Erg == 0xff) || (MomCPU < MinCPU))
  {
    WrXError(ErrNum_InvCtrlReg, Asc); return False;
  }
  else return True;
}

static Boolean DecodeSReg(char *Asc, Word *Erg)
{
  int z;
  Boolean Result = FALSE;

  for (z = 0; RegDefs[z].Name; z++)
    if (!as_strcasecmp(Asc, RegDefs[z].Name))
      break;
  if (RegDefs[z].Name)
  {
    if (MomCPU < RegDefs[z].MinCPU);
    else if ((!DSPAvail) && RegDefs[z].NeedsDSP);
    else
    {
      Result = TRUE;
      *Erg = RegDefs[z].Code;
    }
  }
  return Result;
}

static LongInt ExtOp(LongInt Inp, Byte Src, Boolean Signed)
{
  switch (Src)
  {
    case 0:
      Inp &= 0xff;
      break;
    case 1:
      Inp &= 0xffff;
      break;
  }
  if (Signed)
  {
    if (Src < 1)
      if ((Inp & 0x80) == 0x80)
        Inp += 0xff00;
    if (Src < 2)
      if ((Inp & 0x8000) == 0x8000)
        Inp += 0xffff0000;
  }
  return Inp;
}

static LongInt OpMask(ShortInt OpSize)
{
  switch (OpSize)
  {
    case eSymbolSize8Bit:
      return 0xff;
    case eSymbolSize16Bit:
      return 0xffff;
    case eSymbolSize32Bit:
      return 0xffffffff;
    default:
      return 0;
  }
}

static void DecodeAdr(const tStrComp *pArg, Word Mask, Boolean Signed)
{
  Word HReg;
  char *pos;
  ShortInt BaseReg, IndReg;
  tSymbolSize DOpSize;
  LongInt DispAcc;
  Boolean OK, FirstFlag;
  tSymbolFlags Flags;

  AdrMode = ModNone;

  switch (DecodeReg(pArg, &HReg, False))
  {
    case eIsReg:
      AdrPart = HReg;
      AdrMode = ModReg;
      goto chk;
    case eIsNoReg:
      break;
    case eRegAbort:
      return;
  }

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

    StrCompRefRight(&Arg, pArg, 1);
    if (IsIndirect(Arg.str.p_str))
    {
      tStrComp Remainder;

      StrCompIncRefLeft(&Arg, 1);
      StrCompShorten(&Arg, 1);
      BaseReg = RegNone;
      IndReg = RegNone;
      DispAcc = 0;
      FirstFlag = False;
      OK = True;
      do
      {
        pos = QuotPos(Arg.str.p_str, ',');
        if (pos)
          StrCompSplitRef(&Arg, &Remainder, &Arg, pos);
        if (!as_strcasecmp(Arg.str.p_str, "PC"))
        {
          if (BaseReg == RegNone)
            BaseReg = RegPC;
          else
          {
            WrError(ErrNum_InvAddrMode);
            OK = False;
          }
        }
        else if (!as_strcasecmp(Arg.str.p_str, "GBR"))
        {
          if (BaseReg == RegNone)
            BaseReg = RegGBR;
          else
          {
            WrError(ErrNum_InvAddrMode);
            OK = False;
          }
        }
        else switch (DecodeReg(&Arg, &HReg, False))
        {
          case eIsReg:
            if (IndReg == RegNone)
              IndReg = HReg;
            else if ((BaseReg == RegNone) && (HReg == 0))
              BaseReg = 0;
            else if ((IndReg == 0) && (BaseReg == RegNone))
            {
              BaseReg = 0;
              IndReg = HReg;
            }
            else
            {
              WrStrErrorPos(ErrNum_InvAddrMode, &Arg); OK = False;
            }
            break;
          case eIsNoReg:
            DispAcc += EvalStrIntExpressionWithFlags(&Arg, Int32, &OK, &Flags);
            if (mFirstPassUnknown(Flags))
              FirstFlag = True;
            break;
          case eRegAbort:
            OK = False;
        }
        if (pos)
          Arg = Remainder;
      }
      while (pos && OK);
      if (FirstFlag) DispAcc = 0;
      if ((OK) && ((DispAcc & ((1 << OpSize) - 1)) != 0))
      {
        WrError(ErrNum_NotAligned);
        OK = False;
      }
      else if ((OK) && (DispAcc < 0))
      {
        WrXError(ErrNum_UnderRange, "Disp<0");
        OK = False;
      }
      else DispAcc = DispAcc >> OpSize;
      if (OK)
      {
        switch (BaseReg)
        {
          case 0:
            if ((IndReg < 0) || (DispAcc != 0)) WrError(ErrNum_InvAddrMode);
            else
            {
              AdrMode = ModR0Base;
              AdrPart = IndReg;
            }
            break;
          case RegGBR:
            if ((IndReg == 0) && (DispAcc == 0)) AdrMode = ModGBRR0;
            else if (IndReg != RegNone) WrError(ErrNum_InvAddrMode);
            else if (DispAcc > 255) WrError(ErrNum_OverRange);
            else
            {
              AdrMode = ModGBRBase;
              AdrPart = DispAcc;
            }
            break;
          case RegNone:
            if (IndReg == RegNone) WrError(ErrNum_InvAddrMode);
            else if (DispAcc > 15) WrError(ErrNum_OverRange);
            else
            {
              AdrMode = ModIndReg;
              AdrPart = (IndReg << 4) + DispAcc;
            }
            break;
          case RegPC:
            if (IndReg != RegNone) WrError(ErrNum_InvAddrMode);
            else if (DispAcc > 255) WrError(ErrNum_OverRange);
            else
            {
              AdrMode = ModPCRel;
              AdrPart = DispAcc;
            }
            break;
        }
      }
      goto chk;
    }
    else /* !IsIndirect */
    {
      int ArgLen = strlen(Arg.str.p_str);

      if ((ArgLen > 1) && (*Arg.str.p_str == '-'))
      {
        StrCompIncRefLeft(&Arg, 1);
        if (DecodeReg(&Arg, &HReg, True) == eIsReg)
        {
          AdrPart = HReg;
          AdrMode = ModPreDec;
        }
      }
      else if ((ArgLen > 1) && (Arg.str.p_str[ArgLen - 1] == '+'))
      {
        StrCompShorten(&Arg, 1);
        if (DecodeReg(&Arg, &HReg, True) == eIsReg)
        {
          AdrPart = HReg;
          AdrMode = ModPostInc;
        }
      }
      else if (DecodeReg(&Arg, &HReg, True))
      {
        AdrPart = HReg;
        AdrMode = ModIReg;
      }
      goto chk;
    }
  }

  if (*pArg->str.p_str == '#')
  {
    switch (OpSize)
    {
      case eSymbolSize8Bit:
        DispAcc = EvalStrIntExpressionOffsWithFlags(pArg, 1, Int8, &OK, &Flags);
        break;
      case eSymbolSize16Bit:
        DispAcc = EvalStrIntExpressionOffsWithFlags(pArg, 1, Int16, &OK, &Flags);
        break;
      case eSymbolSize32Bit:
        DispAcc = EvalStrIntExpressionOffsWithFlags(pArg, 1, Int32, &OK, &Flags);
        break;
      default:
        DispAcc = 0;
        OK = True;
        Flags = eSymbolFlag_None;
    }
    if (OK)
    {
      Boolean Critical = mFirstPassUnknown(Flags) || mUsesForwards(Flags);

      /* minimale Groesse optimieren */

      DOpSize = (OpSize == eSymbolSize8Bit) ? eSymbolSize8Bit : (Critical ? eSymbolSize16Bit : eSymbolSize8Bit);
      while (((ExtOp(DispAcc, DOpSize, Signed) ^ DispAcc) & OpMask(OpSize)) != 0)
        DOpSize++;
      if (DOpSize == 0)
      {
        AdrPart = DispAcc & 0xff;
        AdrMode = ModImm;
      }
      else if (Mask & MModPCRel)
      {
        tStrComp LStrComp;
        String LStr;
        tSymbolSize lit_size;
        Byte data_offset = 0;

        StrCompMkTemp(&LStrComp, LStr, sizeof(LStr));

        lit_size = (DOpSize == 2) ? eSymbolSize32Bit : eSymbolSize16Bit;

        literal_make(&LStrComp, &data_offset, DispAcc, lit_size, Critical);

        /* Distanz abfragen - im naechsten Pass... */

        DispAcc = EvalStrIntExpressionWithFlags(&LStrComp, Int32, &OK, &Flags) + data_offset;
        if (OK)
        {
          if (mFirstPassUnknown(Flags))
            DispAcc = 0;
          else if (lit_size == eSymbolSize32Bit)
            DispAcc = (DispAcc - (PCRelAdr() & 0xfffffffc)) >> 2;
          else
            DispAcc = (DispAcc - PCRelAdr()) >> 1;
          if (DispAcc < 0)
          {
            WrXError(ErrNum_UnderRange, "Disp<0");
            OK = False;
          }
          else if ((DispAcc > 255) && !mSymbolQuestionable(Flags)) WrError(ErrNum_DistTooBig);
          else
          {
            AdrMode = ModPCRel;
            AdrPart = DispAcc;
            OpSize = lit_size;
          }
        }
      }
      else
        WrError(ErrNum_InvAddrMode);
    }
    goto chk;
  }

  /* absolut ueber PC-relativ abwickeln */

  if ((OpSize != eSymbolSize16Bit) && (OpSize != eSymbolSize32Bit)) WrError(ErrNum_InvOpSize);
  else
  {
    DispAcc = EvalStrIntExpressionWithFlags(pArg, Int32, &OK, &Flags);
    if (mFirstPassUnknown(Flags))
      DispAcc = 0;
    else if (OpSize == eSymbolSize32Bit)
      DispAcc -= (PCRelAdr() & 0xfffffffc);
    else
      DispAcc -= PCRelAdr();
    if (DispAcc < 0)
      WrXError(ErrNum_UnderRange, "Disp<0");
    else if ((DispAcc & ((1 << OpSize) - 1)) != 0)
      WrError(ErrNum_NotAligned);
    else
    {
      DispAcc = DispAcc >> OpSize;
      if (DispAcc > 255) WrError(ErrNum_OverRange);
      else
      {
        AdrMode = ModPCRel;
        AdrPart = DispAcc;
      }
    }
  }

chk:
  if ((AdrMode != ModNone) && ((Mask & (1 << AdrMode)) == 0))
  {
    WrError(ErrNum_InvAddrMode);
    AdrMode = ModNone;
  }
}

static void SetCode(Word Code)
{
  CodeLen = 2;
  WAsmCode[0] = Code;
}

/*-------------------------------------------------------------------------*/
/* Instruction Decoders */

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

  if (!ChkArgCnt(0, 0));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else if (ChkMinCPU(pOrder->MinCPU))
  {
    SetCode(pOrder->Code);
    if ((!SupAllowed) && (pOrder->Priv)) WrError(ErrNum_PrivOrder);
  }
}

static void DecodeMOV(Word Code)
{
  Word HReg;

  UNUSED(Code);

  if (OpSize == eSymbolSizeUnknown)
    SetOpSize(eSymbolSize32Bit);
  if (!ChkArgCnt(2, 2));
  else if (OpSize > eSymbolSize32Bit) WrError(ErrNum_InvOpSize);
  else if (DecodeReg(&ArgStr[1], &HReg, False) == eIsReg)
  {
    DecodeAdr(&ArgStr[2], MModReg | MModIReg | MModPreDec | MModIndReg | MModR0Base | MModGBRBase, True);
    switch (AdrMode)
    {
      case ModReg:
        if (OpSize != eSymbolSize32Bit) WrError(ErrNum_InvOpSize);
        else
          SetCode(0x6003 + (HReg << 4) + (AdrPart << 8));
        break;
      case ModIReg:
        SetCode(0x2000 + (HReg  << 4) + (AdrPart << 8) + OpSize);
        break;
      case ModPreDec:
        SetCode(0x2004 + (HReg << 4) + (AdrPart << 8) + OpSize);
        break;
      case ModIndReg:
        if (OpSize == eSymbolSize32Bit)
          SetCode(0x1000 + (HReg << 4) + (AdrPart & 15) + ((AdrPart & 0xf0) << 4));
        else if (HReg != 0)
          WrError(ErrNum_InvAddrMode);
        else
          SetCode(0x8000 + AdrPart + (((Word)OpSize) << 8));
        break;
      case ModR0Base:
        SetCode(0x0004 + (AdrPart << 8) + (HReg << 4) + OpSize);
        break;
      case ModGBRBase:
        if (HReg != 0)
          WrError(ErrNum_InvAddrMode);
        else
          SetCode(0xc000 + AdrPart + (((Word)OpSize) << 8));
        break;
    }
  }
  else if (DecodeReg(&ArgStr[2], &HReg, False) == eIsReg)
  {
    DecodeAdr(&ArgStr[1], MModImm | MModPCRel | MModIReg | MModPostInc | MModIndReg | MModR0Base | MModGBRBase, True);
    switch (AdrMode)
    {
      case ModIReg:
        SetCode(0x6000 + (AdrPart << 4) + (((Word)HReg) << 8) + OpSize);
        break;
      case ModPostInc:
        SetCode(0x6004 + (AdrPart << 4) + (((Word)HReg) << 8) + OpSize);
        break;
      case ModIndReg:
        if (OpSize == eSymbolSize32Bit)
          SetCode(0x5000 + (((Word)HReg) << 8) + AdrPart);
        else if (HReg != 0)
          WrError(ErrNum_InvAddrMode);
        else
          SetCode(0x8400 + AdrPart + (((Word)OpSize) << 8));
        break;
      case ModR0Base:
        SetCode(0x000c + (AdrPart << 4) + (((Word)HReg) << 8) + OpSize);
        break;
      case ModGBRBase:
        if (HReg != 0)
          WrError(ErrNum_InvAddrMode);
        else
          SetCode(0xc400 + AdrPart + (((Word)OpSize) << 8));
        break;
      case ModPCRel:
        if (OpSize == eSymbolSize8Bit)
          WrError(ErrNum_InvAddrMode);
        else
          SetCode(0x9000 + (((Word)OpSize - 1) << 14) + (((Word)HReg) << 8) + AdrPart);
        break;
      case ModImm:
        SetCode(0xe000 + (((Word)HReg) << 8) + AdrPart);
        break;
    }
  }
  else
    WrError(ErrNum_InvAddrMode);
}

static void DecodeMOVA(Word Code)
{
  Word HReg;

  UNUSED(Code);

  if (!ChkArgCnt(2, 2));
  else if (!DecodeReg(&ArgStr[2], &HReg, True));
  else if (HReg != 0) WrStrErrorPos(ErrNum_InvReg, &ArgStr[2]);
  else
  {
    SetOpSize(eSymbolSize32Bit);
    DecodeAdr(&ArgStr[1], MModPCRel, False);
    if (AdrMode != ModNone)
      SetCode(0xc700 + AdrPart);
  }
}

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

  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else
  {
    DecodeAdr(&ArgStr[1], MModIReg, False);
    if (AdrMode != ModNone)
      SetCode(WAsmCode[0] = 0x0083 + (AdrPart << 8));
  }
}

static void DecodeLDC_STC(Word IsLDC)
{
  if (OpSize == eSymbolSizeUnknown)
    SetOpSize(eSymbolSize32Bit);

  if (ChkArgCnt(2, 2))
  {
    tStrComp *pArg1 = IsLDC ? &ArgStr[2] : &ArgStr[1],
             *pArg2 = IsLDC ? &ArgStr[1] : &ArgStr[2];
    Word HReg;

    if (DecodeCtrlReg(pArg1->str.p_str, &HReg))
    {
      DecodeAdr(pArg2, MModReg | (IsLDC ? MModPostInc : MModPreDec), False);
      switch (AdrMode)
      {
        case ModReg:
          SetCode((IsLDC ? 0x400e : 0x0002) + (AdrPart << 8) + (HReg << 4));
          break;
        case ModPostInc:
          SetCode(0x4007 + (AdrPart << 8) + (HReg << 4));
          break;
        case ModPreDec:
          SetCode(0x4003 + (AdrPart << 8) + (HReg << 4));
          break;
      }
      if ((AdrMode != ModNone) && (!SupAllowed))
        WrError(ErrNum_PrivOrder);
    }
  }
}

static void DecodeLDS_STS(Word IsLDS)
{
  if (OpSize == eSymbolSizeUnknown)
    SetOpSize(eSymbolSize32Bit);

  if (ChkArgCnt(2, 2))
  {
    tStrComp *pArg1 = IsLDS ? &ArgStr[2] : &ArgStr[1],
             *pArg2 = IsLDS ? &ArgStr[1] : &ArgStr[2];
    Word HReg;

    if (!DecodeSReg(pArg1->str.p_str, &HReg)) WrError(ErrNum_InvCtrlReg);
    else
    {
      DecodeAdr(pArg2, MModReg | (IsLDS ? MModPostInc : MModPreDec), False);
      switch (AdrMode)
      {
        case ModReg:
          SetCode((IsLDS << 14) + 0x000a + (AdrPart << 8) + (HReg << 4));
          break;
        case ModPostInc:
          SetCode(0x4006 + (AdrPart << 8) + (HReg << 4));
          break;
        case ModPreDec:
          SetCode(0x4002 + (AdrPart << 8) + (HReg << 4));
          break;
      }
    }
  }
}

static void DecodeOneReg(Word Index)
{
  const OneRegOrder *pOrder = OneRegOrders + Index;

  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else if (ChkMinCPU(pOrder->MinCPU))
  {
    DecodeAdr(&ArgStr[1], MModReg, False);
    if (AdrMode != ModNone)
      SetCode(pOrder->Code + (AdrPart << 8));
    if ((!SupAllowed) && (pOrder->Priv)) WrError(ErrNum_PrivOrder);
    if (pOrder->Delayed)
    {
      CurrDelayed = True;
      DelayedAdr = 0x7fffffff;
      ChkDelayed();
    }
  }
}

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

  if (OpSize == eSymbolSizeUnknown)
    SetOpSize(eSymbolSize8Bit);
  if (!ChkArgCnt(1, 1));
  else if (OpSize != eSymbolSize8Bit) WrError(ErrNum_InvOpSize);
  else
  {
    DecodeAdr(&ArgStr[1], MModIReg, False);
    if (AdrMode != ModNone)
      SetCode(0x401b + (AdrPart << 8));
  }
}

static void DecodeTwoReg(Word Index)
{
  const TwoRegOrder *pOrder = TwoRegOrders + Index;

  if (!ChkArgCnt(2, 2));
  else if (*AttrPart.str.p_str && (OpSize != pOrder->DefSize)) WrError(ErrNum_UseLessAttr);
  else if (ChkMinCPU(pOrder->MinCPU))
  {
    DecodeAdr(&ArgStr[1], MModReg, False);
    if (AdrMode != ModNone)
    {
      WAsmCode[0] = pOrder->Code + (AdrPart << 4);
      DecodeAdr(&ArgStr[2], MModReg, False);
      if (AdrMode != ModNone)
        SetCode(WAsmCode[0] + (((Word)AdrPart) << 8));
      if ((!SupAllowed) && (pOrder->Priv))
        WrError(ErrNum_PrivOrder);
    }
  }
}

static void DecodeMulReg(Word Index)
{
  const FixedMinOrder *pOrder = MulRegOrders + Index;

  if (ChkArgCnt(2, 2)
   && ChkMinCPU(pOrder->MinCPU))
  {
    if (!*AttrPart.str.p_str)
      OpSize = eSymbolSize32Bit;
    if (OpSize != eSymbolSize32Bit) WrError(ErrNum_InvOpSize);
    else
    {
      DecodeAdr(&ArgStr[1], MModReg, False);
      if (AdrMode != ModNone)
      {
        WAsmCode[0] = pOrder->Code + (AdrPart << 4);
        DecodeAdr(&ArgStr[2], MModReg, False);
        if (AdrMode != ModNone)
          SetCode(WAsmCode[0] + (((Word)AdrPart) << 8));
      }
    }
  }
}

static void DecodeBW(Word Index)
{
  const FixedOrder *pOrder = BWOrders + Index;

  if (OpSize == eSymbolSizeUnknown)
    SetOpSize(eSymbolSize16Bit);
  if (!ChkArgCnt(2, 2));
  else if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
  else
  {
    DecodeAdr(&ArgStr[1], MModReg, False);
    if (AdrMode != ModNone)
    {
      WAsmCode[0] = pOrder->Code + OpSize + (AdrPart << 4);
      DecodeAdr(&ArgStr[2], MModReg, False);
      if (AdrMode != ModNone)
        SetCode(WAsmCode[0] + (((Word)AdrPart) << 8));
    }
  }
}

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

  if (OpSize == eSymbolSizeUnknown)
    SetOpSize(eSymbolSize16Bit);
  if (!ChkArgCnt(2, 2));
  else if ((OpSize != eSymbolSize16Bit) && (OpSize != eSymbolSize32Bit)) WrError(ErrNum_InvOpSize);
  else if ((OpSize == eSymbolSize32Bit) && !ChkMinCPU(CPU7600));
  else
  {
    DecodeAdr(&ArgStr[1], MModPostInc, False);
    if (AdrMode != ModNone)
    {
      WAsmCode[0] = 0x000f + (AdrPart << 4) + (((Word)2 - OpSize) << 14);
      DecodeAdr(&ArgStr[2], MModPostInc, False);
      if (AdrMode != ModNone)
        SetCode(WAsmCode[0] + (((Word)AdrPart) << 8));
    }
  }
}

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

  if (!ChkArgCnt(2, 2));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else
  {
    DecodeAdr(&ArgStr[2], MModReg, False);
    if (AdrMode != ModNone)
    {
      Word HReg = AdrPart;

      OpSize = eSymbolSize32Bit;
      DecodeAdr(&ArgStr[1], MModReg | MModImm, True);
      switch (AdrMode)
      {
        case ModReg:
          SetCode(0x300c + (((Word)HReg) << 8) + (AdrPart << 4));
          break;
        case ModImm:
          SetCode(0x7000 + AdrPart + (((Word)HReg) << 8));
          break;
      }
    }
  }
}

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

  if (!ChkArgCnt(2, 2));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else
  {
    DecodeAdr(&ArgStr[2], MModReg, False);
    if (AdrMode != ModNone)
    {
      Word HReg = AdrPart;

      OpSize = eSymbolSize32Bit;
      DecodeAdr(&ArgStr[1], MModReg | MModImm, True);
      switch (AdrMode)
      {
        case ModReg:
          SetCode(0x3000 + (((Word)HReg) << 8) + (AdrPart << 4));
          break;
        case ModImm:
          if (HReg != 0) WrError(ErrNum_InvAddrMode);
          else
            SetCode(0x8800 + AdrPart);
          break;
      }
    }
  }
}

static void DecodeLog(Word Code)
{
  Word HReg;

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[2], MModReg | MModGBRR0, False);
    switch (AdrMode)
    {
      case ModReg:
        if (*AttrPart.str.p_str && (OpSize != eSymbolSize32Bit)) WrError(ErrNum_InvOpSize);
        else
        {
          OpSize = eSymbolSize32Bit;
          HReg = AdrPart;
          DecodeAdr(&ArgStr[1], MModReg | MModImm, False);
          switch (AdrMode)
          {
            case ModReg:
              SetCode(0x2008 + Code + (((Word)HReg) << 8) + (AdrPart << 4));
              break;
            case ModImm:
              if (HReg != 0) WrError(ErrNum_InvAddrMode);
              else
                SetCode(0xc800 + (Code << 8) + AdrPart);
              break;
          }
        }
        break;
      case ModGBRR0:
        DecodeAdr(&ArgStr[1], MModImm, False);
        if (AdrMode != ModNone)
          SetCode(0xcc00 + (Code << 8) + AdrPart);
        break;
    }
  }
}

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

  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else
  {
    OpSize = eSymbolSize8Bit;
    DecodeAdr(&ArgStr[1], MModImm, False);
    if (AdrMode == ModImm)
      SetCode(0xc300 + AdrPart);
    ChkDelayed();
  }
}

static void DecodeBT_BF(Word Code)
{
  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else if ((Code & 0x400) && !ChkMinCPU(CPU7600));
  else
  {
    Boolean OK;
    tSymbolFlags Flags;
    LongInt AdrLong;

    DelayedAdr = EvalStrIntExpressionWithFlags(&ArgStr[1], Int32, &OK, &Flags);
    AdrLong = DelayedAdr - (EProgCounter() + 4);
    if (OK)
    {
      if (Odd(AdrLong)) WrError(ErrNum_DistIsOdd);
      else if (((AdrLong < -256) || (AdrLong > 254)) && !mSymbolQuestionable(Flags)) WrError(ErrNum_JmpDistTooBig);
      else
      {
        SetCode(Code + ((AdrLong >> 1) & 0xff));
        if (Code & 0x400)
          CurrDelayed = True;
        ChkDelayed();
      }
    }
  }
}

static void DecodeBRA_BSR(Word Code)
{
  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else
  {
    Boolean OK;
    tSymbolFlags Flags;
    LongInt AdrLong;

    DelayedAdr = EvalStrIntExpressionWithFlags(&ArgStr[1], Int32, &OK, &Flags);
    AdrLong = DelayedAdr - (EProgCounter() + 4);
    if (OK)
    {
      if (Odd(AdrLong)) WrError(ErrNum_DistIsOdd);
      else if (((AdrLong < -4096) || (AdrLong > 4094)) && !mSymbolQuestionable(Flags)) WrError(ErrNum_JmpDistTooBig);
      else
      {
        SetCode(Code + ((AdrLong >> 1) & 0xfff));
        CurrDelayed = True;
        ChkDelayed();
      }
    }
  }
}

static void DecodeJSR_JMP(Word Code)
{
  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else
  {
    DecodeAdr(&ArgStr[1], MModIReg, False);
    if (AdrMode != ModNone)
    {
      SetCode(Code + (AdrPart << 8));
      CurrDelayed = True;
      DelayedAdr = 0x7fffffff;
      ChkDelayed();
    }
  }
}

static void DecodeDCT_DCF(Word Cond)
{
  char *pos;
  int z;

  if (!DSPAvail)
  {
    WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
    return;
  }

  /* strip off DSP condition */

  if (!ChkArgCnt(1, ArgCntMax))
    return;

  pos = FirstBlank(ArgStr[1].str.p_str);
  if (!pos)
  {
    StrCompCopy(&OpPart, &ArgStr[1]);
    for (z = 1; z < ArgCnt; z++)
      StrCompCopy(&ArgStr[z], &ArgStr[z + 1]);
    ArgCnt--;
  }
  else
    StrCompSplitLeft(&ArgStr[1], &OpPart, pos);

  UNUSED(Cond);
}

static LargeInt ltorg_16(const as_literal_t *p_lit, tStrComp *p_name)
{
  LargeInt ret;

  SetMaxCodeLen(CodeLen + 2);
  WAsmCode[CodeLen >> 1] = p_lit->value;
  ret = EProgCounter() + CodeLen;
  EnterIntSymbol(p_name, ret, ActPC, False);
  CodeLen += 2;
  return ret;
}

static LargeInt ltorg_32(const as_literal_t *p_lit, tStrComp *p_name)
{
  LargeInt ret;

  SetMaxCodeLen(CodeLen + 6);
  if (((EProgCounter() + CodeLen) & 2) != 0)
  {
    WAsmCode[CodeLen >> 1] = 0;
    CodeLen += 2;
  }
  WAsmCode[CodeLen >> 1] = (p_lit->value >> 16);
  WAsmCode[(CodeLen >> 1) + 1] = (p_lit->value & 0xffff);
  ret = EProgCounter() + CodeLen;
  EnterIntSymbol(p_name, ret, ActPC, False);
  CodeLen += 4;
  return ret;
}

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

  if (!ChkArgCnt(0, 0));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else
  {
    if ((EProgCounter() & 3) == 0)
    {
      literals_dump(ltorg_32, eSymbolSize32Bit, MomSectionHandle, True);
      literals_dump(ltorg_16, eSymbolSize16Bit, MomSectionHandle, False);
    }
    else
    {
      literals_dump(ltorg_16, eSymbolSize16Bit, MomSectionHandle, False);
      literals_dump(ltorg_32, eSymbolSize32Bit, MomSectionHandle, True);
    }
  }
}

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

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

static void AddOneReg(const char *NName, Word NCode, CPUVar NMin, Boolean NPriv, Boolean NDel)
{
  order_array_rsv_end(OneRegOrders, OneRegOrder);
  OneRegOrders[InstrZ].Code = NCode;
  OneRegOrders[InstrZ].MinCPU = NMin;
  OneRegOrders[InstrZ].Priv = NPriv;
  OneRegOrders[InstrZ].Delayed = NDel;
  AddInstTable(InstTable, NName, InstrZ++, DecodeOneReg);
}

static void AddTwoReg(const char *NName, Word NCode, Boolean NPriv, CPUVar NMin, ShortInt NDef)
{
  order_array_rsv_end(TwoRegOrders, TwoRegOrder);
  TwoRegOrders[InstrZ].Priv = NPriv;
  TwoRegOrders[InstrZ].DefSize = NDef;
  TwoRegOrders[InstrZ].MinCPU = NMin;
  TwoRegOrders[InstrZ].Code = NCode;
  AddInstTable(InstTable, NName, InstrZ++, DecodeTwoReg);
}

static void AddMulReg(const char *NName, Word NCode, CPUVar NMin)
{
  order_array_rsv_end(MulRegOrders, FixedMinOrder);
  MulRegOrders[InstrZ].Code = NCode;
  MulRegOrders[InstrZ].MinCPU = NMin;
  AddInstTable(InstTable, NName, InstrZ++, DecodeMulReg);
}

static void AddBW(const char *NName, Word NCode)
{
  order_array_rsv_end(BWOrders, FixedOrder);
  BWOrders[InstrZ].Code = NCode;
  AddInstTable(InstTable, NName, InstrZ++, DecodeBW);
}

static void AddSReg(const char *NName, Word NCode, CPUVar NMin, Boolean NDSP)
{
  order_array_rsv_end(RegDefs, TRegDef);
  RegDefs[InstrZ].Name = NName;
  RegDefs[InstrZ].Code = NCode;
  RegDefs[InstrZ].MinCPU = NMin;
  RegDefs[InstrZ++].NeedsDSP = NDSP;
}

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

  add_null_pseudo(InstTable);

  AddInstTable(InstTable, "MOV", 0, DecodeMOV);
  AddInstTable(InstTable, "MOVA", 0, DecodeMOVA);
  AddInstTable(InstTable, "PREF", 0, DecodePREF);
  AddInstTable(InstTable, "LDC", 1, DecodeLDC_STC);
  AddInstTable(InstTable, "STC", 0, DecodeLDC_STC);
  AddInstTable(InstTable, "LDS", 1, DecodeLDS_STS);
  AddInstTable(InstTable, "STS", 0, DecodeLDS_STS);
  AddInstTable(InstTable, "TAS", 0, DecodeTAS);
  AddInstTable(InstTable, "MAC", 0, DecodeMAC);
  AddInstTable(InstTable, "ADD", 0, DecodeADD);
  AddInstTable(InstTable, "CMP/EQ", 0, DecodeCMPEQ);
  AddInstTable(InstTable, "TRAPA", 0, DecodeTRAPA);
  AddInstTable(InstTable, "BF", 0x8b00, DecodeBT_BF);
  AddInstTable(InstTable, "BT", 0x8900, DecodeBT_BF);
  AddInstTable(InstTable, "BF/S", 0x8f00, DecodeBT_BF);
  AddInstTable(InstTable, "BT/S", 0x8d00, DecodeBT_BF);
  AddInstTable(InstTable, "BRA", 0xa000, DecodeBRA_BSR);
  AddInstTable(InstTable, "BSR", 0xb000, DecodeBRA_BSR);
  AddInstTable(InstTable, "JSR", 0x400b, DecodeJSR_JMP);
  AddInstTable(InstTable, "JMP", 0x402b, DecodeJSR_JMP);
  AddInstTable(InstTable, "DCT", 1, DecodeDCT_DCF);
  AddInstTable(InstTable, "DCF", 2, DecodeDCT_DCF);
  AddInstTable(InstTable, "LTORG", 0, DecodeLTORG);

  InstrZ = 0;
  AddFixed("CLRT"  , 0x0008, False, CPU7000);
  AddFixed("CLRMAC", 0x0028, False, CPU7000);
  AddFixed("NOP"   , 0x0009, False, CPU7000);
  AddFixed("RTE"   , 0x002b, False, CPU7000);
  AddFixed("SETT"  , 0x0018, False, CPU7000);
  AddFixed("SLEEP" , 0x001b, False, CPU7000);
  AddFixed("RTS"   , 0x000b, False, CPU7000);
  AddFixed("DIV0U" , 0x0019, False, CPU7000);
  AddFixed("BRK"   , 0x0000, True , CPU7000);
  AddFixed("RTB"   , 0x0001, True , CPU7000);
  AddFixed("CLRS"  , 0x0048, False, CPU7700);
  AddFixed("SETS"  , 0x0058, False, CPU7700);
  AddFixed("LDTLB" , 0x0038, True , CPU7700);

  InstrZ = 0;
  AddOneReg("MOVT"  , 0x0029, CPU7000, False, False);
  AddOneReg("CMP/PZ", 0x4011, CPU7000, False, False);
  AddOneReg("CMP/PL", 0x4015, CPU7000, False, False);
  AddOneReg("ROTL"  , 0x4004, CPU7000, False, False);
  AddOneReg("ROTR"  , 0x4005, CPU7000, False, False);
  AddOneReg("ROTCL" , 0x4024, CPU7000, False, False);
  AddOneReg("ROTCR" , 0x4025, CPU7000, False, False);
  AddOneReg("SHAL"  , 0x4020, CPU7000, False, False);
  AddOneReg("SHAR"  , 0x4021, CPU7000, False, False);
  AddOneReg("SHLL"  , 0x4000, CPU7000, False, False);
  AddOneReg("SHLR"  , 0x4001, CPU7000, False, False);
  AddOneReg("SHLL2" , 0x4008, CPU7000, False, False);
  AddOneReg("SHLR2" , 0x4009, CPU7000, False, False);
  AddOneReg("SHLL8" , 0x4018, CPU7000, False, False);
  AddOneReg("SHLR8" , 0x4019, CPU7000, False, False);
  AddOneReg("SHLL16", 0x4028, CPU7000, False, False);
  AddOneReg("SHLR16", 0x4029, CPU7000, False, False);
  AddOneReg("LDBR"  , 0x0021, CPU7000, True , False);
  AddOneReg("STBR"  , 0x0020, CPU7000, True , False);
  AddOneReg("DT"    , 0x4010, CPU7600, False, False);
  AddOneReg("BRAF"  , 0x0023, CPU7600, False, True );
  AddOneReg("BSRF"  , 0x0003, CPU7600, False, True );

  InstrZ = 0;
  AddTwoReg("XTRCT" , 0x200d, False, CPU7000, 2);
  AddTwoReg("ADDC"  , 0x300e, False, CPU7000, 2);
  AddTwoReg("ADDV"  , 0x300f, False, CPU7000, 2);
  AddTwoReg("CMP/HS", 0x3002, False, CPU7000, 2);
  AddTwoReg("CMP/GE", 0x3003, False, CPU7000, 2);
  AddTwoReg("CMP/HI", 0x3006, False, CPU7000, 2);
  AddTwoReg("CMP/GT", 0x3007, False, CPU7000, 2);
  AddTwoReg("CMP/STR", 0x200c, False, CPU7000, 2);
  AddTwoReg("DIV1"  , 0x3004, False, CPU7000, 2);
  AddTwoReg("DIV0S" , 0x2007, False, CPU7000, -1);
  AddTwoReg("MULS"  , 0x200f, False, CPU7000, 1);
  AddTwoReg("MULU"  , 0x200e, False, CPU7000, 1);
  AddTwoReg("NEG"   , 0x600b, False, CPU7000, 2);
  AddTwoReg("NEGC"  , 0x600a, False, CPU7000, 2);
  AddTwoReg("SUB"   , 0x3008, False, CPU7000, 2);
  AddTwoReg("SUBC"  , 0x300a, False, CPU7000, 2);
  AddTwoReg("SUBV"  , 0x300b, False, CPU7000, 2);
  AddTwoReg("NOT"   , 0x6007, False, CPU7000, 2);
  AddTwoReg("SHAD"  , 0x400c, False, CPU7700, 2);
  AddTwoReg("SHLD"  , 0x400d, False, CPU7700, 2);

  InstrZ = 0;
  AddMulReg("MUL"   , 0x0007, CPU7600);
  AddMulReg("DMULU" , 0x3005, CPU7600);
  AddMulReg("DMULS" , 0x300d, CPU7600);

  InstrZ = 0;
  AddBW("SWAP", 0x6008); AddBW("EXTS", 0x600e); AddBW("EXTU", 0x600c);

  InstrZ = 0;
  AddInstTable(InstTable, "TST", InstrZ++, DecodeLog);
  AddInstTable(InstTable, "AND", InstrZ++, DecodeLog);
  AddInstTable(InstTable, "XOR", InstrZ++, DecodeLog);
  AddInstTable(InstTable, "OR" , InstrZ++, DecodeLog);

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

  InstrZ = 0;
  AddSReg("MACH",  0, CPU7000, FALSE);
  AddSReg("MACL",  1, CPU7000, FALSE);
  AddSReg("PR"  ,  2, CPU7000, FALSE);
  AddSReg("DSR" ,  6, CPU7000, TRUE );
  AddSReg("A0"  ,  7, CPU7000, TRUE );
  AddSReg("X0"  ,  8, CPU7000, TRUE );
  AddSReg("X1"  ,  9, CPU7000, TRUE );
  AddSReg("Y0"  , 10, CPU7000, TRUE );
  AddSReg("Y1"  , 11, CPU7000, TRUE );
  AddSReg(NULL  ,  0, CPU7000, FALSE);
}

static void DeinitFields(void)
{
  DestroyInstTable(InstTable);
  order_array_free(FixedOrders);
  order_array_free(OneRegOrders);
  order_array_free(TwoRegOrders);
  order_array_free(MulRegOrders);
  order_array_free(BWOrders);
  order_array_free(RegDefs);
}

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

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

static void MakeCode_7000(void)
{
  OpSize = eSymbolSizeUnknown;

  /* ab hier (und weiter in der Hauptroutine) stehen die Befehle,
     die Code erzeugen, deshalb wird der Merker fuer verzoegerte
     Spruenge hier weiter geschaltet. */

  PrevDelayed = CurrDelayed;
  CurrDelayed = False;

  /* Attribut verwursten */

  if (*AttrPart.str.p_str)
    SetOpSize(AttrPartOpSize[0]);

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

/*!------------------------------------------------------------------------
 * \fn     InternSymbol_7000(char *pArg, TempResult *pResult)
 * \brief  handle built-in symbols in SH7x00
 * \param  pArg source argument
 * \param  pResult result buffer
 * ------------------------------------------------------------------------ */

static void InternSymbol_7000(char *pArg, TempResult *pResult)
{
  Word Reg;

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

static Boolean IsDef_7000(void)
{
  return Memo("REG");
}

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

static void SwitchTo_7000(void)
{
  const TFamilyDescr *p_descr = FindFamilyByName("SH7x00");

  TurnWords = True;
  SetIntConstMode(eIntConstModeMoto);

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

  ValidSegs = 1 << SegCode;
  Grans[SegCode] = 1; ListGrans[SegCode] = 2; SegInits[SegCode] = 0;
  SegLimits[SegCode] = (LargeWord)IntTypeDefs[UInt32].Max;

  DecodeAttrPart = DecodeAttrPart_7000;
  MakeCode = MakeCode_7000;
  IsDef = IsDef_7000;
  InternSymbol = InternSymbol_7000;
  DissectReg = DissectReg_7000;
  SwitchFrom = SwitchFrom_7000;
  InitFields();
  onoff_supmode_add();
  AddONOFF("COMPLITERALS", &CompLiterals, CompLiteralsName, False);
  AddMoto16PseudoONOFF(False);

  if (!onoff_test_and_set(e_onoff_reg_dsp))
    SetFlag(&DSPAvail, DSPSymName, False);
  AddONOFF(DSPCmdName, &DSPAvail, DSPSymName, False);

  CurrDelayed = False; PrevDelayed = False;
}

void code7000_init(void)
{
  CPU7000 = AddCPU("SH7000", SwitchTo_7000);
  CPU7600 = AddCPU("SH7600", SwitchTo_7000);
  CPU7700 = AddCPU("SH7700", SwitchTo_7000);
}
