/* codest6.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator ST6-Familie                                                 */
/*                                                                           */
/*****************************************************************************/

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

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

#include "codest6.h"

#define ModNone (-1)
#define ModAcc 0
#define MModAcc (1 << ModAcc)
#define ModDir 1
#define MModDir (1 << ModDir)
#define ModInd 2
#define MModInd (1 << ModInd)


static Byte AdrMode;
static ShortInt AdrType;
static Byte AdrVal;

static LongInt WinAssume, PRPRVal;

typedef struct
{
  const char *pName;
  IntType CodeAdrInt;
} tCPUProps;

static as_assume_rec_t ASSUMEST6s[] =
{
  { "PRPR",    &PRPRVal  , 0, 0x03, 0x04, NULL },
  { "ROMBASE", &WinAssume, 0, 0x3f, 0x40, NULL },
};
static const tCPUProps *pCurrCPUProps;

/*---------------------------------------------------------------------------------*/
/* Helper Functions */

static void ResetAdr(void)
{
  AdrType = ModNone; AdrCnt = 0;
}

static void DecodeAdr(const tStrComp *pArg, Byte Mask)
{
  Integer AdrInt;
  tEvalResult EvalResult;

  ResetAdr();

  if ((!as_strcasecmp(pArg->str.p_str, "A")) && (Mask & MModAcc))
  {
    AdrType = ModAcc;
    goto chk;
  }

  if (!as_strcasecmp(pArg->str.p_str, "(X)"))
  {
    AdrType = ModInd;
    AdrMode = 0;
    goto chk;
  }

  if (!as_strcasecmp(pArg->str.p_str, "(Y)"))
  {
    AdrType = ModInd;
    AdrMode = 1;
    goto chk;
  }

  AdrInt = EvalStrIntExpressionWithResult(pArg, UInt16, &EvalResult);
  if (EvalResult.OK)
  {
    if (EvalResult.AddrSpaceMask & (1 << SegCode))
    {
      AdrType = ModDir;
      AdrVal = (AdrInt & 0x3f) + 0x40;
      AdrCnt=1;
      if (!mFirstPassUnknown(EvalResult.Flags))
        if (WinAssume != (AdrInt >> 6)) WrError(ErrNum_InAccPage);
    }
    else
    {
      if (mFirstPassUnknown(EvalResult.Flags)) AdrInt = Lo(AdrInt);
      if (AdrInt > 0xff) WrError(ErrNum_OverRange);
      else
      {
        AdrType = ModDir;
        AdrVal = AdrInt;
        goto chk;
      }
    }
  }

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

static Boolean IsReg(Byte Adr)
{
  return ((Adr & 0xfc) == 0x80);
}

static Byte MirrBit(Byte inp)
{
  return (((inp & 1) << 2) + (inp & 2) + ((inp & 4) >> 2));
}

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

/*
 * Compact representation of bits in symbol table:
 * bits 0..2: bit position
 * bits 3...10: register address in DATA/SFR space
 */

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

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

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

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

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

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

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

  Addr = EvalStrIntExpression(pRegArg, UInt8, &OK);
  if (!OK)
    return False;

  *pResult = AssembleBitSymbol(BitPos, Addr);

  return True;
}

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

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

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

  if (Start == Stop)
  {
    tEvalResult EvalResult;

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

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

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

  /* other # of arguments not allowed */

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

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

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

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

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

  DissectBitSymbol(Inp, &Address, &BitPos);

  as_snprintf(pDest, DestSize, "%02.*u%s.%u",
              ListRadixBase, (unsigned)Address, GetIntConstIntelSuffix(ListRadixBase),
              (unsigned)BitPos);
}

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

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

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

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

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

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

