/* codepdk.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* AS - Target Padauk MCUs */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <string.h>
#include "bpemu.h"
#include "strutil.h"
#include "cpulist.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmitree.h"
#include "asmstructs.h"
#include "codevars.h"
#include "codepseudo.h"
#include "fourpseudo.h"
#include "codepdk.h"
typedef enum
{
eCoreNone,
eCorePDK13,
eCorePDK14,
eCorePDK15,
eCorePDK16
} tCPUCore;
enum
{
eInstCapCOMP_AM_MA = 1 << 0,
eInstCapNADD_AM_MA = 1 << 1,
eInstCapMUL = 1 << 2,
eInstCapXOR_IOA = 1 << 3,
eInstCap_SWAPM = 1 << 4,
eInstCapNMOV_AM_MA = 1 << 5,
eInstCapPUSHW_POPW = 1 << 6,
eInstCapPMODE = 1 << 7
};
typedef struct
{
const char *pName;
Word FlashEndD16;
Byte RAMEnd, IOAreaEnd;
tCPUCore Core;
Word InstCaps;
} tCPUProps;
typedef enum
{
ModNone = 0,
ModMem = 1,
ModIO = 2,
ModImm = 3,
ModAcc = 4
} tAdrMode;
#define MModMem (1 << ModMem)
#define MModIO (1 << ModIO)
#define MModImm (1 << ModImm)
#define MModAcc (1 << ModAcc)
static const tCPUProps *pCurrCPUProps;
static IntType CodeAdrIntType,
CodeWordIntType,
DataAdrIntType,
DataBitAdrIntType,
IOAdrIntType;
static Byte DataMemBits,
DataBitMemBits,
CodeMemBits,
IOMemBits;
static Word AccInstOffs;
static ShortInt OpSize;
/*!------------------------------------------------------------------------
* \fn DecodeAdr(tStrComp *pArg, Word Mask, IntType MemIntType, Word *pResult)
* \brief decode address expression
* \param pArg string argument in source
* \param Mask bit mask of allowed modes
* \param MemIntType integer range for memory addresses
* \param pResult resulting address for memory/IO
* \return decoded address mode or none
* ------------------------------------------------------------------------ */
static tAdrMode DecodeAdr(tStrComp *pArg, Word Mask, IntType MemIntType, Word *pResult)
{
tAdrMode AdrMode = ModNone;
Boolean OK;
IntType AutoIntType;
LongInt AddrOrImm;
int ArgLen;
tEvalResult EvalResult;
if (!as_strcasecmp(pArg->str.p_str, "A"))
{
AdrMode = ModAcc;
goto check;
}
/* explicit memory: disp[addr], [addr], addr[idx] */
ArgLen
= strlen(pArg
->str.
p_str);
if ((ArgLen >= 2) && (pArg->str.p_str[ArgLen - 1] == ']'))
{
tStrComp Part1, Part2;
LongInt Num1, Num2;
Boolean EitherUnknown;
char *pSep;
tEvalResult EvalResult1, EvalResult2;
StrCompShorten(pArg, 1);
pSep = RQuotPos(pArg->str.p_str, '[');
if (!pSep)
{
WrStrErrorPos(ErrNum_BrackErr, pArg);
goto check;
}
StrCompSplitRef(&Part1, &Part2, pArg, pSep);
EitherUnknown = False;
if (*Part1.str.p_str)
{
Num1 = EvalStrIntExpressionWithResult(&Part1, MemIntType, &EvalResult1);
if (!EvalResult1.OK)
goto check;
EitherUnknown = EitherUnknown || mFirstPassUnknown(EvalResult1.Flags);
}
else
{
EvalResult1.OK = False;
EvalResult1.Flags = eSymbolFlag_None;
EvalResult1.AddrSpaceMask = 0;
Num1 = 0;
}
Num2 = EvalStrIntExpressionWithResult(&Part2, MemIntType, &EvalResult2);
if (!EvalResult2.OK)
goto check;
EitherUnknown = EitherUnknown || mFirstPassUnknown(EvalResult2.Flags);
Num1 += Num2;
if (EitherUnknown)
{
Num1 &= SegLimits[SegData];
if (OpSize == eSymbolSize16Bit)
Num1 &= ~1;
}
if ((OpSize == eSymbolSize16Bit) && (Num1 & 1)) WrStrErrorPos(ErrNum_NotAligned, pArg);
else if (ChkRange(Num1, 0, SegLimits[SegData]))
{
ChkSpace(SegData, EvalResult1.AddrSpaceMask | EvalResult2.AddrSpaceMask);
AdrMode = ModMem;
*pResult = Num1;
}
goto check;
}
/* explicit I/O */
if (!as_strncasecmp(pArg->str.p_str, "IO", 2) && IsIndirect(pArg->str.p_str + 2))
{
*pResult = EvalStrIntExpressionOffsWithResult(pArg, 2, IOAdrIntType, &EvalResult);
if (EvalResult.OK)
{
ChkSpace(SegIO, EvalResult.AddrSpaceMask);
AdrMode = ModIO;
}
goto check;
}
/* explicit immediate */
if (*pArg->str.p_str == '#')
{
*pResult = EvalStrIntExpressionOffs(pArg, 1, Int8, &OK) & 0xff;
if (OK)
AdrMode = ModImm;
goto check;
}
/* OK, guess what is meant... */
AutoIntType = Int8;
if (Lo(IntTypeDefs[IOAdrIntType].SignAndWidth) > Lo(IntTypeDefs[AutoIntType].SignAndWidth))
AutoIntType = IOAdrIntType;
if (Lo(IntTypeDefs[MemIntType].SignAndWidth) > Lo(IntTypeDefs[AutoIntType].SignAndWidth))
AutoIntType = MemIntType;
AddrOrImm = EvalStrIntExpressionWithResult(pArg, AutoIntType, &EvalResult);
if (EvalResult.OK)
{
if (EvalResult.AddrSpaceMask == 1 << SegIO)
{
if (mFirstPassUnknown(EvalResult.Flags) && (AddrOrImm > (LongInt)SegLimits[SegIO]))
AddrOrImm &= SegLimits[SegIO];
if (AddrOrImm > (LongInt)SegLimits[SegIO])
WrStrErrorPos(ErrNum_OverRange, pArg);
else
{
AdrMode = ModIO;
*pResult = AddrOrImm;
}
}
else if (EvalResult.AddrSpaceMask == 1 << SegData)
{
if (mFirstPassUnknown(EvalResult.Flags) && (AddrOrImm > (LongInt)SegLimits[SegData]))
AddrOrImm &= SegLimits[SegData];
if (AddrOrImm > (LongInt)SegLimits[SegData])
WrStrErrorPos(ErrNum_OverRange, pArg);
else
{
AdrMode = ModMem;
*pResult = AddrOrImm;
}
}
else
{
if (mFirstPassUnknown(EvalResult.Flags) && ((AddrOrImm > 0xff) || (AddrOrImm < -128)))
AddrOrImm &= 0xff;
if (!ChkRange(AddrOrImm, -128, 255))
WrStrErrorPos(ErrNum_OverRange, pArg);
else
{
AdrMode = ModImm;
*pResult = AddrOrImm & 0xff;
}
}
}
check:
if ((AdrMode != ModNone) && (!(Mask & (1 << AdrMode))))
{
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
AdrMode = ModNone;
}
return AdrMode;
}
static Boolean CoreMask(Word Mask)
{
return !!(Mask & (1 << pCurrCPUProps->Core));
}
/*--------------------------------------------------------------------------*/
/* Bit Symbol Handling */
/*
* Compact representation of bits in symbol table:
* bits 0..2: bit position
* bits 3...n: I/O or memory address
* bit 15: 1 for I/O, 0 for memory
*/
/*!------------------------------------------------------------------------
* \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 EvalStrIntExpression(pArg, UInt3, pOK);
}
/*!------------------------------------------------------------------------
* \fn AssembleBitSymbol(Byte BitPos, Word Address, Boolean IsIO)
* \brief build the compact internal representation of a bit symbol
* \param BitPos bit position in word
* \param Address register address
* \param IsIO true for bit in I/O space
* \return compact representation
* ------------------------------------------------------------------------ */
static LongWord AssembleBitSymbol(Byte BitPos, Word Address, Boolean IsIO)
{
return (BitPos & 7)
| (((LongWord)Address & 0x1ff) << 3)
| (IsIO ? 0x8000u : 0x0000);
}
/*!------------------------------------------------------------------------
* \fn DissectBitSymbol(LongWord BitSymbol, Word *pAddress, Byte *pBitPos, Boolean *pIO)
* \brief transform compact representation of bit symbol into components
* \param BitSymbol compact storage
* \param pAddress I/O or memory address
* \param pBitPos bit position
* \param pIO 1 for I/O, 0 for memory address
* \return constant True
* ------------------------------------------------------------------------ */
static Boolean DissectBitSymbol(LongWord BitSymbol, Word *pAddress, Byte *pBitPos, Boolean *pIO)
{
*pAddress = (BitSymbol >> 3) & 0x1ff;
*pBitPos = BitSymbol & 7;
*pIO = !!(BitSymbol & 0x8000u);
return True;
}
/*!------------------------------------------------------------------------
* \fn DecodeBitArg2(LongWord *pResult, tStrComp *pAddrArg, const tStrComp *pBitArg)
* \brief encode a bit symbol, address & bit position separated
* \param pResult resulting encoded bit
* \param pAddrArg memory/IO address argument
* \param pBitArg bit argument
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean DecodeBitArg2(LongWord *pResult, tStrComp *pAddrArg, const tStrComp *pBitArg)
{
Boolean OK;
Word Address;
Byte BitPos;
Boolean IsIO;
BitPos = EvalBitPosition(pBitArg, &OK);
if (!OK)
return False;
switch (DecodeAdr(pAddrArg, MModMem | MModIO, DataBitAdrIntType, &Address))
{
case ModMem:
IsIO = False;
break;
case ModIO:
IsIO = True;
break;
default:
return False;
}
*pResult = AssembleBitSymbol(BitPos, Address, IsIO);
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)
{
char *pSep
= strchr(ArgStr
[Start
].
str.
p_str, '.');
if (pSep)
{
tStrComp AddressComp, PosComp;
StrCompSplitRef(&AddressComp, &PosComp, &ArgStr[Start], pSep);
return DecodeBitArg2(pResult, &AddressComp, &PosComp);
}
else
{
tEvalResult EvalResult;
*pResult = EvalStrIntExpressionWithResult(&ArgStr[Start], UInt16, &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[Start], &ArgStr[Stop]);
/* other # of arguments not allowed */
else
{
WrError(ErrNum_WrongArgCnt);
return False;
}
}
/*!------------------------------------------------------------------------
* \fn DissectBit_Padauk(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_Padauk(char *pDest, size_t DestSize, LargeWord Inp)
{
Byte BitPos;
Word Address;
Boolean IsIO;
DissectBitSymbol(Inp, &Address, &BitPos, &IsIO);
if (IsIO)
as_snprintf(pDest, DestSize, "IO(0x%x).%u", (unsigned)Address, (unsigned)BitPos);
else
as_snprintf(pDest, DestSize, "[0x%x].%u", (unsigned)Address, (unsigned)BitPos);
}
/*!------------------------------------------------------------------------
* \fn ExpandBit_Padauk(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 ExpandBit_Padauk(const tStrComp *pVarName, const struct sStructElem *pStructElem, LargeWord Base)
{
LongWord Address = Base + pStructElem->Offset;
Boolean IsIO = (ActPC == SegIO);
if (!ChkRange(Address, 0, IntTypeDefs[IsIO ? IOAdrIntType : DataBitAdrIntType].Max)
|| !ChkRange(pStructElem->BitPos, 0, 7))
return;
PushLocHandle(-1);
EnterIntSymbol(pVarName, AssembleBitSymbol(pStructElem->BitPos, Address, IsIO), SegBData, False);
PopLocHandle();
/* TODO: MakeUseList? */
}
/*!------------------------------------------------------------------------
* \fn ImmCode(Word Code13)
* \brief translate PDK13 arithmetic op code to actual code code for immediate src
* \param Code13 PDK13 code
* \return Immediate Opcode
* ------------------------------------------------------------------------ */
static Word ImmCode(Word Code13)
{
switch (pCurrCPUProps->Core)
{
case eCorePDK14:
return 0x20 | ((Code13 & 0x10) >> 1) | (Code13 & 7);
case eCorePDK15:
return 0x40 | Code13;
case eCorePDK16:
return 0x08 | Code13;
default:
return Code13;
}
}
/*!------------------------------------------------------------------------
* \fn AMCode(Word Code13, Boolean AccDest)
* \brief translate PDK13 arithmetic op code to actual code code for Acc<->[M]
* \param Code13 PDK13 code
* \param AccDest: true if A<-M
* \return Opcode
* ------------------------------------------------------------------------ */
static Word AMCode(Word Code13, Boolean AccDest)
{
switch (pCurrCPUProps->Core)
{
case eCorePDK16:
return (Code13 << 1) | (AccDest ? 1 : 0);
default:
return Code13 | (AccDest ? 8 : 0);
}
}
/*!------------------------------------------------------------------------
* \fn MCode(Word Code13)
* \brief translate PDK13 arithmetic op code to actual code code for [M]
* \param Code13 PDK13 code
* \return Opcode
* ------------------------------------------------------------------------ */
static Word MCode(Word Code13)
{
switch (pCurrCPUProps->Core)
{
case eCorePDK16:
return 0x30 | Code13;
default:
return 0x20 | Code13;
}
}
/*---------------------------------------------------------------------------*/
static void DecodeFixed(Word Code)
{
if (ChkArgCnt(0, 0))
WAsmCode[CodeLen++] = Code;
}
static void DecodeACC(Word Code)
{
Word Address;
if (ChkArgCnt(1, 1)
&& DecodeAdr(&ArgStr[1], MModAcc, DataAdrIntType, &Address))
WAsmCode[CodeLen++] = Code;
}
static void DecodeSWAP(Word Code)
{
Word Address;
if (ChkArgCnt(1, 1))
switch (DecodeAdr(&ArgStr[1], MModAcc | ((pCurrCPUProps->InstCaps & eInstCap_SWAPM) ? MModMem : 0), DataAdrIntType, &Address))
{
case ModAcc:
WAsmCode[CodeLen++] = Code;
break;
case ModMem:
WAsmCode[CodeLen++] = ((pCurrCPUProps->Core == eCorePDK16 ? 0x3e: 0x0a) << DataMemBits) | Address;
break;
default:
break;
}
}
static void DecodeADDC_SUBC(Word Code)
{
Word Address;
switch (ArgCnt)
{
case 1:
switch (DecodeAdr(&ArgStr[1], MModAcc | MModMem, DataAdrIntType, &Address))
{
case ModAcc:
WAsmCode[CodeLen++] = (AccInstOffs + 0) | Code;
break;
case ModMem:
WAsmCode[CodeLen++] = (MCode(Code) << DataMemBits) | Address;
break;
default:
break;
}
break;
case 2:
if (!as_strcasecmp(ArgStr[1].str.p_str, "A"))
{
if (DecodeAdr(&ArgStr[2], MModMem, DataAdrIntType, &Address))
WAsmCode[CodeLen++] = (AMCode(0x12 + Code, True) << DataMemBits) | Address;
}
else if (!as_strcasecmp(ArgStr[2].str.p_str, "A"))
{
if (DecodeAdr(&ArgStr[1], MModMem, DataAdrIntType, &Address))
WAsmCode[CodeLen++] = (AMCode(0x12 + Code, False) << DataMemBits) | Address;
}
break;
default:
(void)ChkArgCnt(1, 2);
}
}
static void DecodeACCOrM(Word Code)
{
Word Address;
if (ChkArgCnt(1, 1))
switch (DecodeAdr(&ArgStr[1], MModMem | MModAcc, DataAdrIntType, &Address))
{
case ModAcc:
WAsmCode[CodeLen++] = AccInstOffs + Code;
break;
case ModMem:
WAsmCode[CodeLen++] = (MCode(Code) << DataMemBits) | Address;
break;
default:
break;
}
}
static void DecodeDELAY(Word Code)
{
Word Address;
if (ChkArgCnt(1, 1))
switch (DecodeAdr(&ArgStr[1], MModMem | MModAcc | MModImm, DataAdrIntType, &Address))
{
case ModAcc:
WAsmCode[CodeLen++] = AccInstOffs + Code;
break;
case ModMem:
WAsmCode[CodeLen++] = (MCode(Code) << DataMemBits) | Address;
break;
case ModImm:
WAsmCode[CodeLen++] = 0x0e00 | Address;
break;
default:
break;
}
}
static void DecodeM(Word Code)
{
Word Address;
if (ChkArgCnt(1, 1)
&& DecodeAdr(&ArgStr[1], MModMem, DataAdrIntType, &Address))
WAsmCode[CodeLen++] = (MCode(Code) << DataMemBits) | Address;
}
static void DecodeRET(Word Code)
{
Word Value;
UNUSED(Code);
switch (ArgCnt)
{
case 0:
WAsmCode[CodeLen++] = (AccInstOffs == 0x60) ? 0x7a : 0x3a;
break;
case 1:
if (DecodeAdr(&ArgStr[1], MModImm, DataAdrIntType, &Value))
WAsmCode[CodeLen++] = Code | Value;
break;
default:
(void)ChkArgCnt(0, 1);
}
}
static void DecodeXOR(Word Code)
{
Word DestAddress, SrcAddress,
OpCode = Lo(Code),
IOCode = Hi(Code);
if (ChkArgCnt(2,2))
switch (DecodeAdr(&ArgStr[1], MModAcc | MModMem | ((pCurrCPUProps->InstCaps & eInstCapXOR_IOA) ? MModIO : 0), DataAdrIntType, &DestAddress))
{
case ModAcc:
switch (DecodeAdr(&ArgStr[2], MModMem | MModImm | ((pCurrCPUProps->Core >= eCorePDK16) ? MModIO : 0), DataAdrIntType, &SrcAddress))
{
case ModMem:
WAsmCode[CodeLen++] = (AMCode(OpCode, True) << DataMemBits) | SrcAddress;
break;
case ModImm:
WAsmCode[CodeLen++] = (ImmCode(OpCode) << 8) | SrcAddress;
break;
case ModIO:
WAsmCode[CodeLen++] = ((IOCode + 1) << IOMemBits) | SrcAddress;
break;
default:
break;
}
break;
case ModMem:
if (DecodeAdr(&ArgStr[2], MModAcc, DataAdrIntType, &SrcAddress))
WAsmCode[CodeLen++] = (AMCode(OpCode, False) << DataMemBits) | DestAddress;
break;
case ModIO:
if (DecodeAdr(&ArgStr[2], MModAcc, DataAdrIntType, &SrcAddress))
WAsmCode[CodeLen++] = (IOCode << IOMemBits) | DestAddress;
break;
default:
break;
}
}
static void DecodeAccToM(Word Code)
{
Word DestAddress, SrcAddress;
if (ChkArgCnt(2, 2))
switch (DecodeAdr(&ArgStr[1], MModAcc | MModMem, DataAdrIntType, &DestAddress))
{
case ModAcc:
switch (DecodeAdr(&ArgStr[2], MModMem | MModImm, DataAdrIntType, &SrcAddress))
{
case ModMem:
WAsmCode[CodeLen++] = (AMCode(Code, True) << DataMemBits) | SrcAddress;
break;
case ModImm:
WAsmCode[CodeLen++] = (ImmCode(Code) << 8) | SrcAddress;
break;
default:
break;
}
break;
case ModMem:
if (DecodeAdr(&ArgStr[2], MModAcc, DataAdrIntType, &SrcAddress))
WAsmCode[CodeLen++] = (AMCode(Code, False) << DataMemBits) | DestAddress;
break;
default:
break;
}
}
static void DecodeCOMP_NADD_NMOV(Word Code)
{
Word DestAddress, SrcAddress;
UNUSED(Code);
if (ChkArgCnt(2, 2))
switch (DecodeAdr(&ArgStr[1], MModAcc | MModMem, DataAdrIntType, &DestAddress))
{
case ModAcc:
if (DecodeAdr(&ArgStr[2], MModMem, DataAdrIntType, &SrcAddress))
WAsmCode[CodeLen++] = (((Code << 1) + 0) << DataMemBits) | SrcAddress;
break;
case ModMem:
if (DecodeAdr(&ArgStr[2], MModAcc, DataAdrIntType, &SrcAddress))
WAsmCode[CodeLen++] = (((Code << 1) + 1) << DataMemBits) | DestAddress;
break;
default:
break;
}
}
static void DecodeMOV(Word Code)
{
Word DestAddress, SrcAddress,
OpCode = Lo(Code),
IOCode = Hi(Code) & 15;
if (ChkArgCnt(2,2))
switch (DecodeAdr(&ArgStr[1], MModAcc | MModMem | MModIO, DataAdrIntType, &DestAddress))
{
case ModAcc:
switch (DecodeAdr(&ArgStr[2], MModMem | MModImm | MModIO, DataAdrIntType, &SrcAddress))
{
case ModMem:
WAsmCode[CodeLen++] = (AMCode(OpCode, True) << DataMemBits) | SrcAddress;
break;
case ModImm:
WAsmCode[CodeLen++] = (ImmCode(OpCode) << 8) | SrcAddress;
break;
case ModIO:
WAsmCode[CodeLen++] = ((IOCode + 1) << IOMemBits) | SrcAddress;
break;
default:
break;
}
break;
case ModMem:
if (DecodeAdr(&ArgStr[2], MModAcc, DataAdrIntType, &SrcAddress))
WAsmCode[CodeLen++] = (AMCode(OpCode, False) << DataMemBits) | DestAddress;
break;
case ModIO:
if (DecodeAdr(&ArgStr[2], MModAcc, DataAdrIntType, &SrcAddress))
WAsmCode[CodeLen++] = (IOCode << IOMemBits) | DestAddress;
break;
default:
break;
}
}
static void DecodeGOTO_CALL(Word Code)
{
if (ChkArgCnt(1, 1))
{
tEvalResult EvalResult;
Word Address = EvalStrIntExpressionWithResult(&ArgStr[1], CodeAdrIntType, &EvalResult);
if (EvalResult.OK)
{
ChkSpace(SegCode, EvalResult.AddrSpaceMask);
WAsmCode[CodeLen++] = (Code << CodeMemBits) | Address;
}
}
}
static void DecodeCnEQSN(Word Code)
{
Word SrcAddress, DestAddress;
if (ChkArgCnt(2, 2))
switch (DecodeAdr(&ArgStr[1], MModAcc | ((pCurrCPUProps->Core >= eCorePDK16) ? MModMem : 0), DataAdrIntType, &DestAddress))
{
case ModAcc:
switch (DecodeAdr(&ArgStr[2], MModMem | MModImm, DataAdrIntType, &SrcAddress))
{
case ModMem:
WAsmCode[CodeLen++] = (Code << DataMemBits) | SrcAddress;
break;
case ModImm:
WAsmCode[CodeLen++] = (ImmCode(0x12 + (Code & 1)) << 8) | SrcAddress;
break;
default:
break;
}
break;
case ModMem:
if (DecodeAdr(&ArgStr[2], MModAcc, DataAdrIntType, &SrcAddress))
WAsmCode[CodeLen++] = ((Code ^ 1) << DataMemBits) | DestAddress;
break;
default:
break;
}
}
static void DecodeEvenAddr(tStrComp *pArg, Word Code1, Word Code2)
{
Word Address;
OpSize = eSymbolSize16Bit;
if (DecodeAdr(pArg, MModMem, (pCurrCPUProps->Core == eCorePDK13) ? UInt5 : DataAdrIntType, &Address))
WAsmCode[CodeLen++] = (Code1 << ((pCurrCPUProps->Core == eCorePDK13) ? 5 : DataMemBits)) | Code2 | Address;
}
static void DecodeSTT16_LDT16(Word Code)
{
if (ChkArgCnt(1, 1))
DecodeEvenAddr(&ArgStr[1], Hi(Code), Lo(Code));
}
static void DecodeLDTAB(Word Code)
{
if (ChkArgCnt(1, 1))
DecodeEvenAddr(&ArgStr[1], 0x05, Code);
}
static void DecodeIDXM(Word Code)
{
if (ChkArgCnt(2, 2))
{
if (!as_strcasecmp(ArgStr[1].str.p_str, "A"))
DecodeEvenAddr(&ArgStr[2], Code, 1);
else if (!as_strcasecmp(ArgStr[2].str.p_str, "A"))
DecodeEvenAddr(&ArgStr[1], Code, 0);
}
}
static void DecodeBitOp(Word Code)
{
LongWord BitSpec;
Word OpCode = Lo(Code);
if (DecodeBitArg(&BitSpec, 1, ArgCnt))
{
Word Address;
Byte BitPos;
Boolean IsIO;
DissectBitSymbol(BitSpec, &Address, &BitPos, &IsIO);
if (IsIO)
{
if (pCurrCPUProps->Core == eCorePDK16)
WAsmCode[CodeLen++] = 0x2000 | (OpCode << (3 + IOMemBits)) | (BitPos << IOMemBits) | Address;
else
WAsmCode[CodeLen++] = (3 << (5 + IOMemBits)) | (OpCode << (3 + IOMemBits)) | (BitPos << IOMemBits) | Address;
}
else if (pCurrCPUProps->Core == eCorePDK13)
WAsmCode[CodeLen++] = (Code & 0xff00u) | ((OpCode & 2) << (4 - 1 + DataBitMemBits)) | (BitPos << (1 + DataBitMemBits)) | ((Code & 1) << DataBitMemBits) | Address;
else
WAsmCode[CodeLen++] = (Code & 0xff00u) | (OpCode << (3 + DataBitMemBits)) | (BitPos << DataBitMemBits) | Address;
}
}
static void DecodeBitOpIO(Word Code)
{
LongWord BitSpec;
if (DecodeBitArg(&BitSpec, 1, ArgCnt))
{
Word Address;
Byte BitPos;
Boolean IsIO;
DissectBitSymbol(BitSpec, &Address, &BitPos, &IsIO);
if (IsIO)
WAsmCode[CodeLen++] = (Code << (3 + IOMemBits)) | (BitPos << IOMemBits) | Address;
else
WrError(ErrNum_InvAddrMode);
}
}
static void DecodeConstU5(Word Code)
{
if (ChkArgCnt(1, 1))
{
Boolean OK;
Word Num = EvalStrIntExpressionOffs(&ArgStr[1], !!(*ArgStr[1].str.p_str == '#'), UInt5, &OK);
if (OK)
WAsmCode[CodeLen++] = Code | (Num & 0x1f);
}
}
static void DecodeConstU4(Word Code)
{
if (ChkArgCnt(1, 1))
{
Boolean OK;
Word Num = EvalStrIntExpressionOffs(&ArgStr[1], !!(*ArgStr[1].str.p_str == '#'), UInt4, &OK);
if (OK)
WAsmCode[CodeLen++] = Code | (Num & 0x0f);
}
}
static void DecodeBIT(Word Code)
{
UNUSED(Code);
/* if in structure definition, add special element to structure */
if (ActPC == StructSeg)
{
Boolean OK;
Byte BitPos;
PStructElem pElement;
tStrComp BitComp, *pBitComp, AddrComp, *pAddrComp;
switch (ArgCnt)
{
case 1:
{
char *pSep
= strchr(ArgStr
[1].
str.
p_str, '.');
if (!pSep)
goto fail;
StrCompSplitRef(&AddrComp, &BitComp, &ArgStr[1], pSep);
pBitComp = &BitComp;
pAddrComp = &AddrComp;
break;
}
case 2:
pAddrComp = &ArgStr[1];
pBitComp = &ArgStr[2];
break;
default:
fail:
WrError(ErrNum_WrongArgCnt);
return;
}
BitPos = EvalBitPosition(pBitComp, &OK);
if (!OK)
return;
pElement = CreateStructElem(&LabPart);
pElement->pRefElemName = as_strdup(pAddrComp->str.p_str);
pElement->OpSize = eSymbolSize8Bit;
pElement->BitPos = BitPos;
pElement->ExpandFnc = ExpandBit_Padauk;
AddStructElem(pInnermostNamedStruct->StructRec, pElement);
}
else
{
LongWord BitSpec;
if (DecodeBitArg(&BitSpec, 1, ArgCnt))
{
*ListLine = '=';
DissectBit_Padauk(ListLine + 1, STRINGSIZE - 3, BitSpec);
PushLocHandle(-1);
EnterIntSymbol(&LabPart, BitSpec, SegBData, False);
PopLocHandle();
/* TODO: MakeUseList? */
}
}
}
static void DecodeDATA_Padauk(Word Code)
{
UNUSED(Code);
DecodeDATA(CodeWordIntType, DataAdrIntType);
}
static void DecodeSFR(Word Code)
{
UNUSED(Code);
CodeEquate(SegIO, 0, SegLimits[SegIO]);
}
/*---------------------------------------------------------------------------*/
static void InitFields(void)
{
Word Base, MovIOCode, RETCode, SWAPCCode, BitOpCode, XORIOCode, STT16_LDT16Code, IDXMCode, CEQSNCode, CNEQSNCode;
InstTable = CreateInstTable(203);
switch (pCurrCPUProps->Core)
{
case eCorePDK13:
MovIOCode = 0x0400;
RETCode = 0x0100;
SWAPCCode = 0;
BitOpCode = 0x0200;
XORIOCode = 0x0300;
STT16_LDT16Code = 0x0600;
IDXMCode = 7;
CEQSNCode = 0x2e;
CNEQSNCode = 0x2f;
break;
case eCorePDK14:
MovIOCode = 0x0600;
RETCode = 0x0200;
SWAPCCode = 2;
BitOpCode = 0x2000;
XORIOCode = 0x0300;
STT16_LDT16Code = 0x0600;
IDXMCode = 7;
CEQSNCode = 0x2e;
CNEQSNCode = 0x2f;
break;
case eCorePDK15:
MovIOCode = 0x0200;
RETCode = 0x0200;
SWAPCCode = 0x17;
BitOpCode = 0x4000;
XORIOCode = 0x0100;
STT16_LDT16Code = 0x0600;
IDXMCode = 7;
CEQSNCode = 0x2e;
CNEQSNCode = 0x2f;
break;
case eCorePDK16:
MovIOCode = 0x0200;
RETCode = 0x0f00;
SWAPCCode = 0x17;
BitOpCode = 0x8000;
XORIOCode = 0x4000;
STT16_LDT16Code = 0x0100;
IDXMCode = 4;
CNEQSNCode = 0x0b;
CEQSNCode = 0x1c;
break;
default:
WrError(ErrNum_InternalError);
}
AddInstTable(InstTable, "NOP", NOPCode, DecodeFixed);
if (pCurrCPUProps->Core <= eCorePDK14)
{
AddInstTable(InstTable, "LDSPTL", 0x0006, DecodeFixed);
AddInstTable(InstTable, "LDSPTH", 0x0007, DecodeFixed);
}
else
{
AddInstTable(InstTable, "LDTABL", 0, DecodeLDTAB);
AddInstTable(InstTable, "LDTABH", 1, DecodeLDTAB);
}
Base = (AccInstOffs == 0x60) ? 0x70 : 0x30;
AddInstTable(InstTable, "WDRESET", Base + 0x00, DecodeFixed);
AddInstTable(InstTable, "PUSHAF" , Base + 0x02, DecodeFixed);
AddInstTable(InstTable, "POPAF" , Base + 0x03, DecodeFixed);
AddInstTable(InstTable, "RESET" , Base + 0x05, DecodeFixed);
AddInstTable(InstTable, "STOPSYS", Base + 0x06, DecodeFixed);
AddInstTable(InstTable, "STOPEXE", Base + 0x07, DecodeFixed);
AddInstTable(InstTable, "ENGINT" , Base + 0x08, DecodeFixed);
AddInstTable(InstTable, "DISGINT", Base + 0x09, DecodeFixed);
AddInstTable(InstTable, "RETI" , Base + 0x0b, DecodeFixed);
if (pCurrCPUProps->InstCaps & eInstCapMUL)
AddInstTable(InstTable, "MUL" , Base + 0x0c, DecodeFixed);
AddInstTable(InstTable, "RET" , RETCode, DecodeRET);
AddInstTable(InstTable, "ADDC", 0, DecodeADDC_SUBC);
AddInstTable(InstTable, "SUBC", 1, DecodeADDC_SUBC);
AddInstTable(InstTable, "IZSN", 2, DecodeACCOrM);
AddInstTable(InstTable, "DZSN", 3, DecodeACCOrM);
AddInstTable(InstTable, "NOT" , 8, DecodeACCOrM);
AddInstTable(InstTable, "NEG" , 9, DecodeACCOrM);
AddInstTable(InstTable, "SR" ,10, DecodeACCOrM);
AddInstTable(InstTable, "SL" ,11, DecodeACCOrM);
AddInstTable(InstTable, "SRC" ,12, DecodeACCOrM);
AddInstTable(InstTable, "SLC" ,13, DecodeACCOrM);
if (pCurrCPUProps->Core >= eCorePDK16)
AddInstTable(InstTable, "DELAY", 15, DecodeDELAY);
AddInstTable(InstTable, "PCADD", AccInstOffs + 7, DecodeACC);
AddInstTable(InstTable, "SWAP", AccInstOffs + 14, DecodeSWAP);
AddInstTable(InstTable, "INC" , 4, DecodeM);
AddInstTable(InstTable, "DEC" , 5, DecodeM);
AddInstTable(InstTable, "CLEAR", 6, DecodeM);
AddInstTable(InstTable, "XCH" , 7, DecodeM);
if (pCurrCPUProps->InstCaps & eInstCapNADD_AM_MA)
AddInstTable(InstTable, "COMP", pCurrCPUProps->Core >= eCorePDK16 ? 0x0f : 0x06, DecodeCOMP_NADD_NMOV);
if (pCurrCPUProps->InstCaps & eInstCapCOMP_AM_MA)
AddInstTable(InstTable, "NADD", pCurrCPUProps->Core >= eCorePDK16 ? 0x0d : 0x07, DecodeCOMP_NADD_NMOV);
if (pCurrCPUProps->InstCaps & eInstCapNMOV_AM_MA)
AddInstTable(InstTable, "NMOV", pCurrCPUProps->Core >= eCorePDK16 ? 0x0c : 0x04, DecodeCOMP_NADD_NMOV);
AddInstTable(InstTable, "ADD", 0x10, DecodeAccToM);
AddInstTable(InstTable, "SUB", 0x11, DecodeAccToM);
AddInstTable(InstTable, "AND", 0x14, DecodeAccToM);
AddInstTable(InstTable, "OR" , 0x15, DecodeAccToM);
AddInstTable(InstTable, "XOR", XORIOCode | 0x16, DecodeXOR);
AddInstTable(InstTable, "MOV", MovIOCode | 0x17, DecodeMOV);
AddInstTable(InstTable, "CEQSN", CEQSNCode, DecodeCnEQSN);
if (pCurrCPUProps->Core >= eCorePDK14)
AddInstTable(InstTable, "CNEQSN", CNEQSNCode | 1, DecodeCnEQSN);
AddInstTable(InstTable, "STT16", STT16_LDT16Code | 0, DecodeSTT16_LDT16);
AddInstTable(InstTable, "LDT16", STT16_LDT16Code | 1, DecodeSTT16_LDT16);
if (pCurrCPUProps->InstCaps & eInstCapPUSHW_POPW)
{
AddInstTable(InstTable, "POPW", 0x0200, DecodeSTT16_LDT16);
AddInstTable(InstTable, "PUSHW", 0x0201, DecodeSTT16_LDT16);
}
if (pCurrCPUProps->Core >= eCorePDK16)
{
AddInstTable(InstTable, "IGOTO", 0x0300, DecodeSTT16_LDT16);
AddInstTable(InstTable, "ICALL", 0x0301, DecodeSTT16_LDT16);
}
AddInstTable(InstTable, "IDXM" , IDXMCode, DecodeIDXM);
AddInstTable(InstTable, "GOTO", 6, DecodeGOTO_CALL);
AddInstTable(InstTable, "CALL", 7, DecodeGOTO_CALL);
AddInstTable(InstTable, "T0SN", BitOpCode | 0, DecodeBitOp);
AddInstTable(InstTable, "T1SN", BitOpCode | 1, DecodeBitOp);
AddInstTable(InstTable, "SET0", BitOpCode | 2, DecodeBitOp);
AddInstTable(InstTable, "SET1", BitOpCode | 3, DecodeBitOp);
if (pCurrCPUProps->Core >= eCorePDK16)
{
AddInstTable(InstTable, "TOG", 0x14, DecodeBitOpIO);
AddInstTable(InstTable, "WAIT0", 0x15, DecodeBitOpIO);
AddInstTable(InstTable, "WAIT1", 0x16, DecodeBitOpIO);
}
if (SWAPCCode)
AddInstTable(InstTable, "SWAPC", SWAPCCode, DecodeBitOpIO);
if (pCurrCPUProps->InstCaps & eInstCapPMODE)
AddInstTable(InstTable, "PMODE", 0x0040, DecodeConstU5);
if (pCurrCPUProps->InstCaps & eInstCapPUSHW_POPW)
{
AddInstTable(InstTable, "POPWPC" , 0x0060, DecodeConstU4);
AddInstTable(InstTable, "PUSHWPC", 0x0070, DecodeConstU4);
}
AddInstTable(InstTable, "BIT", 0, DecodeBIT);
AddInstTable(InstTable, "DATA", 0, DecodeDATA_Padauk);
AddInstTable(InstTable, "SFR", 0, DecodeSFR);
AddInstTable(InstTable, "RES", 0, DecodeRES);
}
static void DeinitFields(void)
{
DestroyInstTable(InstTable);
}
/*---------------------------------------------------------------------------*/
static void MakeCode_Padauk(void)
{
CodeLen = 0;
DontPrint = False;
OpSize = eSymbolSize8Bit;
if (Memo("")) return;
if (!LookupInstTable(InstTable, OpPart.str.p_str))
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
}
static Boolean IsDef_Padauk(void)
{
return Memo("BIT")
|| Memo("SFR");
}
static void SwitchFrom_Padauk(void)
{
DeinitFields();
}
static void SwitchTo_Padauk(void *pUser)
{
static const char CommentLeadIn[] = { ';', '\0', '/', '/', '\0', '\0' };
pCurrCPUProps = (const tCPUProps*)pUser;
TurnWords = False;
SetIntConstMode(eIntConstModeC);
PCSymbol = "*";
HeaderID = 0x3b;
NOPCode = 0x0000;
DivideChars = ",";
pCommentLeadIn = CommentLeadIn;
HasAttrs = False;
ValidSegs = (1 << SegCode) | (1 << SegData) | (1 << SegIO);
Grans[SegCode] = 2; ListGrans[SegCode] = 2; SegInits[SegCode] = 0;
Grans[SegData] = 1; ListGrans[SegData] = 1; SegInits[SegData] = 0; SegLimits[SegData] = pCurrCPUProps->RAMEnd;
Grans[SegIO ] = 1; ListGrans[SegIO ] = 1; SegInits[SegIO ] = 0; SegLimits[SegIO] = pCurrCPUProps->IOAreaEnd;
SegLimits[SegCode] = ((LongWord)pCurrCPUProps->FlashEndD16) << 4 | 0xf;
CodeAdrIntType = GetSmallestUIntType(SegLimits[SegCode]);
CodeWordIntType = GetUIntTypeByBits(13 + (pCurrCPUProps->Core - eCorePDK13));
DataAdrIntType = GetSmallestUIntType(SegLimits[SegData]);
DataBitAdrIntType = (pCurrCPUProps->Core == eCorePDK13) ? UInt4 : DataAdrIntType;
IOAdrIntType = GetSmallestUIntType(SegLimits[SegIO ]);
#if 0
fprintf(stderr
, "Data 0x%lx DataBit 0x%lx Code 0x%lx IO 0x%lx\n",
IntTypeDefs[DataAdrIntType].Max,
IntTypeDefs[DataBitAdrIntType].Max,
IntTypeDefs[CodeAdrIntType].Max,
IntTypeDefs[IOAdrIntType].Max);
#endif
switch (pCurrCPUProps->Core)
{
case eCorePDK13:
DataBitAdrIntType = UInt4;
IOMemBits = 5;
break;
case eCorePDK14:
DataBitAdrIntType = UInt6;
IOMemBits = 6;
break;
case eCorePDK15:
DataBitAdrIntType = UInt7;
IOMemBits = 7;
break;
case eCorePDK16:
DataBitAdrIntType = UInt9;
IOMemBits = 6;
break;
default:
break;
}
DataBitMemBits = Lo(IntTypeDefs[DataBitAdrIntType].SignAndWidth);
DataMemBits = 6 + (pCurrCPUProps->Core - eCorePDK13);
CodeMemBits = 10 + (pCurrCPUProps->Core - eCorePDK13);
AccInstOffs = CoreMask((1 << eCorePDK14) | (1 << eCorePDK15)) ? 0x0060 : 0x0010;
MakeCode = MakeCode_Padauk;
IsDef = IsDef_Padauk;
SwitchFrom = SwitchFrom_Padauk;
DissectBit = DissectBit_Padauk;
InitFields();
}
static const tCPUProps CPUProps[] =
{
{ "PMC150" , 0x3f, 0x3f, 0x1f, eCorePDK13, eInstCapXOR_IOA },
{ "PMS150" , 0x3f, 0x3f, 0x1f, eCorePDK13, eInstCapXOR_IOA },
{ "PFS154" , 0x7f, 0x7f, 0x3f, eCorePDK14, eInstCapXOR_IOA },
{ "PMC131" , 0x5f, 0x57, 0x3f, eCorePDK14, eInstCapCOMP_AM_MA | eInstCapMUL | eInstCapNADD_AM_MA },
{ "PMS130" , 0x5f, 0x57, 0x3f, eCorePDK14, eInstCapCOMP_AM_MA | eInstCapMUL | eInstCapNADD_AM_MA },
{ "PMS131" , 0x5f, 0x57, 0x3f, eCorePDK14, eInstCapCOMP_AM_MA | eInstCapMUL | eInstCapNADD_AM_MA },
{ "PMS132" , 0x7f, 0x7f, 0x3f, eCorePDK14, eInstCapCOMP_AM_MA | eInstCapMUL | eInstCapNADD_AM_MA | eInstCapXOR_IOA },
{ "PMS132B" , 0x7f, 0x7f, 0x3f, eCorePDK14, eInstCapCOMP_AM_MA | eInstCapMUL | eInstCapNADD_AM_MA | eInstCapXOR_IOA },
{ "PMS152" , 0x4f, 0x4f, 0x3f, eCorePDK14, eInstCapCOMP_AM_MA | eInstCapNADD_AM_MA | eInstCapXOR_IOA },
{ "PMS154B" , 0x7f, 0x7f, 0x3f, eCorePDK14, eInstCapCOMP_AM_MA | eInstCapNADD_AM_MA | eInstCapXOR_IOA },
{ "PMS154C" , 0x7f, 0x7f, 0x3f, eCorePDK14, eInstCapCOMP_AM_MA | eInstCapNADD_AM_MA | eInstCapXOR_IOA },
{ "PFS173" , 0xbf, 0xff, 0x7f, eCorePDK15, eInstCapCOMP_AM_MA | eInstCapNADD_AM_MA },
{ "PMS133" , 0xbf, 0xff, 0x7f, eCorePDK15, eInstCapCOMP_AM_MA | eInstCapMUL | eInstCapNADD_AM_MA | eInstCapXOR_IOA | eInstCapNMOV_AM_MA | eInstCap_SWAPM },
{ "PMS134" , 0xff, 0xff, 0x7f, eCorePDK15, eInstCapCOMP_AM_MA | eInstCapMUL | eInstCapNADD_AM_MA | eInstCapXOR_IOA | eInstCapNMOV_AM_MA | eInstCap_SWAPM },
{ "DF69" , 0xff, 0xcf, 0x3f, eCorePDK16, eInstCapCOMP_AM_MA | eInstCapMUL | eInstCapNADD_AM_MA | eInstCapXOR_IOA | eInstCapNMOV_AM_MA | eInstCap_SWAPM | eInstCapPUSHW_POPW | eInstCapPMODE },
{ "MCS11" , 0xff, 0xcf, 0x3f, eCorePDK16, eInstCapCOMP_AM_MA | eInstCapMUL | eInstCapNADD_AM_MA | eInstCapXOR_IOA | eInstCapNMOV_AM_MA | eInstCap_SWAPM | eInstCapPUSHW_POPW | eInstCapPMODE },
{ "PMC232" , 0x7f, 0x9f, 0x3f, eCorePDK16, eInstCapCOMP_AM_MA | eInstCapNADD_AM_MA | eInstCapXOR_IOA | eInstCapNMOV_AM_MA | eInstCap_SWAPM },
{ "PMC234" , 0xff, 0xcf, 0x3f, eCorePDK16, eInstCapCOMP_AM_MA | eInstCapNADD_AM_MA | eInstCapXOR_IOA | eInstCapNMOV_AM_MA | eInstCap_SWAPM },
{ "PMC251" , 0x3f, 0x3f, 0x3f, eCorePDK16, eInstCapCOMP_AM_MA | eInstCapNADD_AM_MA | eInstCapXOR_IOA | eInstCapNMOV_AM_MA | eInstCap_SWAPM },
{ "PMC271" , 0x3f, 0x3f, 0x3f, eCorePDK16, eInstCapCOMP_AM_MA | eInstCapNADD_AM_MA | eInstCapXOR_IOA | eInstCapNMOV_AM_MA | eInstCap_SWAPM },
{ "PMC884" , 0xff, 0xff, 0x3f, eCorePDK16, eInstCapCOMP_AM_MA | eInstCapMUL | eInstCapNADD_AM_MA | eInstCapXOR_IOA | eInstCapNMOV_AM_MA | eInstCap_SWAPM | eInstCapPUSHW_POPW | eInstCapPMODE },
{ "PMS232" , 0x7f, 0x9f, 0x3f, eCorePDK16, eInstCapCOMP_AM_MA | eInstCapNADD_AM_MA | eInstCapXOR_IOA | eInstCapNMOV_AM_MA | eInstCap_SWAPM },
{ "PMS234" , 0xff, 0xcf, 0x3f, eCorePDK16, eInstCapCOMP_AM_MA | eInstCapNADD_AM_MA | eInstCapXOR_IOA | eInstCapNMOV_AM_MA | eInstCap_SWAPM },
{ "PMS271" , 0x3f, 0x3f, 0x3f, eCorePDK16, eInstCapCOMP_AM_MA | eInstCapNADD_AM_MA | eInstCapXOR_IOA | eInstCapNMOV_AM_MA | eInstCap_SWAPM },
{ NULL , 0x00, 0x00, 0x00, eCoreNone , 0 }
};
void codepdk_init(void)
{
const tCPUProps *pProp;
for (pProp = CPUProps; pProp->pName; pProp++)
(void)AddCPUUser(pProp->pName, SwitchTo_Padauk, (void*)pProp, NULL);
}