/* code9900.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator TMS99xx(x)                                                  */
/*                                                                           */
/*****************************************************************************/

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

#include "strutil.h"
#include "be_le.h"
#include "bpemu.h"
#include "nls.h"
#include "chunks.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmcode.h"
#include "asmallg.h"
#include "onoff_common.h"
#include "asmitree.h"
#include "codepseudo.h"
#include "codevars.h"
#include "ibmfloat.h"
#include "chartrans.h"
#include "errmsg.h"
#include "headids.h"

#include "code9900.h"

#define CKPT_NOTHING 16

enum
{
  eCoreNone = 0,
  eCore990_10  = 1 << 0,
  eCore990_12  = 1 << 1,
  eCore9900    = 1 << 2,
  eCore9940    = 1 << 3,
  eCore9995    = 1 << 4,
  eCore99105   = 1 << 5,
  eCore99110   = 1 << 6,
  eCoreAll     = eCore990_10 | eCore990_12 | eCore9900 | eCore9940 | eCore9995 | eCore99105 | eCore99110,

  eCoreFlagSupMode = 1 << 7
};

typedef struct
{
  const char *pName;
  Byte CoreFlags;
} tCPUProps;

typedef struct
{
  Word Code;
  Byte Flags;
} tOrder;

static const tCPUProps *pCurrCPUProps;
static tOrder *SingOrders, *ImmOrders, *FixedOrders, *RegOrders,
              *Type11Orders, *Type11aOrders, *Type12Orders, *Type15Orders,
              *Type16Orders, *Type17Orders, *Type20Orders;
static Boolean IsWord;
static Word AdrVal, AdrPart, DefCkpt;

/*-------------------------------------------------------------------------*/
/* Adressparser */

static Boolean DecodeReg(const tStrComp *pArg, Word *Erg)
{
  Boolean OK;
  *Erg = EvalStrIntExpression(pArg, UInt4, &OK);
  return OK;
}

static char *HasDisp(char *Asc)
{
  char *p;
  int Lev, Len = strlen(Asc);

  if ((Len >= 2) && (Asc[Len - 1] == ')'))
  {
    p = Asc + Len - 2; Lev = 0;
    while ((p >= Asc) && (Lev != -1))
    {
      switch (*p)
      {
        case '(': Lev--; break;
        case ')': Lev++; break;
      }
      if (Lev != -1) p--;
    }
    if (Lev != -1)
    {
      WrError(ErrNum_BrackErr);
      p = NULL;
    }
  }
  else
    p = NULL;

  return p;
}

static Boolean DecodeAdr(const tStrComp *pArg)
{
  Boolean IncFlag;
  Boolean OK;
  char *p;

  AdrCnt = 0;

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

    StrCompRefRight(&IArg, pArg, 1);
    if (IArg.str.p_str[strlen(IArg.str.p_str) - 1] == '+')
    {
      IncFlag = True;
      StrCompShorten(&IArg, 1);
    }
    else
      IncFlag = False;
    if (DecodeReg(&IArg, &AdrPart))
    {
      AdrPart += 0x10 + (Ord(IncFlag) << 5);
      return True;
    }
    return False;
  }

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

    StrCompRefRight(&IArg, pArg, 1);
    p = HasDisp(IArg.str.p_str);
    if (!p)
    {
      tSymbolFlags Flags;

      AdrVal = EvalStrIntExpressionWithFlags(&IArg, UInt16, &OK, &Flags);
      if (OK)
      {
        AdrPart = 0x20;
        AdrCnt = 1;
        if (!mFirstPassUnknown(Flags) && IsWord && Odd(AdrVal))
          WrError(ErrNum_AddrNotAligned);
        return True;
      }
    }
    else
    {
      tStrComp Disp, Reg;

      StrCompSplitRef(&Disp, &Reg, &IArg, p);
      StrCompShorten(&Reg, 1);
      if (DecodeReg(&Reg, &AdrPart))
      {
        if (AdrPart == 0) WrStrErrorPos(ErrNum_InvReg, &Reg);
        else
        {
          AdrVal = EvalStrIntExpression(&Disp, Int16, &OK);
          if (OK)
          {
            AdrPart += 0x20;
            AdrCnt = 1;
            return True;
          }
        }
      }
    }
    return False;
  }

  if (DecodeReg(pArg, &AdrPart))
    return True;
  else
  {
    WrError(ErrNum_InvAddrMode);
    return False;
  }
}

static Boolean DecodeBitField(tStrComp *pArg, Word *pResult)
{
  tStrComp Arg, Start, Count;
  Boolean OK1, OK2;
  char *pSep;

  if (!IsIndirect(pArg->str.p_str))
  {
    WrStrErrorPos(ErrNum_InvBitField, pArg);
    return False;
  }
  StrCompRefRight(&Arg, pArg, 1);
  StrCompShorten(&Arg, 1);
  pSep = strchr(Arg.str.p_str, ',');
  if (!pSep)
  {
    WrStrErrorPos(ErrNum_InvBitField, pArg);
    return False;
  }
  StrCompSplitRef(&Start, &Count, &Arg, pSep);
  *pResult = EvalStrIntExpression(&Count, UInt4, &OK1)
           | (EvalStrIntExpression(&Start, UInt4, &OK2) << 12);
  return OK1 && OK2;
}

static void PutByte(Byte Value)
{
  if ((CodeLen & 1) && !HostBigEndian)
  {
    BAsmCode[CodeLen] = BAsmCode[CodeLen - 1];
    BAsmCode[CodeLen - 1] = Value;
  }
  else
  {
    BAsmCode[CodeLen] = Value;
  }
  CodeLen++;
}

