/*
 * AS-Portierung
 *
 * AS-Codegeneratormodul fuer die Texas Instruments TMS320C5x-Familie
 *
 */

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

#include "nls.h"
#include "bpemu.h"
#include "strutil.h"
#include "chunks.h"
#include "errmsg.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmitree.h"
#include "codepseudo.h"
#include "codevars.h"
#include "tipseudo.h"
#include "be_le.h"
#include "errmsg.h"
#include "headids.h"

#include "code3205x.h"

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

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

typedef struct
{
  CPUVar MinCPU;
  Word Code;
  Boolean Cond;
} JmpOrder;

typedef struct
{
  const char *Name;
  CPUVar MinCPU;
  Word Mode;
} tAdrMode;

typedef struct
{
  const char *Name;
  CPUVar MinCPU;
  Word CodeAND;
  Word CodeOR;
  Byte IsZL;
  Byte IsC;
  Byte IsV;
  Byte IsTP;
} Condition;

typedef struct
{
  const char *name;
  CPUVar MinCPU;
  Word Code;
} tBitTable;

#define NOCONDITION 0xffff

static FixedOrder *FixedOrders;
static FixedOrder *AdrOrders;
static JmpOrder *JmpOrders;
static FixedOrder *PluOrders;
static tAdrMode *AdrModes;
static Condition *Conditions;
static tBitTable *BitTable;

static Word AdrMode;

static CPUVar CPU320203;
static CPUVar CPU32050;
static CPUVar CPU32051;
static CPUVar CPU32053;

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

static Word EvalARExpression(const tStrComp *pArg, Boolean *OK)
{
  *OK = True;

  if ((as_toupper(pArg->str.p_str[0]) == 'A')
   && (as_toupper(pArg->str.p_str[1]) == 'R')
   && (pArg->str.p_str[2] >= '0')
   && (pArg->str.p_str[2] <= '7')
   && (pArg->str.p_str[3] <= '\0'))
     return pArg->str.p_str[2] - '0';
  return EvalStrIntExpression(pArg, UInt3, OK);
}

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

static Boolean DecodeAdr(const tStrComp *pArg, int MinArgCnt, int aux, Boolean Must1)
{
  Word h;
  tAdrMode *pAdrMode = AdrModes;
  tEvalResult EvalResult;

  /* Annahme: nicht gefunden */

  Boolean AdrOK = False;

  /* Adressierungsmodus suchen */

  while (pAdrMode->Name && as_strcasecmp(pAdrMode->Name, pArg->str.p_str))
   pAdrMode++;

  /* nicht gefunden: dann absolut */

  if (!pAdrMode->Name)
  {
    /* ARn-Register darf dann nicht vorhanden sein */

    if (aux <= ArgCnt)
    {
      (void)ChkArgCnt(MinArgCnt, aux - 1);
      return False;
    }

    /* Adresse berechnen */

    h = EvalStrIntExpressionWithResult(pArg, Int16, &EvalResult);
    if (!EvalResult.OK)
      return False;
    AdrOK = True;

    /* Adresslage pruefen */

    if (Must1 && (h >= 0x80) && !mFirstPassUnknown(EvalResult.Flags))
    {
      WrError(ErrNum_UnderRange);
      return False;
    }

    /* nur untere 7 Bit gespeichert */

    AdrMode = h & 0x7f;
    ChkSpace(SegData, EvalResult.AddrSpaceMask);
  }

  /* ansonsten evtl. noch Adressregister dazu */

  else
  {
    /* auf dieser CPU nicht erlaubter Modus ? */

    if (!ChkMinCPUExt(pAdrMode->MinCPU, ErrNum_AddrModeNotSupported))
      return False;

    AdrMode = pAdrMode->Mode;
    if (aux <= ArgCnt)
    {
      h = EvalARExpression(&ArgStr[aux], &AdrOK);
      if (AdrOK) AdrMode |= 0x8 | h;
    }
    else
      AdrOK = True;
  }

  return AdrOK;
}

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

static Word DecodeCond(int argp)
{
  Condition *pCondition;
  Byte cntzl = 0, cntc = 0, cntv = 0, cnttp = 0;
  Word ret = 0x300;

  while (argp <= ArgCnt)
  {
    for (pCondition = Conditions; pCondition->Name && as_strcasecmp(pCondition->Name, ArgStr[argp].str.p_str); pCondition++);

    if (!pCondition->Name)
    {
      WrError(ErrNum_UndefCond);
      return ret;
    }
    ret &= pCondition->CodeAND;
    ret |= pCondition->CodeOR;
    cntzl += pCondition->IsZL;
    cntc += pCondition->IsC;
    cntv += pCondition->IsV;
    cnttp += pCondition->IsTP;
    argp++;
  }

  if ((cnttp > 1) || (cntzl > 1) || (cntv > 1) || (cntc > 1))
    WrStrErrorPos(ErrNum_UndefCond, &ArgStr[argp]);

  return ret;
}

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

static Word DecodeShift(const tStrComp *pArg, Boolean *OK)
{
  Word Shift;
  tSymbolFlags Flags;

  Shift = EvalStrIntExpressionWithFlags(pArg, UInt5, OK, &Flags);
  if (*OK)
  {
    if (mFirstPassUnknown(Flags)) Shift &= 15;
    *OK = ChkRange(Shift, 0, 16);
  }
  return Shift;
}

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

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

  if (ChkArgCnt(0, 0)
   && ChkMinCPU(pOrder->MinCPU))
  {
    CodeLen = 1;
    WAsmCode[0] = pOrder->Code;
  }
}