static void DecodeFixed(Word Code)
{
  if (ChkArgCnt(0, 0))
  {
    CodeLen = 1;
    BAsmCode[0] = Code;
  }
}

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

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModAcc | MModDir | MModInd);
    switch (AdrType)
    {
      case ModAcc:
        DecodeAdr(&ArgStr[2], MModDir | MModInd);
        switch (AdrType)
        {
          case ModDir:
            if (IsReg(AdrVal))
            {
              CodeLen = 1;
              BAsmCode[0] = 0x35 + ((AdrVal & 3) << 6);
            }
            else
            {
              CodeLen = 2;
              BAsmCode[0] = 0x1f;
              BAsmCode[1] = AdrVal;
            }
            break;
          case ModInd:
            CodeLen = 1;
            BAsmCode[0] = 0x07 + (AdrMode << 3);
            break;
        }
        break;
      case ModDir:
        DecodeAdr(&ArgStr[2], MModAcc);
        if (AdrType != ModNone)
        {
          if (IsReg(AdrVal))
          {
            CodeLen = 1;
            BAsmCode[0] = 0x3d + ((AdrVal & 3) << 6);
          }
          else
          {
            CodeLen = 2;
            BAsmCode[0] = 0x9f;
            BAsmCode[1] = AdrVal;
          }
        }
        break;
      case ModInd:
        DecodeAdr(&ArgStr[2], MModAcc);
        if (AdrType != ModNone)
        {
          CodeLen = 1;
          BAsmCode[0] = 0x87 + (AdrMode << 3);
        }
        break;
    }
  }
}

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

  if (ChkArgCnt(2, 2))
  {
    Boolean OK;

    Integer AdrInt = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
    if (OK)
    {
      DecodeAdr(&ArgStr[1], MModAcc | MModDir);
      switch (AdrType)
      {
        case ModAcc:
          CodeLen = 2;
          BAsmCode[0] = 0x17;
          BAsmCode[1] = Lo(AdrInt);
          break;
        case ModDir:
          CodeLen = 3;
          BAsmCode[0] = 0x0d;
          BAsmCode[1] = AdrVal;
          BAsmCode[2] = Lo(AdrInt);
          break;
      }
    }
  }
}

static void DecodeRel(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    Boolean OK;
    tSymbolFlags Flags;
    Integer AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt16, &OK, &Flags) - (EProgCounter() + 1);

    if (OK)
    {
      if (!mSymbolQuestionable(Flags) && ((AdrInt < -16) || (AdrInt > 15))) WrError(ErrNum_JmpDistTooBig);
      else
      {
        CodeLen = 1;
        BAsmCode[0] = Code + ((AdrInt << 3) & 0xf8);
      }
    }
  }
}

static void DecodeJP_CALL(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    Boolean OK;
    Word AdrInt;
    tSymbolFlags Flags;

    AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[1], pCurrCPUProps->CodeAdrInt, &OK, &Flags);
    if (OK)
    {
      Word DestPage = AdrInt >> 11;

      /* CPU program space's page 1 (800h...0fffh) always accesses ROM space page 1.
         CPU program space's page 0 (000h...7ffh) accesses 2K ROM space pages as defined by PRPR. */

      if (!mFirstPassUnknown(Flags) && (DestPage != 1))
      {
        Word SrcPage = EProgCounter() >> 11;

        /* Jump from page 1 is allowed to page defined by PRPR.
           Jump from any other page is only allowed back to page 1 or within same page. */

        if (DestPage != ((SrcPage == 1) ? PRPRVal : SrcPage)) WrError(ErrNum_InAccPage);

        AdrInt &= 0x7ff;
      }
      CodeLen = 2;
      BAsmCode[0] = Code + ((AdrInt & 0x00f) << 4);
      BAsmCode[1] = AdrInt >> 4;
    }
  }
}

static void DecodeALU(Word Code)
{
  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModAcc);
    if (AdrType != ModNone)
    {
      DecodeAdr(&ArgStr[2], MModDir | MModInd);
      switch (AdrType)
      {
        case ModDir:
          CodeLen = 2;
          BAsmCode[0] = Code + 0x18;
          BAsmCode[1] = AdrVal;
          break;
        case ModInd:
          CodeLen = 1;
          BAsmCode[0] = Code + (AdrMode << 3);
          break;
      }
    }
  }
}