static Boolean EvalDist(const tStrComp *pArg, Word *pResult, Word InstrLen)
{
  Boolean OK;
  Integer AdrInt;
  tSymbolFlags Flags;

  AdrInt = EvalStrIntExpressionOffsWithFlags(pArg, !!(*pArg->str.p_str == '@'), UInt16, &OK, &Flags) - (EProgCounter() + InstrLen);
  if (OK && !mSymbolQuestionable(Flags) && Odd(AdrInt))
  {
    WrStrErrorPos(ErrNum_DistIsOdd, pArg);
    OK = False;
  }
  if (OK && !mSymbolQuestionable(Flags) && ((AdrInt < -256) || (AdrInt > 254)))
  {
    WrStrErrorPos(ErrNum_JmpDistTooBig, pArg);
    OK = False;
  }
  if (OK)
    *pResult = (AdrInt / 2) & 0xff;
  return OK;
}

static Boolean DecodeCond(const tStrComp *pArg, Word *pResult)
{
  const char *pConds[] =
    { "EQ", "NE", "HE", "L", "GE", "LT", "LE", "H", "LTE", "GT", NULL },
  **pRun;

  for (pRun = pConds; *pRun; pRun++)
    if (!as_strcasecmp(pArg->str.p_str, *pRun))
    {
      *pResult = pRun - pConds;
      return True;
    }
  WrStrErrorPos(ErrNum_UndefCond, pArg);
  return False;
}

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

static void CheckSupMode(void)
{
  if (!SupAllowed && (pCurrCPUProps->CoreFlags & eCoreFlagSupMode))
    WrError(ErrNum_PrivOrder);
}

static Boolean CheckCore(Byte CoreReqFlags)
{
  if (!(CoreReqFlags & pCurrCPUProps->CoreFlags))
  {
    WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
    return False;
  }
  else
    return True;
}

static Boolean CheckNotMode3(const tStrComp *pArg)
{
  if ((AdrPart & 0x30) == 0x30)
  {
    WrStrErrorPos(ErrNum_InvAddrMode, pArg);
    return False;
  }
  else
    return True;
}

static void DecodeTwo(Word Code)
{
  Word HPart;

  if (ChkArgCnt(2, 2)
   && DecodeAdr(&ArgStr[1]))
  {
    WAsmCode[0] = AdrPart;
    WAsmCode[1] = AdrVal;
    HPart = AdrCnt;
    if (DecodeAdr(&ArgStr[2]))
    {
      WAsmCode[0] += AdrPart << 6;
      WAsmCode[1 + HPart] = AdrVal;
      CodeLen = (1 + HPart + AdrCnt) << 1;
      WAsmCode[0] += Code;
    }
  }
}

static void DecodeType11(Word Index)
{
  const tOrder *pOrder = &Type11Orders[Index];
  Word AdrCnt1;

  if (ChkArgCnt(2, (pCurrCPUProps->CoreFlags & eCore990_12) ? 3 : 2)
   && CheckCore(pOrder->Flags & eCoreAll)
   && DecodeAdr(&ArgStr[1]))
  {
    Word Count;
    Boolean OK;

    if (ArgCnt == 3)
      Count = EvalStrIntExpression(&ArgStr[3], UInt4, &OK);
    else
    {
      Count = 4;
      OK = True;
    }
    if (OK)
    {
      WAsmCode[0] = pOrder->Code;
      WAsmCode[1] = (Count << 12) | AdrPart;
      WAsmCode[2] = AdrVal;
      AdrCnt1 = AdrCnt;
      if (DecodeAdr(&ArgStr[2]))
      {
        WAsmCode[1] |= AdrPart << 6;
        WAsmCode[2 + AdrCnt1] = AdrVal;
        CodeLen = (2 + AdrCnt1 + AdrCnt) << 1;
      }
    }
  }
}

static void DecodeType11a(Word Index)
{
  const tOrder *pOrder = &Type11aOrders[Index];
  Word AdrCnt1;

  if (ChkArgCnt(2, 2)
   && CheckCore(pOrder->Flags & eCoreAll)
   && DecodeAdr(&ArgStr[1]))
  {
    WAsmCode[0] = pOrder->Code;
    WAsmCode[1] = AdrPart;
    WAsmCode[2] = AdrVal;
    AdrCnt1 = AdrCnt;
    if (DecodeAdr(&ArgStr[2]))
    {
      WAsmCode[1] |= AdrPart << 6;
      WAsmCode[2 + AdrCnt1] = AdrVal;
      CodeLen = (2 + AdrCnt1 + AdrCnt) << 1;
    }
  }
}

static void DecodeType12(Word Index)
{
  const tOrder *pOrder = &Type12Orders[Index];
  Word AdrCnt1, Count, Ckpt;
  Boolean OK;

  if (!ChkArgCnt(2, 4)
   || !CheckCore(pOrder->Flags & eCoreAll)
   || !DecodeAdr(&ArgStr[1]))
    return;
  WAsmCode[0] = pOrder->Code;
  WAsmCode[1] =  AdrPart;
  WAsmCode[2] = AdrVal;
  AdrCnt1 = AdrCnt;

  if (!DecodeAdr(&ArgStr[2]))
    return;
  WAsmCode[1] |= AdrPart << 6;
  WAsmCode[2 + AdrCnt1] = AdrVal;

  if ((ArgCnt < 3) || !*ArgStr[3].str.p_str)
  {
    Count = 0;
    OK = True;
  }
  else
    Count = EvalStrIntExpression(&ArgStr[3], UInt4, &OK);
  if (!OK)
    return;
  WAsmCode[1] |= Count << 12;

  if ((ArgCnt < 4) || !*ArgStr[4].str.p_str)
  {
    if (DefCkpt >= 16)
    {
      WrError(ErrNum_NoDefCkptReg);
      OK = False;
    }
    else
    {
      Ckpt = DefCkpt;
      OK = True;
    }
  }
  else
    OK = DecodeReg(&ArgStr[4], &Ckpt);
  if (!OK)
    return;
  WAsmCode[0] |= Ckpt;
  CodeLen = (2 + AdrCnt1 + AdrCnt) << 1;
}