static void DecodeCmdAdr(Word Index)
{
  const FixedOrder *pOrder = AdrOrders + Index;

  if (ChkArgCnt(1, 2)
   && ChkMinCPU(pOrder->MinCPU)
   && DecodeAdr(&ArgStr[1], 1, 2, False))
  {
    CodeLen = 1;
    WAsmCode[0] = pOrder->Code | AdrMode;
  }
}

static void DecodeCmdJmp(Word Index)
{
  const JmpOrder *pOrder = JmpOrders + Index;

  if (ChkMinCPU(pOrder->MinCPU)
   && ChkArgCnt(1, pOrder->Cond ? ArgCntMax : 3))
  {
    Boolean OK;

    AdrMode  =  0;
    if (pOrder->Cond)
    {
      AdrMode = DecodeCond(2);
      OK = AdrMode != NOCONDITION;
    }
    else if (ArgCnt > 1)
    {
      OK = DecodeAdr(&ArgStr[2], 1, 3, False);
      if ((AdrMode < 0x80) && (OK))
      {
        WrError(ErrNum_InvAddrMode);
        OK = FALSE;
      }
      AdrMode &= 0x7f;
    }
    else
      OK = TRUE;

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

static void DecodeCmdPlu(Word Index)
{
  Boolean OK;
  const FixedOrder *pOrder = PluOrders + Index;

  if (!ChkMinCPU(pOrder->MinCPU));
  else if (*ArgStr[1].str.p_str == '#')
  {
    if (ChkArgCnt(2, 3))
    {
      WAsmCode[1] = EvalStrIntExpressionOffs(&ArgStr[1], 1, Int16, &OK);
      if ((OK) && (DecodeAdr(&ArgStr[2], 2, 3, False)))
      {
        CodeLen = 2;
        WAsmCode[0] = pOrder->Code | 0x0400 | AdrMode;
      }
    }
  }
  else if (strlen(OpPart.str.p_str) == 4) WrError(ErrNum_OnlyImmAddr);
  else
  {
    if (ChkArgCnt(1, 2))
    {
      if (DecodeAdr(&ArgStr[1], 1, 2, False))
      {
        CodeLen = 1;
        WAsmCode[0] = pOrder->Code | AdrMode;
      }
    }
  }
}

static void DecodeADDSUB(Word Index)
{
  Word Shift;
  LongInt AdrLong;
  Boolean OK;

  if (ChkArgCnt(1, 3))
  {
    if (*ArgStr[1].str.p_str == '#')
    {
      if (ChkArgCnt(1, 2))
      {
        OK = True;
        Shift = (ArgCnt == 1) ? 0 : EvalStrIntExpression(&ArgStr[2], UInt4, &OK);
        if (OK)
        {
          AdrLong = EvalStrIntExpressionOffs(&ArgStr[1], 1, UInt16, &OK);
          if (OK)
          {
            if ((Shift == 0) && (Hi(AdrLong) == 0))
            {
              CodeLen = 1;
              WAsmCode[0] = (Index << 9) | 0xb800 | (AdrLong & 0xff);
            }
            else
            {
              CodeLen = 2;
              WAsmCode[0] = ((Index << 4) + 0xbf90) | (Shift & 0xf);
              WAsmCode[1] = AdrLong;
            }
          }
        }
      }
    }
    else
    {
      if (DecodeAdr(&ArgStr[1], 1, 3, False))
      {
        OK = True;
        Shift = (ArgCnt >= 2) ? DecodeShift(&ArgStr[2], &OK) : 0;
        if (OK)
        {
          CodeLen = 1;
          if (Shift == 16)
            WAsmCode[0] = ((Index << 10) | 0x6100) | AdrMode;
          else
            WAsmCode[0] = ((Index << 12) | 0x2000) | ((Shift & 0xf) << 8) | AdrMode;
        }
      }
    }
  }
}

static void DecodeADRSBRK(Word Index)
{
  Word adr_word;
  Boolean OK;

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

  if (*ArgStr[1].str.p_str != '#')
  {
    WrError(ErrNum_OnlyImmAddr); /*invalid parameter*/
    return;
  }

  adr_word = EvalStrIntExpressionOffs(&ArgStr[1], 1, UInt8, &OK);
  if (OK)
  {
    CodeLen = 1;
    WAsmCode[0] = (Index << 10)| 0x7800 | (adr_word & 0xff);
  }
}

static void DecodeLogic(Word Index)
{
  Boolean OK;
  Word Shift;

  if (!ChkArgCnt(1, 2));
  else if (*ArgStr[1].str.p_str == '#')
  {
    WAsmCode[1] = EvalStrIntExpressionOffs(&ArgStr[1], 1, UInt16, &OK);
    if (OK)
    {
      OK = True;
      Shift = (ArgCnt >= 2) ? DecodeShift(&ArgStr[2], &OK) : 0;
      if (OK)
      {
        CodeLen = 2;
        if (Shift >= 16)
          WAsmCode[0] = 0xbe80 | Lo(Index);
        else
          WAsmCode[0] = 0xbfa0 + ((Index & 3) << 4) + (Shift & 0xf);
      }
    }
  }
  else
  {
    if (DecodeAdr(&ArgStr[1], 1, 2, False))
    {
      CodeLen = 1;
      WAsmCode[0] = (Index & 0xff00) | AdrMode;
    }
  }
}

static void DecodeBIT(Word Index)
{
  Word bit;
  Boolean OK;
  UNUSED(Index);

  if (ChkArgCnt(2, 3))
  {
    bit = EvalStrIntExpression(&ArgStr[2], UInt4, &OK);
    if ((OK) && (DecodeAdr(&ArgStr[1], 2, 3, False)))
    {
      CodeLen = 1;
      WAsmCode[0] = 0x4000 | AdrMode | ((bit & 0xf) << 8);
    }
  }
}

static void DecodeBLDD(Word Index)
{
  Boolean OK;
  UNUSED(Index);

  if (!ChkArgCnt(2, 3));
  else if (!as_strcasecmp(ArgStr[1].str.p_str, "BMAR"))
  {
    if (ChkMinCPU(CPU32050))
    {
      if (DecodeAdr(&ArgStr[2], 2, 3, False))
      {
        CodeLen = 1;
        WAsmCode[0] = 0xac00 | AdrMode;
      }
    }
  }
  else if (!as_strcasecmp(ArgStr[2].str.p_str, "BMAR"))
  {
    if (ChkMinCPU(CPU32050))
    {
      if (DecodeAdr(&ArgStr[1], 2, 3, False))
      {
        CodeLen = 1;
        WAsmCode[0] = 0xad00 | AdrMode;
      }
    }
  }
  else if (*ArgStr[1].str.p_str == '#')
  {
    WAsmCode[1] = EvalStrIntExpressionOffs(&ArgStr[1], 1, Int16, &OK);
    if ((OK) && (DecodeAdr(&ArgStr[2], 2, 3, False)))
    {
      CodeLen = 2;
      WAsmCode[0] = 0xa800 | AdrMode;
    }
  }
  else if (*ArgStr[2].str.p_str == '#')
  {
    WAsmCode[1] = EvalStrIntExpressionOffs(&ArgStr[2], 1, Int16, &OK);
    if ((OK) && (DecodeAdr(&ArgStr[1], 2, 3, False)))
    {
      CodeLen = 2;
      WAsmCode[0] = 0xa900 | AdrMode;
    }
  }
  else
    WrError(ErrNum_InvAddrMode); /* invalid addr mode */
}

static void DecodeBLPD(Word Index)
{
  Boolean OK;
  UNUSED(Index);

  if (!ChkArgCnt(2, 3));
  else if (!as_strcasecmp(ArgStr[1].str.p_str, "BMAR"))
  {
    if (ChkMinCPU(CPU32050)
     && DecodeAdr(&ArgStr[2], 2, 3, False))
    {
      CodeLen = 1;
      WAsmCode[0] = 0xa400 | AdrMode;
    }
  }
  else if (*ArgStr[1].str.p_str == '#')
  {
    WAsmCode[1] = EvalStrIntExpressionOffs(&ArgStr[1], 1, Int16, &OK);
    if ((OK) && (DecodeAdr(&ArgStr[2], 2, 3, False)))
    {
      CodeLen = 2;
      WAsmCode[0] = 0xa500 | AdrMode;
    }
  }
  else
    WrError(ErrNum_InvAddrMode); /* invalid addressing mode */
}

static void DecodeCLRSETC(Word Index)
{
  tBitTable *pBitTable;

  if (ChkArgCnt(1, 1))
  {
    WAsmCode[0] = Index;
    NLS_UpString(ArgStr[1].str.p_str);

    for (pBitTable = BitTable; pBitTable->name; pBitTable++)
      if (!strcmp(ArgStr[1].str.p_str, pBitTable->name))
      {
        if (ChkMinCPU(pBitTable->MinCPU))
        {
          WAsmCode[0] |= pBitTable->Code;
          CodeLen = 1;
        }
        return;
      }
    WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]); /* invalid instruction */
  }
}