static void DecodeALUImm(Word Code)
{
  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModAcc);
    if (AdrType != ModNone)
    {
      Boolean OK;
      BAsmCode[1] = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
      if (OK)
      {
        CodeLen = 2;
        BAsmCode[0] = Code + 0x10;
      }
    }
  }
}

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

  if (ChkArgCnt(1, 1))
  {
    DecodeAdr(&ArgStr[1], MModAcc | MModDir);
    switch (AdrType)
    {
      case ModAcc:
        CodeLen = 2;
        BAsmCode[0] = 0xdf;
        BAsmCode[1] = 0xff;
        break;
      case ModDir:
        CodeLen = 3;
        BAsmCode[0] = 0x0d;
        BAsmCode[1] = AdrVal;
        BAsmCode[2] = 0;
        break;
    }
  }
}

static void DecodeAcc(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    DecodeAdr(&ArgStr[1], MModAcc);
    if (AdrType != ModNone)
    {
      BAsmCode[CodeLen++] = Lo(Code);
      if (Hi(Code))
        BAsmCode[CodeLen++] = Hi(Code);
    }
  }
}

static void DecodeINC_DEC(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    DecodeAdr(&ArgStr[1], MModDir | MModInd);
    switch (AdrType)
    {
      case ModDir:
        if (IsReg(AdrVal))
        {
          CodeLen = 1;
          BAsmCode[0] = Code + 0x15 + ((AdrVal & 3) << 6);
        }
        else
        {
          CodeLen = 2;
          BAsmCode[0] = 0x7f + (Code << 4);
          BAsmCode[1] = AdrVal;
        }
        break;
      case ModInd:
        CodeLen = 1;
        BAsmCode[0] = 0x67 + (AdrMode << 3) + (Code << 4);
        break;
    }
  }
}

static void DecodeSET_RES(Word Code)
{
  LongWord PackedAddr;

  if (ChkArgCnt(1, 2)
   && DecodeBitArg(&PackedAddr, 1, ArgCnt))
  {
    Word RegAddr;
    Byte BitPos;

    DissectBitSymbol(PackedAddr, &RegAddr, &BitPos);
    BAsmCode[0] = (MirrBit(BitPos) << 5) | Code;
    BAsmCode[1] = RegAddr;
    CodeLen = 2;
  }
}

static void DecodeJRR_JRS(Word Code)
{
  LongWord PackedAddr;

  if (ChkArgCnt(2, 3)
   && DecodeBitArg(&PackedAddr, 1, ArgCnt - 1))
  {
    Word RegAddr;
    Byte BitPos;
    Boolean OK;
    Integer AdrInt;
    tSymbolFlags Flags;

    DissectBitSymbol(PackedAddr, &RegAddr, &BitPos);
    BAsmCode[0] = (MirrBit(BitPos) << 5) | Code;
    BAsmCode[1] = RegAddr;
    AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[ArgCnt], UInt16, &OK, &Flags) - (EProgCounter() + 3);
    if (OK)
    {
      if (!mSymbolQuestionable(Flags) && ((AdrInt > 127) || (AdrInt < -128))) WrError(ErrNum_JmpDistTooBig);
      else
      {
        CodeLen = 3;
        BAsmCode[2] = Lo(AdrInt);
      }
    }
  }
}

static void DecodeSFR(Word Code)
{
  UNUSED(Code);
  code_equate_type(SegData, UInt8);
}

/*!------------------------------------------------------------------------
 * \fn     DecodeASCII_ASCIZ(Word IsZ)
 * \brief  handle ASCII/ASCIZ instructions
 * \param  IsZ 1 if it's ASCIZ
 * ------------------------------------------------------------------------ */