static void DecodeOne(Word Code)
{
  if (ChkArgCnt(2, 2)
   && DecodeAdr(&ArgStr[1]))
  {
    Word HPart;

    WAsmCode[0] = AdrPart;
    WAsmCode[1] = AdrVal;
    if (DecodeReg(&ArgStr[2], &HPart))
    {
      WAsmCode[0] += (HPart << 6) + (Code << 10);
      CodeLen = (1 + AdrCnt) << 1;
    }
  }
}

static void DecodeType15(Word Index)
{
  const tOrder *pOrder = &Type15Orders[Index];
  Word BitField;

  if (ChkArgCnt(2, 2)
   && CheckCore(pOrder->Flags & eCoreAll)
   && DecodeAdr(&ArgStr[1])
   && DecodeBitField(&ArgStr[2], &BitField))
  {
    WAsmCode[0] = pOrder->Code | (BitField & 0x000f);
    WAsmCode[1] = (BitField & 0xf000) | AdrPart;
    WAsmCode[2] = AdrVal;
    CodeLen = (2 + AdrCnt) << 1;
  }
}

static void DecodeType16(Word Index)
{
  const tOrder *pOrder = &Type16Orders[Index];
  Word BitField;

  if (ChkArgCnt(3, 3)
   && CheckCore(pOrder->Flags & eCoreAll)
   && DecodeAdr(&ArgStr[1])
   && DecodeBitField(&ArgStr[3], &BitField))
  {
    Word AdrCnt1 = AdrCnt;

    WAsmCode[0] = pOrder->Code | (BitField & 0x000f);
    WAsmCode[1] = (BitField & 0xf000) | AdrPart;
    WAsmCode[2] = AdrVal;
    if (DecodeAdr(&ArgStr[2]))
    {
      WAsmCode[1] |= (AdrPart << 6);
      WAsmCode[2 + AdrCnt1] = AdrVal;
      CodeLen = (2 + AdrCnt + AdrCnt1) << 1;
    }
  }
}

static void DecodeMOVA(Word Code)
{
  if (ChkArgCnt(2, 2)
   && CheckCore(eCore990_12)
   && DecodeAdr(&ArgStr[1]))
  {
    Word AdrCnt1 = AdrCnt;

    WAsmCode[0] = Code;
    WAsmCode[1] = AdrPart;
    WAsmCode[2] = AdrVal;
    if (DecodeAdr(&ArgStr[2]))
    {
      WAsmCode[1] |= (AdrPart << 6);
      WAsmCode[2 + AdrCnt1] = AdrVal;
      CodeLen = (2 + AdrCnt + AdrCnt1) << 1;
    }
  }
}

static void DecodeType20(Word Index)
{
  const tOrder *pOrder = &Type20Orders[Index];
  Word Condition;

  if (ChkArgCnt(3, 3)
   && CheckCore(pOrder->Flags & eCoreAll)
   && DecodeCond(&ArgStr[1], &Condition)
   && DecodeAdr(&ArgStr[2]))
  {
    Word AdrCnt1 = AdrCnt;

    WAsmCode[0] = pOrder->Code;
    WAsmCode[1] = AdrPart | (Condition << 12);
    WAsmCode[2] = AdrVal;
    if (DecodeAdr(&ArgStr[3]))
    {
      WAsmCode[1] |= (AdrPart << 6);
      WAsmCode[2 + AdrCnt1] = AdrVal;
      CodeLen = (2 + AdrCnt + AdrCnt1) << 1;
    }
  }
}

static void DecodeType17(Word Index)
{
  const tOrder *pOrder = &Type17Orders[Index];
  Word Reg;

  if (ChkArgCnt(2, 3)
   && DecodeReg(&ArgStr[ArgCnt], &Reg))
  {
    Word Delta, Dist;
    Boolean OK;

    if ((ArgCnt == 3) && *ArgStr[2].str.p_str)
      Delta = EvalStrIntExpression(&ArgStr[2], UInt4, &OK);
    else
    {
      Delta = 1;
      OK = True;
    }
    if (OK && EvalDist(&ArgStr[1], &Dist, 4))
    {
      WAsmCode[0] = pOrder->Code;
      WAsmCode[1] = (Dist & 0xff) | (Reg << 8) | (Delta << 12);
      CodeLen = 4;
    }
  }
}

static void DecodeEP(Word Code)
{
  if (ChkArgCnt(4, 4)
   && CheckCore(eCore990_12)
   && DecodeAdr(&ArgStr[1]))
  {
    Word AdrCnt1 = AdrCnt, SrcCount, DestCount;
    Boolean DestOK, SrcOK;

    WAsmCode[0] = Code;
    WAsmCode[1] = AdrPart;
    WAsmCode[2] = AdrVal;

    SrcCount = EvalStrIntExpression(&ArgStr[3], UInt4, &SrcOK);
    DestCount = EvalStrIntExpression(&ArgStr[4], UInt4, &DestOK);

    if (SrcOK && DestOK && DecodeAdr(&ArgStr[2]))
    {
      WAsmCode[0] |= DestCount;
      WAsmCode[1] |= (AdrPart << 6) | (SrcCount << 12);
      WAsmCode[2 + AdrCnt1] = AdrVal;
      CodeLen = (2 + AdrCnt + AdrCnt1) << 1;
    }
  }
}

static void DecodeLDCR_STCR(Word Code)
{
  if (ChkArgCnt(2, 2)
   && DecodeAdr(&ArgStr[1]))
  {
    Word HPart;
    Boolean OK;
    tSymbolFlags Flags;

    WAsmCode[0] = Code + AdrPart;
    WAsmCode[1] = AdrVal;
    HPart = EvalStrIntExpressionWithFlags(&ArgStr[2], UInt5, &OK, &Flags);
    if (mFirstPassUnknown(Flags))
      HPart = 1;
    if (OK)
    {
      if (ChkRange(HPart, 1, 16))
      {
        WAsmCode[0] += (HPart & 15) << 6;
        CodeLen = (1 + AdrCnt) << 1;
      }
    }
  }
  return;
}