static void DecodeCMPRSPM(Word Index)
{
  Boolean OK;

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

static void DecodeIO(Word Index)
{
  if (ChkArgCnt(2, 3)
   && DecodeAdr(&ArgStr[1], 2, 3, False))
  {
    tEvalResult EvalResult;
    WAsmCode[1] = EvalStrIntExpressionWithResult(&ArgStr[2], UInt16, &EvalResult);
    if (EvalResult.OK)
    {
      ChkSpace(SegIO, EvalResult.AddrSpaceMask);
      CodeLen = 2;
      WAsmCode[0] = Index | AdrMode;
    }
  }
}

static void DecodeINTR(Word Index)
{
  Boolean OK;
  UNUSED(Index);

  if (ChkArgCnt(1, 1))
  {
    WAsmCode[0] = EvalStrIntExpression(&ArgStr[1], UInt5, &OK) | 0xbe60;
    if (OK)
      CodeLen = 1;
  }
}

static void DecodeLACC(Word Index)
{
  Boolean OK;
  LongWord AdrLong;
  Word Shift;
  UNUSED(Index);

  if (!ChkArgCnt(1, 3));
  else if (*ArgStr[1].str.p_str == '#')
  {
    if (ChkArgCnt(1, 2))
    {
      AdrLong = EvalStrIntExpressionOffs(&ArgStr[1], 1, Int16, &OK);
      if (OK)
      {
        OK = True;
        Shift = (ArgCnt > 1) ? EvalStrIntExpression(&ArgStr[2], UInt4, &OK) : 0;
        if (OK)
        {
          CodeLen = 2;
          WAsmCode[0] = 0xbf80 | (Shift & 0xf);
          WAsmCode[1] = AdrLong;
        }
      }
    }
  }
  else
  {
    if (DecodeAdr(&ArgStr[1], 1, 3, False))
    {
      OK = True;
      Shift = (ArgCnt >= 2) ? DecodeShift(&ArgStr[2], &OK) : 0;
      if (OK)
      {
        CodeLen = 1;
        if (Shift >= 16)
          WAsmCode[0] = 0x6a00 | AdrMode;
        else
          WAsmCode[0] = 0x1000 | ((Shift & 0xf) << 8) | AdrMode;
      }
    }
  }
}

static void DecodeLACL(Word Index)
{
  Boolean OK;
  UNUSED(Index);

  if (*ArgStr[1].str.p_str == '#')
  {
    if (ChkArgCnt(1, 1))
    {
      WAsmCode[0] = EvalStrIntExpressionOffs(&ArgStr[1], 1, UInt8, &OK);
      if (OK)
      {
        CodeLen = 1;
        WAsmCode[0] |= 0xb900;
      }
    }
  }
  else
  {
    if (ChkArgCnt(1, 2))
    {
      if (DecodeAdr(&ArgStr[1], 1, 2, False))
      {
        WAsmCode[0] = 0x6900 | AdrMode;
        CodeLen = 1;
      }
    }
  }
}

static void DecodeLAR(Word Index)
{
  Word Reg;
  LongWord AdrLong;
  Boolean OK;
  UNUSED(Index);

  if (ChkArgCnt(2, 3))
  {
    Reg = EvalARExpression(&ArgStr[1], &OK);
    if (OK)
    {
      if (*ArgStr[2].str.p_str == '#')
      {
        if (!ChkArgCnt(2, 2))
          return;
        AdrLong = EvalStrIntExpressionOffs(&ArgStr[2], 1, Int16, &OK) & 0xffff;
        if (OK)
        {
          if (AdrLong > 255)
          {
            CodeLen = 2;
            WAsmCode[0] = 0xbf08 | (Reg & 7);
            WAsmCode[1] = AdrLong;
          }
          else
          {
            CodeLen = 1;
            WAsmCode[0] = 0xb000 | ((Reg & 7) << 8) | (AdrLong & 0xff);
          }
        }
      }
      else
      {
        if (DecodeAdr(&ArgStr[2], 2, 3, False))
        {
          CodeLen = 1;
          WAsmCode[0] = 0x0000 | ((Reg & 7) << 8) | AdrMode;
        }
      }
    }
  }
}

static void DecodeLDP(Word Index)
{
  Word konst;
  Boolean OK;
  UNUSED(Index);

  if (*ArgStr[1].str.p_str == '#')
  {
    if (ChkArgCnt(1, 1))
    {
      konst = EvalStrIntExpressionOffs(&ArgStr[1], 1, UInt9, &OK);
      if (OK)
      {
        CodeLen = 1;
        WAsmCode[0] = (konst & 0x1ff) | 0xbc00;
      }
    }
  }
  else
  {
    if (ChkArgCnt(1, 2))
    {
      if (DecodeAdr(&ArgStr[1], 1, 2, False))
      {
        CodeLen = 1;
        WAsmCode[0] = 0x0d00 | AdrMode;
      }
    }
  }
}

static void DecodeLSST(Word Index)
{
  Word konst;
  Boolean OK;

  if (!ChkArgCnt(2, 3));
  else if (*ArgStr[1].str.p_str != '#') WrError(ErrNum_OnlyImmAddr); /* invalid instruction */
  else
  {
    konst = EvalStrIntExpressionOffs(&ArgStr[1], 1, UInt1, &OK);
    if ((OK) && (DecodeAdr(&ArgStr[2], 2, 3, Index)))
    {
      CodeLen = 1;
      WAsmCode[0] = 0x0e00 | (Index << 15) | ((konst & 1) << 8) | AdrMode;
    }
  }
}

static void DecodeMAC(Word Index)
{
  if (ChkArgCnt(2, 3))
  {
    tEvalResult EvalResult;
    WAsmCode[1] = EvalStrIntExpressionWithResult(&ArgStr[1], Int16, &EvalResult);

    if (EvalResult.OK && DecodeAdr(&ArgStr[2], 2, 3, False))
    {
      ChkSpace(SegCode, EvalResult.AddrSpaceMask);
      CodeLen = 2;
      WAsmCode[0] = 0xa200 | (Index << 8) | AdrMode;
    }
  }
}

static void DecodeMPY(Word Index)
{
  LongInt Imm;
  Boolean OK;
  tSymbolFlags Flags;

  if (*ArgStr[1].str.p_str == '#')
  {
    if (ChkArgCnt(1, 1))
    {
      Imm = EvalStrIntExpressionOffsWithFlags(&ArgStr[1], 1, SInt16, &OK, &Flags);
      if (mFirstPassUnknown(Flags))
        Imm &= 0xfff;
      if (OK)
      {
        if ((Imm < -4096) || (Imm > 4095))
        {
          if (ChkMinCPU(CPU32050))
          {
            CodeLen = 2;              /* What does that mean? */
            WAsmCode[0] = 0xbe80;
            WAsmCode[1] = Imm;
          }
        }
        else
        {
          CodeLen = 1;
          WAsmCode[0] = 0xc000 | (Imm & 0x1fff);
        }
      }
    }
  }
  else
  {
    if (ChkArgCnt(1, 2)
     && DecodeAdr(&ArgStr[1], 1, 2, Index))
    {
      CodeLen = 1;
      WAsmCode[0] = 0x5400 | AdrMode;
    }
  }
}

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

  if (ChkArgCnt(1, 2)
   && DecodeAdr(&ArgStr[1], 1, 2, False))
  {
    if (AdrMode < 0x80) WrError(ErrNum_InvAddrMode);
    else
    {
      CodeLen = 1;
      WAsmCode[0] = 0xa080 | (AdrMode & 0x7f);
    }
  }
}

