/* code9331.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Code Generator Toshiba TC9331 */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <ctype.h>
#include <string.h>
#include "bpemu.h"
#include "strutil.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmitree.h"
#include "headids.h"
#include "codevars.h"
#include "errmsg.h"
#include "code9331.h"
static CPUVar CPU9331;
static const char *pFNames[] =
{
"ZF", "SF", "V0F", "V1F",
"LRF", "GF0", "GF1", "GF2",
"GF3", "IFF0", "IFF1", "IFF2",
NULL
};
/* ------------------------------------------------------------------------- */
/* Common Subroutines */
static void StripComment(char *pArg)
{
char *pStart, *pEnd;
while (True)
{
pStart = QuotPos(pArg, '(');
if (!pStart)
return;
pEnd = QuotPos(pStart + 1, ')');
if (!pEnd)
return;
strmov(pStart, pEnd + 1);
KillPrefBlanks(pArg);
KillPostBlanks(pArg);
}
}
static Boolean DecodeRegList(const char *pNames[], const char *pArg, LongWord *pResult)
{
if (!*pArg)
{
*pResult = 0;
return True;
}
for (*pResult = 0; pNames[*pResult]; (*pResult)++)
if (!as_strcasecmp(pArg, pNames[*pResult]))
return True;
WrXError(pNames == pFNames ? ErrNum_UndefCond : ErrNum_InvReg, pArg);
return False;
}
static Boolean DecodeDSTA(const char *pArg, LongWord *pResult, IntType *pSize)
{
static const char *pNames[] =
{
"LC0", "LC1", "CP", "OFP",
"DP0", "DP1", "DP2", "DP3",
"MOD0", "MOD1", "MOD2", "MOD3",
"DF0", "DF1", NULL
};
if (!*pArg)
{
WrXError(ErrNum_InvReg, pArg);
return False;
}
if (!DecodeRegList(pNames, pArg, pResult))
return False;
if (3 == *pResult)
*pSize = UInt6;
else if (2 == *pResult)
*pSize = UInt9;
else
*pSize = (*pResult <= 1) ? UInt8 : UInt7;
return True;
}
static Boolean DecodeWRF(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"WF0", "WF1", "WF2", "W1",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeDEST(const char *pArg, LongWord *pResult, Boolean AllowAll)
{
static const char *pNames[] =
{
"NOP", "X", "W0", "W1",
"Y", "DP", "XAD", "PO",
"SO0", "SO1", "SO2", "XD",
"C", "O", "D", "B",
"XA", "A",
NULL
};
Boolean Result;
Result = DecodeRegList(pNames, pArg, pResult);
if (!Result)
return Result;
switch (*pResult)
{
case 17:
if (AllowAll)
*pResult = 14; /* A -> D */
else
Result = False;
break;
case 16:
if (AllowAll)
*pResult = 11; /* XA -> XD */
else
Result = False;
break;
case 15:
if (!AllowAll)
Result = False;
break;
default:
break;
}
if (!Result)
WrXError(ErrNum_InvReg, pArg);
return Result;
}
static Boolean DecodeSOUR(const char *pArg, LongWord *pResult, Boolean AllowAll)
{
static const char *pNames[] =
{
"RND", "X", "W0", "W1",
"", "DP", "", "PI",
"PO", "SI0", "SI1", "RMR",
"C", "O", "D", "B",
"A",
NULL
};
Boolean Result;
Result = DecodeRegList(pNames, pArg, pResult);
if (!Result)
return Result;
switch (*pResult)
{
case 16:
if (AllowAll)
*pResult = 14; /* A -> D */
else
Result = False;
break;
case 15:
if (!AllowAll)
Result = False;
break;
default:
break;
}
if (!Result)
WrXError(ErrNum_InvReg, pArg);
return Result;
}
static Boolean DecodeXCNT(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"STBY", "XRD", "WRX", "XREF",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeXS(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"X", "W",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeYS(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"Y", "X",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeZS(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"0", "W", "AC",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeWS(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"W0", "W1",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeCP(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"NOP", "CP+",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeDPS(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"DP0", "DP1", "DP2", "DP3",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeMODE(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"NOP", "", "-", "+",
"-DF0", "+DF0", "-DF1", "+DF1",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeOFP(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"NOP", "OFP+",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeER(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"NOP", "ER",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeDSTB(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"W1", "X",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeFORM(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"L", "R",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeGFX(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"GFS", "", "", "GFC",
NULL
};
if (!*pArg)
{
WrXError(ErrNum_InvReg, pArg);
return False;
}
return DecodeRegList(pNames, pArg, pResult);
}
static Boolean DecodeGF(const char *pArg, LongWord *pResult)
{
static const char *pNames[] =
{
"GF0", "GF1", "GF2", "GF3",
"OV0", "OV1", "FCHG", "BNK",
NULL
};
return DecodeRegList(pNames, pArg, pResult);
}
/* ------------------------------------------------------------------------- */
/* Instruction Decoders */
static void DecodeMAIN(Word Code)
{
LongWord Xs, Ys, Zs, Wrf, Ws, Cp, Dps, Mode, Dest, Sour, Xcnt, Ofp, Er,
LCode = Lo(Code);
Boolean UseZS = Hi(Code) || False;
if (!ChkArgCnt(15, 15));
else if (*ArgStr[1].str.p_str) WrError(ErrNum_InvAddrMode);
else if (!DecodeXS(ArgStr[3].str.p_str, &Xs));
else if (!DecodeYS(ArgStr[4].str.p_str, &Ys));
else if (!DecodeZS(ArgStr[5].str.p_str, &Zs));
else if (!DecodeWRF(ArgStr[6].str.p_str, &Wrf));
else if (!DecodeWS(ArgStr[7].str.p_str, &Ws));
else if (!DecodeCP(ArgStr[8].str.p_str, &Cp));
else if (!DecodeDPS(ArgStr[9].str.p_str, &Dps));
else if (!DecodeMODE(ArgStr[10].str.p_str, &Mode));
else if (!DecodeDEST(ArgStr[11].str.p_str, &Dest, True));
else if (!DecodeSOUR(ArgStr[12].str.p_str, &Sour, True));
else if (!DecodeXCNT(ArgStr[13].str.p_str, &Xcnt));
else if (Xcnt == 2) WrStrErrorPos(ErrNum_InvReg, &ArgStr[13]);
else if (!DecodeOFP(ArgStr[14].str.p_str, &Ofp));
else if (!DecodeER(ArgStr[15].str.p_str, &Er));
else
{
Boolean OK = True;
Word Shift;
tSymbolFlags Flags = eSymbolFlag_None;
Shift = *ArgStr[2].str.p_str ? EvalStrIntExpressionWithFlags(&ArgStr[2], UInt3, &OK, &Flags) : 0;
if (mFirstPassUnknown(Flags))
Shift = 0;
DAsmCode[0] = (LCode << 26)
| (Xs << 24) | (Ys << 23)
| (Wrf << 20) | (Ws << 22) | (Cp << 16) | (Dps << 13)
| (Mode << 10) | (Dest << 0) | (Sour << 4) | (Xcnt << 8)
| (Ofp << 15) | (Er << 25);
if (UseZS)
DAsmCode[0] |= (Zs << 26);
switch (Shift)
{
case 0:
break;
case 1:
DAsmCode[0] |= 0x00040000ul;
break;
case 4:
DAsmCode[0] |= 0x00080000ul;
break;
default:
WrStrErrorPos(ErrNum_InvShiftArg, &ArgStr[2]);
return;
}
CodeLen = 1;
}
}
static void DecodeLDA(Word Code)
{
LongWord DstA, Wrf, Dest, Sour, Xcnt;
IntType IntSize;
UNUSED(Code);
if (!ChkArgCnt(7, 7));
else if (*ArgStr[1].str.p_str) WrError(ErrNum_InvAddrMode);
else if (!DecodeDSTA(ArgStr[2].str.p_str, &DstA, &IntSize));
else if (!DecodeWRF(ArgStr[4].str.p_str, &Wrf));
else if (!DecodeDEST(ArgStr[5].str.p_str, &Dest, False));
else if (!DecodeSOUR(ArgStr[6].str.p_str, &Sour, False));
else if (Sour > 14) WrStrErrorPos(ErrNum_InvReg, &ArgStr[6]);
else if (!DecodeXCNT(ArgStr[7].str.p_str, &Xcnt));
else if (Xcnt == 2) WrStrErrorPos(ErrNum_InvReg, &ArgStr[7]);
else
{
Boolean OK;
LongWord Value = EvalStrIntExpression(&ArgStr[3], IntSize, &OK);
if (OK)
{
DAsmCode[0] = 0x04000000ul
| (DstA << 22) | (Wrf << 20) | (Dest << 0) | (Sour << 4) | (Xcnt << 8)
| ((Value << 10) & 0x7fc00);
CodeLen = 1;
}
}
}
static void DecodeLDB(Word Code)
{
LongWord DstB, Form;
UNUSED(Code);
if (!ChkArgCnt(4, 4));
else if (*ArgStr[1].str.p_str) WrError(ErrNum_InvAddrMode);
else if (!DecodeDSTB(ArgStr[2].str.p_str, &DstB));
else if (!DecodeFORM(ArgStr[4].str.p_str, &Form));
else
{
Boolean OK;
LongWord Value = EvalStrIntExpression(&ArgStr[3], UInt24, &OK);
if (OK)
{
DAsmCode[0] = 0x08000000ul
| (DstB << 1) | (Form << 0)
| ((Value & 0xffffff) << 2);
CodeLen = 1;
}
}
}
static void DecodeBR(Word Code)
{
LongWord Cp, Dps, Mode, Dest, Sour, Xcnt, Ofp;
if (!ChkArgCnt(9, 9));
else if (*ArgStr[1].str.p_str) WrError(ErrNum_InvAddrMode);
else if (!DecodeCP(ArgStr[3].str.p_str, &Cp));
else if (!DecodeDPS(ArgStr[4].str.p_str, &Dps));
else if (!DecodeMODE(ArgStr[5].str.p_str, &Mode));
else if (!DecodeDEST(ArgStr[6].str.p_str, &Dest, False));
else if (!DecodeSOUR(ArgStr[7].str.p_str, &Sour, False));
else if (!DecodeXCNT(ArgStr[8].str.p_str, &Xcnt));
else if (!DecodeOFP(ArgStr[9].str.p_str, &Ofp));
else
{
Boolean OK;
LongWord Address;
tSymbolFlags Flags;
Address = EvalStrIntExpressionWithFlags(&ArgStr[2], UInt9, &OK, &Flags);
if (mFirstPassUnknown(Flags))
Address &= 0xff;
if (OK && ChkRange(Address, 0, SegLimits[SegCode]))
{
DAsmCode[0] = (((LongWord)Code) << 26)
| (Address << 17) | (Cp << 16) | (Dps << 13) | (Mode << 10)
| (Dest << 0) | (Sour << 4) | (Xcnt << 8) | (Ofp << 15);
CodeLen = 1;
}
}
}
static void DecodeJC(Word Code)
{
LongWord F, Cp, Dps, Mode, Dest, Sour, Xcnt, Ofp;
if (!ChkArgCnt(10, 10));
else if (*ArgStr[1].str.p_str) WrError(ErrNum_InvAddrMode);
else if (!DecodeRegList(pFNames, ArgStr[3].str.p_str, &F));
else if (!DecodeCP(ArgStr[4].str.p_str, &Cp));
else if (!DecodeDPS(ArgStr[5].str.p_str, &Dps));
else if (!DecodeMODE(ArgStr[6].str.p_str, &Mode));
else if (!DecodeDEST(ArgStr[7].str.p_str, &Dest, False));
else if (!DecodeSOUR(ArgStr[8].str.p_str, &Sour, False));
else if (!DecodeXCNT(ArgStr[9].str.p_str, &Xcnt));
else if (!DecodeOFP(ArgStr[10].str.p_str, &Ofp));
else
{
Boolean OK;
LongWord Address;
tSymbolFlags Flags;
Address = EvalStrIntExpressionWithFlags(&ArgStr[2], UInt9, &OK, &Flags);
if (mFirstPassUnknown(Flags))
Address &= 0xff;
if (OK && ChkRange(Address, 0, SegLimits[SegCode]))
{
F = (F << 2) + ((LongWord)Code);
DAsmCode[0] = (F << 24)
| (Address << 17) | (Cp << 16) | (Dps << 13) | (Mode << 10)
| (Dest << 0) | (Sour << 4) | (Xcnt << 8) | (Ofp << 15);
CodeLen = 1;
}
}
}
static void DecodeRET(Word Code)
{
LongWord Xs, Ys, Wrf, Ws, Cp, Dps, Mode, Dest, Sour, Xcnt, Ofp;
UNUSED(Code);
if (!ChkArgCnt(13, 13));
else if (*ArgStr[1].str.p_str) WrError(ErrNum_InvAddrMode);
else if (!DecodeXS(ArgStr[3].str.p_str, &Xs));
else if (!DecodeYS(ArgStr[4].str.p_str, &Ys));
else if (!DecodeWRF(ArgStr[5].str.p_str, &Wrf));
else if (!DecodeWS(ArgStr[6].str.p_str, &Ws));
else if (!DecodeCP(ArgStr[7].str.p_str, &Cp));
else if (!DecodeDPS(ArgStr[8].str.p_str, &Dps));
else if (!DecodeMODE(ArgStr[9].str.p_str, &Mode));
else if (!DecodeDEST(ArgStr[10].str.p_str, &Dest, True));
else if (!DecodeSOUR(ArgStr[11].str.p_str, &Sour, True));
else if (!DecodeXCNT(ArgStr[12].str.p_str, &Xcnt));
else if (Xcnt == 2) WrStrErrorPos(ErrNum_InvReg, &ArgStr[12]);
else if (!DecodeOFP(ArgStr[13].str.p_str, &Ofp));
else
{
Boolean OK = True;
Word Shift;
tSymbolFlags Flags = eSymbolFlag_None;
Shift = *ArgStr[2].str.p_str ? EvalStrIntExpressionWithFlags(&ArgStr[2], UInt3, &OK, &Flags) : 0;
if (mFirstPassUnknown(Flags))
Shift = 0;
DAsmCode[0] = 0xc4000000ul
| (Xs << 24) | (Ys << 23)
| (Wrf << 20) | (Ws << 22) | (Cp << 16) | (Dps << 13)
| (Mode << 10) | (Dest << 0) | (Sour << 4) | (Xcnt << 8)
| (Ofp << 15);
switch (Shift)
{
case 0:
break;
case 1:
DAsmCode[0] |= 0x00040000ul;
break;
case 4:
DAsmCode[0] |= 0x00080000ul;
break;
default:
WrStrErrorPos(ErrNum_InvShiftArg, &ArgStr[2]);
return;
}
/* ??? */
if ((Sour == 15) || (Dest == 15))
DAsmCode[0] |= 0x00020000;
CodeLen = 1;
}
}
static void DecodeGMAx(Word Code)
{
LongWord Gfx, Gf, Wrf, Ws, Cp, Dps, Mode, Dest, Sour, Xcnt, Ofp;
if (!ChkArgCnt(12, 12));
else if (*ArgStr[1].str.p_str) WrError(ErrNum_InvAddrMode);
else if (!DecodeGFX(ArgStr[2].str.p_str, &Gfx));
else if (!DecodeGF(ArgStr[3].str.p_str, &Gf));
else if (!DecodeWRF(ArgStr[4].str.p_str, &Wrf));
else if (!DecodeWS(ArgStr[5].str.p_str, &Ws));
else if (!DecodeCP(ArgStr[6].str.p_str, &Cp));
else if (!DecodeDPS(ArgStr[7].str.p_str, &Dps));
else if (!DecodeMODE(ArgStr[8].str.p_str, &Mode));
else if (!DecodeDEST(ArgStr[9].str.p_str, &Dest, True));
else if (!DecodeSOUR(ArgStr[10].str.p_str, &Sour, True));
else if (!DecodeXCNT(ArgStr[11].str.p_str, &Xcnt));
else if (Xcnt == 2) WrStrErrorPos(ErrNum_InvReg, &ArgStr[11]);
else if (!DecodeOFP(ArgStr[12].str.p_str, &Ofp));
else
{
DAsmCode[0] = 0x0c000000ul | (((LongWord)Code) << 16)
| (Gfx << 28) | (Gf << 23)
| (Wrf << 20) | (Ws << 22) | (Cp << 16) | (Dps << 13)
| (Mode << 10) | (Dest << 0) | (Sour << 4) | (Xcnt << 8)
| (Ofp << 15);
/* ??? */
if ((Sour == 15) || (Dest == 15))
DAsmCode[0] |= 0x00020000;
CodeLen = 1;
}
}
/* ------------------------------------------------------------------------- */
/* Dynamic Code Table Handling */
static void InitFields(void)
{
InstTable = CreateInstTable(107);
AddInstTable(InstTable, "NOP", 0x0000, DecodeMAIN);
AddInstTable(InstTable, "AND", 0x0004, DecodeMAIN);
AddInstTable(InstTable, "OR", 0x0005, DecodeMAIN);
AddInstTable(InstTable, "XOR", 0x0006, DecodeMAIN);
AddInstTable(InstTable, "NOT", 0x0007, DecodeMAIN);
AddInstTable(InstTable, "SUB", 0x0108, DecodeMAIN);
AddInstTable(InstTable, "ABS", 0x000b, DecodeMAIN);
AddInstTable(InstTable, "CMP", 0x010c, DecodeMAIN);
AddInstTable(InstTable, "WCL", 0x0010, DecodeMAIN);
AddInstTable(InstTable, "WRS", 0x0011, DecodeMAIN);
AddInstTable(InstTable, "ACS", 0x0012, DecodeMAIN);
AddInstTable(InstTable, "MAD", 0x0114, DecodeMAIN);
AddInstTable(InstTable, "MADS", 0x0118, DecodeMAIN);
AddInstTable(InstTable, "DMAD", 0x001e, DecodeMAIN);
AddInstTable(InstTable, "DMAS", 0x001f, DecodeMAIN);
AddInstTable(InstTable, "LDA", 0, DecodeLDA);
AddInstTable(InstTable, "LDB", 0, DecodeLDB);
AddInstTable(InstTable, "JMP0", 0x20, DecodeBR);
AddInstTable(InstTable, "JMP1", 0x21, DecodeBR);
AddInstTable(InstTable, "JNZ0", 0x22, DecodeBR);
AddInstTable(InstTable, "JNZ1", 0x23, DecodeBR);
AddInstTable(InstTable, "JZ0", 0x32, DecodeBR);
AddInstTable(InstTable, "JZ1", 0x33, DecodeBR);
AddInstTable(InstTable, "CALL", 0x30, DecodeBR);
AddInstTable(InstTable, "JC", 0xd0, DecodeJC);
AddInstTable(InstTable, "JNC", 0x90, DecodeJC);
AddInstTable(InstTable, "RET", 0, DecodeRET);
AddInstTable(InstTable, "GMA" , 0, DecodeGMAx);
AddInstTable(InstTable, "GMAD", 4, DecodeGMAx);
AddInstTable(InstTable, "GMAS", 8, DecodeGMAx);
}
static void DeinitFields(void)
{
DestroyInstTable(InstTable);
}
/* ------------------------------------------------------------------------- */
/* Adaptors */
static void MakeCode_9331(void)
{
int z;
CodeLen = 0;
DontPrint = False;
/* TC9331 knows default instructions: may be NOP or GF command */
if (Memo(""))
{
switch (ArgCnt)
{
case 12:
strmaxcpy(OpPart.str.p_str, "GMA", sizeof(OpPart));
break;
case 15:
strmaxcpy(OpPart.str.p_str, "NOP", sizeof(OpPart));
break;
case 0:
return;
default:
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
return;
}
}
/* Toshiba assembler treats parts in ( ) as comments - trim them
out of the arguments. This will also break more complex formulas,
but you are not going to use them on a processor of 320 words
of program space anyway... */
for (z = 1; z < ArgCnt; z++)
StripComment(ArgStr[z].str.p_str);
if (!LookupInstTable(InstTable, OpPart.str.p_str))
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
}
static Boolean IsDef_9331(void)
{
return False;
}
static void SwitchFrom_9331(void)
{
DeinitFields();
}
static void SwitchTo_9331(void)
{
const TFamilyDescr *pDescr;
pDescr = FindFamilyByName("TC9331");
TurnWords = False;
SetIntConstMode(eIntConstModeIntel);
PCSymbol = "$";
HeaderID = pDescr->Id;
NOPCode = 0x00000000;
DivideChars = ",";
HasAttrs = False;
ValidSegs = 1 << SegCode;
Grans[SegCode] = 4; ListGrans[SegCode] = 4; SegInits[SegCode] = 0;
SegLimits[SegCode] = 319;
MakeCode = MakeCode_9331;
IsDef = IsDef_9331;
SwitchFrom = SwitchFrom_9331;
InitFields();
}
extern void code9331_init(void)
{
CPU9331 = AddCPU("TC9331", SwitchTo_9331);
}