static void DecodeShift(Word Code)
{
  if (ChkArgCnt(2, 2)
   && DecodeReg(&ArgStr[1], WAsmCode + 0))
  {
    Word HPart;

    if (DecodeReg(&ArgStr[2], &HPart))
    {
      WAsmCode[0] += (HPart << 4) + (Code << 8);
      CodeLen = 2;
    }
  }
}

static void DecodeSLAM_SRAM(Word Code)
{
  Word HPart;

  if (ChkArgCnt(2, 2)
   && CheckCore(eCore990_12 | eCore99105 | eCore99110)
   && DecodeReg(&ArgStr[2], &HPart)
   && DecodeAdr(&ArgStr[1]))
  {
    WAsmCode[0] = Code;
    WAsmCode[1] = 0x4000 | (HPart << 6) | AdrPart;
    WAsmCode[2] = AdrVal;
    CodeLen = (2 + AdrCnt) << 1;
  }
}

static void DecodeImm(Word Index)
{
  const tOrder *pOrder = &ImmOrders[Index];

  if (ChkArgCnt(2, 2)
   && CheckCore(pOrder->Flags & eCoreAll)
   && DecodeReg(&ArgStr[1], WAsmCode + 0))
  {
    Boolean OK;

    WAsmCode[1] = EvalStrIntExpression(&ArgStr[2], Int16, &OK);
    if (OK)
    {
      WAsmCode[0] |= pOrder->Code;
      CodeLen = 4;
    }
  }
}

static void DecodeLIIM(Word Code)
{
  if (ChkArgCnt(1, 1)
   && CheckCore(eCore9940))
  {
    Boolean OK;

    WAsmCode[0] = EvalStrIntExpression(&ArgStr[1], UInt2, &OK);
    if (OK)
    {
      WAsmCode[0] |= Code;
      CodeLen = 2;
    }
  }
}

static void DecodeRegOrder(Word Index)
{
  const tOrder *pOrder = &RegOrders[Index];

  if (ChkArgCnt(1, 1)
   && CheckCore(pOrder->Flags & eCoreAll)
   && DecodeReg(&ArgStr[1], WAsmCode + 0))
  {
    WAsmCode[0] |= pOrder->Code;
    CodeLen = 2;
  }
}

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

  if (ChkArgCnt(2, 2)
   && CheckCore(eCore990_10 | eCore990_12 | eCore99105 | eCore99110)
   && DecodeReg(&ArgStr[1], WAsmCode + 0))
  {
    Boolean OK;

    WAsmCode[0] += 0x320 + (EvalStrIntExpression(&ArgStr[2], UInt1, &OK) << 4);
    if (OK)
      CodeLen = 2;
    CheckSupMode();
  }
}

static void DecodeMPYS_DIVS(Word Code)
{
  if (ChkArgCnt(1, 1)
   && CheckCore(eCore990_12 | eCore9995 | eCore99105 | eCore99110)
   && DecodeAdr(&ArgStr[1]))
  {
    WAsmCode[0] = Code + AdrPart;
    WAsmCode[1] = AdrVal;
    CodeLen = (1 + AdrCnt) << 1;
  }
}

static void DecodeSBit(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    Boolean OK;

    WAsmCode[0] = EvalStrIntExpression(&ArgStr[1], SInt8, &OK);
    if (OK)
    {
      WAsmCode[0] = (WAsmCode[0] & 0xff) | Code;
      CodeLen = 2;
    }
  }
}

static void DecodeBit(Word Code)
{
  if (ChkArgCnt(2, 2)
   && CheckCore(eCore990_12 | eCore99105 | eCore99110)
   && DecodeAdr(&ArgStr[1])
   && CheckNotMode3(&ArgStr[1]))
  {
    Boolean OK;

    WAsmCode[1] = (EvalStrIntExpression(&ArgStr[2], UInt4, &OK) << 6) | AdrPart;
    if (OK)
    {
      WAsmCode[0] = Code;
      WAsmCode[2] = AdrVal;
      CodeLen = (2 + AdrCnt) << 1;
    }
  }
}

static void DecodeJmp(Word Code)
{
  Word Dist;

  if (ChkArgCnt(1, 1)
   && EvalDist(&ArgStr[1], &Dist, 2))
  {
    WAsmCode[0] = Code | Dist;
    CodeLen = 2;
  }
}

static void DecodeLWPI_LIMI(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    Boolean OK;

    WAsmCode[1] = EvalStrIntExpression(&ArgStr[1], UInt16, &OK);
    if (OK)
    {
      WAsmCode[0] = Code & 0x7fff;
      CodeLen = 4;
      if (Code & 0x8000)
        CheckSupMode();
    }
  }
}

static void DecodeSing(Word Index)
{
  const tOrder *pOrder = &SingOrders[Index];

  if (ChkArgCnt(1, 1)
   && CheckCore(pOrder->Flags & eCoreAll)
   && DecodeAdr(&ArgStr[1]))
  {
    WAsmCode[0] = pOrder->Code | AdrPart;
    WAsmCode[1] = AdrVal;
    CodeLen = (1 + AdrCnt) << 1;
    if (pOrder->Flags & eCoreFlagSupMode)
      CheckSupMode();
  }
}

static void DecodeFixed(Word Index)
{
  const tOrder *pOrder = &FixedOrders[Index];

  if (ChkArgCnt(0, 0)
   && CheckCore(pOrder->Flags & eCoreAll))
  {
    WAsmCode[0] = pOrder->Code;
    CodeLen = 2;
    if (pOrder->Flags & eCoreFlagSupMode)
      CheckSupMode();
  }
}