static void DecodeRETC(Word Index)
{
  if (!ChkArgCnt(1, ArgCntMax));
  else if (Index && !ChkMinCPU(CPU32050));
  else
  {
    CodeLen = 1;
    WAsmCode[0] = 0xec00 | (Index << 12) | DecodeCond(1);
  }
}

static void DecodeRPT(Word Index)
{
  Word Imm;
  Boolean OK;
  UNUSED(Index);

  if (*ArgStr[1].str.p_str == '#')
  {
    if (ChkArgCnt(1, 1))
    {
      Imm = EvalStrIntExpressionOffs(&ArgStr[1], 1, (MomCPU >= CPU32050) ? UInt16 : UInt8, &OK);
      if (OK)
      {
        if (Imm > 255)
        {
          CodeLen = 2;
          WAsmCode[0] = 0xbec4;
          WAsmCode[1] = Imm;
        }
        else
        {
          CodeLen = 1;
          WAsmCode[0] = 0xbb00 | (Imm & 0xff);
        }
      }
    }
  }
  else
  {
    if (ChkArgCnt(1, 2))
    {
      if (DecodeAdr(&ArgStr[1], 1, 2, False))
      {
        CodeLen = 1;
        WAsmCode[0] = 0x0b00 | AdrMode;
      }
    }
  }
}