static void DecodeASCII_ASCIZ(Word IsZ)
{
  if (ChkArgCnt(1, ArgCntMax))
  {
    int l;
    Boolean OK = True;
    tStrComp *pArg;
    TempResult t;

    as_tempres_ini(&t);
    forallargs(pArg, OK)
    {
      EvalStrExpression(pArg, &t);
      switch (t.Typ)
      {
        case TempString:
        {
          if (as_chartrans_xlate_nonz_dynstr(CurrTransTable->p_table, &t.Contents.str, pArg))
            OK = False;
          else
          {
            l = t.Contents.str.len;
            if (SetMaxCodeLen(CodeLen + l + IsZ))
            {
              WrStrErrorPos(ErrNum_CodeOverflow, pArg); OK = False;
            }
            else
            {
              memcpy(BAsmCode + CodeLen, t.Contents.str.p_str, l);
              CodeLen += l;
              if (IsZ)
                BAsmCode[CodeLen++] = 0;
            }
          }
          break;
        }
        case TempNone:
          OK = False;
          break;
        default:
          WrStrErrorPos(ErrNum_ExpectString, pArg);
          OK = False;
      }
    }
    as_tempres_free(&t);
    if (!OK)
      CodeLen = 0;
  }
}

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

static void DecodeBIT(Word Code)
{
  LongWord BitSpec;

  UNUSED(Code);

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

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

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

/*---------------------------------------------------------------------------------*/
/* code table handling */

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

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

static void AddALU(const char *NName, const char *NNameImm, Byte NCode)
{
  AddInstTable(InstTable, NName, NCode, DecodeALU);
  AddInstTable(InstTable, NNameImm, NCode, DecodeALUImm);
}

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

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

  add_null_pseudo(InstTable);

  AddInstTable(InstTable, "LD", 0, DecodeLD);
  AddInstTable(InstTable, "LDI", 0, DecodeLDI);
  AddInstTable(InstTable, "JP", 0x09, DecodeJP_CALL);
  AddInstTable(InstTable, "CALL", 0x01, DecodeJP_CALL);
  AddInstTable(InstTable, "CLR", 0, DecodeCLR);
  AddInstTable(InstTable, "INC", 0, DecodeINC_DEC);
  AddInstTable(InstTable, "DEC", 8, DecodeINC_DEC);
  AddInstTable(InstTable, "SET", 0x1b, DecodeSET_RES);
  AddInstTable(InstTable, "RES", 0x0b, DecodeSET_RES);
  AddInstTable(InstTable, "JRR", 0x03, DecodeJRR_JRS);
  AddInstTable(InstTable, "JRS", 0x13, DecodeJRR_JRS);
  AddInstTable(InstTable, "SFR", 0, DecodeSFR);
  AddInstTable(InstTable, "ASCII", 0, DecodeASCII_ASCIZ);
  AddInstTable(InstTable, "ASCIZ", 1, DecodeASCII_ASCIZ);
  AddInstTable(InstTable, "BYTE", 0, DecodeMotoBYT);
  AddInstTable(InstTable, "WORD", e_moto_pseudo_flags_le, DecodeMotoADR);
  AddInstTable(InstTable, "BLOCK", e_moto_pseudo_flags_none, DecodeMotoDFS);
  AddInstTable(InstTable, "BIT", 0, DecodeBIT);

  AddFixed("NOP" , 0x04);
  AddFixed("RET" , 0xcd);
  AddFixed("RETI", 0x4d);
  AddFixed("STOP", 0x6d);
  AddFixed("WAIT", 0xed);

  AddRel("JRZ" , 0x04);
  AddRel("JRNZ", 0x00);
  AddRel("JRC" , 0x06);
  AddRel("JRNC", 0x02);

  AddALU("ADD" , "ADDI" , 0x47);
  AddALU("AND" , "ANDI" , 0xa7);
  AddALU("CP"  , "CPI"  , 0x27);
  AddALU("SUB" , "SUBI" , 0xc7);

  AddAcc("COM", 0x002d);
  AddAcc("RLC", 0x00ad);
  AddAcc("SLA", 0xff5f);
}

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

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

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

/*!------------------------------------------------------------------------
 * \fn     InitCode_ST6(void)
 * \brief  per-pass initializations for ST6
 * ------------------------------------------------------------------------ */

static void InitCode_ST6(void)
{
  WinAssume = 0x40;
  PRPRVal = 0;
}

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

static Boolean IsDef_ST6(void)
{
  return Memo("SFR") || Memo("BIT");
}