static void DecodeRTWP(Word Code)
{
  Word Variant;
  Word MaxVariant = (((pCurrCPUProps->CoreFlags & eCoreAll) == eCore99105)
                  || ((pCurrCPUProps->CoreFlags & eCoreAll) == eCore99110)) ? 4 : 0;
  tEvalResult EvalResult;

  switch (ArgCnt)
  {
    case 0:
      Variant = 0;
      EvalResult.OK = True;
      break;
    case 1:
      Variant = EvalStrIntExpressionWithResult(&ArgStr[1], UInt3, &EvalResult);
      if (!EvalResult.OK)
        return;
      if (mFirstPassUnknown(EvalResult.Flags))
        Variant = 0;
      else if (Variant > MaxVariant)
      {
        WrStrErrorPos(ErrNum_OverRange, &ArgStr[1]);
        return;
      }
      else if (Variant == 3)
      {
        WrStrErrorPos(ErrNum_InvArg, &ArgStr[1]);
        return;
      }
      break;
    default:
      (void)ChkArgCnt(0,1);
      return;
  }
  if (EvalResult.OK)
  {
    WAsmCode[CodeLen >> 1] = Code + Variant;
    CodeLen += 2;
  }
}

static void DecodeBYTE(Word Code)
{
  TempResult t;

  UNUSED(Code);

  as_tempres_ini(&t);
  if (ChkArgCnt(1, ArgCntMax))
  {
    Boolean OK = True;
    tStrComp *pArg;

    forallargs(pArg, OK)
    {
      KillBlanks(pArg->str.p_str);
      EvalStrExpression(pArg, &t);
      switch (t.Typ)
      {
        case TempInt:
          if (mFirstPassUnknown(t.Flags))
            t.Contents.Int &= 0xff;
          if (!RangeCheck(t.Contents.Int, Int8)) WrStrErrorPos(ErrNum_OverRange, pArg);
          else if (SetMaxCodeLen(CodeLen + 1))
          {
            WrStrErrorPos(ErrNum_CodeOverflow, pArg);
            OK = False;
          }
          else
            PutByte(t.Contents.Int);
          break;
        case TempString:
          if (SetMaxCodeLen(t.Contents.str.len + CodeLen))
          {
            WrStrErrorPos(ErrNum_CodeOverflow, pArg);
            OK = False;
          }
          else
          {
            char *p, *pEnd;

            if (as_chartrans_xlate_nonz_dynstr(CurrTransTable->p_table, &t.Contents.str, pArg))
              OK = False;
            else
            {
              pEnd = t.Contents.str.p_str + t.Contents.str.len;
              for (p = t.Contents.str.p_str; p < pEnd; PutByte(*(p++)));
            }
          }
          break;
        case TempFloat:
          WrStrErrorPos(ErrNum_StringOrIntButFloat, pArg);
          /* fall-through */
        default:
          OK = False;
      }
    }
    if (!OK)
      CodeLen = 0;
  }
  as_tempres_free(&t);
}

static void DecodeWORD(Word Code)
{
  int z;
  Boolean OK;
  Word HVal16;

  UNUSED(Code);

  if (ChkArgCnt(1, ArgCntMax))
  {
    z = 1;
    OK = True;
    do
    {
      HVal16 = EvalStrIntExpression(&ArgStr[z], Int16, &OK);
      if (OK)
      {
        WAsmCode[CodeLen >> 1] = HVal16;
        CodeLen += 2;
      }
      z++;
    }
    while ((z <= ArgCnt) && (OK));
    if (!OK)
      CodeLen = 0;
  }
}

static void DecodeFLOAT(Word DestLen)
{
  if (ChkArgCnt(1, ArgCntMax))
  {
    int z, ret;
    Boolean OK;
    as_float_t FVal;

    OK = True;
    for (z = 1; (z <= ArgCnt) && OK; z++)
    {
      FVal = EvalStrFloatExpression(&ArgStr[z], &OK);
      if (!OK)
        break;
      SetMaxCodeLen(CodeLen + DestLen);
      ret = as_float_2_ibm_float(&WAsmCode[CodeLen >> 1], FVal, DestLen == 8);
      if (ret < 0)
      {
        asmerr_check_fp_dispose_result(ret, &ArgStr[z]);
        OK = False;
        break;
      }
      CodeLen += DestLen;
    }
    if (!OK)
      CodeLen = 0;
  }
}

static void DecodeBSS(Word Code)
{
  Boolean OK;
  Word HVal16;
  tSymbolFlags Flags;

  UNUSED(Code);

  if (ChkArgCnt(1, 1))
  {
    HVal16 = EvalStrIntExpressionWithFlags(&ArgStr[1], Int16, &OK, &Flags);
    if (mFirstPassUnknown(Flags)) WrError(ErrNum_FirstPassCalc);
    else if (OK)
    {
      if (!HVal16) WrError(ErrNum_NullResMem);
      DontPrint = True;
      CodeLen = HVal16;
      BookKeeping();
    }
  }
}

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

  if (ChkArgCnt(1, 1)
   && CheckCore(eCore990_12))
  {
    Word NewDefCkpt;

    if (!as_strcasecmp(ArgStr[1].str.p_str, "NOTHING"))
      DefCkpt = CKPT_NOTHING;
    else
      if (DecodeReg(&ArgStr[1], &NewDefCkpt))
        DefCkpt = NewDefCkpt;
  }
}

/*!------------------------------------------------------------------------
 * \fn     make_pc_even(Word index)
 * \brief  assure machine instruction ends up on even address
 * ------------------------------------------------------------------------ */

static void make_pc_even(Word index)
{
  UNUSED(index);

  if (Odd(EProgCounter()))
  {
    if (DoPadding)
      InsertPadding(1, False);
    else
      WrError(ErrNum_AddrNotAligned);
  }
}

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