static void DecodeSAC(Word Index)
{
  Boolean OK;
  Word Shift;

  if (ChkArgCnt(1, 3))
  {
    OK = True;
    Shift = (ArgCnt >= 2) ? EvalStrIntExpression(&ArgStr[2], UInt3, &OK) : 0;

    if ((DecodeAdr(&ArgStr[1], 1, 3, False)) && (OK))
    {
      CodeLen = 1;
      WAsmCode[0] = (Index << 11) | 0x9000 | AdrMode | ((Shift & 7) << 8);
    }
  }
}

static void DecodeSAR(Word Index)
{
  Word Reg;
  Boolean OK;
  UNUSED(Index);

  if (ChkArgCnt(2, 3))
  {
    Reg = EvalARExpression(&ArgStr[1], &OK);

    if ((OK) && (DecodeAdr(&ArgStr[2], 2, 3, False)))
    {
      CodeLen = 1;
      WAsmCode[0] = 0x8000 | ((Reg & 7) << 8) | AdrMode;
    }
  }
}

static void DecodeBSAR(Word Index)
{
  Word Shift;
  Boolean OK;
  tSymbolFlags Flags;

  UNUSED(Index);

  if (ChkArgCnt(1, 1)
   && ChkMinCPU(CPU32050))
  {
    Shift = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt5, &OK, &Flags);
    if (mFirstPassUnknown(Flags))
      Shift = 1;
    if (OK)
    {
      if (ChkRange(Shift, 1, 16))
      {
        CodeLen = 1;
        WAsmCode[0] = 0xbfe0 | ((Shift - 1) & 0xf);
      }
    }
  }
}

static void DecodeLSAMM(Word Index)
{
  if (ChkArgCnt(1, 2)
   && ChkMinCPU(CPU32050)
   && DecodeAdr(&ArgStr[1], 1, 2, True))
  {
    CodeLen = 1;
    WAsmCode[0] = 0x0800 | (Index << 15) | AdrMode;
  }
}

static void DecodeLSMMR(Word Index)
{
  Boolean OK;

  if (!ChkArgCnt(2, 3));
  else if (!ChkMinCPU(CPU32050));
  else if (ArgStr[2].str.p_str[0] != '#') WrError(ErrNum_OnlyImmAddr);
  else
  {
    WAsmCode[1] = EvalStrIntExpressionOffs(&ArgStr[2], 1, Int16, &OK);
    if ((OK) && (DecodeAdr(&ArgStr[1], 2, 3, True)))
    {
      CodeLen = 2;
      WAsmCode[0] = 0x0900 | (Index << 15) | AdrMode;
    }
  }
}

static void DecodeRPTB(Word Index)
{
  Boolean OK;
  UNUSED(Index);

  if (ChkArgCnt(1, 1)
   && ChkMinCPU(CPU32050))
  {
    WAsmCode[1] = EvalStrIntExpression(&ArgStr[1], Int16, &OK);
    if (OK)
    {
      CodeLen = 2;
      WAsmCode[0] = 0xbec6;
    }
  }
}

static void DecodeRPTZ(Word Index)
{
  Boolean OK;
  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if (!ChkMinCPU(CPU32050));
  else if (*ArgStr[1].str.p_str != '#') WrError(ErrNum_OnlyImmAddr);
  else
  {
    WAsmCode[1] = EvalStrIntExpressionOffs(&ArgStr[1], 1, Int16, &OK);
    if (OK)
    {
      CodeLen = 2;
      WAsmCode[0] = 0xbec5;
    }
  }
}

static void DecodeXC(Word Index)
{
  Word Mode;
  Boolean OK;
  tSymbolFlags Flags;

  UNUSED(Index);

  if (ChkArgCnt(2, ArgCntMax)
   && ChkMinCPU(CPU32050))
  {
    Mode = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt2, &OK, &Flags);
    if (OK)
    {
      if ((Mode != 1) && (Mode != 2) && !mFirstPassUnknown(Flags)) WrError(ErrNum_UnderRange);
      else
      {
        CodeLen = 1;
        WAsmCode[0] = (0xd400 + (Mode << 12)) | DecodeCond(2);
      }
    }
  }
}

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

  code_equate_type(SegIO, UInt16);
}

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

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

