/* code16c8x.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* AS-Codegenerator PIC16C8x */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <string.h>
#include "chunks.h"
#include "bpemu.h"
#include "strutil.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmitree.h"
#include "headids.h"
#include "codepseudo.h"
#include "fourpseudo.h"
#include "codevars.h"
#include "errmsg.h"
#include "code16c8x.h"
/*---------------------------------------------------------------------------*/
#define AddCodeSpace 0x300
static CPUVar CPU16C64, CPU16C84, CPU16C873, CPU16C874, CPU16C876, CPU16C877;
/*--------------------------------------------------------------------------*/
/* helper functions */
static Word EvalFExpression(tStrComp *pArg, tEvalResult *pEvalResult)
{
LongInt h;
h = EvalStrIntExpressionWithResult(pArg, UInt9, pEvalResult);
if (pEvalResult->OK)
{
ChkSpace(SegData, pEvalResult->AddrSpaceMask);
return (h & 0x7f);
}
else
return 0;
}
/*--------------------------------------------------------------------------*/
/* instruction decoders */
static void DecodeFixed(Word Code)
{
if (ChkArgCnt(0, 0))
{
WAsmCode[CodeLen++] = Code;
if (Memo("OPTION"))
WrError(ErrNum_Obsolete);
}
}
static void DecodeLit(Word Code)
{
Word AdrWord;
Boolean OK;
if (ChkArgCnt(1, 1))
{
AdrWord = EvalStrIntExpression(&ArgStr[1], Int8, &OK);
if (OK)
WAsmCode[CodeLen++] = Code | Lo(AdrWord);
}
}
static void DecodeAri(Word Code)
{
Word DefaultDir = (Code >> 8) & 0x80;
tEvalResult EvalResult;
Word AdrWord;
Code &= 0x7fff;
if (ChkArgCnt(1, 2))
{
AdrWord = EvalFExpression(&ArgStr[1], &EvalResult);
if (EvalResult.OK)
{
WAsmCode[0] = Code | AdrWord;
if (1 == ArgCnt)
{
WAsmCode[0] |= DefaultDir;
CodeLen = 1;
}
else if (!as_strcasecmp(ArgStr[2].str.p_str, "W"))
CodeLen = 1;
else if (!as_strcasecmp(ArgStr[2].str.p_str, "F"))
{
WAsmCode[0] |= 0x80;
CodeLen = 1;
}
else
{
AdrWord = EvalStrIntExpressionWithResult(&ArgStr[2], UInt1, &EvalResult);
if (EvalResult.OK)
{
WAsmCode[0] |= AdrWord << 7;
CodeLen = 1;
}
}
}
}
}
static void DecodeBit(Word Code)
{
if (ChkArgCnt(2, 2))
{
tEvalResult EvalResult;
Word AdrWord = EvalStrIntExpressionWithResult(&ArgStr[2], UInt3, &EvalResult);
if (EvalResult.OK)
{
WAsmCode[0] = EvalFExpression(&ArgStr[1], &EvalResult);
if (EvalResult.OK)
{
WAsmCode[0] |= Code | (AdrWord << 7);
CodeLen = 1;
}
}
}
}
static void DecodeF(Word Code)
{
if (ChkArgCnt(1, 1))
{
tEvalResult EvalResult;
Word AdrWord = EvalFExpression(&ArgStr[1], &EvalResult);
if (EvalResult.OK)
WAsmCode[CodeLen++] = Code | AdrWord;
}
}
static void DecodeTRIS(Word Index)
{
Word AdrWord;
tEvalResult EvalResult;
UNUSED(Index);
if (ChkArgCnt(1, 1))
{
AdrWord = EvalStrIntExpressionWithResult(&ArgStr[1], UInt3, &EvalResult);
if (mFirstPassUnknown(EvalResult.Flags))
AdrWord = 5;
if (EvalResult.OK)
if (ChkRange(AdrWord, 5, 6))
{
WAsmCode[CodeLen++] = 0x0060 | AdrWord;
ChkSpace(SegData, EvalResult.AddrSpaceMask);
WrError(ErrNum_Obsolete);
}
}
}
static void DecodeJump(Word Index)
{
if (ChkArgCnt(1, 1))
{
tEvalResult EvalResult;
Word AdrWord = EvalStrIntExpressionWithResult(&ArgStr[1], Int16, &EvalResult);
if (EvalResult.OK)
{
if (AdrWord > (SegLimits[SegCode] - AddCodeSpace)) WrError(ErrNum_OverRange);
else
{
Word XORVal, Mask, RegBit;
ChkSpace(SegCode, EvalResult.AddrSpaceMask);
XORVal = (ProgCounter() ^ AdrWord) & ~0x7ff;
/* add BCF/BSF instruction for non-matching upper address bits
- we might need to extend this for the PICs with more than
8K of program space */
for (RegBit = 3, Mask = 0x800; RegBit <= 4; RegBit++, Mask <<= 1)
if (XORVal & Mask)
WAsmCode[CodeLen++] = 0x100a
| (RegBit << 7)
| ((AdrWord & Mask) >> (RegBit - 2));
WAsmCode[CodeLen++] = Index | (AdrWord & 0x7ff);
}
}
}
}
static void DecodeSFR(Word Index)
{
UNUSED(Index);
CodeEquate(SegData, 0, 511);
}
static void DecodeDATA_16C8x(Word Index)
{
UNUSED(Index);
DecodeDATA(Int14, Int8);
}
static void DecodeZERO(Word Index)
{
Word Size, Shift = (ActPC == SegCode) ? 1 : 0;
Boolean ValOK;
tSymbolFlags Flags;
UNUSED(Index);
if (ChkArgCnt(1, 1))
{
Size = EvalStrIntExpressionWithFlags(&ArgStr[1], Int16, &ValOK, &Flags);
if (mFirstPassUnknown(Flags)) WrError(ErrNum_FirstPassCalc);
if (ValOK && !mFirstPassUnknown(Flags))
{
if (SetMaxCodeLen(Size << Shift)) WrError(ErrNum_CodeOverflow);
else
{
CodeLen = Size;
memset(WAsmCode
, 0, Size
<< Shift
);
}
}
}
}
static void DecodeBANKSEL(Word Index)
{
Word Adr;
Boolean ValOK;
UNUSED(Index);
if (ChkArgCnt(1, 1))
{
Adr = EvalStrIntExpression(&ArgStr[1], UInt9, &ValOK);
if (ValOK)
{
WAsmCode[0] = 0x1283 | ((Adr & 0x80) << 3); /* BxF Status, 5 */
WAsmCode[1] = 0x1303 | ((Adr & 0x100) << 2); /* BxF Status, 6 */
CodeLen = 2;
}
}
}
/*--------------------------------------------------------------------------*/
/* dynamic code table handling */
static void AddFixed(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeFixed);
}
static void AddLit(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeLit);
}
static void AddAri(const char *NName, Word NCode, Word NDir)
{
AddInstTable(InstTable, NName, NCode | (NDir << 15), DecodeAri);
}
static void AddBit(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeBit);
}
static void AddF(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeF);
}
static void InitFields(void)
{
InstTable = CreateInstTable(201);
AddFixed("CLRW" , 0x0100);
AddFixed("NOP" , 0x0000);
AddFixed("CLRWDT", 0x0064);
AddFixed("OPTION", 0x0062);
AddFixed("SLEEP" , 0x0063);
AddFixed("RETFIE", 0x0009);
AddFixed("RETURN", 0x0008);
AddLit("ADDLW", 0x3e00);
AddLit("ANDLW", 0x3900);
AddLit("IORLW", 0x3800);
AddLit("MOVLW", 0x3000);
AddLit("RETLW", 0x3400);
AddLit("SUBLW", 0x3c00);
AddLit("XORLW", 0x3a00);
AddAri("ADDWF" , 0x0700, 0);
AddAri("ANDWF" , 0x0500, 0);
AddAri("COMF" , 0x0900, 1);
AddAri("DECF" , 0x0300, 1);
AddAri("DECFSZ", 0x0b00, 1);
AddAri("INCF" , 0x0a00, 1);
AddAri("INCFSZ", 0x0f00, 1);
AddAri("IORWF" , 0x0400, 0);
AddAri("MOVF" , 0x0800, 0);
AddAri("RLF" , 0x0d00, 1);
AddAri("RRF" , 0x0c00, 1);
AddAri("SUBWF" , 0x0200, 0);
AddAri("SWAPF" , 0x0e00, 1);
AddAri("XORWF" , 0x0600, 0);
AddBit("BCF" , 0x1000);
AddBit("BSF" , 0x1400);
AddBit("BTFSC", 0x1800);
AddBit("BTFSS", 0x1c00);
AddF("CLRF" , 0x0180);
AddF("MOVWF", 0x0080);
AddInstTable(InstTable, "TRIS", 0, DecodeTRIS);
AddInstTable(InstTable, "GOTO", 0x2800, DecodeJump);
AddInstTable(InstTable, "CALL", 0x2000, DecodeJump);
AddInstTable(InstTable, "SFR" , 0, DecodeSFR);
AddInstTable(InstTable, "RES" , 0, DecodeRES);
AddInstTable(InstTable, "DATA", 0, DecodeDATA_16C8x);
AddInstTable(InstTable, "ZERO", 0, DecodeZERO);
AddInstTable(InstTable, "BANKSEL", 0, DecodeBANKSEL);
}
static void DeinitFields(void)
{
DestroyInstTable(InstTable);
}
/*--------------------------------------------------------------------------*/
static void MakeCode_16c8x(void)
{
CodeLen = 0; DontPrint = False;
/* zu ignorierendes */
if (Memo("")) return;
/* seek instruction */
if (!LookupInstTable(InstTable, OpPart.str.p_str))
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
}
static Boolean IsDef_16c8x(void)
{
return (Memo("SFR"));
}
static Boolean ChkPC_16c8x(LargeWord Addr)
{
if ((ActPC == SegCode) && (Addr > (LargeWord)SegLimits[SegCode]))
return ((Addr >= 0x2000) && (Addr <= 0x2007));
else
return (Addr <= (LargeWord)SegLimits[ActPC]);
}
static void SwitchFrom_16c8x(void)
{
DeinitFields();
}
static void SwitchTo_16c8x(void)
{
const TFamilyDescr *pDescr;
TurnWords = False;
SetIntConstMode(eIntConstModeMoto);
pDescr = FindFamilyByName("16C8x");
PCSymbol = "*";
HeaderID = pDescr->Id;
NOPCode = 0x0000;
DivideChars = ",";
HasAttrs = False;
ValidSegs = (1 << SegCode) | (1 << SegData);
Grans[SegCode] = 2; ListGrans[SegCode] = 2; SegInits[SegCode] = 0;
if (MomCPU == CPU16C64)
SegLimits[SegCode] = 0x7ff;
else if (MomCPU == CPU16C873)
SegLimits[SegCode] = 0x0fff;
else if (MomCPU == CPU16C874)
SegLimits[SegCode] = 0x0fff;
else if (MomCPU == CPU16C876)
SegLimits[SegCode] = 0x1fff;
else if (MomCPU == CPU16C877)
SegLimits[SegCode] = 0x1fff;
else
SegLimits[SegCode] = 0x3ff;
SegLimits[SegCode] += AddCodeSpace;
Grans[SegData] = 1; ListGrans[SegData] = 1; SegInits[SegData] = 0;
SegLimits[SegData] = 0x1ff;
Grans[SegEEData] = 1; ListGrans[SegEEData] = 1; SegInits[SegEEData] = 0;
if ((MomCPU == CPU16C877) || (MomCPU == CPU16C876))
SegLimits[SegEEData] = 0xff;
else if ((MomCPU == CPU16C874) || (MomCPU == CPU16C873))
SegLimits[SegEEData] = 0x7f;
else
SegLimits[SegEEData] = 0x3f;
ChkPC = ChkPC_16c8x;
MakeCode = MakeCode_16c8x;
IsDef = IsDef_16c8x;
SwitchFrom = SwitchFrom_16c8x;
InitFields();
}
void code16c8x_init(void)
{
CPU16C64 = AddCPU("16C64", SwitchTo_16c8x);
CPU16C84 = AddCPU("16C84", SwitchTo_16c8x);
CPU16C873 = AddCPU("16C873", SwitchTo_16c8x);
CPU16C874 = AddCPU("16C874", SwitchTo_16c8x);
CPU16C876 = AddCPU("16C876", SwitchTo_16c8x);
CPU16C877 = AddCPU("16C877", SwitchTo_16c8x);
}