/*!------------------------------------------------------------------------
 * \fn     SwitchFrom_ST6(void)
 * \brief  cleanup after switching away from target
 * ------------------------------------------------------------------------ */

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

static Boolean TrueFnc(void)
{
  return True;
}

/*!------------------------------------------------------------------------
 * \fn     InternSymbol_ST6(char *pArg, TempResult *pErg)
 * \brief  check for built-in symbols
 * \param  pAsc ASCII repr. of symbol
 * \param  pErg result buffer
 * ------------------------------------------------------------------------ */

static void InternSymbol_ST6(char *pArg, TempResult *pErg)
{
  int z;
#define RegCnt 5
  static const char RegNames[RegCnt + 1][2] = {"A", "V", "W", "X", "Y"};
  static const Byte RegCodes[RegCnt + 1] = {0xff, 0x82, 0x83, 0x80, 0x81};

  for (z = 0; z < RegCnt; z++)
    if (!as_strcasecmp(pArg, RegNames[z]))
    {
      as_tempres_set_int(pErg, RegCodes[z]);
      pErg->AddrSpaceMask |= (1 << SegData);
    }
}

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

static void SwitchTo_ST6(void *pUser)
{
  const TFamilyDescr *p_descr = FindFamilyByName("ST6");
  int ASSUMEOffset;

  pCurrCPUProps = (const tCPUProps*)pUser;
  TurnWords = False;
  SetIntConstMode(eIntConstModeIntel);
  SetIsOccupiedFnc = TrueFnc;

  PCSymbol = "PC";
  HeaderID = p_descr->Id;
  NOPCode = 0x04;
  DivideChars = ",";
  HasAttrs = False;

  ValidSegs = (1 << SegCode) | (1 << SegData);
  Grans[SegCode] = 1; ListGrans[SegCode] = 1; SegInits[SegCode] = 0;
  SegLimits[SegCode] = IntTypeDefs[pCurrCPUProps->CodeAdrInt].Max;
  Grans[SegData] = 1; ListGrans[SegData] = 1; SegInits[SegData] = 0;
  SegLimits[SegData] = 0xff;

  ASSUMEOffset = (SegLimits[SegCode] > 0xfff) ? 0 : 1;
  assume_set(ASSUMEST6s + ASSUMEOffset, as_array_size(ASSUMEST6s) - ASSUMEOffset);

  MakeCode = MakeCode_ST6;
  IsDef = IsDef_ST6;
  SwitchFrom = SwitchFrom_ST6;
  DissectBit = DissectBit_ST6;
  InternSymbol = InternSymbol_ST6;

  InitFields();
}

/*!------------------------------------------------------------------------
 * \fn     codest6_init(void)
 * \brief  register ST6 target
 * ------------------------------------------------------------------------ */

static const tCPUProps CPUProps[] =
{
  { "ST6200", UInt12 },
  { "ST6201", UInt12 },
  { "ST6203", UInt12 },
  { "ST6208", UInt12 },
  { "ST6209", UInt12 },
  { "ST6210", UInt12 },
  { "ST6215", UInt12 },
  { "ST6218", UInt13 },
  { "ST6220", UInt12 },
  { "ST6225", UInt12 },
  { "ST6228", UInt13 },
  { "ST6230", UInt13 },
  { "ST6232", UInt13 },
  { "ST6235", UInt13 },
  { "ST6240", UInt13 },
  { "ST6242", UInt13 },
  { "ST6245", UInt12 },
  { "ST6246", UInt12 },
  { "ST6252", UInt12 },
  { "ST6253", UInt12 },
  { "ST6255", UInt12 },
  { "ST6260", UInt12 },
  { "ST6262", UInt12 },
  { "ST6263", UInt12 },
  { "ST6265", UInt12 },
  { "ST6280", UInt13 },
  { "ST6285", UInt13 },
  { NULL    , (IntType)0 },
};

void codest6_init(void)
{
  const tCPUProps *pProp;

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

  AddInitPassProc(InitCode_ST6);
}