static void AddAdr(const char *NName, CPUVar MinCPU, Word NCode)
{
  order_array_rsv_end(AdrOrders, FixedOrder);
  AdrOrders[InstrZ].MinCPU = MinCPU;
  AdrOrders[InstrZ].Code = NCode;
  AddInstTable(InstTable, NName, InstrZ++, DecodeCmdAdr);
}

static void AddJmp(const char *NName, CPUVar MinCPU, Word NCode, Boolean NCond)
{
  order_array_rsv_end(JmpOrders, JmpOrder);
  JmpOrders[InstrZ].MinCPU = MinCPU;
  JmpOrders[InstrZ].Code = NCode;
  JmpOrders[InstrZ].Cond = NCond;
  AddInstTable(InstTable, NName, InstrZ++, DecodeCmdJmp);
}

static void AddPlu(const char *NName, CPUVar MinCPU, Word NCode)
{
  order_array_rsv_end(PluOrders, FixedOrder);
  PluOrders[InstrZ].MinCPU = MinCPU;
  PluOrders[InstrZ].Code = NCode;
  AddInstTable(InstTable, NName, InstrZ++, DecodeCmdPlu);
}

static void AddAdrMode(const char *NName, CPUVar MinCPU, Word NMode)
{
  order_array_rsv_end(AdrModes, tAdrMode);
  AdrModes[InstrZ].Name = NName;
  AdrModes[InstrZ].MinCPU = MinCPU;
  AdrModes[InstrZ++].Mode = NMode;
}

static void AddCond(const char *NName, CPUVar MinCPU, Word NCodeAND, Word NCodeOR, Byte NIsZL,
                    Byte NIsC, Byte NIsV, Byte NIsTP)
{
  order_array_rsv_end(Conditions, Condition);
  Conditions[InstrZ].Name = NName;
  Conditions[InstrZ].MinCPU = MinCPU;
  Conditions[InstrZ].CodeAND = NCodeAND;
  Conditions[InstrZ].CodeOR = NCodeOR;
  Conditions[InstrZ].IsZL = NIsZL;
  Conditions[InstrZ].IsC = NIsC;
  Conditions[InstrZ].IsV = NIsV;
  Conditions[InstrZ++].IsTP = NIsTP;
}