static void AddTwo(const char *NName16, const char *NName8, Word NCode)
{
  AddInstTable(InstTable, NName16, (NCode << 13)         , DecodeTwo);
  AddInstTable(InstTable, NName8,  (NCode << 13) + 0x1000, DecodeTwo);
}

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

static void AddSing(const char *NName, Word NCode, Byte Flags)
{
  order_array_rsv_end(SingOrders, tOrder);
  SingOrders[InstrZ].Code = NCode;
  SingOrders[InstrZ].Flags = Flags;
  AddInstTable(InstTable, NName, InstrZ++, DecodeSing);
}

static void AddSBit(const char *NName, Word NCode)
{
  AddInstTable(InstTable, NName, NCode << 8, DecodeSBit);
}

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

static void AddJmp(const char *NName, Word NCode)
{
  AddInstTable(InstTable, NName, NCode << 8, DecodeJmp);
}

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

static void AddImm(const char *NName, Word NCode, Word Flags)
{
  order_array_rsv_end(ImmOrders, tOrder);
  ImmOrders[InstrZ].Code = NCode << 4;
  ImmOrders[InstrZ].Flags = Flags;
  AddInstTable(InstTable, NName, InstrZ++, DecodeImm);
}

static void AddReg(const char *NName, Word NCode, Word Flags)
{
  order_array_rsv_end(RegOrders, tOrder);
  RegOrders[InstrZ].Code = NCode << 4;
  RegOrders[InstrZ].Flags = Flags;
  AddInstTable(InstTable, NName, InstrZ++, DecodeRegOrder);
}

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

static void AddType11(const char *NName, Word NCode, Word Flags)
{
  order_array_rsv_end(Type11Orders, tOrder);
  Type11Orders[InstrZ].Code = NCode;
  Type11Orders[InstrZ].Flags = Flags;
  AddInstTable(InstTable, NName, InstrZ++, DecodeType11);
}

static void AddType11a(const char *NName, Word NCode, Word Flags)
{
  order_array_rsv_end(Type11aOrders, tOrder);
  Type11aOrders[InstrZ].Code = NCode;
  Type11aOrders[InstrZ].Flags = Flags;
  AddInstTable(InstTable, NName, InstrZ++, DecodeType11a);
}

static void AddType12(const char *NName, Word NCode, Word Flags)
{
  order_array_rsv_end(Type12Orders, tOrder);
  Type12Orders[InstrZ].Code = NCode;
  Type12Orders[InstrZ].Flags = Flags;
  AddInstTable(InstTable, NName, InstrZ++, DecodeType12);
}

static void AddType15(const char *NName, Word NCode, Word Flags)
{
  order_array_rsv_end(Type15Orders, tOrder);
  Type15Orders[InstrZ].Code = NCode;
  Type15Orders[InstrZ].Flags = Flags;
  AddInstTable(InstTable, NName, InstrZ++, DecodeType15);
}

static void AddType16(const char *NName, Word NCode, Word Flags)
{
  order_array_rsv_end(Type16Orders, tOrder);
  Type16Orders[InstrZ].Code = NCode;
  Type16Orders[InstrZ].Flags = Flags;
  AddInstTable(InstTable, NName, InstrZ++, DecodeType16);
}

static void AddType17(const char *NName, Word NCode, Word Flags)
{
  order_array_rsv_end(Type17Orders, tOrder);
  Type17Orders[InstrZ].Code = NCode;
  Type17Orders[InstrZ].Flags = Flags;
  AddInstTable(InstTable, NName, InstrZ++, DecodeType17);
}

