/* codekcpsm.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Codegenerator Xilinx kcpsm */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "nls.h"
#include "strutil.h"
#include "bpemu.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmitree.h"
#include "asmallg.h"
#include "intpseudo.h"
#include "codevars.h"
#include "headids.h"
#include "errmsg.h"
#include "codekcpsm.h"
#undef DEBUG_PRINTF
typedef struct
{
const char *Name;
Word Code;
} Condition;
#define WorkOfs 0xe0
#define COND_CODE_TRUE 0
#define IOopCnt 2
#define ModNone (-1)
#define ModWReg 0
#define MModWReg (1 << ModWReg)
#define ModAbs 1
#define MModAbs (1 << ModAbs)
#define ModImm 4
#define MModImm (1 << ModImm)
#define ModIRReg 6
#define MModIRReg (1 << ModIRReg)
#define ModInd 7
#define MModInd (1 << ModInd)
static ShortInt AdrType;
static Word AdrMode,AdrIndex;
static Condition *Conditions;
static CPUVar CPUKCPSM;
/*--------------------------------------------------------------------------*/
/* Code Helpers */
/*!------------------------------------------------------------------------
* \fn IsWRegCore(const char *pArg, Word *pResult)
* \brief check whether argument is CPU register
* \param pArg argument
* \param pResult register number if it is
* \return True if it is
* ------------------------------------------------------------------------ */
static Boolean IsWRegCore(const char *pArg, Word *pResult)
{
Boolean retValue;
if ((strlen(pArg
) < 2) || (as_toupper
(*pArg
) != 'S'))
retValue = False;
else
{
Boolean OK;
*pResult = ConstLongInt(pArg + 1, &OK, 10);
if (!OK)
retValue = False;
else
retValue = (*pResult <= 15);
}
#ifdef DEBUG_PRINTF
fprintf( stderr
, "IsWRegCore: %s %d\n", Asc
, retValue
);
#endif
return retValue;
}
/*!------------------------------------------------------------------------
* \fn DissectReg_KCPSM(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
* \brief dissect register symbols - KCPSM3 variant
* \param pDest destination buffer
* \param DestSize destination buffer size
* \param Value numeric register value
* \param InpSize register size
* ------------------------------------------------------------------------ */
static void DissectReg_KCPSM(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
{
switch (InpSize)
{
case eSymbolSize8Bit:
as_snprintf(pDest, DestSize, "S%x", (unsigned)Value);
pDest[1] = as_toupper(pDest[1]);
break;
default:
as_snprintf(pDest, DestSize, "%d-%u", (int)InpSize, (unsigned)Value);
}
}
/*!------------------------------------------------------------------------
* \fn IsWReg(const tStrComp *pArg, Word *pResult, Boolean MustBeReg)
* \brief check whether argument is CPU register, including register aliases
* \param pArg argument
* \param pResult register number if it is
* \param MustBeReg expecting register as arg?
* \return reg eval result
* ------------------------------------------------------------------------ */
static tRegEvalResult IsWReg(const tStrComp *pArg, Word *pResult, Boolean MustBeReg)
{
tRegDescr RegDescr;
tEvalResult EvalResult;
tRegEvalResult RegEvalResult;
if (IsWRegCore(pArg->str.p_str, pResult))
return eIsReg;
RegEvalResult = EvalStrRegExpressionAsOperand(pArg, &RegDescr, &EvalResult, eSymbolSize8Bit, MustBeReg);
*pResult = RegDescr.Reg;
return RegEvalResult;
}
static void DecodeAdr(const tStrComp *pArg, Byte Mask, int Segment)
{
tEvalResult EvalResult;
char *p;
int ArgLen;
AdrType = ModNone;
/* immediate ? */
if (*pArg->str.p_str == '#')
{
AdrMode = EvalStrIntExpressionOffsWithResult(pArg, 1, UInt8, &EvalResult);
if (EvalResult.OK)
AdrType = ModImm;
goto chk;
}
/* Register ? */
switch (IsWReg(pArg, &AdrMode, False))
{
case eIsReg:
AdrType = ModWReg;
goto chk;
case eIsNoReg:
break;
case eRegAbort:
return;
}
/* indiziert ? */
ArgLen
= strlen(pArg
->str.
p_str);
if ((ArgLen >= 4) && (pArg->str.p_str[ArgLen - 1] == ')'))
{
p = pArg->str.p_str + ArgLen - 1;
while ((p >= pArg->str.p_str) && (*p != '('))
p--;
if (*p != '(') WrError(ErrNum_BrackErr);
else
{
tStrComp RegComp, DispComp;
StrCompSplitRef(&DispComp, &RegComp, pArg, p);
StrCompShorten(&RegComp, 1);
if (IsWReg(&RegComp, &AdrMode, True) == eIsReg)
{
AdrIndex = EvalStrIntExpressionWithResult(&DispComp, UInt8, &EvalResult);
if (EvalResult.OK)
{
AdrType = ModInd;
ChkSpace(SegData, EvalResult.AddrSpaceMask);
}
goto chk;
}
}
}
/* einfache direkte Adresse ? */
AdrMode = EvalStrIntExpressionWithResult(pArg, UInt8, &EvalResult);
if (EvalResult.OK)
{
AdrType = ModAbs;
if (Segment != SegNone)
ChkSpace(Segment, EvalResult.AddrSpaceMask);
goto chk;
}
chk:
if ((AdrType != ModNone) && ((Mask & (1 << AdrType)) == 0))
{
WrError(ErrNum_InvAddrMode);
AdrType = ModNone;
}
}
static Boolean DecodeCond(char *Asc, Word *p_code)
{
int Cond;
for (Cond = 0; Conditions[Cond].Name; Cond++)
if (!strcmp(Conditions
[Cond
].
Name, Asc
))
{
*p_code = Conditions[Cond].Code;
return True;
}
return False;
}
/*--------------------------------------------------------------------------*/
/* Instruction Decoders */
static void DecodeFixed(Word Code)
{
if (ChkArgCnt(0, 0))
{
CodeLen = 1;
WAsmCode[0] = Code;
}
}
static void DecodeLOAD(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(2, 2))
{
DecodeAdr(&ArgStr[1], MModWReg, SegNone);
switch (AdrType)
{
case ModWReg:
{
Word Save = AdrMode;
DecodeAdr(&ArgStr[2], MModWReg | MModAbs | MModImm, SegNone);
switch (AdrType)
{
case ModWReg:
#ifdef DEBUG_PRINTF
fprintf( stderr
, "LOAD-->ModWReg %d %d\n", AdrMode
, Save
);
#endif
WAsmCode[0] = 0xc000 | (Save << 8) | ( AdrMode << 4 );
CodeLen = 1;
break;
case ModAbs:
#ifdef DEBUG_PRINTF
fprintf( stderr
, "LOAD-->ModAbs %d %d\n", AdrMode
, Save
);
#endif
WAsmCode[0] = 0xc000 | (Save << 8) | ( AdrMode << 4 );
CodeLen = 1;
break;
case ModImm:
#ifdef DEBUG_PRINTF
fprintf( stderr
, "LOAD-->ModImm %d %d\n", AdrMode
, Save
);
#endif
WAsmCode[0] = (Save << 8) | AdrMode;
CodeLen = 1;
break;
}
break;
}
}
}
}
static void DecodeALU2(Word Code)
{
if (ChkArgCnt(2, 2))
{
DecodeAdr(&ArgStr[1], MModWReg, SegNone);
switch (AdrType)
{
case ModWReg:
{
Word Save = AdrMode;
DecodeAdr(&ArgStr[2], MModAbs | MModWReg | MModImm, SegNone);
switch (AdrType)
{
case ModWReg:
WAsmCode[0] = 0xc000 | (Save << 8) | ( AdrMode << 4 ) | Code;
CodeLen = 1;
break;
case ModImm:
case ModAbs:
WAsmCode[0] = (Code << 12 ) | (Save << 8) | AdrMode;
CodeLen = 1;
break;
}
break;
}
}
}
}
static void DecodeALU1(Word Code)
{
if (ChkArgCnt(1, 1))
{
DecodeAdr(&ArgStr[1], MModWReg, SegNone);
switch (AdrType)
{
case ModWReg:
WAsmCode[0] = 0xd000 | (AdrMode << 8) | Code;
CodeLen = 1;
break;
}
}
}
static void DecodeCALL(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 2))
{
Word cond_code;
if (ArgCnt == 1)
cond_code = COND_CODE_TRUE;
else if (!DecodeCond(ArgStr[1].str.p_str, &cond_code))
{
WrStrErrorPos(ErrNum_UndefCond, &ArgStr[1]);
return;
}
DecodeAdr(&ArgStr[ArgCnt], MModAbs | ModImm, SegCode);
switch (AdrType)
{
case ModAbs:
case ModImm:
WAsmCode[0] = 0x8300 | (cond_code << 10) | Lo(AdrMode);
CodeLen = 1;
break;
}
}
}
static void DecodeJUMP(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 2))
{
Word cond_code;
if (ArgCnt == 1)
cond_code= COND_CODE_TRUE;
else if (!DecodeCond(ArgStr[1].str.p_str, &cond_code))
{
WrStrErrorPos(ErrNum_UndefCond, &ArgStr[1]);
return;
}
DecodeAdr(&ArgStr[ArgCnt], MModAbs | MModImm, SegCode);
switch (AdrType)
{
case ModAbs:
case ModImm:
WAsmCode[0] = 0x8100 | (cond_code << 10) | Lo(AdrMode);
CodeLen = 1;
break;
}
}
}
static void DecodeRETURN(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(0, 1))
{
Word cond_code;
if (ArgCnt == 0)
cond_code = COND_CODE_TRUE;
else if (!DecodeCond(ArgStr[1].str.p_str, &cond_code))
{
WrStrErrorPos(ErrNum_UndefCond, &ArgStr[1]);
return ;
}
WAsmCode[0] = 0x8080 | (cond_code << 10);
CodeLen = 1;
}
}
static void DecodeIOop(Word Code)
{
if (ChkArgCnt(2, 2))
{
DecodeAdr(&ArgStr[1], MModWReg, SegNone);
switch (AdrType)
{
case ModWReg:
{
Word Save = AdrMode;
DecodeAdr(&ArgStr[2], MModInd | MModImm | MModAbs, SegData);
switch (AdrType)
{
case ModInd:
WAsmCode[0] = 0x1000 | ((Code | Save) << 8) | ( AdrMode << 4);
CodeLen = 1;
break;
case ModImm:
case ModAbs:
WAsmCode[0] = ((Code | Save) << 8) | AdrMode;
CodeLen = 1;
break;
}
break;
}
}
}
}
static void DecodeRETURNI(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 1))
{
NLS_UpString(ArgStr[1].str.p_str);
if (!strcmp(ArgStr
[1].
str.
p_str, "ENABLE"))
{
WAsmCode[0] = 0x80f0;
CodeLen = 1;
}
else if (!strcmp(ArgStr
[1].
str.
p_str, "DISABLE"))
{
WAsmCode[0] = 0x80d0;
CodeLen = 1;
}
}
}
static void DecodeENABLE_DISABLE(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 1))
{
NLS_UpString(ArgStr[1].str.p_str);
if (!as_strcasecmp(ArgStr[1].str.p_str, "INTERRUPT"))
{
WAsmCode[0] = Code;
CodeLen = 1;
}
}
}
static void DecodeCONSTANT(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(2, 2))
{
TempResult t;
Boolean OK;
as_tempres_ini(&t);
as_tempres_set_int(&t, EvalStrIntExpressionWithFlags(&ArgStr[2], Int32, &OK, &t.Flags));
if (OK && !mFirstPassUnknown(t.Flags))
{
SetListLineVal(&t);
PushLocHandle(-1);
EnterIntSymbol(&ArgStr[1], t.Contents.Int, SegNone, False);
PopLocHandle();
}
as_tempres_free(&t);
}
}
/*--------------------------------------------------------------------------*/
/* code table handling */
static void AddFixed(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeFixed);
}
static void AddALU2(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeALU2);
}
static void AddALU1(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeALU1);
}
static void AddIOop(const Char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeIOop);
}
static void AddCondition(const char *NName, Word NCode)
{
order_array_rsv_end(Conditions, Condition);
Conditions[InstrZ].Name = NName;
Conditions[InstrZ++].Code = NCode;
}
static void InitFields(void)
{
InstTable = CreateInstTable(201);
AddInstTable(InstTable, "LOAD", 0, DecodeLOAD);
AddInstTable(InstTable, "CALL", 0, DecodeCALL);
AddInstTable(InstTable, "JUMP", 0, DecodeJUMP);
AddInstTable(InstTable, "RETURN", 0, DecodeRETURN);
AddInstTable(InstTable, "RETURNI", 0, DecodeRETURNI);
AddInstTable(InstTable, "ENABLE", 0x8030, DecodeENABLE_DISABLE);
AddInstTable(InstTable, "DISABLE", 0x8010, DecodeENABLE_DISABLE);
AddInstTable(InstTable, "REG", 0, CodeREG);
AddInstTable(InstTable, "NAMEREG", 0, CodeNAMEREG);
AddInstTable(InstTable, "CONSTANT", 0, DecodeCONSTANT);
AddFixed("EI" , 0x8030); AddFixed("DI" , 0x8010);
AddFixed("RETIE" , 0x80f0); AddFixed("RETID" , 0x80d0);
AddFixed("NOP" , 0xc000); /* fake */
AddALU2("ADD" , 0x04);
AddALU2("ADDCY" , 0x05);
AddALU2("SUB" , 0x06);
AddALU2("SUBCY" , 0x07);
AddALU2("OR" , 0x02);
AddALU2("AND" , 0x01);
AddALU2("XOR" , 0x03);
AddALU1("SR0" , 0x0e);
AddALU1("SR1" , 0x0f);
AddALU1("SRX" , 0x0a);
AddALU1("SRA" , 0x08);
AddALU1("RR" , 0x0c);
AddALU1("SL0" , 0x06);
AddALU1("SL1" , 0x07);
AddALU1("SLX" , 0x04);
AddALU1("SLA" , 0x00);
AddALU1("RL" , 0x02);
AddIOop("INPUT" , 0xa0);
AddIOop("OUTPUT" , 0xe0);
InstrZ = 0;
AddCondition("T" , COND_CODE_TRUE);
AddCondition("C" , 6); AddCondition("NC" , 7);
AddCondition("Z" , 4); AddCondition("NZ" , 5);
AddCondition(NULL , 0);
}
static void DeinitFields(void)
{
DestroyInstTable(InstTable);
order_array_free(Conditions);
}
/*---------------------------------------------------------------------*/
/*!------------------------------------------------------------------------
* \fn InternSymbol_KCPSM(char *pArg, TempResult *pResult)
* \brief handle built-in (register) symbols for KCPSM
* \param pArg source argument
* \param pResult result buffer
* ------------------------------------------------------------------------ */
static void InternSymbol_KCPSM(char *pArg, TempResult *pResult)
{
Word RegNum;
if (IsWRegCore(pArg, &RegNum))
{
pResult->Typ = TempReg;
pResult->DataSize = eSymbolSize8Bit;
pResult->Contents.RegDescr.Reg = RegNum;
pResult->Contents.RegDescr.Dissect = DissectReg_KCPSM;
pResult->Contents.RegDescr.compare = NULL;
}
}
static void MakeCode_KCPSM(void)
{
CodeLen = 0; DontPrint = False;
/* zu ignorierendes */
if (Memo("")) return;
/* Pseudoanweisungen */
if (DecodeIntelPseudo(True)) return;
if (!LookupInstTable(InstTable, OpPart.str.p_str))
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
}
static Boolean IsDef_KCPSM(void)
{
return (Memo("REG"));
}
static void SwitchFrom_KCPSM(void)
{
DeinitFields();
}
static void SwitchTo_KCPSM(void)
{
const TFamilyDescr *FoundDescr;
FoundDescr = FindFamilyByName("KCPSM");
TurnWords = True;
SetIntConstMode(eIntConstModeIntel);
PCSymbol = "$";
HeaderID = FoundDescr->Id;
NOPCode = 0xc0; /* nop = load s0,s0 */
DivideChars = ",";
HasAttrs = False;
ValidSegs = (1 << SegCode) | (1 << SegData);
Grans[SegCode] = 2; ListGrans[SegCode] = 2; SegInits[SegCode] = 0; SegLimits[SegCode] = 0xff;
Grans[SegData] = 1; ListGrans[SegData] = 1; SegInits[SegData] = 0; SegLimits[SegData] = 0xff;
MakeCode = MakeCode_KCPSM;
IsDef = IsDef_KCPSM;
InternSymbol = InternSymbol_KCPSM;
DissectReg = DissectReg_KCPSM;
SwitchFrom = SwitchFrom_KCPSM;
InitFields();
}
void codekcpsm_init(void)
{
CPUKCPSM = AddCPU("KCPSM", SwitchTo_KCPSM);
AddCopyright("XILINX KCPSM(Picoblaze)-Generator (C) 2003 Andreas Wassatsch");
}