static void AddBit(const char *NName, CPUVar MinCPU, Word NCode)
{
  order_array_rsv_end(BitTable, tBitTable);
  BitTable[InstrZ].name = NName;
  BitTable[InstrZ].MinCPU = MinCPU;
  BitTable[InstrZ++].Code = NCode;
}

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

  add_null_pseudo(InstTable);

  InstrZ = 0;
  AddFixed("ABS",    CPU320203, 0xbe00); AddFixed("ADCB",   CPU32050 , 0xbe11);
  AddFixed("ADDB",   CPU32050 , 0xbe10); AddFixed("ANDB",   CPU32050 , 0xbe12);
  AddFixed("CMPL",   CPU320203, 0xbe01); AddFixed("CRGT",   CPU32050 , 0xbe1b);
  AddFixed("CRLT",   CPU32050 , 0xbe1c); AddFixed("EXAR",   CPU32050 , 0xbe1d);
  AddFixed("LACB",   CPU32050 , 0xbe1f); AddFixed("NEG",    CPU320203, 0xbe02);
  AddFixed("ORB",    CPU32050 , 0xbe13); AddFixed("ROL",    CPU320203, 0xbe0c);
  AddFixed("ROLB",   CPU32050 , 0xbe14); AddFixed("ROR",    CPU320203, 0xbe0d);
  AddFixed("RORB",   CPU32050 , 0xbe15); AddFixed("SACB",   CPU32050 , 0xbe1e);
  AddFixed("SATH",   CPU32050 , 0xbe5a); AddFixed("SATL",   CPU32050 , 0xbe5b);
  AddFixed("SBB",    CPU32050 , 0xbe18); AddFixed("SBBB",   CPU32050 , 0xbe19);
  AddFixed("SFL",    CPU320203, 0xbe09); AddFixed("SFLB",   CPU32050 , 0xbe16);
  AddFixed("SFR",    CPU320203, 0xbe0a); AddFixed("SFRB",   CPU32050 , 0xbe17);
  AddFixed("XORB",   CPU32050 , 0xbe1a); AddFixed("ZAP",    CPU32050 , 0xbe59);
  AddFixed("APAC",   CPU320203, 0xbe04); AddFixed("PAC",    CPU320203, 0xbe03);
  AddFixed("SPAC",   CPU320203, 0xbe05); AddFixed("ZPR",    CPU32050 , 0xbe58);
  AddFixed("BACC",   CPU320203, 0xbe20); AddFixed("BACCD",  CPU32050 , 0xbe21);
  AddFixed("CALA",   CPU320203, 0xbe30); AddFixed("CALAD",  CPU32050 , 0xbe3d);
  AddFixed("NMI",    CPU320203, 0xbe52); AddFixed("RET",    CPU320203, 0xef00);
  AddFixed("RETD",   CPU32050 , 0xff00); AddFixed("RETE",   CPU32050 , 0xbe3a);
  AddFixed("RETI",   CPU32050 , 0xbe38); AddFixed("TRAP",   CPU320203, 0xbe51);
  AddFixed("IDLE",   CPU320203, 0xbe22); AddFixed("NOP",    CPU320203, 0x8b00);
  AddFixed("POP",    CPU320203, 0xbe32); AddFixed("PUSH",   CPU320203, 0xbe3c);
  AddFixed("IDLE2",  CPU32050 , 0xbe23);

  InstrZ = 0;
  AddAdr("ADDC",   CPU320203, 0x6000); AddAdr("ADDS",   CPU320203, 0x6200);
  AddAdr("ADDT",   CPU320203, 0x6300); AddAdr("LACT",   CPU320203, 0x6b00);
  AddAdr("SUBB",   CPU320203, 0x6400); AddAdr("SUBC",   CPU320203, 0x0a00);
  AddAdr("SUBS",   CPU320203, 0x6600); AddAdr("SUBT",   CPU320203, 0x6700);
  AddAdr("ZALR",   CPU320203, 0x6800); AddAdr("MAR",    CPU320203, 0x8b00);
  AddAdr("LPH",    CPU320203, 0x7500); AddAdr("LT",     CPU320203, 0x7300);
  AddAdr("LTA",    CPU320203, 0x7000); AddAdr("LTD",    CPU320203, 0x7200);
  AddAdr("LTP",    CPU320203, 0x7100); AddAdr("LTS",    CPU320203, 0x7400);
  AddAdr("MADD",   CPU32050 , 0xab00); AddAdr("MADS",   CPU32050 , 0xaa00);
  AddAdr("MPYA",   CPU320203, 0x5000); AddAdr("MPYS",   CPU320203, 0x5100);
  AddAdr("MPYU",   CPU320203, 0x5500); AddAdr("SPH",    CPU320203, 0x8d00);
  AddAdr("SPL",    CPU320203, 0x8c00); AddAdr("SQRA",   CPU320203, 0x5200);
  AddAdr("SQRS",   CPU320203, 0x5300); AddAdr("BLDP",   CPU32050 , 0x5700);
  AddAdr("DMOV",   CPU320203, 0x7700); AddAdr("TBLR",   CPU320203, 0xa600);
  AddAdr("TBLW",   CPU320203, 0xa700); AddAdr("BITT",   CPU320203, 0x6f00);
  AddAdr("POPD",   CPU320203, 0x8a00); AddAdr("PSHD",   CPU320203, 0x7600);

  InstrZ = 0;
  AddJmp("B",      CPU320203, 0x7980,  False);
  AddJmp("BD",     CPU32050 , 0x7d80,  False);
  AddJmp("BANZ",   CPU320203, 0x7b80,  False);
  AddJmp("BANZD",  CPU32050 , 0x7f80,  False);
  AddJmp("BCND",   CPU320203, 0xe000,  True);
  AddJmp("BCNDD",  CPU32050 , 0xf000,  True);
  AddJmp("CALL",   CPU320203, 0x7a80,  False);
  AddJmp("CALLD",  CPU32050 , 0x7e80,  False);
  AddJmp("CC",     CPU320203, 0xe800,  True);
  AddJmp("CCD",    CPU32050 , 0xf800,  True);

  InstrZ = 0;
  AddPlu("APL",   CPU32050 , 0x5a00); AddPlu("CPL",   CPU32050 , 0x5b00);
  AddPlu("OPL",   CPU32050 , 0x5900); AddPlu("SPLK",  CPU320203, 0xaa00);
  AddPlu("XPL",   CPU32050 , 0x5800);

  InstrZ = 0;
  AddAdrMode( "*-",     CPU320203, 0x90 ); AddAdrMode( "*+",     CPU320203, 0xa0 );
  AddAdrMode( "*BR0-",  CPU320203, 0xc0 ); AddAdrMode( "*0-",    CPU320203, 0xd0 );
  AddAdrMode( "*AR0-",  CPU32050 , 0xd0 ); AddAdrMode( "*0+",    CPU320203, 0xe0 );
  AddAdrMode( "*AR0+",  CPU32050 , 0xe0 ); AddAdrMode( "*BR0+",  CPU320203, 0xf0 );
  AddAdrMode( "*",      CPU320203, 0x80 ); AddAdrMode( NULL,     CPU32050 , 0);

  InstrZ = 0;
  AddCond("EQ",  CPU32050 , 0xf33, 0x088, 1, 0, 0, 0);
  AddCond("NEQ", CPU32050 , 0xf33, 0x008, 1, 0, 0, 0);
  AddCond("LT",  CPU32050 , 0xf33, 0x044, 1, 0, 0, 0);
  AddCond("LEQ", CPU32050 , 0xf33, 0x0cc, 1, 0, 0, 0);
  AddCond("GT",  CPU32050 , 0xf33, 0x004, 1, 0, 0, 0);
  AddCond("GEQ", CPU32050 , 0xf33, 0x08c, 1, 0, 0, 0);
  AddCond("NC",  CPU32050 , 0xfee, 0x001, 0, 1, 0, 0);
  AddCond("C",   CPU32050 , 0xfee, 0x011, 0, 1, 0, 0);
  AddCond("NOV", CPU32050 , 0xfdd, 0x002, 0, 0, 1, 0);
  AddCond("OV",  CPU32050 , 0xfdd, 0x022, 0, 0, 1, 0);
  AddCond("BIO", CPU32050 , 0x0ff, 0x000, 0, 0, 0, 1);
  AddCond("NTC", CPU32050 , 0x0ff, 0x200, 0, 0, 0, 1);
  AddCond("TC",  CPU32050 , 0x0ff, 0x100, 0, 0, 0, 1);
  AddCond("UNC", CPU32050 , 0x0ff, 0x300, 0, 0, 0, 1);
  AddCond(NULL,  CPU32050 , 0xfff, 0x000, 0, 0, 0, 0);

  InstrZ = 0;
  AddBit("OVM",  CPU320203, 0xbe42 ); AddBit("SXM",  CPU320203, 0xbe46 );
  AddBit("HM",   CPU32050 , 0xbe48 ); AddBit("TC",   CPU320203, 0xbe4a );
  AddBit("C",    CPU320203, 0xbe4e ); AddBit("XF",   CPU320203, 0xbe4c );
  AddBit("CNF",  CPU320203, 0xbe44 ); AddBit("INTM", CPU320203, 0xbe40 );
  AddBit(NULL,   CPU32050 , 0     );

  AddInstTable(InstTable, "ADD"  , 0, DecodeADDSUB);
  AddInstTable(InstTable, "SUB"  , 1, DecodeADDSUB);
  AddInstTable(InstTable, "ADRK" , 0, DecodeADRSBRK);
  AddInstTable(InstTable, "SBRK" , 1, DecodeADRSBRK);
  AddInstTable(InstTable, "AND"  , 0x6e01, DecodeLogic);
  AddInstTable(InstTable, "OR"   , 0x6d02, DecodeLogic);
  AddInstTable(InstTable, "XOR"  , 0x6c03, DecodeLogic);
  AddInstTable(InstTable, "BIT"  , 0, DecodeBIT);
  AddInstTable(InstTable, "BLDD" , 0, DecodeBLDD);
  AddInstTable(InstTable, "BLPD" , 0, DecodeBLPD);
  AddInstTable(InstTable, "CLRC" , 0, DecodeCLRSETC);
  AddInstTable(InstTable, "SETC" , 1, DecodeCLRSETC);
  AddInstTable(InstTable, "CMPR" , 0xbf44, DecodeCMPRSPM);
  AddInstTable(InstTable, "SPM"  , 0xbf00, DecodeCMPRSPM);
  AddInstTable(InstTable, "IN"   , 0xaf00, DecodeIO);
  AddInstTable(InstTable, "OUT"  , 0x0c00, DecodeIO);
  AddInstTable(InstTable, "INTR" , 0, DecodeINTR);
  AddInstTable(InstTable, "LACC" , 0, DecodeLACC);
  AddInstTable(InstTable, "LACL" , 0, DecodeLACL);
  AddInstTable(InstTable, "LAR"  , 0, DecodeLAR);
  AddInstTable(InstTable, "LDP"  , 0, DecodeLDP);
  AddInstTable(InstTable, "SST"  , 1, DecodeLSST);
  AddInstTable(InstTable, "LST"  , 0, DecodeLSST);
  AddInstTable(InstTable, "MAC"  , 0, DecodeMAC);
  AddInstTable(InstTable, "MACD" , 1, DecodeMAC);
  AddInstTable(InstTable, "MPY"  , 0, DecodeMPY);
  AddInstTable(InstTable, "NORM" , 0, DecodeNORM);
  AddInstTable(InstTable, "RETC" , 0, DecodeRETC);
  AddInstTable(InstTable, "RETCD", 1, DecodeRETC);
  AddInstTable(InstTable, "RPT"  , 0, DecodeRPT);
  AddInstTable(InstTable, "SACL" , 0, DecodeSAC);
  AddInstTable(InstTable, "SACH" , 1, DecodeSAC);
  AddInstTable(InstTable, "SAR"  , 0, DecodeSAR);
  AddInstTable(InstTable, "BSAR" , 0, DecodeBSAR);
  AddInstTable(InstTable, "LAMM" , 0, DecodeLSAMM);
  AddInstTable(InstTable, "SAMM" , 1, DecodeLSAMM);
  AddInstTable(InstTable, "LMMR" , 1, DecodeLSMMR);
  AddInstTable(InstTable, "SMMR" , 0, DecodeLSMMR);
  AddInstTable(InstTable, "RPTB" , 0, DecodeRPTB);
  AddInstTable(InstTable, "RPTZ" , 0, DecodeRPTZ);
  AddInstTable(InstTable, "XC"   , 0, DecodeXC);
  AddInstTable(InstTable, "PORT" , 0, DecodePORT);

  add_ti_pseudo(InstTable);
}