static void AddType20(const char *NName, Word NCode, Word Flags)
{
  order_array_rsv_end(Type20Orders, tOrder);
  Type20Orders[InstrZ].Code = NCode;
  Type20Orders[InstrZ].Flags = Flags;
  AddInstTable(InstTable, NName, InstrZ++, DecodeType20);
}

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

  add_null_pseudo(InstTable);

  inst_table_set_prefix_proc(InstTable, make_pc_even, 0);

  AddInstTable(InstTable, "LDCR", 0x3000, DecodeLDCR_STCR);
  AddInstTable(InstTable, "STCR", 0x3400, DecodeLDCR_STCR);
  AddInstTable(InstTable, "LMF", 0, DecodeLMF);
  AddInstTable(InstTable, "MPYS", 0x01c0, DecodeMPYS_DIVS);
  AddInstTable(InstTable, "DIVS", 0x0180, DecodeMPYS_DIVS);
  AddInstTable(InstTable, "LWPI", 0x02e0, DecodeLWPI_LIMI);
  AddInstTable(InstTable, "LIMI", 0x8300, DecodeLWPI_LIMI);
  AddInstTable(InstTable, "WORD", 0, DecodeWORD);
  AddInstTable(InstTable, "SINGLE", 4, DecodeFLOAT);
  AddInstTable(InstTable, "DOUBLE", 8, DecodeFLOAT);
  AddInstTable(InstTable, "CKPT", 0, DecodeCKPT);

  AddTwo("A"   , "AB"   , 5); AddTwo("C"   , "CB"   , 4); AddTwo("S"   , "SB"   , 3);
  AddTwo("SOC" , "SOCB" , 7); AddTwo("SZC" , "SZCB" , 2); AddTwo("MOV" , "MOVB" , 6);

  AddOne("COC" , 0x08); AddOne("CZC" , 0x09); AddOne("XOR" , 0x0a);
  AddOne("MPY" , 0x0e); AddOne("DIV" , 0x0f); AddOne("XOP" , 0x0b);

  InstrZ = 0;
  AddSing("B"   , 0x0440, eCoreAll);
  AddSing("BL"  , 0x0680, eCoreAll);
  AddSing("BLWP", 0x0400, eCoreAll);
  AddSing("CLR" , 0x04c0, eCoreAll);
  AddSing("SETO", 0x0700, eCoreAll);
  AddSing("INV" , 0x0540, eCoreAll);
  AddSing("NEG" , 0x0500, eCoreAll);
  AddSing("ABS" , 0x0740, eCoreAll);
  AddSing("SWPB", 0x06c0, eCoreAll);
  AddSing("INC" , 0x0580, eCoreAll);
  AddSing("INCT", 0x05c0, eCoreAll);
  AddSing("DEC" , 0x0600, eCoreAll);
  AddSing("DECT", 0x0640, eCoreAll);
  AddSing("X"   , 0x0480, eCoreAll);
  if (!(pCurrCPUProps->CoreFlags & eCore99110))
  {
    AddSing("LDS" , 0x0780, eCoreFlagSupMode | eCore990_10 | eCore990_12);
    AddSing("LDD" , 0x07c0, eCoreFlagSupMode | eCore990_10 | eCore990_12);
  }
  AddSing("DCA" , 0x2c00, eCore9940);
  AddSing("DCS" , 0x2c40, eCore9940);
  AddSing("BIND", 0x0140, eCore990_12 | eCore99105 | eCore99110);
  AddSing("AR"  , 0x0c40, eCore990_12 | eCore99110);
  AddSing("SR"  , 0x0cc0, eCore990_12 | eCore99110);
  AddSing("MR"  , 0x0d00, eCore990_12 | eCore99110);
  AddSing("DR"  , 0x0d40, eCore990_12 | eCore99110);
  AddSing("LR"  , 0x0d80, eCore990_12 | eCore99110);
  AddSing("STR" , 0x0dc0, eCore990_12 | eCore99110);
  AddSing("CIR" , 0x0c80, eCore990_12 | eCore99110);
  AddSing("EVAD", 0x0100, eCore99105 | eCore99110);
  AddSing("AD"  , 0x0e40, eCore990_12);
  AddSing("CID" , 0x0e80, eCore990_12);
  AddSing("SD"  , 0x0ec0, eCore990_12);
  AddSing("MD"  , 0x0f00, eCore990_12);
  AddSing("DD"  , 0x0f40, eCore990_12);
  AddSing("LD"  , 0x0f80, eCore990_12);
  AddSing("STD" , 0x0fc0, eCore990_12);

  AddSBit("SBO" , 0x1d); AddSBit("SBZ", 0x1e); AddSBit("TB" , 0x1f);

  AddJmp("JEQ", 0x13); AddJmp("JGT", 0x15); AddJmp("JH" , 0x1b);
  AddJmp("JHE", 0x14); AddJmp("JL" , 0x1a); AddJmp("JLE", 0x12);
  AddJmp("JLT", 0x11); AddJmp("JMP", 0x10); AddJmp("JNC", 0x17);
  AddJmp("JNE", 0x16); AddJmp("JNO", 0x19); AddJmp("JOC", 0x18);
  AddJmp("JOP", 0x1c);

  AddShift("SLA", 0x0a); AddShift("SRA", 0x08);
  AddShift("SRC", 0x0b); AddShift("SRL", 0x09);

  InstrZ = 0;
  AddImm("AI"  , 0x022, eCoreAll);
  AddImm("ANDI", 0x024, eCoreAll);
  AddImm("CI"  , 0x028, eCoreAll);
  AddImm("LI"  , 0x020, eCoreAll);
  AddImm("ORI" , 0x026, eCoreAll);
  AddImm("BLSK", 0x00b, eCore990_12 | eCore99105 | eCore99110);

  InstrZ = 0;
  AddType11("AM"  , 0x002a, eCore990_12 | eCore99105 | eCore99110);
  AddType11("SM"  , 0x0029, eCore990_12 | eCore99105 | eCore99110);
  AddType11("NRM" , 0x0c08, eCore990_12);
  AddType11("RTO" , 0x001e, eCore990_12);
  AddType11("LTO" , 0x001f, eCore990_12);
  AddType11("CNTO", 0x0020, eCore990_12);
  AddType11("BDC" , 0x0023, eCore990_12);
  AddType11("DBC" , 0x0024, eCore990_12);
  AddType11("SWPM", 0x0025, eCore990_12);
  AddType11("XORM", 0x0026, eCore990_12);
  AddType11("ORM" , 0x0027, eCore990_12);
  AddType11("ANDM", 0x0028, eCore990_12);

  InstrZ = 0;
  AddType11a("CR"  , 0x0301, eCore99110);
  AddType11a("MM"  , 0x0302, eCore99110);

  AddInstTable(InstTable, "SLAM", 0x001d, DecodeSLAM_SRAM);
  AddInstTable(InstTable, "SRAM", 0x001c, DecodeSLAM_SRAM);

  InstrZ = 0;
  AddReg("STST", 0x02c, eCoreAll);
  AddReg("LST" , 0x008, eCore9995 | eCore99105 | eCore99110 | eCore990_12);
  AddReg("STWP", 0x02a, eCoreAll);
  AddReg("LWP" , 0x009, eCore9995 | eCore99105 | eCore99110 | eCore990_12);
  AddReg("STPC", 0x003, eCore990_12);
  AddReg("LIM" , 0x007, eCore990_12);
  AddReg("LCS" , 0x00a, eCore990_12);

  AddBit("TMB" , 0x0c09);
  AddBit("TCMB", 0x0c0a);
  AddBit("TSMB", 0x0c0b);

  InstrZ = 0;
  AddInstTable(InstTable, "RTWP", 0x0380, DecodeRTWP);
  AddFixed("IDLE", 0x0340, eCoreFlagSupMode | eCoreAll);
  AddFixed("RSET", 0x0360, eCoreFlagSupMode | (eCoreAll & ~eCore9940));
  AddFixed("CKOF", 0x03c0, eCoreFlagSupMode | (eCoreAll & ~eCore9940));
  AddFixed("CKON", 0x03a0, eCoreFlagSupMode | (eCoreAll & ~eCore9940));
  AddFixed("LREX", 0x03e0, eCoreFlagSupMode | (eCoreAll & ~eCore9940));
  AddFixed("CER" , 0x0c06, eCore990_12 | eCore99110);
  AddFixed("CRE" , 0x0c04, eCore990_12 | eCore99110);
  AddFixed("NEGR", 0x0c02, eCore990_12 | eCore99110);
  AddFixed("CRI" , 0x0c00, eCore990_12 | eCore99110);
  AddFixed("EMD" , 0x002d, eCore990_12);
  AddFixed("EINT", 0x002e, eCore990_12);
  AddFixed("DINT", 0x002f, eCore990_12);
  AddFixed("CDI" , 0x0c01, eCore990_12);
  AddFixed("NEGD", 0x0c03, eCore990_12);
  AddFixed("CDE" , 0x0c05, eCore990_12);
  AddFixed("CED" , 0x0c07, eCore990_12);
  AddFixed("XIT" , 0x0c0e, eCore990_12);
  if (pCurrCPUProps->CoreFlags & eCore99110)
  {
    AddFixed("LDS" , 0x0780, eCoreFlagSupMode | eCore99110);
    AddFixed("LDD" , 0x07c0, eCoreFlagSupMode | eCore99110);
  }

  InstrZ = 0;
  AddType12("SNEB", 0x0e10, eCore990_12);
  AddType12("CRC" , 0x0e20, eCore990_12);
  AddType12("TS"  , 0x0e30, eCore990_12);
  AddType12("CS"  , 0x0040, eCore990_12);
  AddType12("SEQB", 0x0050, eCore990_12);
  AddType12("MOVS", 0x0060, eCore990_12);
  AddType12("MVSR", 0x00c0, eCore990_12);
  AddType12("MVSK", 0x00d0, eCore990_12);
  AddType12("POPS", 0x00e0, eCore990_12);
  AddType12("PSHS", 0x00f0, eCore990_12);

  InstrZ = 0;
  AddType15("IOF" , 0x0e00, eCore990_12);

  InstrZ = 0;
  AddType16("INSF", 0x0c10, eCore990_12);
  AddType16("XV"  , 0x0c30, eCore990_12);
  AddType16("XF"  , 0x0c20, eCore990_12);

  InstrZ = 0;
  AddType17("SRJ" , 0x0c0c, eCore990_12);
  AddType17("ARJ" , 0x0c0d, eCore990_12);

  AddInstTable(InstTable, "MOVA", 0x002b, DecodeMOVA);

  InstrZ = 0;
  AddType20("SLSL", 0x0021, eCore990_12);
  AddType20("SLSP", 0x0020, eCore990_12);

  AddInstTable(InstTable, "EP" , 0x03f0, DecodeEP);

  AddInstTable(InstTable, "LIIM", 0x2c80, DecodeLIIM);

  /* may be aligned arbitrarily */

  inst_table_set_prefix_proc(InstTable, NULL, 0);
  AddInstTable(InstTable, "BYTE", 0, DecodeBYTE);
  AddInstTable(InstTable, "BSS", 0, DecodeBSS);
}

