/* code87c800.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Codegenerator TLCS-870 */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <ctype.h>
#include <string.h>
#include "nls.h"
#include "bpemu.h"
#include "strutil.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmitree.h"
#include "asmcode.h"
#include "codepseudo.h"
#include "intpseudo.h"
#include "codevars.h"
#include "errmsg.h"
#include "code87c800.h"
typedef struct
{
const char *Name;
Byte Code;
} CondRec;
enum
{
ModNone = -1,
ModReg8 = 0,
ModReg16 = 1,
ModImm = 2,
ModAbs = 3,
ModMem = 4
};
#define MModReg8 (1 << ModReg8)
#define MModReg16 (1 << ModReg16)
#define MModImm (1 << ModImm)
#define MModAbs (1 << ModAbs)
#define MModMem (1 << ModMem)
#define AccReg 0
#define WAReg 0
#define COND_CODE_TRUE 6
#define Reg8Cnt 8
static const char Reg8Names[] = "AWCBEDLH";
static CPUVar CPU87C00, CPU87C20, CPU87C40, CPU87C70;
static ShortInt OpSize;
static Byte AdrVals[4];
static ShortInt AdrType;
static Byte AdrMode;
static CondRec *Conditions;
/*--------------------------------------------------------------------------*/
static void DecodeAdr(const tStrComp *pArg, Byte Erl)
{
static const char Reg16Names[][3] =
{
"WA", "BC", "DE", "HL"
};
static const int Reg16Cnt = sizeof(Reg16Names) / sizeof(*Reg16Names);
static const char AdrRegs[][3] =
{
"HL", "DE", "C", "PC", "A"
};
static const int AdrRegCnt = sizeof(AdrRegs) / sizeof(*AdrRegs);
int z;
Byte RegFlag;
Boolean OK;
LongInt DispAcc;
AdrType = ModNone;
AdrCnt = 0;
if (strlen(pArg
->str.
p_str) == 1)
{
for (z = 0; z < Reg8Cnt; z++)
if (as_toupper(*pArg->str.p_str) == Reg8Names[z])
{
AdrType = ModReg8;
OpSize = 0;
AdrMode = z;
goto chk;
}
}
for (z = 0; z < Reg16Cnt; z++)
if (!as_strcasecmp(pArg->str.p_str, Reg16Names[z]))
{
AdrType = ModReg16;
OpSize = 1;
AdrMode = z;
goto chk;
}
if (IsIndirect(pArg->str.p_str))
{
tStrComp Arg, Remainder;
char *EPos;
Boolean NegFlag, NNegFlag, FirstFlag;
LongInt DispPart;
StrCompRefRight(&Arg, pArg, 1);
StrCompShorten(&Arg, 1);
if (!as_strcasecmp(Arg.str.p_str, "-HL"))
{
AdrType = ModMem;
AdrMode = 7;
goto chk;
}
if (!as_strcasecmp(Arg.str.p_str, "HL+"))
{
AdrType = ModMem;
AdrMode = 6;
goto chk;
}
RegFlag = 0;
DispAcc = 0;
NegFlag = False;
OK = True;
FirstFlag = False;
do
{
KillPrefBlanksStrCompRef(&Arg);
EPos = indir_split_pos(Arg.str.p_str);
NNegFlag = EPos && (*EPos == '-');
if (EPos)
StrCompSplitRef(&Arg, &Remainder, &Arg, EPos);
KillPostBlanksStrComp(&Arg);
for (z = 0; z < AdrRegCnt; z++)
if (!as_strcasecmp(Arg.str.p_str, AdrRegs[z]))
break;
if (z >= AdrRegCnt)
{
tSymbolFlags Flags;
DispPart = EvalStrIntExpressionWithFlags(&Arg, Int32, &OK, &Flags);
FirstFlag |= mFirstPassUnknown(Flags);
DispAcc = NegFlag ? DispAcc - DispPart : DispAcc + DispPart;
}
else if ((NegFlag) || (RegFlag & (1 << z)))
{
WrError(ErrNum_InvAddrMode);
OK = False;
}
else
RegFlag |= 1 << z;
NegFlag = NNegFlag;
if (EPos)
Arg = Remainder;
}
while (EPos && OK);
if (DispAcc != 0)
RegFlag |= 1 << AdrRegCnt;
if (OK)
switch (RegFlag)
{
case 0x20:
if (FirstFlag)
DispAcc &= 0xff;
if (DispAcc > 0xff) WrError(ErrNum_OverRange);
else
{
AdrType = ModAbs;
AdrMode = 0;
AdrCnt = 1;
AdrVals[0] = DispAcc & 0xff;
}
break;
case 0x02:
AdrType = ModMem;
AdrMode = 2;
break;
case 0x01:
AdrType = ModMem;
AdrMode = 3;
break;
case 0x21:
if (FirstFlag)
DispAcc &= 0x7f;
if (ChkRange(DispAcc, -128, 127))
{
AdrType = ModMem;
AdrMode = 4;
AdrCnt = 1;
AdrVals[0] = DispAcc & 0xff;
}
break;
case 0x05:
AdrType = ModMem;
AdrMode = 5;
break;
case 0x18:
AdrType = ModMem;
AdrMode = 1;
break;
default:
WrError(ErrNum_InvAddrMode);
}
goto chk;
}
else
switch (OpSize)
{
case -1:
WrError(ErrNum_UndefOpSizes);
break;
case 0:
AdrVals[0] = EvalStrIntExpression(pArg, Int8, &OK);
if (OK)
{
AdrType = ModImm;
AdrCnt = 1;
}
break;
case 1:
DispAcc = EvalStrIntExpression(pArg, Int16, &OK);
if (OK)
{
AdrType = ModImm;
AdrCnt = 2;
AdrVals[0] = DispAcc & 0xff;
AdrVals[1] = (DispAcc >> 8) & 0xff;
}
break;
}
chk:
if ((AdrType != ModNone) && (!((1 << AdrType) & Erl)))
{
AdrType = ModNone;
AdrCnt = 0;
WrError(ErrNum_InvAddrMode);
}
}
static Boolean SplitBit(tStrComp *pArg, Byte *Erg)
{
char *p;
tStrComp BitArg;
p = RQuotPos(pArg->str.p_str, '.');
if (!p)
return False;
StrCompSplitRef(pArg, &BitArg, pArg, p);
if (strlen(BitArg.
str.
p_str) != 1) return False
;
else
if ((*BitArg.str.p_str >= '0') && (*BitArg.str.p_str <= '7'))
{
*Erg = *BitArg.str.p_str - '0';
return True;
}
else
{
for (*Erg = 0; *Erg < Reg8Cnt; (*Erg)++)
if (as_toupper(*BitArg.str.p_str) == Reg8Names[*Erg])
break;
if (*Erg < Reg8Cnt)
{
*Erg += 8;
return True;
}
else
return False;
}
}
static void CodeMem(Byte Entry, Byte Opcode)
{
BAsmCode[0] = Entry + AdrMode;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
BAsmCode[1 + AdrCnt] = Opcode;
}
/*!------------------------------------------------------------------------
* \fn decode_condition(const char *p_cond_str, Byte *p_cond_code)
* \brief parse condition code
* \param p_cond_str source argument
* \param p_cond_code returns code if found
* \return True if found
* ------------------------------------------------------------------------ */
static Boolean decode_condition(const char *p_cond_str, Byte *p_cond_code)
{
int z;
for (z = 0; Conditions[z].Name; z++)
if (!as_strcasecmp(p_cond_str, Conditions[z].Name))
{
*p_cond_code = Conditions[z].Code;
return True;
}
return False;
}
/*!------------------------------------------------------------------------
* \fn cond_code_tf(Byte cond_code)
* \brief is condition code True or False?
* \param cond_code code to check
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean cond_code_tf(Byte cond_code)
{
return (cond_code == COND_CODE_TRUE)
|| (cond_code == 7);
}
/*--------------------------------------------------------------------------*/
static void DecodeFixed(Word Code)
{
if (ChkArgCnt(0, 0))
{
CodeLen = 0;
if (Hi(Code) != 0)
BAsmCode[CodeLen++] = Hi(Code);
BAsmCode[CodeLen++] = Lo(Code);
}
}
static void DecodeLD(Word Code)
{
Boolean OK;
Byte HReg, HCnt, HMode, HVal;
UNUSED(Code);
if (!ChkArgCnt(2, 2));
else if (!as_strcasecmp(ArgStr[1].str.p_str, "SP"))
{
OpSize=1;
DecodeAdr(&ArgStr[2], MModImm+MModReg16);
switch (AdrType)
{
case ModReg16:
CodeLen = 2; BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = 0xfa;
break;
case ModImm:
CodeLen = 3;
BAsmCode[0] = 0xfa;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
break;
}
}
else if (!as_strcasecmp(ArgStr[2].str.p_str, "SP"))
{
DecodeAdr(&ArgStr[1], MModReg16);
switch (AdrType)
{
case ModReg16:
CodeLen = 2;
BAsmCode[0] = 0xe8 + AdrMode;
BAsmCode[1] = 0xfb;
break;
}
}
else if (!as_strcasecmp(ArgStr[1].str.p_str, "RBS"))
{
BAsmCode[1] = EvalStrIntExpression(&ArgStr[2], Int4, &OK);
if (OK)
{
CodeLen = 2;
BAsmCode[0] = 0x0f;
}
}
else if (!as_strcasecmp(ArgStr[1].str.p_str, "CF"))
{
if (!SplitBit(&ArgStr[2], &HReg)) WrError(ErrNum_InvBitPos);
else
{
DecodeAdr(&ArgStr[2], MModReg8 | MModAbs | MModMem);
switch (AdrType)
{
case ModReg8:
if (HReg >= 8) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = 0xd8 | HReg;
}
break;
case ModAbs:
if (HReg >= 8) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0xd8 | HReg;
BAsmCode[1] = AdrVals[0];
}
break;
case ModMem:
if (HReg < 8)
{
CodeLen = 2 + AdrCnt;
CodeMem(0xe0, 0xd8 | HReg);
}
else if ((AdrMode != 2) && (AdrMode != 3)) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0xe0 | HReg;
BAsmCode[1] = 0x9c | AdrMode;
}
break;
}
}
}
else if (!as_strcasecmp(ArgStr[2].str.p_str, "CF"))
{
if (!SplitBit(&ArgStr[1], &HReg)) WrError(ErrNum_InvBitPos);
else
{
DecodeAdr(&ArgStr[1], MModReg8 | MModAbs | MModMem);
switch (AdrType)
{
case ModReg8:
if (HReg >= 8) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = 0xc8 | HReg;
}
break;
case ModAbs:
case ModMem:
if (HReg < 8)
{
CodeLen = 2 + AdrCnt;
CodeMem(0xe0, 0xc8 | HReg);
}
else if ((AdrMode != 2) && (AdrMode != 3)) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0xe0 | HReg;
BAsmCode[1] = 0x98 | AdrMode;
}
break;
}
}
}
else
{
DecodeAdr(&ArgStr[1], MModReg8 | MModReg16 | MModAbs | MModMem);
switch (AdrType)
{
case ModReg8:
HReg = AdrMode;
DecodeAdr(&ArgStr[2], MModReg8 | MModAbs | MModMem | MModImm);
switch (AdrType)
{
case ModReg8:
if (HReg == AccReg)
{
CodeLen = 1;
BAsmCode[0] = 0x50 | AdrMode;
}
else if (AdrMode == AccReg)
{
CodeLen = 1;
BAsmCode[0] = 0x58 | HReg;
}
else
{
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = 0x58 | HReg;
}
break;
case ModAbs:
if (HReg == AccReg)
{
CodeLen = 2;
BAsmCode[0] = 0x22;
BAsmCode[1] = AdrVals[0];
}
else
{
CodeLen = 3;
BAsmCode[0] = 0xe0;
BAsmCode[1] = AdrVals[0];
BAsmCode[2] = 0x58 | HReg;
}
break;
case ModMem:
if ((HReg == AccReg) && (AdrMode == 3)) /* A,(HL) */
{
CodeLen = 1;
BAsmCode[0] = 0x23;
}
else
{
CodeLen = 2 + AdrCnt;
CodeMem(0xe0, 0x58 | HReg);
if ((HReg >= 6) && (AdrMode == 6)) WrError(ErrNum_Unpredictable);
}
break;
case ModImm:
CodeLen = 2;
BAsmCode[0] = 0x30 | HReg;
BAsmCode[1] = AdrVals[0];
break;
}
break;
case ModReg16:
HReg = AdrMode;
DecodeAdr(&ArgStr[2], MModReg16 | MModAbs | MModMem | MModImm);
switch (AdrType)
{
case ModReg16:
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = 0x14 | HReg;
break;
case ModAbs:
CodeLen = 3;
BAsmCode[0] = 0xe0;
BAsmCode[1] = AdrVals[0];
BAsmCode[2] = 0x14 | HReg;
break;
case ModMem:
if (AdrMode > 5) WrError(ErrNum_InvAddrMode); /* (-HL), (HL+) */
else
{
CodeLen = 2 + AdrCnt;
BAsmCode[0] = 0xe0 | AdrMode;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
BAsmCode[1 + AdrCnt] = 0x14 + HReg;
}
break;
case ModImm:
CodeLen = 3;
BAsmCode[0] = 0x14 | HReg;
memcpy(BAsmCode
+ 1, AdrVals
, 2);
break;
}
break;
case ModAbs:
HReg = AdrVals[0];
OpSize = 0;
DecodeAdr(&ArgStr[2], MModReg8 | MModReg16 | MModAbs | MModMem | MModImm);
switch (AdrType)
{
case ModReg8:
if (AdrMode == AccReg)
{
CodeLen = 2;
BAsmCode[0] = 0x2a;
BAsmCode[1] = HReg;
}
else
{
CodeLen = 3;
BAsmCode[0] = 0xf0;
BAsmCode[1] = HReg;
BAsmCode[2] = 0x50 | AdrMode;
}
break;
case ModReg16:
CodeLen = 3;
BAsmCode[0] = 0xf0;
BAsmCode[1] = HReg;
BAsmCode[2] = 0x10 | AdrMode;
break;
case ModAbs:
CodeLen = 3;
BAsmCode[0] = 0x26;
BAsmCode[1] = AdrVals[0];
BAsmCode[2] = HReg;
break;
case ModMem:
if (AdrMode > 5) WrError(ErrNum_InvAddrMode); /* (-HL),(HL+) */
else
{
CodeLen = 3 + AdrCnt;
BAsmCode[0] = 0xe0 | AdrMode;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
BAsmCode[1 + AdrCnt] = 0x26;
BAsmCode[2 + AdrCnt] = HReg;
}
break;
case ModImm:
CodeLen = 3;
BAsmCode[0] = 0x2c;
BAsmCode[1] = HReg;
BAsmCode[2] = AdrVals[0];
break;
}
break;
case ModMem:
HVal = AdrVals[0];
HCnt = AdrCnt;
HMode = AdrMode;
OpSize = 0;
DecodeAdr(&ArgStr[2], MModReg8 | MModReg16 | MModAbs | MModMem | MModImm);
switch (AdrType)
{
case ModReg8:
if ((HMode == 3) && (AdrMode == AccReg)) /* (HL),A */
{
CodeLen = 1;
BAsmCode[0] = 0x2b;
}
else if ((HMode == 1) || (HMode == 5)) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2 + HCnt;
BAsmCode[0] = 0xf0 | HMode;
memcpy(BAsmCode
+ 1, &HVal
, HCnt
);
BAsmCode[1 + HCnt] = 0x50 | AdrMode;
if ((HMode == 6) && (AdrMode >= 6)) WrError(ErrNum_Unpredictable);
}
break;
case ModReg16:
if ((HMode < 2) || (HMode > 4)) WrError(ErrNum_InvAddrMode); /* (HL),(DE),(HL+d) */
else
{
CodeLen = 2 + HCnt;
BAsmCode[0] = 0xf0 | HMode;
memcpy(BAsmCode
+ 1, &HVal
, HCnt
);
BAsmCode[1 + HCnt] = 0x10 | AdrMode;
}
break;
case ModAbs:
if (HMode != 3) WrError(ErrNum_InvAddrMode); /* (HL) */
else
{
CodeLen = 3;
BAsmCode[0] = 0xe0;
BAsmCode[1] = AdrVals[0];
BAsmCode[2] = 0x27;
}
break;
case ModMem:
if (HMode != 3) WrError(ErrNum_InvAddrMode); /* (HL) */
else if (AdrMode > 5) WrError(ErrNum_InvAddrMode); /* (-HL),(HL+) */
else
{
CodeLen = 2 + AdrCnt;
BAsmCode[0] = 0xe0 | AdrMode;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
BAsmCode[1 + AdrCnt] = 0x27;
}
break;
case ModImm:
if ((HMode == 1) || (HMode == 5)) WrError(ErrNum_InvAddrMode); /* (HL+C),(PC+A) */
else if (HMode == 3) /* (HL) */
{
CodeLen = 2;
BAsmCode[0] = 0x2d;
BAsmCode[1] = AdrVals[0];
}
else
{
CodeLen = 3 + HCnt;
BAsmCode[0] = 0xf0 + HMode;
memcpy(BAsmCode
+ 1, &HVal
, HCnt
);
BAsmCode[1 + HCnt] = 0x2c;
BAsmCode[2 + HCnt] = AdrVals[0];
}
break;
}
break;
}
}
}
static void DecodeXCH(Word Code)
{
Byte HReg;
UNUSED(Code);
if (ChkArgCnt(2, 2))
{
DecodeAdr(&ArgStr[1], MModReg8 | MModReg16 | MModAbs | MModMem);
switch (AdrType)
{
case ModReg8:
HReg = AdrMode;
DecodeAdr(&ArgStr[2], MModReg8 | MModAbs | MModMem);
switch (AdrType)
{
case ModReg8:
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = 0xa8 | HReg;
break;
case ModAbs:
case ModMem:
CodeLen = 2 + AdrCnt;
CodeMem(0xe0, 0xa8 | HReg);
if ((HReg >= 6) && (AdrMode == 6)) WrError(ErrNum_Unpredictable);
break;
}
break;
case ModReg16:
HReg = AdrMode;
DecodeAdr(&ArgStr[2], MModReg16);
if (AdrType != ModNone)
{
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = 0x10 | HReg;
}
break;
case ModAbs:
BAsmCode[1] = AdrVals[0];
DecodeAdr(&ArgStr[2], MModReg8);
if (AdrType != ModNone)
{
CodeLen = 3;
BAsmCode[0] = 0xe0;
BAsmCode[2] = 0xa8 | AdrMode;
}
break;
case ModMem:
BAsmCode[0] = 0xe0 | AdrMode;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
HReg = AdrCnt;
DecodeAdr(&ArgStr[2], MModReg8);
if (AdrType != ModNone)
{
CodeLen = 2 + HReg;
BAsmCode[1 + HReg] = 0xa8 | AdrMode;
if ((AdrMode >= 6) && ((BAsmCode[0] & 0x0f) == 6)) WrError(ErrNum_Unpredictable);
}
break;
}
}
}
static void DecodeCLR(Word Code)
{
Byte HReg;;
UNUSED(Code);
if (!ChkArgCnt(1, 1));
else if (!as_strcasecmp(ArgStr[1].str.p_str, "CF"))
{
CodeLen = 1;
BAsmCode[0] = 0x0c;
}
else if (SplitBit(&ArgStr[1], &HReg))
{
DecodeAdr(&ArgStr[1], MModReg8 | MModAbs | MModMem);
switch (AdrType)
{
case ModReg8:
if (HReg >= 8) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = 0x48 | HReg;
}
break;
case ModAbs:
if (HReg >= 8) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0x48 | HReg;
BAsmCode[1] = AdrVals[0];
}
break;
case ModMem:
if (HReg <= 8)
{
CodeLen = 2 + AdrCnt;
CodeMem(0xe0, 0x48 | HReg);
}
else if ((AdrMode != 2) && (AdrMode != 3)) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0xe0 | HReg;
BAsmCode[1] = 0x88 | AdrMode;
}
break;
}
}
else
{
DecodeAdr(&ArgStr[1], MModReg8 | MModReg16 | MModAbs | MModMem);
switch (AdrType)
{
case ModReg8:
CodeLen = 2;
BAsmCode[0] = 0x30 | AdrMode;
BAsmCode[1] = 0;
break;
case ModReg16:
CodeLen = 3;
BAsmCode[0] = 0x14 | AdrMode;
BAsmCode[1] = 0;
BAsmCode[2] = 0;
break;
case ModAbs:
CodeLen = 2;
BAsmCode[0] = 0x2e;
BAsmCode[1] = AdrVals[0];
break;
case ModMem:
if ((AdrMode == 5) || (AdrMode == 1)) WrError(ErrNum_InvAddrMode); /* (PC+A, HL+C) */
else if (AdrMode == 3) /* (HL) */
{
CodeLen = 1;
BAsmCode[0] = 0x2f;
}
else
{
CodeLen = 3 + AdrCnt;
BAsmCode[0] = 0xf0 | AdrMode;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
BAsmCode[1 + AdrCnt] = 0x2c;
BAsmCode[2 + AdrCnt] = 0;
}
break;
}
}
}
static void DecodeLDW(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(2, 2))
{
Boolean OK;
Integer AdrInt = EvalStrIntExpression(&ArgStr[2], Int16, &OK);
if (OK)
{
DecodeAdr(&ArgStr[1], MModReg16 | MModAbs | MModMem);
switch (AdrType)
{
case ModReg16:
CodeLen = 3;
BAsmCode[0] = 0x14 | AdrMode;
BAsmCode[1] = AdrInt & 0xff;
BAsmCode[2] = AdrInt >> 8;
break;
case ModAbs:
CodeLen = 4;
BAsmCode[0] = 0x24;
BAsmCode[1] = AdrVals[0];
BAsmCode[2] = AdrInt & 0xff;
BAsmCode[3] = AdrInt >> 8;
break;
case ModMem:
if (AdrMode != 3) WrError(ErrNum_InvAddrMode); /* (HL) */
else
{
CodeLen = 3;
BAsmCode[0] = 0x25;
BAsmCode[1] = AdrInt & 0xff;
BAsmCode[2] = AdrInt >> 8;
}
break;
}
}
}
}
static void DecodePUSH_POP(Word Code)
{
if (!ChkArgCnt(1, 1));
else if (!as_strcasecmp(ArgStr[1].str.p_str, "PSW"))
{
CodeLen = 1;
BAsmCode[0] = Code;
}
else
{
DecodeAdr(&ArgStr[1], MModReg16);
if (AdrType != ModNone)
{
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = Code;
}
}
}
static void DecodeTEST_CPL_SET(Word Code)
{
Byte HReg;
if (!ChkArgCnt(1, 1));
else if (!as_strcasecmp(ArgStr[1].str.p_str, "CF"))
{
if (Code == 0xd8) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 1;
BAsmCode[0] = 0x0d + Ord(Code == 0xc0);
}
}
else if (!SplitBit(&ArgStr[1], &HReg)) WrError(ErrNum_InvBitPos);
else
{
DecodeAdr(&ArgStr[1], MModReg8 | MModAbs | MModMem);
switch (AdrType)
{
case ModReg8:
if (HReg >= 8) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = Code | HReg;
}
break;
case ModAbs:
if (HReg >= 8) WrError(ErrNum_InvAddrMode);
else if (Code == 0xc0)
{
CodeLen = 3;
CodeMem(0xe0, Code | HReg);
}
else
{
CodeLen = 2;
BAsmCode[0] = Code | HReg;
BAsmCode[1] = AdrVals[0];
}
break;
case ModMem:
if (HReg < 8)
{
CodeLen = 2 + AdrCnt;
CodeMem(0xe0, Code | HReg);
}
else if ((AdrMode != 2) && (AdrMode != 3)) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0xe0 | HReg;
BAsmCode[1] = ((Code & 0x18) >> 1) | ((Code & 0x80) >> 3) | 0x80 | AdrMode;
}
break;
}
}
}
static void DecodeReg(Word Code)
{
if (ChkArgCnt(1, 1))
{
DecodeAdr(&ArgStr[1], MModReg8);
if (AdrType != ModNone)
{
if (AdrMode == AccReg)
{
CodeLen = 1;
BAsmCode[0] = Code;
}
else
{
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = Code;
}
}
}
}
static void DecodeALU(Word Code)
{
Byte HReg;
Boolean OK;
if (!ChkArgCnt(2, 2));
else if (!as_strcasecmp(ArgStr[1].str.p_str, "CF"))
{
if (Code != 5) WrError(ErrNum_InvAddrMode); /* XOR */
else if (!SplitBit(&ArgStr[2], &HReg)) WrError(ErrNum_InvBitPos);
else if (HReg >= 8) WrError(ErrNum_InvAddrMode);
else
{
DecodeAdr(&ArgStr[2], MModReg8 | MModAbs | MModMem);
switch (AdrType)
{
case ModReg8:
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = 0xd0 | HReg;
break;
case ModAbs:
case ModMem:
CodeLen = 2 + AdrCnt;
CodeMem(0xe0, 0xd0 | HReg);
break;
}
}
}
else
{
DecodeAdr(&ArgStr[1], MModReg8 | MModReg16 | MModMem | MModAbs);
switch (AdrType)
{
case ModReg8:
HReg = AdrMode;
DecodeAdr(&ArgStr[2], MModReg8 | MModMem | MModAbs | MModImm);
switch (AdrType)
{
case ModReg8:
if (HReg == AccReg)
{
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = 0x60 | Code;
}
else if (AdrMode == AccReg)
{
CodeLen = 2;
BAsmCode[0] = 0xe8 | HReg;
BAsmCode[1] = 0x68 | Code;
}
else WrError(ErrNum_InvAddrMode);
break;
case ModMem:
if (HReg != AccReg) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2 + AdrCnt;
BAsmCode[0] = 0xe0 | AdrMode;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
BAsmCode[1 + AdrCnt] = 0x78 | Code;
}
break;
case ModAbs:
if (HReg != AccReg) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0x78 | Code;
BAsmCode[1] = AdrVals[0];
}
break;
case ModImm:
if (HReg == AccReg)
{
CodeLen = 2;
BAsmCode[0] = 0x70 | Code;
BAsmCode[1] = AdrVals[0];
}
else
{
CodeLen = 3;
BAsmCode[0] = 0xe8 | HReg;
BAsmCode[1] = 0x70 | Code;
BAsmCode[2] = AdrVals[0];
}
break;
}
break;
case ModReg16:
HReg = AdrMode;
DecodeAdr(&ArgStr[2], MModImm | MModReg16);
switch (AdrType)
{
case ModImm:
CodeLen = 4;
BAsmCode[0] = 0xe8 | HReg;
BAsmCode[1] = 0x38 | Code;
memcpy(BAsmCode
+ 2, AdrVals
, AdrCnt
);
break;
case ModReg16:
if (HReg != WAReg) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = 0x30 | Code;
}
break;
}
break;
case ModAbs:
if (!as_strcasecmp(ArgStr[2].str.p_str, "(HL)"))
{
CodeLen = 3;
BAsmCode[0] = 0xe0;
BAsmCode[1] = AdrVals[0];
BAsmCode[2] = 0x60 | Code;
}
else
{
BAsmCode[3] = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
if (OK)
{
CodeLen = 4;
BAsmCode[0] = 0xe0;
BAsmCode[1] = AdrVals[0];
BAsmCode[2] = 0x70 | Code;
}
}
break;
case ModMem:
if (!as_strcasecmp(ArgStr[2].str.p_str, "(HL)"))
{
CodeLen = 2 + AdrCnt;
BAsmCode[0] = 0xe0 | AdrMode;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
BAsmCode[1 + AdrCnt] = 0x60 | Code;
}
else
{
BAsmCode[2 + AdrCnt] = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
if (OK)
{
CodeLen = 3 + AdrCnt;
BAsmCode[0] = 0xe0 | AdrMode;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
BAsmCode[1 + AdrCnt] = 0x70 | Code;
}
}
break;
}
}
}
static void DecodeMCMP(Word Code)
{
Byte HReg;
Boolean OK;
UNUSED(Code);
if (ChkArgCnt(2, 2))
{
HReg = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
if (OK)
{
DecodeAdr(&ArgStr[1], MModMem | MModAbs);
if (AdrType != ModNone)
{
CodeLen = 3 + AdrCnt;
CodeMem(0xe0, 0x2f);
BAsmCode[2 + AdrCnt] = HReg;
}
}
}
}
static void DecodeINC_DEC(Word Code)
{
if (ChkArgCnt(1, 1))
{
DecodeAdr(&ArgStr[1], MModReg8 | MModReg16 | MModAbs | MModMem);
switch (AdrType)
{
case ModReg8:
CodeLen = 1;
BAsmCode[0] = 0x60 | Code | AdrMode;
break;
case ModReg16:
CodeLen = 1;
BAsmCode[0] = 0x10 | Code | AdrMode;
break;
case ModAbs:
CodeLen = 2;
BAsmCode[0] = 0x20 | Code;
BAsmCode[1] = AdrVals[0];
break;
case ModMem:
if (AdrMode == 3) /* (HL) */
{
CodeLen = 1;
BAsmCode[0] = 0x21 | Code;
}
else
{
CodeLen = 2 + AdrCnt;
BAsmCode[0] = 0xe0 | AdrMode;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
BAsmCode[1 + AdrCnt] = 0x20 | Code;
}
break;
}
}
}
static void DecodeMUL(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(2, 2))
{
DecodeAdr(&ArgStr[1], MModReg8);
if (AdrType == ModReg8)
{
Byte HReg = AdrMode;
DecodeAdr(&ArgStr[2], MModReg8);
if (AdrType == ModReg8)
{
if ((HReg ^ AdrMode) != 1) WrError(ErrNum_InvRegPair);
else
{
HReg = HReg >> 1;
if (HReg == 0)
{
CodeLen = 1;
BAsmCode[0] = 0x02;
}
else
{
CodeLen = 2;
BAsmCode[0] = 0xe8 | HReg;
BAsmCode[1] = 0x02;
}
}
}
}
}
}
static void DecodeDIV(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(2, 2))
{
DecodeAdr(&ArgStr[1], MModReg16);
if (AdrType == ModReg16)
{
Byte HReg = AdrMode;
DecodeAdr(&ArgStr[2], MModReg8);
if (AdrType == ModReg8)
{
if (AdrMode != 2) WrError(ErrNum_InvAddrMode); /* C */
else if (HReg == 0)
{
CodeLen = 1;
BAsmCode[0] = 0x03;
}
else
{
CodeLen = 2;
BAsmCode[0] = 0xe8 | HReg;
BAsmCode[1] = 0x03;
if (HReg == 1)
WrError(ErrNum_Unpredictable);
}
}
}
}
}
static void DecodeROLD_RORD(Word Code)
{
if (!ChkArgCnt(2, 2));
else if (as_strcasecmp(ArgStr[1].str.p_str, "A")) WrError(ErrNum_InvAddrMode);
else
{
DecodeAdr(&ArgStr[2], MModAbs | MModMem);
if (AdrType != ModNone)
{
CodeLen = 2 + AdrCnt;
CodeMem(0xe0, Code);
if (AdrMode == 1)
WrError(ErrNum_Unpredictable);
}
}
}
static void DecodeJRS(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(2, 2))
{
Integer AdrInt;
Byte cond_code;
Boolean OK;
tSymbolFlags Flags;
if (!decode_condition(ArgStr[1].str.p_str, &cond_code) || !cond_code_tf(cond_code)) WrStrErrorPos(ErrNum_UndefCond, &ArgStr[1]);
else
{
AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[2], Int16, &OK, &Flags) - (EProgCounter() + 2);
if (OK)
{
if (((AdrInt < -16) || (AdrInt > 15)) && !mSymbolQuestionable(Flags)) WrError(ErrNum_JmpDistTooBig);
else
{
CodeLen = 1;
BAsmCode[0] = ((cond_code - 2) << 5) | (AdrInt & 0x1f);
}
}
}
}
}
static void DecodeJR(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 2))
{
Integer AdrInt;
Byte cond_code;
Boolean OK;
tSymbolFlags Flags;
if (ArgCnt == 1)
cond_code = COND_CODE_TRUE;
else if (!decode_condition(ArgStr[1].str.p_str, &cond_code))
{
WrStrErrorPos(ErrNum_UndefCond, &ArgStr[1]);
return;
}
AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[ArgCnt], Int16, &OK, &Flags) - (EProgCounter() + 2);
if (OK)
{
if (((AdrInt < -128) || (AdrInt > 127)) && !mSymbolQuestionable(Flags)) WrError(ErrNum_JmpDistTooBig);
else
{
CodeLen = 2;
BAsmCode[0] = (ArgCnt == 1) ? 0xfb : 0xd0 | cond_code;
BAsmCode[1] = AdrInt & 0xff;
}
}
}
}
static void DecodeJP_CALL(Word Code)
{
if (ChkArgCnt(1, 1))
{
OpSize = 1;
DecodeAdr(&ArgStr[1], MModReg16 | MModAbs | MModMem | MModImm);
switch (AdrType)
{
case ModReg16:
CodeLen = 2;
BAsmCode[0] = 0xe8 | AdrMode;
BAsmCode[1] = Code;
break;
case ModAbs:
CodeLen = 3;
BAsmCode[0] = 0xe0;
BAsmCode[1] = AdrVals[0];
BAsmCode[2] = Code;
break;
case ModMem:
if (AdrMode > 5) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2 + AdrCnt;
BAsmCode[0] = 0xe0 | AdrMode;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
BAsmCode[1 + AdrCnt] = Code;
}
break;
case ModImm:
if ((AdrVals[1] == 0xff) && (Code == 0xfc))
{
CodeLen = 2;
BAsmCode[0] = 0xfd;
BAsmCode[1] = AdrVals[0];
}
else
{
CodeLen = 3;
BAsmCode[0] = Code;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
}
break;
}
}
}
static void DecodeCALLV(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 1))
{
Boolean OK;
Byte HVal = EvalStrIntExpression(&ArgStr[1], Int4, &OK);
if (OK)
{
CodeLen = 1;
BAsmCode[0] = 0xc0 | (HVal & 15);
}
}
}
static void DecodeCALLP(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 1))
{
Boolean OK;
Integer AdrInt = EvalStrIntExpression(&ArgStr[1], Int16, &OK);
if (OK)
{
if ((Hi(AdrInt) != 0xff) && (Hi(AdrInt) != 0)) WrError(ErrNum_OverRange);
else
{
CodeLen = 2;
BAsmCode[0] = 0xfd;
BAsmCode[1] = Lo(AdrInt);
}
}
}
}
/*--------------------------------------------------------------------------*/
static void AddFixed(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeFixed);
}
static void AddCond(const char *NName, Byte NCode)
{
order_array_rsv_end(Conditions, CondRec);
Conditions[InstrZ].Name = NName;
Conditions[InstrZ++].Code = NCode;
}
static void AddReg(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeReg);
}
static void InitFields(void)
{
InstTable = CreateInstTable(203);
AddInstTable(InstTable, "LD", 0, DecodeLD);
AddInstTable(InstTable, "XCH", 0, DecodeXCH);
AddInstTable(InstTable, "CLR", 0, DecodeCLR);
AddInstTable(InstTable, "LDW", 0, DecodeLDW);
AddInstTable(InstTable, "PUSH", 7, DecodePUSH_POP);
AddInstTable(InstTable, "POP", 6, DecodePUSH_POP);
AddInstTable(InstTable, "TEST", 0xd8, DecodeTEST_CPL_SET);
AddInstTable(InstTable, "CPL", 0xc0, DecodeTEST_CPL_SET);
AddInstTable(InstTable, "SET", 0x40, DecodeTEST_CPL_SET);
AddInstTable(InstTable, "MCMP", 0, DecodeMCMP);
AddInstTable(InstTable, "INC", 0, DecodeINC_DEC);
AddInstTable(InstTable, "DEC", 8, DecodeINC_DEC);
AddInstTable(InstTable, "MUL", 0, DecodeMUL);
AddInstTable(InstTable, "DIV", 0, DecodeDIV);
AddInstTable(InstTable, "ROLD", 8, DecodeROLD_RORD);
AddInstTable(InstTable, "RORD", 9, DecodeROLD_RORD);
AddInstTable(InstTable, "JRS", 0, DecodeJRS);
AddInstTable(InstTable, "JR", 0, DecodeJR);
AddInstTable(InstTable, "JP", 0xfe, DecodeJP_CALL);
AddInstTable(InstTable, "CALL", 0xfc, DecodeJP_CALL);
AddInstTable(InstTable, "CALLV", 0, DecodeCALLV);
AddInstTable(InstTable, "CALLP", 0, DecodeCALLP);
AddFixed("DI" , 0x483a);
AddFixed("EI" , 0x403a);
AddFixed("RET" , 0x0005);
AddFixed("RETI", 0x0004);
AddFixed("RETN", 0xe804);
AddFixed("SWI" , 0x00ff);
AddFixed("NOP" , 0x0000);
InstrZ = 0;
AddCond("EQ", 0); AddCond("Z" , 0);
AddCond("NE", 1); AddCond("NZ", 1);
AddCond("CS", 2); AddCond("LT", 2);
AddCond("CC", 3); AddCond("GE", 3);
AddCond("LE", 4); AddCond("GT", 5);
AddCond("T" , COND_CODE_TRUE); AddCond("F" , 7);
AddCond(NULL, 0);
AddReg("DAA" , 0x0a); AddReg("DAS" , 0x0b);
AddReg("SHLC", 0x1c); AddReg("SHRC", 0x1d);
AddReg("ROLC", 0x1e); AddReg("RORC", 0x1f);
AddReg("SWAP", 0x01);
InstrZ = 0;
AddInstTable(InstTable, "ADDC", InstrZ++, DecodeALU);
AddInstTable(InstTable, "ADD" , InstrZ++, DecodeALU);
AddInstTable(InstTable, "SUBB", InstrZ++, DecodeALU);
AddInstTable(InstTable, "SUB" , InstrZ++, DecodeALU);
AddInstTable(InstTable, "AND" , InstrZ++, DecodeALU);
AddInstTable(InstTable, "XOR" , InstrZ++, DecodeALU);
AddInstTable(InstTable, "OR" , InstrZ++, DecodeALU);
AddInstTable(InstTable, "CMP" , InstrZ++, DecodeALU);
}
static void DeinitFields(void)
{
DestroyInstTable(InstTable);
order_array_free(Conditions);
}
/*--------------------------------------------------------------------------*/
static void MakeCode_87C800(void)
{
CodeLen = 0;
DontPrint = False;
OpSize = -1;
/* zu ignorierendes */
if (Memo(""))
return;
/* Pseudoanweisungen */
if (DecodeIntelPseudo(False))
return;
if (!LookupInstTable(InstTable, OpPart.str.p_str))
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
}
static Boolean IsDef_87C800(void)
{
return False;
}
static void SwitchFrom_87C800(void)
{
DeinitFields();
}
static Boolean TrueFnc(void)
{
return True;
}
static void SwitchTo_87C800(void)
{
TurnWords = False;
SetIntConstMode(eIntConstModeIntel);
SetIsOccupiedFnc = TrueFnc;
PCSymbol = "$";
HeaderID = 0x54;
NOPCode = 0x00;
DivideChars = ",";
HasAttrs = False;
ValidSegs = 1 << SegCode;
Grans[SegCode] = 1;
ListGrans[SegCode] = 1;
SegInits[SegCode] = 0;
SegLimits[SegCode] = 0xffff;
MakeCode = MakeCode_87C800;
IsDef = IsDef_87C800;
SwitchFrom = SwitchFrom_87C800;
InitFields();
}
void code87c800_init(void)
{
CPU87C00 = AddCPU("87C00", SwitchTo_87C800);
CPU87C20 = AddCPU("87C20", SwitchTo_87C800);
CPU87C40 = AddCPU("87C40", SwitchTo_87C800);
CPU87C70 = AddCPU("87C70", SwitchTo_87C800);
}