static void DeinitFields(void)
{
  DestroyInstTable(InstTable);
  order_array_free(FixedOrders);
  order_array_free(AdrOrders);
  order_array_free(JmpOrders);
  order_array_free(PluOrders);
  order_array_free(AdrModes);
  order_array_free(Conditions);
  order_array_free(BitTable);
}

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

static void MakeCode_3205x(void)
{
  /* Pseudoanweisungen */

  if (decode_ti_qxx())
    return;

  /* per Hash-Tabelle */

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

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

static Boolean IsDef_3205x(void)
{
  return Memo("PORT") || IsTIDef();
}

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

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

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

static void SwitchTo_3205x(void)
{
  const TFamilyDescr *p_descr = FindFamilyByName("TMS320C5x");

  TurnWords = False;
  SetIntConstMode(eIntConstModeIntel);

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

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

  MakeCode = MakeCode_3205x;
  IsDef = IsDef_3205x;
  SwitchFrom = SwitchFrom_3205x;
  InitFields();
}

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

void code3205x_init(void)
{
  CPU320203 = AddCPU("320C203", SwitchTo_3205x);
  CPU32050  = AddCPU("320C50",  SwitchTo_3205x);
  CPU32051  = AddCPU("320C51",  SwitchTo_3205x);
  CPU32053  = AddCPU("320C53",  SwitchTo_3205x);

  AddCopyright("TMS320C5x-Generator (C) 1995/96 Thomas Sailer");
}