static void DeinitFields(void)
{
  DestroyInstTable(InstTable);
  order_array_free(SingOrders);
  order_array_free(ImmOrders);
  order_array_free(FixedOrders);
  order_array_free(RegOrders);
  order_array_free(Type11Orders);
  order_array_free(Type11aOrders);
  order_array_free(Type12Orders);
  order_array_free(Type15Orders);
  order_array_free(Type16Orders);
  order_array_free(Type17Orders);
  order_array_free(Type20Orders);
}

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

static void MakeCode_9900(void)
{
  IsWord = False;

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

static Boolean IsDef_9900(void)
{
  return False;
}

static void InternSymbol_9900(char *Asc, TempResult*Erg)
{
  char *p_end;
  char *h = Asc;
  LargeInt Num;

  as_tempres_set_none(Erg);
  if ((strlen(Asc) >= 2) && (as_toupper(*Asc) == 'R'))
    h = Asc + 1;
  else if ((strlen(Asc) >= 3) && (as_toupper(*Asc) == 'W') && (as_toupper(Asc[1]) == 'R'))
    h = Asc + 2;

  Num = strtoul(h, &p_end, 10);
  if (*p_end || (Num < 0) || (Num > 15))
    return;

  as_tempres_set_int(Erg, Num);
}

static void SwitchTo_9900(void *pUser)
{
  const TFamilyDescr *p_descr = FindFamilyByName("TMS9900");

  TurnWords = True;
  SetIntConstMode(eIntConstModeIntel);

  PCSymbol = "$";
  HeaderID = p_descr->Id;
  NOPCode = 0x0000;
  DivideChars = ",";
  HasAttrs = False;

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

  pCurrCPUProps = (const tCPUProps*)pUser;

  MakeCode = MakeCode_9900;
  IsDef = IsDef_9900;
  SwitchFrom = DeinitFields;
  InternSymbol = InternSymbol_9900;
  AddONOFF(DoPaddingName, &DoPadding , DoPaddingName , False);
  onoff_supmode_add();

  InitFields();
}

static void InitCode_TI990(void)
{
  DefCkpt = CKPT_NOTHING; /* CKPT NOTHING */
}

static const tCPUProps CPUProps[] =
{
  { "TI990/4"  , eCore9900                      },
  { "TI990/10" , eCore990_10 | eCoreFlagSupMode },
  { "TI990/12" , eCore990_12 | eCoreFlagSupMode },
  { "TMS9900"  , eCore9900                      },
  { "TMS9940"  , eCore9940                      },
  { "TMS9995"  , eCore9995                      },
  { "TMS99105" , eCore99105  | eCoreFlagSupMode },
  { "TMS99110" , eCore99110  | eCoreFlagSupMode },
  { NULL       , eCoreNone                      },
};

void code9900_init(void)
{
  const tCPUProps *pProp;

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

  AddInitPassProc(InitCode_TI990);
}
