/* code48.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Codegeneratormodul MCS-48-Familie */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include "bpemu.h"
#include <string.h>
#include <ctype.h>
#include "nls.h"
#include "strutil.h"
#include "stringlists.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmallg.h"
#include "asmitree.h"
#include "intpseudo.h"
#include "codevars.h"
#include "errmsg.h"
#include "code48.h"
typedef struct
{
const char *Name;
Byte Code;
} SelOrder;
typedef enum
{
ModImm = 0,
ModReg = 1,
ModInd = 2,
ModAcc = 3,
ModNone = -1
} tAdrMode;
#define MModImm (1 << ModImm)
#define MModReg (1 << ModReg)
#define MModInd (1 << ModInd)
#define MModAcc (1 << ModAcc)
#define eCPUFlagCMOS (1ul << 0)
#define eCPUFlagSiemens (1ul << 1)
#define eCPUFlagDEC_DJNZ_IREG (1ul << 2)
#define eCPUFlagXMem (1ul << 3)
#define eCPUFlagUPIPort (1ul << 4)
#define eCPUFlagPort0 (1ul << 5)
#define eCPUFlagPort1 (1ul << 6)
#define eCPUFlagPort2 (1ul << 7)
#define eCPUFlagIOExpander (1ul << 8)
#define eCPUFlagUserFlags (1ul << 9)
#define eCPUFlagT0 (1ul << 10)
#define eCPUFlagT0CLK (1ul << 11)
#define eCPUFlagCondBitJmp (1ul << 12)
#define eCPUFlagTransferA_PSW (1ul << 13)
#define eCPUFlagBUS (1ul << 14)
#define eCPUFlagRegBanks (1ul << 15)
#define eCPUFlagADConv (1ul << 16)
#define eCPUFlagLogToPort (1ul << 17)
#define eCPUFlagDEC_REG (1ul << 18)
#define eCPUFlagMOVP3 (1ul << 19)
#define eCPUFlagINTLogic (1ul << 20)
#define eCPUFlagOKI (1ul << 21)
#define eCPUFlagSerial (1ul << 22)
#define eCPUFlag84xx (1ul << 23)
#define MB_NOTHING 0xff
typedef struct
{
const char *pName;
Word CodeSize;
LongWord Flags;
} tCPUProps;
typedef struct
{
const char *p_val;
Byte code;
} clr_cpl_t;
static const tCPUProps *pCurrCPUProps;
static tAdrMode AdrMode;
static Byte AdrVal;
clr_cpl_t *clr_cpl_args;
static SelOrder *SelOrders;
static LongInt Reg_MB;
/****************************************************************************/
/*!------------------------------------------------------------------------
* \fn DecodeRegCore(const char *pAsc, tRegInt *pValue, tSymbolSize *pSize)
* \brief check whether argument describes a CPU register
* \param pAsc argument
* \param pValue resulting register # if yes
* \param pSize resulting register size if yes
* \return true if yes
* ------------------------------------------------------------------------ */
static Boolean DecodeRegCore(const char *pAsc, tRegInt *pValue, tSymbolSize *pSize)
{
|| (as_toupper(pAsc[0]) != 'R')
return False;
*pValue = pAsc[1] - '0';
*pSize = eSymbolSize8Bit;
return (*pValue <= 7);
}
/*!------------------------------------------------------------------------
* \fn DissectReg_48(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
* \brief dissect register symbols - 8048 variant
* \param pDest destination buffer
* \param DestSize destination buffer size
* \param Value numeric register value
* \param InpSize register size
* ------------------------------------------------------------------------ */
static void DissectReg_48(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
{
switch (InpSize)
{
case eSymbolSize8Bit:
as_snprintf(pDest, DestSize, "R%u", (unsigned)Value);
break;
default:
as_snprintf(pDest, DestSize, "%d-%u", (int)InpSize, (unsigned)Value);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeReg(const tStrComp *pArg, Byte *pValue, Boolean MustBeReg)
* \brief check whether argument is a CPU register or user-defined register alias
* \param pArg argument
* \param pValue resulting register # if yes
* \param MustBeReg expect register at this arg?
* \return eIsReg/eIsNoReg/eRegAbort
* ------------------------------------------------------------------------ */
static tRegEvalResult DecodeReg(const tStrComp *pArg, Byte *pValue, Boolean MustBeReg)
{
tSymbolSize Size;
tRegDescr RegDescr;
tEvalResult EvalResult;
tRegEvalResult RegEvalResult;
if (DecodeRegCore(pArg->str.p_str, &RegDescr.Reg, &Size))
{
*pValue = RegDescr.Reg;
return eIsReg;
}
RegEvalResult = EvalStrRegExpressionAsOperand(pArg, &RegDescr, &EvalResult, eSymbolSizeUnknown, MustBeReg);
*pValue = RegDescr.Reg;
return RegEvalResult;
}
static Boolean IsPort(const char *pArg, Word PortMask, Byte *pPortNum)
{
if (!as_strcasecmp(pArg, "BUS"))
*pPortNum = 8;
&& (as_toupper(pArg[0]) == 'P')
*pPortNum = pArg[1] - '0';
else
return False;
return !!(PortMask & (1 << *pPortNum));
}
static Boolean IsSerialPort(const char *pArg, Word PortMask, Byte *pPortNum)
{
&& (as_toupper(pArg[0]) == 'S')
*pPortNum = pArg[1] - '0';
else
return False;
return !!(PortMask & (1 << *pPortNum));
}
static tAdrMode DecodeAdr(const tStrComp *pArg, unsigned Mask)
{
Boolean OK;
AdrMode = ModNone;
if (*pArg->str.p_str == '\0') return ModNone;
if (!as_strcasecmp(pArg->str.p_str, "A"))
{
AdrMode = ModAcc;
goto found;
}
if (*pArg->str.p_str == '#')
{
AdrVal = EvalStrIntExpressionOffs(pArg, 1, Int8, &OK);
if (OK)
{
AdrMode = ModImm;
BAsmCode[1] = AdrVal;
goto found;
}
}
switch (DecodeReg(pArg, &AdrVal, False))
{
case eIsReg:
AdrMode = ModReg;
goto found;
case eRegAbort:
return ModNone;
default:
break;
}
if (*pArg->str.p_str == '@')
{
tStrComp Arg;
StrCompRefRight(&Arg, pArg, 1);
if (!DecodeReg(&Arg, &AdrVal, True))
return ModNone;
if (AdrVal > 1)
{
WrStrErrorPos(ErrNum_InvReg, &Arg);
return ModNone;
}
AdrMode = ModInd;
goto found;
}
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
found:
if ((AdrMode != ModNone) && !(Mask & (1 << AdrMode)))
{
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
AdrMode= ModNone;
}
return AdrMode;
}
static Boolean ChkCPUFlags(LongWord CPUFlags)
{
if (pCurrCPUProps->Flags & CPUFlags)
return True;
WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
return False;
}
static Boolean AChkCPUFlags(LongWord CPUFlags, const tStrComp *pArg)
{
if (pCurrCPUProps->Flags & CPUFlags)
return True;
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
return False;
}
static void ChkPx(Byte PortNum, const tStrComp *pArg)
{
if (!(pCurrCPUProps->Flags & (eCPUFlagPort0 << PortNum)))
{
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
CodeLen = 0;
}
}
static Boolean IsIReg3(const tStrComp *pArg)
{
tStrComp Arg;
Byte RegNum;
if (*pArg->str.p_str != '@')
return False;
StrCompRefRight(&Arg, pArg, 1);
if (!DecodeReg(&Arg, &RegNum, True))
return False;
if (RegNum != 3)
{
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
return False;
}
return True;
}
/****************************************************************************/
static void DecodeADD_ADDC(Word Code)
{
if (!ChkArgCnt(2, 2));
else if (as_strcasecmp(ArgStr[1].str.p_str, "A")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
switch (DecodeAdr(&ArgStr[2], MModImm | MModReg | MModInd))
{
case ModImm:
CodeLen = 2;
BAsmCode[0] = Code + 0x03;
break;
case ModReg:
CodeLen = 1;
BAsmCode[0] = Code + 0x68 + AdrVal;
break;
case ModInd:
CodeLen = 1;
BAsmCode[0] = Code + 0x60 + AdrVal;
break;
default:
break;
}
}
}
static void DecodeANL_ORL_XRL(Word Code)
{
Byte PortNum;
Word PortMask = 0x06;
if (pCurrCPUProps->Flags & eCPUFlagBUS)
PortMask |= 0x100;
if (pCurrCPUProps->Flags & eCPUFlag84xx)
PortMask |= 0x01;
if (!ChkArgCnt(2, 2));
else if (!as_strcasecmp(ArgStr[1].str.p_str, "A"))
{
switch (DecodeAdr(&ArgStr[2], MModImm | MModReg | MModInd))
{
case ModImm:
CodeLen = 2;
BAsmCode[0] = Code + 0x43;
break;
case ModReg:
CodeLen = 1;
BAsmCode[0] = Code + 0x48 + AdrVal;
break;
case ModInd:
CodeLen = 1;
BAsmCode[0] = Code + 0x40 + AdrVal;
break;
default:
break;
}
}
else if (IsPort(ArgStr[1].str.p_str, PortMask, &PortNum))
{
if (Code == 0x90) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]); /* no XRL to ports */
else if (AChkCPUFlags(eCPUFlagLogToPort, &ArgStr[1]))
{
if (DecodeAdr(&ArgStr[2], MModImm) == ModImm)
{
CodeLen = 2;
BAsmCode[0] = Code + 0x88 + (PortNum & 3);
if (PortNum)
ChkPx(PortNum, &ArgStr[1]);
}
}
}
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
}
static void DecodeCALL_JMP(Word Code)
{
if (!ChkArgCnt(1, 1));
else if ((EProgCounter() & 0x7fe) == 0x7fe) WrError(ErrNum_NotOnThisAddress);
else
{
tEvalResult EvalResult;
Word AdrWord = EvalStrIntExpressionWithResult(&ArgStr[1], Int16, &EvalResult);
if (EvalResult.OK)
{
if (AdrWord > SegLimits[SegCode]) WrStrErrorPos(ErrNum_OverRange, &ArgStr[1]);
else
{
Word DestBank = (AdrWord >> 11) & 3,
CurrBank = (EProgCounter() >> 11) & 3;
if (Reg_MB == MB_NOTHING)
{
if (CurrBank != DestBank)
{
BAsmCode[0] = SelOrders[DestBank].Code;
CodeLen = 1;
}
}
else if ((DestBank != Reg_MB) && !mFirstPassUnknownOrQuestionable(EvalResult.Flags))
WrStrErrorPos(ErrNum_InAccPage, &ArgStr[1]);
BAsmCode[CodeLen + 1] = AdrWord & 0xff;
BAsmCode[CodeLen] = Code + ((AdrWord & 0x700) >> 3);
CodeLen += 2;
ChkSpace(SegCode, EvalResult.AddrSpaceMask);
}
}
}
}
static void DecodeCLR_CPL(Word Code)
{
if (!ChkArgCnt(1, 1));
else
{
int z = 0;
Boolean OK = False;
NLS_UpString(ArgStr[1].str.p_str);
do
{
if (!strcmp(clr_cpl_args
[z
].
p_val, ArgStr
[1].
str.
p_str))
{
if ((*ArgStr[1].str.p_str == 'F') && !(pCurrCPUProps->Flags & eCPUFlagUserFlags)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
CodeLen = 1;
BAsmCode[0] = clr_cpl_args[z].code;
OK = True;
}
}
z++;
}
while ((clr_cpl_args[z].p_val) && (CodeLen != 1));
if (!OK)
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
BAsmCode[0] += Code;
}
}
static void DecodeAcc(Word Code)
{
if (!ChkArgCnt(1, 1));
else if (as_strcasecmp(ArgStr[1].str.p_str, "A")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
CodeLen = 1;
BAsmCode[0] = Code;
}
}
static void DecodeDEC(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(1, 1));
else
{
switch (DecodeAdr(&ArgStr[1], MModAcc | MModReg | MModInd))
{
case ModAcc:
CodeLen = 1;
BAsmCode[0] = 0x07;
break;
case ModReg:
if (AChkCPUFlags(eCPUFlagDEC_REG, &ArgStr[1]))
{
CodeLen = 1;
BAsmCode[0] = 0xc8 + AdrVal;
}
break;
case ModInd:
if (AChkCPUFlags(eCPUFlagDEC_DJNZ_IREG, &ArgStr[1]))
{
CodeLen = 1;
BAsmCode[0] = 0xc0 | AdrVal;
}
break;
default:
break;
}
}
}
static void DecodeDIS_EN(Word Code)
{
if (ChkArgCnt(1, 1))
{
NLS_UpString(ArgStr[1].str.p_str);
if (!strcmp(ArgStr
[1].
str.
p_str, "I"))
{
if (AChkCPUFlags(eCPUFlagINTLogic, &ArgStr[1]))
{
CodeLen = 1;
BAsmCode[0] = Code + 0x05;
}
}
else if (!strcmp(ArgStr
[1].
str.
p_str, "TCNTI"))
{
if (AChkCPUFlags(eCPUFlagINTLogic, &ArgStr[1]))
{
CodeLen = 1;
BAsmCode[0] = Code + 0x25;
}
}
else if (!strcmp(ArgStr
[1].
str.
p_str, "SI"))
{
if (AChkCPUFlags(eCPUFlagSerial, &ArgStr[1]))
{
CodeLen = 1;
BAsmCode[0] = Code + 0x85;
}
}
else if ((Memo
("EN")) && (!strcmp(ArgStr
[1].
str.
p_str, "DMA")))
{
if (AChkCPUFlags(eCPUFlagUPIPort, &ArgStr[1]))
{
BAsmCode[0] = Code + 0xe5;
CodeLen = 1;
}
}
else if ((Memo
("EN")) && (!strcmp(ArgStr
[1].
str.
p_str, "FLAGS")))
{
if (AChkCPUFlags(eCPUFlagUPIPort, &ArgStr[1]))
{
BAsmCode[0] = Code + 0xf5;
CodeLen = 1;
}
}
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
}
}
static void DecodeDJNZ(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(2, 2));
else
{
switch (DecodeAdr(&ArgStr[1], MModReg | MModInd))
{
case ModReg:
CodeLen = 1;
BAsmCode[0] = 0xe8 + AdrVal;
break;
case ModInd:
if (AChkCPUFlags(eCPUFlagDEC_DJNZ_IREG, &ArgStr[1]))
{
CodeLen = 1;
BAsmCode[0] = 0xe0 + AdrVal;
}
break;
default:
break;
}
if (CodeLen > 0)
{
Boolean OK;
Word AdrWord;
tSymbolFlags Flags;
AdrWord = EvalStrIntExpressionWithFlags(&ArgStr[2], Int16, &OK, &Flags);
if (OK)
{
if (ChkSamePage(EProgCounter() + CodeLen, AdrWord, 8, Flags))
BAsmCode[CodeLen++] = AdrWord & 0xff;
}
}
}
}
static void DecodeENT0(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 1) && ChkCPUFlags(eCPUFlagT0CLK))
{
if (as_strcasecmp(ArgStr[1].str.p_str, "CLK")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
CodeLen = 1;
BAsmCode[0] = 0x75;
}
}
}
static void DecodeINC(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(1, 1));
else
{
switch (DecodeAdr(&ArgStr[1], MModAcc | MModReg | MModInd))
{
case ModAcc:
CodeLen = 1;
BAsmCode[0] = 0x17;
break;
case ModReg:
CodeLen = 1;
BAsmCode[0] = 0x18 + AdrVal;
break;
case ModInd:
CodeLen = 1;
BAsmCode[0] = 0x10 + AdrVal;
break;
default:
break;
}
}
}
static void DecodeIN(Word Code)
{
Byte PortNum;
UNUSED(Code);
if (!ChkArgCnt(2, 2));
else if (as_strcasecmp(ArgStr[1].str.p_str, "A")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else if (!as_strcasecmp(ArgStr[2].str.p_str, "DBB"))
{
if (AChkCPUFlags(eCPUFlagUPIPort, &ArgStr[2]))
{
CodeLen = 1;
BAsmCode[0] = 0x22;
}
}
else if (!IsPort(ArgStr[2].str.p_str, 0x07, &PortNum)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
CodeLen = 1;
BAsmCode[0] = 0x08 + PortNum;
ChkPx(PortNum, &ArgStr[2]);
}
}
static void DecodeINS(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(2, 2));
else if (as_strcasecmp(ArgStr[1].str.p_str, "A")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else if (as_strcasecmp(ArgStr[2].str.p_str, "BUS")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else if (AChkCPUFlags(eCPUFlagBUS, &ArgStr[2]))
{
CodeLen = 1;
BAsmCode[0] = 0x08;
}
}
static void DecodeJMPP(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(1, 1));
else if (as_strcasecmp(ArgStr[1].str.p_str, "@A")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
CodeLen = 1;
BAsmCode[0] = 0xb3;
}
}
static void DecodeCond(Word Code)
{
if (ChkArgCnt(1, 1))
{
tEvalResult EvalResult;
Word AdrWord;
AdrWord = EvalStrIntExpressionWithResult(&ArgStr[1], UInt12, &EvalResult);
if (EvalResult.OK && ChkSamePage(EProgCounter() + 1, AdrWord, 8, EvalResult.Flags))
{
CodeLen = 2;
BAsmCode[0] = Code;
BAsmCode[1] = AdrWord & 0xff;
ChkSpace(SegCode, EvalResult.AddrSpaceMask);
}
}
}
static void DecodeJB(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(2, 2) && ChkCPUFlags(eCPUFlagCondBitJmp))
{
Boolean OK;
AdrVal = EvalStrIntExpression(&ArgStr[1], UInt3, &OK);
if (OK)
{
Word AdrWord;
tSymbolFlags Flags;
AdrWord = EvalStrIntExpressionWithFlags(&ArgStr[2], UInt12, &OK, &Flags);
if (OK && ChkSamePage(EProgCounter() + 1, AdrWord, 8, Flags))
{
CodeLen = 2;
BAsmCode[0] = 0x12 + (AdrVal << 5);
BAsmCode[1] = AdrWord & 0xff;
}
}
}
}
static void DecodeMOV(Word Code)
{
Byte PortNum;
UNUSED(Code);
if (!ChkArgCnt(2, 2));
else if (!as_strcasecmp(ArgStr[1].str.p_str, "A"))
{
if (!as_strcasecmp(ArgStr[2].str.p_str, "T"))
{
CodeLen = 1;
BAsmCode[0] = 0x42;
}
else if (IsPort(ArgStr[2].str.p_str, 0x06, &PortNum))
{
if (AChkCPUFlags(eCPUFlagOKI, &ArgStr[2]))
{
CodeLen = 1;
BAsmCode[0] = 0x53 + (PortNum << 4);
}
}
else if (!as_strcasecmp(ArgStr[2].str.p_str, "PSW"))
{
if (AChkCPUFlags(eCPUFlagTransferA_PSW, &ArgStr[2]))
{
CodeLen = 1;
BAsmCode[0] = 0xc7;
}
}
else if (IsSerialPort(ArgStr[2].str.p_str, 0x03, &PortNum))
{
if (AChkCPUFlags(eCPUFlagSerial, &ArgStr[2]))
{
CodeLen = 1;
BAsmCode[0] = 0x0c + PortNum;
}
}
else
{
switch (DecodeAdr(&ArgStr[2], MModReg | MModInd | MModImm))
{
case ModReg:
CodeLen = 1;
BAsmCode[0] = 0xf8 + AdrVal;
break;
case ModInd:
CodeLen = 1;
BAsmCode[0] = 0xf0 + AdrVal;
break;
case ModImm:
CodeLen = 2;
BAsmCode[0] = 0x23;
break;
default:
break;
}
}
}
else if (IsPort(ArgStr[1].str.p_str, 0x02, &PortNum))
{
if (IsIReg3(&ArgStr[2]))
{
if (AChkCPUFlags(eCPUFlagOKI, &ArgStr[1]))
{
CodeLen = 1;
BAsmCode[0] = 0xe3 | (PortNum << 4);
}
}
}
else if (IsSerialPort(ArgStr[1].str.p_str, 0x07, &PortNum))
{
if (AChkCPUFlags(eCPUFlagSerial, &ArgStr[1]))
{
switch (DecodeAdr(&ArgStr[2], MModAcc | MModImm))
{
case ModAcc:
CodeLen = 1;
BAsmCode[0] = 0x3c + PortNum;
break;
case ModImm:
CodeLen = 2;
BAsmCode[0] = 0x9c + PortNum;
break;
default:
break;
}
}
}
else if (!as_strcasecmp(ArgStr[2].str.p_str, "A"))
{
if (!as_strcasecmp(ArgStr[1].str.p_str, "STS"))
{
if (AChkCPUFlags(eCPUFlagUPIPort, &ArgStr[1]))
{
CodeLen = 1;
BAsmCode[0] = 0x90;
}
}
else if (!as_strcasecmp(ArgStr[1].str.p_str, "T"))
{
CodeLen = 1;
BAsmCode[0] = 0x62;
}
else if (!as_strcasecmp(ArgStr[1].str.p_str, "PSW"))
{
if (AChkCPUFlags(eCPUFlagTransferA_PSW, &ArgStr[1]))
{
CodeLen = 1;
BAsmCode[0] = 0xd7;
}
}
else
{
switch (DecodeAdr(&ArgStr[1], MModReg | MModInd))
{
case ModReg:
CodeLen = 1;
BAsmCode[0] = 0xa8 + AdrVal;
break;
case ModInd:
CodeLen = 1;
BAsmCode[0] = 0xa0 + AdrVal;
break;
default:
break;
}
}
}
else if (*ArgStr[2].str.p_str == '#')
{
Boolean OK;
Word AdrWord = EvalStrIntExpressionOffs(&ArgStr[2], 1, Int8, &OK);
if (OK)
{
switch (DecodeAdr(&ArgStr[1], MModReg | MModInd))
{
case ModReg:
CodeLen = 2;
BAsmCode[0] = 0xb8 + AdrVal;
BAsmCode[1] = AdrWord;
break;
case ModInd:
CodeLen = 2;
BAsmCode[0] = 0xb0 + AdrVal;
BAsmCode[1] = AdrWord;
break;
default:
break;
}
}
}
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
}
static void DecodeANLD_ORLD_MOVD(Word Code)
{
Byte PortNum;
if (ChkArgCnt(2, 2) && ChkCPUFlags(eCPUFlagIOExpander))
{
const tStrComp *pArg1 = &ArgStr[1],
*pArg2 = &ArgStr[2];
if ((Code == 0x3c) && (!as_strcasecmp(ArgStr[1].str.p_str, "A"))) /* MOVD */
{
pArg1 = &ArgStr[2];
pArg2 = &ArgStr[1];
Code = 0x0c;
}
if (as_strcasecmp(pArg2->str.p_str, "A")) WrStrErrorPos(ErrNum_InvAddrMode, pArg2);
else if (!IsPort(pArg1->str.p_str, 0xf0, &PortNum)) WrStrErrorPos(ErrNum_InvAddrMode, pArg1);
else
{
PortNum -= 4;
if ((PortNum == 3) && (pCurrCPUProps->Flags & eCPUFlagSiemens)) WrStrErrorPos(ErrNum_InvAddrMode, pArg2);
else
{
CodeLen = 1;
BAsmCode[0] = Code + PortNum;
}
}
}
}
static void DecodeMOVP_MOVP3(Word Code)
{
if (!ChkArgCnt(2, 2));
else if ((Code == 0xe3) && !ChkCPUFlags(eCPUFlagMOVP3));
else if (as_strcasecmp(ArgStr[1].str.p_str, "A")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else if (as_strcasecmp(ArgStr[2].str.p_str, "@A")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
CodeLen = 1;
BAsmCode[0] = Code;
}
}
static void DecodeMOVP1(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(2, 2));
else if (!ChkCPUFlags(eCPUFlagOKI));
else if (as_strcasecmp(ArgStr[1].str.p_str, "P")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else if (IsIReg3(&ArgStr[2]))
{
CodeLen = 1;
BAsmCode[0] = 0xc3;
}
}
static void DecodeMOVX(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(2, 2)
&& ChkCPUFlags(eCPUFlagXMem))
{
const tStrComp *pArg1 = &ArgStr[1], *pArg2 = &ArgStr[2];
Byte Code = 0x80;
if (!as_strcasecmp(pArg2->str.p_str, "A"))
{
pArg2 = &ArgStr[1];
pArg1 = &ArgStr[2];
Code += 0x10;
}
if (as_strcasecmp(pArg1->str.p_str, "A")) WrStrErrorPos(ErrNum_InvAddrMode, pArg1);
else
{
if (DecodeAdr(pArg2, MModInd) == ModInd)
{
CodeLen = 1;
BAsmCode[0] = Code + AdrVal;
}
}
}
}
static void DecodeNOP(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(0, 0));
else
{
CodeLen = 1;
BAsmCode[0] = 0x00;
}
}
static void DecodeOUT(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(2, 2));
else if (as_strcasecmp(ArgStr[1].str.p_str, "DBB")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else if (as_strcasecmp(ArgStr[2].str.p_str, "A")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else if (AChkCPUFlags(eCPUFlagUPIPort, &ArgStr[1]))
{
BAsmCode[0] = 0x02;
CodeLen = 1;
}
}
static void DecodeOUTL(Word Code)
{
UNUSED(Code);
NLS_UpString(ArgStr[1].str.p_str);
if (!ChkArgCnt(2, 2));
else
{
Word PortMask = 0x07;
Byte PortNum;
if (pCurrCPUProps->Flags & eCPUFlagBUS)
PortMask |= 0x100;
if (as_strcasecmp(ArgStr[2].str.p_str, "A")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else if (!IsPort(ArgStr[1].str.p_str, PortMask, &PortNum)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else if (PortNum == 8)
{
CodeLen = 1;
BAsmCode[0] = 0x02;
}
else
{
CodeLen = 1;
BAsmCode[0] = PortNum ? (0x38 + PortNum) : 0x90;
ChkPx(PortNum, &ArgStr[1]);
}
}
}
static void DecodeRET_RETR(Word Code)
{
if (ChkArgCnt(0, 0))
{
/* RETR not present if no interrupts at all (8021), or replaced by RETI (8022) */
if ((Code == 0x93) && (!(pCurrCPUProps->Flags & eCPUFlagINTLogic) || (pCurrCPUProps->Flags & eCPUFlagADConv))) WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
else
{
CodeLen = 1;
BAsmCode[0] = Code;
}
}
}
static void DecodeSEL(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 1))
{
Boolean OK = False;
int z;
NLS_UpString(ArgStr[1].str.p_str);
for (z = 0; SelOrders[z].Name; z++)
if (!strcmp(ArgStr
[1].
str.
p_str, SelOrders
[z
].
Name))
{
/* SEL MBx not allowed if program memory cannot be larger than 2K.
Similar is true for the Philips-specific MB2/MB3 arguments if
less than 6K/8K ROM is present: */
if (!strncmp(SelOrders
[z
].
Name, "MB", 2) && (pCurrCPUProps
->CodeSize
<= 0x7ff));
else if (!strcmp(SelOrders
[z
].
Name, "MB2") && (pCurrCPUProps
->CodeSize
<= 0xfff));
else if (!strcmp(SelOrders
[z
].
Name, "MB32") && (pCurrCPUProps
->CodeSize
<= 0x17ff));
else if (!strncmp(SelOrders
[z
].
Name, "RB", 2) && !(pCurrCPUProps
->Flags
& eCPUFlagRegBanks
));
else if (!strncmp(SelOrders
[z
].
Name, "AN", 2) && !(pCurrCPUProps
->Flags
& eCPUFlagADConv
));
else
{
CodeLen = 1;
BAsmCode[0] = SelOrders[z].Code;
OK = True;
}
}
if (!OK)
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
}
}
static void DecodeSTOP(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(1, 1));
else if (as_strcasecmp(ArgStr[1].str.p_str, "TCNT")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
CodeLen = 1;
BAsmCode[0] = 0x65;
}
}
static void DecodeSTRT(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(1, 1));
else
{
NLS_UpString(ArgStr[1].str.p_str);
if (!strcmp(ArgStr
[1].
str.
p_str, "CNT"))
{
CodeLen = 1;
BAsmCode[0] = 0x45;
}
else if (!strcmp(ArgStr
[1].
str.
p_str, "T"))
{
CodeLen = 1;
BAsmCode[0] = 0x55;
}
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
}
}
static void DecodeXCH(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(2, 2));
else
{
const tStrComp *pArg1 = &ArgStr[1], *pArg2 = &ArgStr[2];
if (!as_strcasecmp(pArg2->str.p_str, "A"))
{
pArg2 = &ArgStr[1];
pArg1 = &ArgStr[2];
}
if (as_strcasecmp(pArg1->str.p_str, "A")) WrStrErrorPos(ErrNum_InvAddrMode, pArg1);
else
{
switch (DecodeAdr(pArg2, MModReg | MModInd))
{
case ModReg:
CodeLen = 1;
BAsmCode[0] = 0x28 + AdrVal;
break;
case ModInd:
CodeLen = 1;
BAsmCode[0] = 0x20 + AdrVal;
break;
default:
break;
}
}
}
}
static void DecodeXCHD(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(2, 2));
else
{
const tStrComp *pArg1 = &ArgStr[1], *pArg2 = &ArgStr[2];
if (!as_strcasecmp(pArg2->str.p_str, "A"))
{
pArg2 = &ArgStr[1];
pArg1 = &ArgStr[2];
}
if (as_strcasecmp(pArg1->str.p_str, "A")) WrStrErrorPos(ErrNum_InvAddrMode, pArg1);
else
{
if (DecodeAdr(pArg2, MModInd) == ModInd)
{
CodeLen = 1;
BAsmCode[0] = 0x30 + AdrVal;
}
}
}
}
static void DecodeRAD(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(0, 0) && ChkCPUFlags(eCPUFlagADConv))
{
CodeLen = 1;
BAsmCode[0] = 0x80;
}
}
static void DecodeRETI(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(0, 0) && ChkCPUFlags(eCPUFlagADConv)) /* check for 8022 */
{
CodeLen = 1;
BAsmCode[0] = 0x93;
}
}
static void DecodeIDL_HALT(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(0, 0)
&& ChkCPUFlags(eCPUFlagCMOS))
{
CodeLen = 1;
BAsmCode[0] = (pCurrCPUProps->Flags & eCPUFlagSiemens) ? 0xf3 : 0x01;
}
}
static void DecodeOKIFixed(Word Code)
{
if (ChkArgCnt(0, 0) && ChkCPUFlags(eCPUFlagOKI))
{
CodeLen = 1;
BAsmCode[0] = Code;
}
}
/****************************************************************************/
static void AddAcc(const char *Name, Byte Code)
{
AddInstTable(InstTable, Name, Code, DecodeAcc);
}
static void AddCond(const char *Name, Byte Code)
{
AddInstTable(InstTable, Name, Code, DecodeCond);
}
static void AddSel(const char *Name, Byte Code)
{
order_array_rsv_end(SelOrders, SelOrder);
SelOrders[InstrZ].Name = Name;
SelOrders[InstrZ].Code = Code;
InstrZ++;
}
static void add_clr_cpl(const char *p_name, Byte code)
{
order_array_rsv_end(clr_cpl_args, clr_cpl_t);
clr_cpl_args[InstrZ].p_val = p_name;
clr_cpl_args[InstrZ].code = code;
InstrZ++;
}
static void InitFields(void)
{
InstTable = CreateInstTable(203);
AddInstTable(InstTable, "ADD", 0x00, DecodeADD_ADDC);
AddInstTable(InstTable, "ADDC", 0x10, DecodeADD_ADDC);
AddInstTable(InstTable, "ORL", 0x00, DecodeANL_ORL_XRL);
AddInstTable(InstTable, "ANL", 0x10, DecodeANL_ORL_XRL);
AddInstTable(InstTable, "XRL", 0x90, DecodeANL_ORL_XRL);
AddInstTable(InstTable, "CALL", 0x14, DecodeCALL_JMP);
AddInstTable(InstTable, "JMP", 0x04, DecodeCALL_JMP);
AddInstTable(InstTable, "CLR", 0x00, DecodeCLR_CPL);
AddInstTable(InstTable, "CPL", 0x10, DecodeCLR_CPL);
AddInstTable(InstTable, "DEC", 0, DecodeDEC);
AddInstTable(InstTable, "DIS", 0x10, DecodeDIS_EN);
AddInstTable(InstTable, "EN", 0x00, DecodeDIS_EN);
AddInstTable(InstTable, "DJNZ", 0x00, DecodeDJNZ);
AddInstTable(InstTable, "ENT0", 0x00, DecodeENT0);
AddInstTable(InstTable, "INC", 0x00, DecodeINC);
AddInstTable(InstTable, "IN", 0x00, DecodeIN);
AddInstTable(InstTable, "INS", 0x00, DecodeINS);
AddInstTable(InstTable, "JMPP", 0x00, DecodeJMPP);
AddInstTable(InstTable, "JB", 0x00, DecodeJB);
AddInstTable(InstTable, "MOV", 0x00, DecodeMOV);
AddInstTable(InstTable, "ANLD", 0x9c, DecodeANLD_ORLD_MOVD);
AddInstTable(InstTable, "ORLD", 0x8c, DecodeANLD_ORLD_MOVD);
AddInstTable(InstTable, "MOVD", 0x3c, DecodeANLD_ORLD_MOVD);
AddInstTable(InstTable, "MOVP", 0xa3, DecodeMOVP_MOVP3);
AddInstTable(InstTable, "MOVP3", 0xe3, DecodeMOVP_MOVP3);
AddInstTable(InstTable, "MOVP1", 0x00, DecodeMOVP1);
AddInstTable(InstTable, "MOVX", 0x00, DecodeMOVX);
AddInstTable(InstTable, "NOP", 0x00, DecodeNOP);
AddInstTable(InstTable, "OUT", 0x00, DecodeOUT);
AddInstTable(InstTable, "OUTL", 0x00, DecodeOUTL);
AddInstTable(InstTable, "RET", 0x83, DecodeRET_RETR);
AddInstTable(InstTable, "RETR", 0x93, DecodeRET_RETR);
AddInstTable(InstTable, "SEL", 0x00, DecodeSEL);
AddInstTable(InstTable, "STOP", 0x00, DecodeSTOP);
AddInstTable(InstTable, "STRT", 0x00, DecodeSTRT);
AddInstTable(InstTable, "XCH", 0x00, DecodeXCH);
AddInstTable(InstTable, "XCHD", 0x00, DecodeXCHD);
AddInstTable(InstTable, "RAD", 0x00, DecodeRAD);
AddInstTable(InstTable, "RETI", 0x00, DecodeRETI);
AddInstTable(InstTable, "IDL", 0x00, DecodeIDL_HALT);
AddInstTable(InstTable, "HALT", 0x00, DecodeIDL_HALT);
AddInstTable(InstTable, "HLTS", 0x82, DecodeOKIFixed);
AddInstTable(InstTable, "FLT", 0xa2, DecodeOKIFixed);
AddInstTable(InstTable, "FLTT", 0xc2, DecodeOKIFixed);
AddInstTable(InstTable, "FRES", 0xe2, DecodeOKIFixed);
InstrZ = 0;
add_clr_cpl("A", 0x27);
add_clr_cpl("C", 0x97);
add_clr_cpl("F0", 0x85);
add_clr_cpl("F1", 0xa5);
AddCond("JTF" , 0x16);
AddCond("JC" , 0xf6);
AddCond("JNC" , 0xe6);
AddCond("JZ" , 0xc6);
AddCond("JNZ" , 0x96);
if (pCurrCPUProps->Flags & eCPUFlagT0)
{
AddCond("JT0" , 0x36);
AddCond("JNT0" , 0x26);
}
AddCond("JT1" , 0x56);
AddCond("JNT1" , 0x46);
if (pCurrCPUProps->Flags & eCPUFlagUserFlags)
{
AddCond("JF0" , 0xb6);
AddCond("JF1" , 0x76);
}
if (pCurrCPUProps->Flags & eCPUFlagUPIPort)
{
AddCond("JNIBF", 0xd6);
AddCond("JOBF" , 0x86);
}
else
AddCond("JNI" , (pCurrCPUProps->Flags & eCPUFlagSiemens) ? 0x66 : 0x86);
if (pCurrCPUProps->Flags & eCPUFlagCondBitJmp)
{
AddCond("JB0" , 0x12);
AddCond("JB1" , 0x32);
AddCond("JB2" , 0x52);
AddCond("JB3" , 0x72);
AddCond("JB4" , 0x92);
AddCond("JB5" , 0xb2);
AddCond("JB6" , 0xd2);
AddCond("JB7" , 0xf2);
}
if (pCurrCPUProps->Flags & eCPUFlag84xx)
AddCond("JNTF", 0x06);
AddAcc("DA" , 0x57);
AddAcc("RL" , 0xe7);
AddAcc("RLC" , 0xf7);
AddAcc("RR" , 0x77);
AddAcc("RRC" , 0x67);
AddAcc("SWAP", 0x47);
/* Leave MBx first, used by CALL/JMP! */
InstrZ = 0;
AddSel("MB0" , 0xe5);
AddSel("MB1" , 0xf5);
AddSel("MB2" , 0xa5);
AddSel("MB3" , 0xb5);
AddSel("RB0" , 0xc5);
AddSel("RB1" , 0xd5);
AddSel("AN0" , 0x95);
AddSel("AN1" , 0x85);
AddSel(NULL , 0);
AddInstTable(InstTable, "REG", 0, CodeREG);
}
static void DeinitFields(void)
{
DestroyInstTable(InstTable);
order_array_free(clr_cpl_args);
order_array_free(SelOrders);
}
static void MakeCode_48(void)
{
CodeLen = 0;
DontPrint = False;
/* zu ignorierendes */
if (Memo(""))
return;
/* Pseudoanweisungen */
if (DecodeIntelPseudo(False))
return;
if (!LookupInstTable(InstTable, OpPart.str.p_str))
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
}
static Boolean IsDef_48(void)
{
return Memo("REG");
}
/*!------------------------------------------------------------------------
* \fn InternSymbol_48(char *pArg, TempResult *pResult)
* \brief handle built-in symbols on MCS-48
* \param pArg source argument
* \param pResult result buffer
* ------------------------------------------------------------------------ */
static void InternSymbol_48(char *pArg, TempResult *pResult)
{
tRegInt Erg;
tSymbolSize Size;
if (DecodeRegCore(pArg, &Erg, &Size))
{
pResult->Typ = TempReg;
pResult->DataSize = Size;
pResult->Contents.RegDescr.Reg = Erg;
pResult->Contents.RegDescr.Dissect = DissectReg_48;
pResult->Contents.RegDescr.compare = NULL;
}
}
static void SwitchFrom_48(void)
{
DeinitFields();
}
static void InitCode_48(void)
{
Reg_MB = MB_NOTHING;
}
static void SwitchTo_48(void *pUser)
{
#define ASSUME48Count (sizeof(ASSUME48s) / sizeof(*ASSUME48s))
static ASSUMERec ASSUME48s[] =
{
{ "MB" , &Reg_MB , 0, 1, MB_NOTHING, NULL },
};
pCurrCPUProps = (const tCPUProps*)pUser;
ASSUME48s[0].Max = (pCurrCPUProps->CodeSize >> 11) & 3;
TurnWords = False;
SetIntConstMode(eIntConstModeIntel);
PCSymbol = "$";
HeaderID = 0x21;
NOPCode = 0x00;
DivideChars = ",";
HasAttrs = False;
/* limit code segement size only vor variants known to have no
external program memory */
ValidSegs = (1 << SegCode) | (1 << SegIData);
Grans[SegCode ] = 1; ListGrans[SegCode ] = 1; SegInits[SegCode ] = 0;
SegLimits[SegCode] = pCurrCPUProps->CodeSize;
Grans[SegIData] = 1; ListGrans[SegIData] = 1; SegInits[SegIData] = 0x20;
SegLimits[SegIData] = 0xff;
if (pCurrCPUProps->Flags & eCPUFlagXMem)
{
ValidSegs |= (1 << SegXData);
Grans[SegXData] = 1; ListGrans[SegXData] = 1; SegInits[SegXData] = 0;
SegLimits[SegXData] = 0xff;
}
MakeCode = MakeCode_48;
IsDef = IsDef_48;
InternSymbol = InternSymbol_48;
DissectReg = DissectReg_48;
SwitchFrom = SwitchFrom_48;
InitFields();
pASSUMERecs = ASSUME48s;
ASSUMERecCnt = ASSUME48Count;
}
/* Limit code segment size only for variants known to have no
external program memory: */
static tCPUProps CPUProps[] =
{
{ "8021" , 0x3ff, eCPUFlagPort0 | eCPUFlagPort1 | eCPUFlagPort2 },
{ "8022" , 0x7ff, eCPUFlagPort0 | eCPUFlagPort1 | eCPUFlagPort2 | eCPUFlagT0 | eCPUFlagBUS | eCPUFlagADConv | eCPUFlagINTLogic },
{ "8401" , 0x1fff,eCPUFlagDEC_DJNZ_IREG | eCPUFlagPort0 | eCPUFlagPort1 | eCPUFlagPort2 | eCPUFlagT0 | eCPUFlagCondBitJmp | eCPUFlagTransferA_PSW | eCPUFlagRegBanks | eCPUFlagLogToPort | eCPUFlagDEC_REG | eCPUFlagINTLogic | eCPUFlagSerial | eCPUFlag84xx },
{ "8421" , 0x7ff, eCPUFlagDEC_DJNZ_IREG | eCPUFlagPort0 | eCPUFlagPort1 | eCPUFlagPort2 | eCPUFlagT0 | eCPUFlagCondBitJmp | eCPUFlagTransferA_PSW | eCPUFlagRegBanks | eCPUFlagLogToPort | eCPUFlagDEC_REG | eCPUFlagINTLogic | eCPUFlagSerial | eCPUFlag84xx },
{ "8441" , 0xfff, eCPUFlagDEC_DJNZ_IREG | eCPUFlagPort0 | eCPUFlagPort1 | eCPUFlagPort2 | eCPUFlagT0 | eCPUFlagCondBitJmp | eCPUFlagTransferA_PSW | eCPUFlagRegBanks | eCPUFlagLogToPort | eCPUFlagDEC_REG | eCPUFlagINTLogic | eCPUFlagSerial | eCPUFlag84xx },
{ "8461" , 0x17ff,eCPUFlagDEC_DJNZ_IREG | eCPUFlagPort0 | eCPUFlagPort1 | eCPUFlagPort2 | eCPUFlagT0 | eCPUFlagCondBitJmp | eCPUFlagTransferA_PSW | eCPUFlagRegBanks | eCPUFlagLogToPort | eCPUFlagDEC_REG | eCPUFlagINTLogic | eCPUFlagSerial | eCPUFlag84xx },
{ "8039" , 0xfff, eCPUFlagXMem | eCPUFlagPort1 | eCPUFlagPort2 | eCPUFlagIOExpander | eCPUFlagUserFlags | eCPUFlagT0 | eCPUFlagT0CLK | eCPUFlagCondBitJmp | eCPUFlagTransferA_PSW | eCPUFlagRegBanks | eCPUFlagLogToPort | eCPUFlagDEC_REG | eCPUFlagMOVP3 | eCPUFlagINTLogic },
{ "8048" , 0xfff, eCPUFlagXMem | eCPUFlagPort1 | eCPUFlagPort2 | eCPUFlagIOExpander | eCPUFlagUserFlags | eCPUFlagT0 | eCPUFlagT0CLK | eCPUFlagCondBitJmp | eCPUFlagTransferA_PSW | eCPUFlagBUS | eCPUFlagRegBanks | eCPUFlagLogToPort | eCPUFlagDEC_REG | eCPUFlagMOVP3 | eCPUFlagINTLogic },
{ "80C39" , 0xfff, eCPUFlagCMOS | eCPUFlagXMem | eCPUFlagPort1 | eCPUFlagPort2 | eCPUFlagIOExpander | eCPUFlagUserFlags | eCPUFlagT0 | eCPUFlagT0CLK | eCPUFlagCondBitJmp | eCPUFlagTransferA_PSW | eCPUFlagRegBanks | eCPUFlagLogToPort | eCPUFlagDEC_REG | eCPUFlagMOVP3 | eCPUFlagINTLogic },
{ "80C48" , 0xfff, eCPUFlagCMOS | eCPUFlagXMem | eCPUFlagPort1 | eCPUFlagPort2 | eCPUFlagIOExpander | eCPUFlagUserFlags | eCPUFlagT0 | eCPUFlagT0CLK | eCPUFlagCondBitJmp | eCPUFlagTransferA_PSW | eCPUFlagBUS | eCPUFlagRegBanks | eCPUFlagLogToPort | eCPUFlagDEC_REG | eCPUFlagMOVP3 | eCPUFlagINTLogic },
{ "8041" , 0x3ff, eCPUFlagUPIPort | eCPUFlagPort1 | eCPUFlagPort2 | eCPUFlagIOExpander | eCPUFlagUserFlags | eCPUFlagT0 | eCPUFlagCondBitJmp | eCPUFlagTransferA_PSW | eCPUFlagBUS | eCPUFlagRegBanks | eCPUFlagLogToPort | eCPUFlagDEC_REG | eCPUFlagMOVP3 | eCPUFlagINTLogic },
{ "8042" , 0x7ff, eCPUFlagUPIPort | eCPUFlagPort1 | eCPUFlagPort2 | eCPUFlagIOExpander | eCPUFlagUserFlags | eCPUFlagT0 | eCPUFlagCondBitJmp | eCPUFlagTransferA_PSW | eCPUFlagBUS | eCPUFlagRegBanks | eCPUFlagLogToPort | eCPUFlagDEC_REG | eCPUFlagMOVP3 | eCPUFlagINTLogic },
{ "80C382" , 0xfff, eCPUFlagCMOS | eCPUFlagSiemens | eCPUFlagDEC_DJNZ_IREG | eCPUFlagXMem | eCPUFlagPort1 | eCPUFlagIOExpander | eCPUFlagT0 | eCPUFlagCondBitJmp | eCPUFlagBUS | eCPUFlagRegBanks | eCPUFlagLogToPort | eCPUFlagDEC_REG | eCPUFlagMOVP3 | eCPUFlagINTLogic },
{ "MSM80C39" , 0xfff, eCPUFlagCMOS | eCPUFlagDEC_DJNZ_IREG | eCPUFlagXMem | eCPUFlagPort1 | eCPUFlagPort2 | eCPUFlagIOExpander | eCPUFlagUserFlags | eCPUFlagT0 | eCPUFlagT0CLK | eCPUFlagCondBitJmp | eCPUFlagTransferA_PSW | eCPUFlagRegBanks | eCPUFlagLogToPort | eCPUFlagDEC_REG | eCPUFlagMOVP3 | eCPUFlagINTLogic | eCPUFlagOKI },
{ "MSM80C48" , 0xfff, eCPUFlagCMOS | eCPUFlagDEC_DJNZ_IREG | eCPUFlagXMem | eCPUFlagPort1 | eCPUFlagPort2 | eCPUFlagIOExpander | eCPUFlagUserFlags | eCPUFlagT0 | eCPUFlagT0CLK | eCPUFlagCondBitJmp | eCPUFlagTransferA_PSW | eCPUFlagBUS | eCPUFlagRegBanks | eCPUFlagLogToPort | eCPUFlagDEC_REG | eCPUFlagMOVP3 | eCPUFlagINTLogic | eCPUFlagOKI },
{ NULL, 0, 0 }
};
void code48_init(void)
{
tCPUProps *pProp;
for (pProp = CPUProps; pProp->pName; pProp++)
(void)AddCPUUser(pProp->pName, SwitchTo_48, (void*)pProp, NULL);
AddInitPassProc(InitCode_48);
}