/* codesx20.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Code Generator Parallax SX20 */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <string.h>
#include <ctype.h>
#include "bpemu.h"
#include "strutil.h"
#include "chunks.h"
#include "headids.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmitree.h"
#include "codepseudo.h"
#include "fourpseudo.h"
#include "codevars.h"
#include "errmsg.h"
#include "codef8.h"
/*---------------------------------------------------------------------------*/
static CPUVar CPUSX20, CPUSX28;
static LongInt Reg_FSR, Reg_STATUS;
/*---------------------------------------------------------------------------*/
static Boolean DecodeRegLinear(const tStrComp *pArg, int Offset, Word *pResult, tEvalResult *pEvalResult)
{
*pResult = EvalStrIntExpressionOffsWithResult(pArg, Offset, UInt8, pEvalResult);
if (pEvalResult->OK)
ChkSpace(SegData, pEvalResult->AddrSpaceMask);
return pEvalResult->OK;
}
static Word Lin2PagedRegAddr(const tStrComp *pArg, Word LinAddr, tSymbolFlags Flags)
{
if (!mFirstPassUnknown(Flags) && (LinAddr & 0x10))
{
if ((Reg_FSR & 0xf0) != (LinAddr & 0xf0))
WrStrErrorPos(ErrNum_InAccPage, pArg);
}
return LinAddr & 0x1f;
}
static Boolean DecodeReg(const tStrComp *pArg, int Offset, Word *pResult)
{
tEvalResult EvalResult;
if (!DecodeRegLinear(pArg, Offset, pResult, &EvalResult))
return False;
*pResult = Lin2PagedRegAddr(pArg, *pResult, EvalResult.Flags);
return True;
}
static Boolean DecodeRegAppendix(tStrComp *pArg, const char *pAppendix, Word *pResult)
{
int ArgLen
= strlen(pArg
->str.
p_str), AppLen
= strlen(pAppendix
);
Boolean Result = False;
if ((ArgLen > AppLen) && !as_strcasecmp(pArg->str.p_str + (ArgLen - AppLen), pAppendix))
{
char Save = pArg->str.p_str[ArgLen - AppLen];
pArg->str.p_str[ArgLen - AppLen] = '\0';
pArg->Pos.Len -= AppLen;
Result = DecodeReg(pArg, 0, pResult);
pArg->str.p_str[ArgLen - AppLen] = Save;
pArg->Pos.Len += AppLen;
}
return Result;
}
/* NOTE: bit symbols have bit position in lower three bits, opposed
to machine coding. Done this way because incrementing makes more
sense this way. */
static Word AssembleBitSymbol(Word RegAddr, Word BitPos)
{
return ((RegAddr & 0xff) << 3) | (BitPos & 7);
}
static void SplitBitSymbol(Word BitSymbol, Word *pRegAddr, Word *pBitPos)
{
*pRegAddr = (BitSymbol >> 3) & 0xff;
*pBitPos = BitSymbol & 7;
}
/*!------------------------------------------------------------------------
* \fn DissectBit_SX20(char *pDest, size_t DestSize, LargeWord Inp)
* \brief dissect compact storage of bit into readable form for listing
* \param pDest destination for ASCII representation
* \param DestSize destination buffer size
* \param Inp compact storage
* ------------------------------------------------------------------------ */
static void DissectBit_SX20(char *pDest, size_t DestSize, LargeWord Inp)
{
Word BitPos, Address;
SplitBitSymbol(Inp, &Address, &BitPos);
as_snprintf(pDest, DestSize, "$%x.%u", (unsigned)Address, (unsigned)BitPos);
}
/*!------------------------------------------------------------------------
* \fn DecodeBitSymbol(const tStrComp *pArg, Word *pBitSymbol)
* \brief decode a bit expression and return in internal format
* \param pArg bit spec in source code
* \param pBitSymbol returns bit in internal format
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean DecodeBitSymbol(const tStrComp *pArg, Word *pBitSymbol, tEvalResult *pEvalResult)
{
char *pSplit;
pSplit
= strchr(pArg
->str.
p_str, '.');
if (!pSplit)
{
*pBitSymbol = EvalStrIntExpressionWithResult(pArg, UInt11, pEvalResult);
if (pEvalResult->OK)
ChkSpace(SegBData, pEvalResult->AddrSpaceMask);
return pEvalResult->OK;
}
else
{
tStrComp RegArg, BitArg;
Boolean BitOK, RegOK;
Word BitPos, RegAddr;
StrCompSplitRef(&RegArg, &BitArg, pArg, pSplit);
BitPos = EvalStrIntExpression(&BitArg, UInt3, &BitOK);
RegOK = DecodeRegLinear(&RegArg, 0, &RegAddr, pEvalResult);
*pBitSymbol = AssembleBitSymbol(RegAddr, BitPos);
return BitOK && RegOK;
}
}
static Boolean DecodeRegBitPacked(const tStrComp *pArg, Word *pPackedResult)
{
Word BitSymbol, RegAddr, BitPos;
tEvalResult EvalResult;
if (!DecodeBitSymbol(pArg, &BitSymbol, &EvalResult))
return False;
SplitBitSymbol(BitSymbol, &RegAddr, &BitPos);
*pPackedResult = (BitPos << 5) | Lin2PagedRegAddr(pArg, RegAddr, EvalResult.Flags);
return True;
}
/*---------------------------------------------------------------------------*/
static void DecodeFixed(Word Code)
{
if (ChkArgCnt(0, 0))
WAsmCode[CodeLen++] = Code;
}
static void DecodeOneReg(Word Code)
{
Word Reg;
if (ChkArgCnt(1, 1)
&& DecodeReg(&ArgStr[1], 0, &Reg))
WAsmCode[CodeLen++] = Code | Reg;
}
static void DecodeNOT(Word Code)
{
if (!ChkArgCnt(1, 1))
return;
if (!as_strcasecmp(ArgStr[1].str.p_str, "W"))
WAsmCode[CodeLen++] = 0xfff;
else
DecodeOneReg(Code);
}
static void DecodeMOV(Word Code)
{
Word Reg;
Boolean OK;
UNUSED(Code);
if (!ChkArgCnt(2, 2))
return;
if (!as_strcasecmp(ArgStr[1].str.p_str, "W"))
{
if (*ArgStr[2].str.p_str == '#')
{
Reg = EvalStrIntExpressionOffs(&ArgStr[2], 1, Int8, &OK);
if (OK)
WAsmCode[CodeLen++] = 0xc00 | (Reg & 0xff);
}
else if (!as_strcasecmp(ArgStr[2].str.p_str, "M"))
WAsmCode[CodeLen++] = 0x042;
else if (!strncmp(ArgStr
[2].
str.
p_str, "/", 1) && DecodeReg
(&ArgStr
[2], 1, &Reg
))
WAsmCode[CodeLen++] = 0x240 | Reg;
else if (!strncmp(ArgStr
[2].
str.
p_str, "--", 2) && DecodeReg
(&ArgStr
[2], 2, &Reg
))
WAsmCode[CodeLen++] = 0x0c0 | Reg;
else if (!strncmp(ArgStr
[2].
str.
p_str, "++", 2) && DecodeReg
(&ArgStr
[2], 2, &Reg
))
WAsmCode[CodeLen++] = 0x280 | Reg;
else if (!strncmp(ArgStr
[2].
str.
p_str, "<<", 2) && DecodeReg
(&ArgStr
[2], 2, &Reg
))
WAsmCode[CodeLen++] = 0x340 | Reg;
else if (!strncmp(ArgStr
[2].
str.
p_str, ">>", 2) && DecodeReg
(&ArgStr
[2], 2, &Reg
))
WAsmCode[CodeLen++] = 0x300 | Reg;
else if (!strncmp(ArgStr
[2].
str.
p_str, "<>", 2) && DecodeReg
(&ArgStr
[2], 2, &Reg
))
WAsmCode[CodeLen++] = 0x380 | Reg;
else if (DecodeRegAppendix(&ArgStr[2], "-W", &Reg))
WAsmCode[CodeLen++] = 0x080 | Reg;
else if (DecodeReg(&ArgStr[2], 0, &Reg))
WAsmCode[CodeLen++] = 0x200 | Reg;
}
else if (!as_strcasecmp(ArgStr[2].str.p_str, "W"))
{
if (!as_strcasecmp(ArgStr[1].str.p_str, "!OPTION"))
WAsmCode[CodeLen++] = 0x002;
else if (!as_strcasecmp(ArgStr[1].str.p_str, "M"))
WAsmCode[CodeLen++] = 0x003;
else if (!strncmp(ArgStr
[1].
str.
p_str, "!", 1) && DecodeReg
(&ArgStr
[1], 1, &Reg
))
{
if (ChkRange(Reg, 0, 7))
WAsmCode[CodeLen++] = 0x000 | Reg;
}
else if (DecodeReg(&ArgStr[1], 0, &Reg))
WAsmCode[CodeLen++] = 0x020 | Reg;
}
else if (!as_strcasecmp(ArgStr[1].str.p_str, "M"))
{
if (*ArgStr[2].str.p_str == '#')
{
Reg = EvalStrIntExpressionOffs(&ArgStr[2], 1, Int4, &OK);
if (OK)
WAsmCode[CodeLen++] = 0x050 | (Reg & 0xf);
}
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
}
else
WrError(ErrNum_InvAddrMode);
}
static void DecodeMOVSZ(Word Code)
{
Word Reg;
UNUSED(Code);
if (!ChkArgCnt(2, 2))
return;
if (!as_strcasecmp(ArgStr[1].str.p_str, "W"))
{
if (!strncmp(ArgStr
[2].
str.
p_str, "--", 2) && DecodeReg
(&ArgStr
[2], 2, &Reg
))
WAsmCode[CodeLen++] = 0x2c0 | Reg;
else if (!strncmp(ArgStr
[2].
str.
p_str, "++", 2) && DecodeReg
(&ArgStr
[2], 2, &Reg
))
WAsmCode[CodeLen++] = 0x3c0 | Reg;
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
}
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
}
static void DecodeLogic(Word Code)
{
Word Arg;
if (!ChkArgCnt(2, 2))
return;
if (!as_strcasecmp(ArgStr[1].str.p_str, "W"))
{
if (*ArgStr[2].str.p_str == '#')
{
Word ImmCode = Code & 0x0f00;
if (ImmCode)
{
Boolean OK;
Arg = EvalStrIntExpressionOffs(&ArgStr[2], 1, Int8, &OK);
if (OK)
WAsmCode[CodeLen++] = ImmCode | (Arg & 0xff);
}
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
}
else if (DecodeReg(&ArgStr[2], 0, &Arg))
WAsmCode[CodeLen++] = (Lo(Code) << 4) | Arg;
}
else if (!as_strcasecmp(ArgStr[2].str.p_str, "W"))
{
if (DecodeReg(&ArgStr[1], 0, &Arg))
WAsmCode[CodeLen++] = (Lo(Code) << 4) | 0x20 | Arg;
}
else
WrError(ErrNum_InvAddrMode);
}
static void DecodeCLR(Word Code)
{
Word Arg;
UNUSED(Code);
if (!ChkArgCnt(1, 1))
return;
if (!as_strcasecmp(ArgStr[1].str.p_str, "W"))
WAsmCode[CodeLen++] = 0x040;
else if (!as_strcasecmp(ArgStr[1].str.p_str, "!WDT"))
WAsmCode[CodeLen++] = 0x004;
else if (DecodeReg(&ArgStr[1], 0, &Arg))
WAsmCode[CodeLen++] = 0x060 | Arg;
}
static void DecodeSUB(Word Code)
{
Word Arg;
if (!ChkArgCnt(2, 2))
return;
if (!as_strcasecmp(ArgStr[2].str.p_str, "W"))
{
if (DecodeReg(&ArgStr[1], 0, &Arg))
WAsmCode[CodeLen++] = (Lo(Code) << 4) | 0x20 | Arg;
}
else
WrError(ErrNum_InvAddrMode);
}
static void DecodeBit(Word Code)
{
Word BitArg;
if (!ChkArgCnt(1, 1))
return;
if (DecodeRegBitPacked(&ArgStr[1], &BitArg))
WAsmCode[CodeLen++] = Code | BitArg;
}
static void DecodeJMP_CALL(Word Code)
{
Word Addr;
Boolean IsCall = (Code == 0x900);
tEvalResult EvalResult;
if (!ChkArgCnt(1, 1))
return;
if (!IsCall)
{
if (!as_strcasecmp(ArgStr[1].str.p_str, "W"))
{
WAsmCode[CodeLen++] = 0x022;
return;
}
else if (!as_strcasecmp(ArgStr[1].str.p_str, "PC+W"))
{
WAsmCode[CodeLen++] = 0x1e2;
return;
}
}
Addr = EvalStrIntExpressionWithResult(&ArgStr[1], UInt11, &EvalResult);
if (!EvalResult.OK)
return;
if (!mFirstPassUnknown(EvalResult.Flags) && IsCall && (Addr & 0x100)) WrStrErrorPos(ErrNum_NotFromThisAddress, &ArgStr[1]);
else
{
if (!mFirstPassUnknown(EvalResult.Flags) && ((Reg_STATUS & 0xe0) != ((Addr >> 4) & 0xe0))) WrStrErrorPos(ErrNum_InAccPage, &ArgStr[1]);
WAsmCode[CodeLen++] = Code | (Addr & 0x1ff);
ChkSpace(SegCode, EvalResult.AddrSpaceMask);
}
}
static void DecodeRETW(Word Code)
{
Boolean OK;
Word Arg;
if (!ChkArgCnt(1, 1))
return;
Arg = EvalStrIntExpression(&ArgStr[1], Int8, &OK);
if (OK)
WAsmCode[CodeLen++] = Code | Arg;
}
static void DecodeBANK(Word Code)
{
Word Arg;
tEvalResult EvalResult;
if (!ChkArgCnt(1, 1))
return;
Arg = EvalStrIntExpressionWithResult(&ArgStr[1], UInt8, &EvalResult);
if (EvalResult.OK)
{
WAsmCode[CodeLen++] = Code | ((Arg >> 5) & 7);
ChkSpace(SegData, EvalResult.AddrSpaceMask);
}
}
static void DecodePAGE(Word Code)
{
tEvalResult EvalResult;
Word Arg;
if (!ChkArgCnt(1, 1))
return;
Arg = EvalStrIntExpressionWithResult(&ArgStr[1], UInt12, &EvalResult);
if (EvalResult.OK)
{
WAsmCode[CodeLen++] = Code | ((Arg >> 9) & 7);
ChkSpace(SegCode, EvalResult.AddrSpaceMask);
}
}
static void DecodeMODE(Word Code)
{
tEvalResult EvalResult;
Word Arg;
if (!ChkArgCnt(1, 1))
return;
Arg = EvalStrIntExpressionWithResult(&ArgStr[1], Int4, &EvalResult);
if (EvalResult.OK)
{
WAsmCode[CodeLen++] = Code | Arg;
ChkSpace(SegCode, EvalResult.AddrSpaceMask);
}
}
static void DecodeSKIP(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(0, 0))
return;
WAsmCode[CodeLen++] = EProgCounter() & 1 ? 0x702 : 0x602;
}
static void DecodeSFR(Word Code)
{
UNUSED(Code);
CodeEquate(SegData, 0, 0xff);
}
static void DecodeBIT(Word Code)
{
Word BitSymbol;
tEvalResult EvalResult;
UNUSED(Code);
if (ChkArgCnt(1, 1)
&& DecodeBitSymbol(&ArgStr[1], &BitSymbol, &EvalResult))
{
*ListLine = '=';
DissectBit_SX20(ListLine + 1, STRINGSIZE - 3, BitSymbol);
PushLocHandle(-1);
EnterIntSymbol(&LabPart, BitSymbol, SegBData, False);
PopLocHandle();
/* TODO: MakeUseList? */
}
}
static void DecodeDATA_SX20(Word Code)
{
UNUSED(Code);
DecodeDATA(Int12, Int8);
}
static void DecodeZERO(Word Code)
{
Word Size;
Boolean ValOK;
tSymbolFlags Flags;
UNUSED(Code);
if (ChkArgCnt(1, 1))
{
Size = EvalStrIntExpressionWithFlags(&ArgStr[1], Int16, &ValOK, &Flags);
if (mFirstPassUnknown(Flags)) WrError(ErrNum_FirstPassCalc);
if (ValOK && !mFirstPassUnknown(Flags))
{
if (SetMaxCodeLen(Size << 1)) WrError(ErrNum_CodeOverflow);
else
{
CodeLen = Size;
memset(WAsmCode
, 0, 2 * Size
);
}
}
}
}
/*---------------------------------------------------------------------------*/
static void InitFields(void)
{
InstTable = CreateInstTable(103);
AddInstTable(InstTable, "NOP" , NOPCode, DecodeFixed);
AddInstTable(InstTable, "RET" , 0x00c, DecodeFixed);
AddInstTable(InstTable, "RETP" , 0x00d, DecodeFixed);
AddInstTable(InstTable, "RETI" , 0x00e, DecodeFixed);
AddInstTable(InstTable, "RETIW", 0x00f, DecodeFixed);
AddInstTable(InstTable, "IREAD", 0x041, DecodeFixed);
AddInstTable(InstTable, "SLEEP", 0x003, DecodeFixed);
AddInstTable(InstTable, "CLC" , 0x403, DecodeFixed);
AddInstTable(InstTable, "CLZ" , 0x443, DecodeFixed);
AddInstTable(InstTable, "SEC" , 0x503, DecodeFixed);
AddInstTable(InstTable, "SEZ" , 0x543, DecodeFixed);
AddInstTable(InstTable, "SC" , 0x703, DecodeFixed);
AddInstTable(InstTable, "SZ" , 0x743, DecodeFixed);
AddInstTable(InstTable, "DEC" , 0x0e0, DecodeOneReg);
AddInstTable(InstTable, "INC" , 0x2a0, DecodeOneReg);
AddInstTable(InstTable, "DECSZ", 0x2e0, DecodeOneReg);
AddInstTable(InstTable, "INCSZ", 0x3e0, DecodeOneReg);
AddInstTable(InstTable, "RL" , 0x360, DecodeOneReg);
AddInstTable(InstTable, "RR" , 0x320, DecodeOneReg);
AddInstTable(InstTable, "SWAP" , 0x3a0, DecodeOneReg);
AddInstTable(InstTable, "TEST" , 0x220, DecodeOneReg);
AddInstTable(InstTable, "NOT" , 0x260, DecodeNOT);
AddInstTable(InstTable, "MOV" , 0, DecodeMOV);
AddInstTable(InstTable, "MOVSZ", 0, DecodeMOVSZ);
AddInstTable(InstTable, "AND" , 0x0e14, DecodeLogic);
AddInstTable(InstTable, "OR" , 0x0d10, DecodeLogic);
AddInstTable(InstTable, "XOR" , 0x0f18, DecodeLogic);
AddInstTable(InstTable, "ADD" , 0x001c, DecodeLogic);
AddInstTable(InstTable, "SUB" , 0x000a, DecodeSUB);
AddInstTable(InstTable, "CLR" , 0, DecodeCLR);
AddInstTable(InstTable, "CLRB" , 0x0400, DecodeBit);
AddInstTable(InstTable, "SB" , 0x0700, DecodeBit);
AddInstTable(InstTable, "SETB" , 0x0500, DecodeBit);
AddInstTable(InstTable, "SNB" , 0x0600, DecodeBit);
AddInstTable(InstTable, "CALL" , 0x0900, DecodeJMP_CALL);
AddInstTable(InstTable, "JMP" , 0x0a00, DecodeJMP_CALL);
AddInstTable(InstTable, "SKIP" , 0 , DecodeSKIP);
AddInstTable(InstTable, "RETW" , 0x0800, DecodeRETW);
AddInstTable(InstTable, "BANK" , 0x0800, DecodeBANK);
AddInstTable(InstTable, "PAGE" , 0x0010, DecodePAGE);
AddInstTable(InstTable, "MODE" , 0x0050, DecodeMODE);
AddInstTable(InstTable, "SFR" , 0, DecodeSFR);
AddInstTable(InstTable, "BIT" , 0, DecodeBIT);
AddInstTable(InstTable, "DATA" , 0, DecodeDATA_SX20);
AddInstTable(InstTable, "ZERO" , 0, DecodeZERO);
AddInstTable(InstTable, "RES" , 0, DecodeRES);
}
static void DeinitFields(void)
{
DestroyInstTable(InstTable);
}
/*---------------------------------------------------------------------------*/
static void MakeCode_SX20(void)
{
CodeLen = 0; DontPrint = False;
/* zu ignorierendes */
if (Memo("")) return;
if (!LookupInstTable(InstTable, OpPart.str.p_str))
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
}
static void SwitchFrom_SX20(void)
{
DeinitFields();
}
static Boolean IsDef_SX20(void)
{
return Memo("SFR") || Memo("BIT");
}
static void SwitchTo_SX20(void)
{
const TFamilyDescr *pDescr = FindFamilyByName("SX20");
#define ASSUMESX20Count (sizeof(ASSUMESX20s) / sizeof(*ASSUMESX20s))
static const ASSUMERec ASSUMESX20s[] =
{
{ "FSR" , &Reg_FSR , 0, 0xff, 0, NULL },
{ "STATUS", &Reg_STATUS, 0, 0xff, 0, NULL },
};
TurnWords = False;
SetIntConstMode(eIntConstModeMoto);
PCSymbol = "*";
HeaderID = pDescr->Id;
NOPCode = 0x000;
DivideChars = ",";
HasAttrs = False;
PageIsOccupied = True;
ValidSegs = (1 << SegCode) + (1 << SegData);
Grans[SegCode] = 2; ListGrans[SegCode] = 2; SegInits[SegCode] = 0;
SegLimits[SegCode] = 2047;
Grans[SegData] = 1; ListGrans[SegData] = 1; SegInits[SegCode] = 0;
SegLimits[SegData] = 0xff;
MakeCode = MakeCode_SX20;
IsDef = IsDef_SX20;
SwitchFrom = SwitchFrom_SX20;
DissectBit = DissectBit_SX20;
InitFields();
pASSUMERecs = ASSUMESX20s;
ASSUMERecCnt = ASSUMESX20Count;
}
void codesx20_init(void)
{
CPUSX20 = AddCPU("SX20", SwitchTo_SX20);
CPUSX28 = AddCPU("SX28", SwitchTo_SX20);
}