/* codekcp3.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Codegenerator Xilinx kcpsm3 */
/* */
/*****************************************************************************/
#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 "codepseudo.h"
#include "codekcp3.h"
typedef struct
{
LongWord Code;
} FixedOrder;
static FixedOrder *RegOrders, *ALUOrders;
static CPUVar CPUKCPSM3;
/*--------------------------------------------------------------------------
* Address Expression Parsing
*--------------------------------------------------------------------------*/
/*!------------------------------------------------------------------------
* \fn IsWRegCore(const char *pArg, LongWord *pResult)
* \brief is argument a built-in register?
* \param pArg argument
* \param pResult register number if yes
* \return true if yes
* ------------------------------------------------------------------------ */
static Boolean IsWRegCore(const char *pArg, LongWord *pResult)
{
Boolean OK;
if ((strlen(pArg
) < 2) || (as_toupper
(*pArg
) != 'S'))
return False;
*pResult = ConstLongInt(pArg + 1, &OK, 16);
if (!OK)
return False;
return (*pResult < 16);
}
/*!------------------------------------------------------------------------
* \fn DissectReg_KCPSM3(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_KCPSM3(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, LongWord *pResult, Boolean MustBeReg)
* \brief is argument a built-in register or register alias?
* \param pArg argument
* \param pResult register number if yes
* \param MustBeReg expect register arg?
* \return reg evel result
* ------------------------------------------------------------------------ */
static tRegEvalResult IsWReg(const tStrComp *pArg, LongWord *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;
}
/*!------------------------------------------------------------------------
* \fn IsIWReg(const tStrComp *pArg, LongWord *pResult)
* \brief is argument an indirect register expression?
* \param pArg argument
* \param pResult register number if yes
* \return true if yes
* ------------------------------------------------------------------------ */
static tRegEvalResult IsIWReg(const tStrComp *pArg, LongWord *pResult)
{
char Tmp[10];
tStrComp TmpComp;
int l
= strlen(pArg
->str.
p_str);
if ((l < 3) || (pArg->str.p_str[0] != '(') || (pArg->str.p_str[l - 1] != ')'))
return eIsNoReg;
StrCompMkTemp(&TmpComp, Tmp, sizeof(Tmp));
StrCompCopySub(&TmpComp, pArg, 1, l - 2);
return IsWReg(&TmpComp, pResult, False);
}
static Boolean IsCond(int OtherArgCnt, LongWord *pErg)
{
static const char Conds[4][3] = { "Z", "NZ", "C", "NC" };
if (ArgCnt <= OtherArgCnt)
{
*pErg = 0;
return True;
}
for (*pErg = 0; *pErg < (sizeof(Conds) / sizeof(*Conds)); (*pErg)++)
if (!as_strcasecmp(Conds[*pErg], ArgStr[1].str.p_str))
{
*pErg |= 4;
return True;
}
return False;
}
/*--------------------------------------------------------------------------
* Code Handlers
*--------------------------------------------------------------------------*/
static void DecodePort(Word Index)
{
UNUSED(Index);
CodeEquate(SegIO, 0, SegLimits[SegIO]);
}
static void DecodeConstant(Word Index)
{
UNUSED(Index);
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);
}
}
static void DecodeOneReg(Word Index)
{
FixedOrder *pOrder = RegOrders + Index;
LongWord Reg;
if (ChkArgCnt(1, 1)
&& IsWReg(&ArgStr[1], &Reg, True))
{
DAsmCode[0] = pOrder->Code | (Reg << 8);
CodeLen = 1;
}
}
static void DecodeALU(Word Index)
{
FixedOrder *pOrder = ALUOrders + Index;
LongWord Src, DReg;
Boolean OK;
if (ChkArgCnt(2, 2)
&& IsWReg(&ArgStr[1], &DReg, True))
switch (IsWReg(&ArgStr[2], &Src, False))
{
case eIsReg:
DAsmCode[0] = pOrder->Code | 0x1000 | (DReg << 8) | (Src << 4);
CodeLen = 1;
break;
case eIsNoReg:
Src = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
if (OK)
{
DAsmCode[0] = pOrder->Code | (DReg << 8) | (Src & 0xff);
CodeLen = 1;
}
break;
case eRegAbort:
break;
}
}
static void DecodeJmp(Word Index)
{
LongWord Cond;
if (ChkArgCnt(1, 2)
&& IsCond(1, &Cond))
{
tEvalResult EvalResult;
LongWord Addr = EvalStrIntExpressionWithResult(&ArgStr[ArgCnt], UInt10, &EvalResult);
if (EvalResult.OK)
{
ChkSpace(SegCode, EvalResult.AddrSpaceMask);
DAsmCode[0] = 0x30000 | Index | (Cond << 10) | (Addr & 0x3ff);
CodeLen = 1;
}
}
}
static void DecodeRet(Word Index)
{
LongWord Cond;
UNUSED(Index);
if (ChkArgCnt(0, 1)
&& IsCond(0, &Cond))
{
DAsmCode[0] = 0x2a000 | (Cond << 10);
CodeLen = 1;
}
}
static void DecodeReti(Word Index)
{
UNUSED(Index);
if (ChkArgCnt(1, 1))
{
if (!as_strcasecmp(ArgStr[1].str.p_str, "DISABLE"))
{
DAsmCode[0] = 0x38000;
CodeLen = 1;
}
else if (!as_strcasecmp(ArgStr[1].str.p_str, "ENABLE"))
{
DAsmCode[0] = 0x38001;
CodeLen = 1;
}
else
WrError(ErrNum_InvAddrMode);
}
}
static void DecodeInt(Word Index)
{
if (ChkArgCnt(1, 1))
{
if (as_strcasecmp(ArgStr[1].str.p_str, "INTERRUPT")) WrError(ErrNum_InvAddrMode);
else
{
DAsmCode[0] = 0x3c000 | Index;
CodeLen = 1;
}
}
}
static void DecodeMem(Word Index)
{
LongWord Reg, Addr;
if (ChkArgCnt(2, 2)
&& IsWReg(&ArgStr[1], &Reg, True))
{
DAsmCode[0] = (((LongWord)Index) << 13) | (Reg << 8);
switch (IsIWReg(&ArgStr[2], &Addr))
{
case eIsReg:
DAsmCode[0] |= 0x01000 | (Addr << 4);
CodeLen = 1;
break;
case eIsNoReg:
{
tEvalResult EvalResult;
Addr = EvalStrIntExpressionWithResult(&ArgStr[2], UInt6, &EvalResult);
if (EvalResult.OK)
{
ChkSpace(SegData, EvalResult.AddrSpaceMask);
DAsmCode[0] |= Addr & 0x3f;
CodeLen = 1;
}
break;
}
case eRegAbort:
break;
}
}
}
static void DecodeIO(Word Index)
{
LongWord Reg, Addr;
if (ChkArgCnt(2, 2)
&& IsWReg(&ArgStr[1], &Reg, True))
{
DAsmCode[0] = (((LongWord)Index) << 13) | (Reg << 8);
switch (IsIWReg(&ArgStr[2], &Addr))
{
case eIsReg:
DAsmCode[0] |= 0x01000 | (Addr << 4);
CodeLen = 1;
break;
case eIsNoReg:
{
tEvalResult EvalResult;
Addr = EvalStrIntExpressionWithResult(&ArgStr[2], UInt8, &EvalResult);
if (EvalResult.OK)
{
ChkSpace(SegIO, EvalResult.AddrSpaceMask);
DAsmCode[0] |= Addr & 0xff;
CodeLen = 1;
}
break;
}
case eRegAbort:
break;
}
}
}
static void DecodeNop(Word Index)
{
UNUSED (Index);
if (ChkArgCnt(0, 0))
{
DAsmCode[0] = NOPCode;
CodeLen = 1;
}
}
/*--------------------------------------------------------------------------
* Instruction Table Handling
*--------------------------------------------------------------------------*/
static void AddReg(const char *NName, LongWord NCode)
{
order_array_rsv_end(RegOrders, FixedOrder);
RegOrders[InstrZ].Code = NCode;
AddInstTable(InstTable, NName, InstrZ++, DecodeOneReg);
}
static void AddALU(const char *NName, LongWord NCode)
{
order_array_rsv_end(ALUOrders, FixedOrder);
ALUOrders[InstrZ].Code = NCode;
AddInstTable(InstTable, NName, InstrZ++, DecodeALU);
}
static void InitFields(void)
{
InstTable = CreateInstTable(97);
InstrZ = 0;
AddReg("RL" , 0x20002);
AddReg("RR" , 0x2000c);
AddReg("SL0", 0x20006);
AddReg("SL1", 0x20007);
AddReg("SLA", 0x20000);
AddReg("SLX", 0x20004);
AddReg("SR0", 0x2000e);
AddReg("SR1", 0x2000f);
AddReg("SRA", 0x20008);
AddReg("SRX", 0x2000a);
InstrZ = 0;
AddALU("ADD" , 0x18000);
AddALU("ADDCY" , 0x1a000);
AddALU("AND" , 0x0a000);
AddALU("COMPARE", 0x14000);
AddALU("LOAD" , 0x00000);
AddALU("OR" , 0x0c000);
AddALU("SUB" , 0x1c000);
AddALU("SUBCY" , 0x1e000);
AddALU("TEST" , 0x12000);
AddALU("XOR" , 0x0e000);
AddInstTable(InstTable, "CALL", 0x0000, DecodeJmp);
AddInstTable(InstTable, "JUMP", 0x4000, DecodeJmp);
AddInstTable(InstTable, "RETURN", 0, DecodeRet);
AddInstTable(InstTable, "RETURNI", 0, DecodeReti);
AddInstTable(InstTable, "ENABLE", 1, DecodeInt);
AddInstTable(InstTable, "DISABLE", 0, DecodeInt);
AddInstTable(InstTable, "FETCH", 0x03, DecodeMem);
AddInstTable(InstTable, "STORE", 0x17, DecodeMem);
AddInstTable(InstTable, "INPUT", 0x02, DecodeIO);
AddInstTable(InstTable, "OUTPUT", 0x16, DecodeIO);
AddInstTable(InstTable, "PORT", 0, DecodePort);
AddInstTable(InstTable, "REG", 0, CodeREG);
AddInstTable(InstTable, "NAMEREG", 0, CodeNAMEREG);
AddInstTable(InstTable, "CONSTANT", 0, DecodeConstant);
AddInstTable(InstTable, "NOP", 0, DecodeNop);
}
static void DeinitFields(void)
{
DestroyInstTable(InstTable);
order_array_free(RegOrders);
order_array_free(ALUOrders);
}
/*--------------------------------------------------------------------------
* Semipublic Functions
*--------------------------------------------------------------------------*/
/*!------------------------------------------------------------------------
* \fn InternSymbol_KCPSM3(char *pArg, TempResult *pResult)
* \brief handle built-in (register) symbols for KCPSM3
* \param pArg source argument
* \param pResult result buffer
* ------------------------------------------------------------------------ */
static void InternSymbol_KCPSM3(char *pArg, TempResult *pResult)
{
LongWord RegNum;
if (IsWRegCore(pArg, &RegNum))
{
pResult->Typ = TempReg;
pResult->DataSize = eSymbolSize8Bit;
pResult->Contents.RegDescr.Reg = RegNum;
pResult->Contents.RegDescr.Dissect = DissectReg_KCPSM3;
pResult->Contents.RegDescr.compare = NULL;
}
}
static Boolean IsDef_KCPSM3(void)
{
return (Memo("REG")) || (Memo("PORT"));
}
static void SwitchFrom_KCPSM3(void)
{
DeinitFields();
}
static void MakeCode_KCPSM3(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 void SwitchTo_KCPSM3(void)
{
const TFamilyDescr *FoundDescr;
FoundDescr = FindFamilyByName("KCPSM3");
TurnWords = True;
SetIntConstMode(eIntConstModeIntel);
PCSymbol = "$"; HeaderID = FoundDescr->Id;
/* NOP = load s0,s0 */
NOPCode = 0x01000;
DivideChars = ","; HasAttrs = False;
ValidSegs = (1 << SegCode) | (1 << SegData) | (1 << SegIO);
Grans[SegCode] = 4; ListGrans[SegCode] = 4; SegInits[SegCode] = 0;
SegLimits[SegCode] = 0x3ff;
Grans[SegData] = 1; ListGrans[SegData] = 1; SegInits[SegData] = 0;
SegLimits[SegData] = 0x3f;
Grans[SegIO] = 1; ListGrans[SegIO] = 1; SegInits[SegIO] = 0;
SegLimits[SegIO] = 0xff;
MakeCode = MakeCode_KCPSM3;
IsDef = IsDef_KCPSM3;
InternSymbol = InternSymbol_KCPSM3;
DissectReg = DissectReg_KCPSM3;
SwitchFrom = SwitchFrom_KCPSM3; InitFields();
}
/*--------------------------------------------------------------------------
* Initialization
*--------------------------------------------------------------------------*/
void codekcpsm3_init(void)
{
CPUKCPSM3 = AddCPU("KCPSM3", SwitchTo_KCPSM3);
}