/* code8008.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Codegenerator Intel 8008 */
/* */
/*****************************************************************************/
#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 "codepseudo.h"
#include "intpseudo.h"
#include "errmsg.h"
#include "code8008.h"
/*---------------------------------------------------------------------------*/
/* Types */
typedef enum
{
eModNone = 0,
eModReg8 = 1,
eModIHL = 2,
eModImm = 3,
eModReg16 = 4
} tAdrMode;
#define AccReg 0
#define MModReg8 (1 << eModReg8)
#define MModReg16 (1 << eModReg16)
#define MModImm (1 << eModImm)
#define MModIHL (1 << eModIHL)
#define MModReg16 (1 << eModReg16)
typedef struct
{
tAdrMode Mode;
Byte Val;
} tAdrVals;
/*---------------------------------------------------------------------------*/
/* Variablen */
static CPUVar CPU8008, CPU8008New;
static const char RegNames[] = "ABCDEHLM";
/*---------------------------------------------------------------------------*/
/* Parser */
static Boolean DecodeReg(char *Asc, tZ80Syntax Syntax, Byte *pErg)
{
const char *p;
return False;
p
= strchr(RegNames
, as_toupper
(*Asc
));
if (!p)
return False;
*pErg = p - RegNames;
if ((!(Syntax & eSyntax808x)) && (*pErg == 7))
return False;
return True;
}
static Boolean DecodeReg16(char *Asc, Byte *pErg)
{
return False;
for (*pErg = 1; *pErg < 7; *pErg += 2)
if ((as_toupper(Asc[0]) == RegNames[*pErg])
&& (as_toupper(Asc[1]) == RegNames[*pErg + 1]))
{
*pErg /= 2;
return True;
}
return False;
}
/*!------------------------------------------------------------------------
* \fn DecodeCondition_Z80(const char *pAsc, Byte *pResult)
* \brief decode Z80-style conditions for JP CALL RET
* \param pAsc source argument
* \param dest buffer
* \return True if success
* ------------------------------------------------------------------------ */
static const char Conditions[][4] =
{
"NC", "NZ", "P", "PO", "C", "Z", "M", "PE"
};
static Boolean DecodeCondition_Z80(const char *pAsc, Byte *pResult)
{
for (*pResult = 0; *pResult < sizeof(Conditions) / sizeof(*Conditions); (*pResult)++)
if (!as_strcasecmp(pAsc, Conditions[*pResult]))
{
*pResult = *pResult << 3;
return True;
}
return False;
}
/*!------------------------------------------------------------------------
* \fn DecodeAdr_Z80(const tStrComp *pArg, Word Mask, tAdrVals *pVals)
* \brief decode address expression in Z80 style syntax
* \param pArg source argument
* \param Mask bit mask of allowed addressig modes
* \param pVals dest buffer
* \return resulting addressing mode
* ------------------------------------------------------------------------ */
static void ResetAdrVals(tAdrVals *pVals)
{
pVals->Mode = eModNone;
pVals->Val = 0;
}
static tAdrMode DecodeAdr_Z80(const tStrComp *pArg, Word Mask, tAdrVals *pVals)
{
Boolean OK;
ResetAdrVals(pVals);
if (DecodeReg(pArg->str.p_str, eSyntaxZ80, &pVals->Val))
{
pVals->Mode = eModReg8;
goto AdrFound;
}
if (DecodeReg16(pArg->str.p_str, &pVals->Val))
{
pVals->Mode = eModReg16;
goto AdrFound;
}
if (!as_strcasecmp(pArg->str.p_str, "(HL)"))
{
pVals->Mode = eModIHL;
goto AdrFound;
}
pVals->Val = EvalStrIntExpression(pArg, Int8, &OK);
if (OK)
pVals->Mode = eModImm;
AdrFound:
if ((pVals->Mode != eModNone) && (!(Mask & (1 << pVals->Mode))))
{
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
ResetAdrVals(pVals);
}
return pVals->Mode;
}
/*!------------------------------------------------------------------------
* \fn CheckAcc_Z80(const tStrComp *pArg)
* \brief check whether (optional first) argument is accumulator
* \param pArg source argument
* \return True if it is
* ------------------------------------------------------------------------ */
static Boolean CheckAcc_Z80(const tStrComp *pArg)
{
tAdrVals AdrVals;
switch (DecodeAdr_Z80(pArg, MModReg8, &AdrVals))
{
case eModReg8:
if (AdrVals.Val != AccReg)
{
WrStrErrorPos(ErrNum_InvReg, pArg);
return False;
}
break;
default:
return False;
}
return True;
}
/*---------------------------------------------------------------------------*/
/* Instruction Decoders */
/*!------------------------------------------------------------------------
* \fn DecodeFixed(Word Code)
* \brief handle instructions without argument
* \param Word instruction code & syntax flag
* ------------------------------------------------------------------------ */
static void DecodeFixed(Word Code)
{
if (ChkArgCnt(0, 0)
&& ChkZ80Syntax((tZ80Syntax)Hi(Code)))
{
BAsmCode[0] = Lo(Code);
CodeLen = 1;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeFixed(Word Code)
* \brief handle instructions with one (8 bit) immediate argument
* \param Index machine code
* ------------------------------------------------------------------------ */
static void DecodeImm(Word Code)
{
if (ChkArgCnt(1, 1)
&& ChkZ80Syntax((tZ80Syntax)Hi(Code)))
{
Boolean OK;
BAsmCode[1] = EvalStrIntExpression(&ArgStr[1], Int8, &OK);
if (OK)
{
BAsmCode[0] = Lo(Code);
CodeLen = 2;
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeJmp(Word Index)
* \brief decode jump/call instructions taking one address argument
* \param Index machine code
* ------------------------------------------------------------------------ */
static void DecodeJmpCore(Byte Code)
{
tEvalResult EvalResult;
Word AdrWord;
AdrWord = EvalStrIntExpressionWithResult(&ArgStr[ArgCnt], UInt14, &EvalResult);
if (EvalResult.OK)
{
BAsmCode[0] = Code;
BAsmCode[1] = Lo(AdrWord);
BAsmCode[2] = Hi(AdrWord) & 0x3f;
CodeLen = 3;
ChkSpace(SegCode, EvalResult.AddrSpaceMask);
}
}
static void DecodeJmp(Word Index)
{
if (ChkArgCnt(1, 1)
&& ChkZ80Syntax(eSyntax808x))
DecodeJmpCore(Lo(Index));
}
/*!------------------------------------------------------------------------
* \fn DecodeJP(Word Code)
* \brief decode JP instruction
* ------------------------------------------------------------------------ */
static void DecodeJP(Word Code)
{
UNUSED(Code);
/* one argument, new 8008 insn set & not exclusively Z80: -> jump on positive or parity even */
if ((CurrZ80Syntax != eSyntaxZ80) && (ArgCnt == 1))
{
DecodeJmp((MomCPU == CPU8008New) ? 0x50 : 0x78);
return;
}
/* for all other stuff, Z80 syntax must be enabled */
if (!ChkArgCnt(1, 2)
|| !ChkZ80Syntax(eSyntaxZ80))
return;
if (ArgCnt == 2)
{
Byte Cond;
if (DecodeCondition_Z80(ArgStr[1].str.p_str, &Cond))
DecodeJmpCore(0x40 | Cond);
}
else
DecodeJmpCore(0x44);
}
/*!------------------------------------------------------------------------
* \fn DecodeCALL(Word Code)
* \brief decode CALL instruction
* ------------------------------------------------------------------------ */
static void DecodeCALL(Word Code)
{
UNUSED(Code);
/* single-arg CALL is only NOT allowed on old 8008 in pure 808x mode : */
if ((CurrZ80Syntax != eSyntaxZ80) && (ArgCnt == 1) && (MomCPU == CPU8008New))
{
DecodeJmp(0x46);
return;
}
if (!ChkArgCnt(1, 2)
|| !ChkZ80Syntax(eSyntaxZ80))
return;
if (ArgCnt == 2)
{
Byte Cond;
if (DecodeCondition_Z80(ArgStr[1].str.p_str, &Cond))
DecodeJmpCore(0x42 | Cond);
}
else
DecodeJmpCore(0x46);
}
/*!------------------------------------------------------------------------
* \fn DecodeRET(Word Code)
* \brief handle RET instruction
* ------------------------------------------------------------------------ */
static void DecodeRET(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(0, (CurrZ80Syntax != eSyntax808x) ? 1 : 0))
{
if (1 == ArgCnt)
{
Byte Cond;
if (DecodeCondition_Z80(ArgStr[1].str.p_str, &Cond))
BAsmCode[CodeLen++] = 0x03 | Cond;
}
else
BAsmCode[CodeLen++] = 0x07;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeRST(Word Index)
* \brief handle RST instruction
* ------------------------------------------------------------------------ */
static void DecodeRST(Word Index)
{
UNUSED(Index);
if (ChkArgCnt(1, 1))
{
Word AdrWord;
tEvalResult EvalResult;
AdrWord = EvalStrIntExpressionWithResult(&ArgStr[1], UInt14, &EvalResult);
if (mFirstPassUnknown(EvalResult.Flags)) AdrWord &= 0x38;
if (EvalResult.OK)
{
if (ChkRange(AdrWord, 0, 0x38))
{
if (AdrWord < 8)
{
BAsmCode[0] = 0x05 | (AdrWord << 3);
CodeLen = 1;
ChkSpace(SegCode, EvalResult.AddrSpaceMask);
}
else if ((AdrWord & 7) != 0) WrError(ErrNum_NotAligned);
else
{
BAsmCode[0] = AdrWord + 0x05;
CodeLen = 1;
ChkSpace(SegCode, EvalResult.AddrSpaceMask);
}
}
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeINP_OUT(Word Index)
* \brief Handle IN(P)/OUT Instructions
* \param IsIN True if IN
* ------------------------------------------------------------------------ */
static void DecodeINP_OUT(Word IsIN)
{
tEvalResult EvalResult;
Byte Addr, AddrArgIdx;
if (Memo("INP") && !ChkZ80Syntax(eSyntax808x))
return;
if (Memo("IN") && (MomCPU == CPU8008) && !ChkZ80Syntax(eSyntaxZ80))
return;
if (!ChkArgCnt((CurrZ80Syntax & eSyntax808x) ? 1 : 2, (CurrZ80Syntax & eSyntaxZ80) ? 2 : 1))
return;
if ((ArgCnt == 2) /* Z80-style with A */
&& !CheckAcc_Z80(&ArgStr[IsIN ? 1 : 2]))
return;
AddrArgIdx = ((ArgCnt == 2) && IsIN) ? 2 : 1;
if (IsIN)
Addr = EvalStrIntExpressionWithResult(&ArgStr[AddrArgIdx], UInt3, &EvalResult);
else
{
Addr = EvalStrIntExpressionWithResult(&ArgStr[AddrArgIdx], UInt5, &EvalResult);
if (mFirstPassUnknown(EvalResult.Flags))
Addr |= 0x08;
if ((EvalResult.OK) && (Addr < 8))
{
WrStrErrorPos(ErrNum_UnderRange, &ArgStr[AddrArgIdx]);
EvalResult.OK = False;
}
}
if (EvalResult.OK)
{
BAsmCode[0] = 0x41 | (Addr << 1);
CodeLen = 1;
ChkSpace(SegIO, EvalResult.AddrSpaceMask);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeMOV(Word Index)
* \brief handle MOV instruction
* ------------------------------------------------------------------------ */
static void DecodeMOV(Word Index)
{
Byte SReg, DReg;
UNUSED(Index);
if (!ChkArgCnt(2, 2));
else if (!ChkZ80Syntax(eSyntax808x));
else if (!DecodeReg(ArgStr[1].str.p_str, eSyntax808x, &DReg)) WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
else if (!DecodeReg(ArgStr[2].str.p_str, eSyntax808x, &SReg)) WrStrErrorPos(ErrNum_InvReg, &ArgStr[2]);
else if ((DReg == 7) && (SReg == 7)) WrError(ErrNum_InvRegPair); /* MOV M,M not allowed - asame opcode as HLT */
else
{
BAsmCode[0] = 0xc0 | (DReg << 3) | SReg;
CodeLen = 1;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeMVI(Word Index)
* \brief handle MVI instruction
* ------------------------------------------------------------------------ */
static void DecodeMVI(Word Index)
{
Byte DReg;
UNUSED(Index);
if (!ChkArgCnt(2, 2));
else if (!ChkZ80Syntax(eSyntax808x));
else if (!DecodeReg(ArgStr[1].str.p_str, eSyntax808x, &DReg)) WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
else
{
Boolean OK;
BAsmCode[1] = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
if (OK)
{
BAsmCode[0] = 0x06 | (DReg << 3);
CodeLen = 2;
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeLXI(Word Index)
* \brief handle (pseudo) LXI instruction
* ------------------------------------------------------------------------ */
static void BuildLXI(Byte DReg, Word Val)
{
BAsmCode[2] = 0x06 | ((DReg + 1) << 3);
BAsmCode[3] = Lo(Val);
BAsmCode[0] = 0x06 | (DReg << 3);
BAsmCode[1] = Hi(Val);
CodeLen = 4;
}
static void DecodeLXI(Word Index)
{
Byte DReg;
UNUSED(Index);
if (!ChkArgCnt(2, 2));
else if (!ChkZ80Syntax(eSyntax808x));
else if (!DecodeReg(ArgStr[1].str.p_str, eSyntax808x, &DReg)) WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
else if ((DReg != 1) && (DReg != 3) && (DReg != 5)) WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
else
{
Boolean OK;
Word Val;
Val = EvalStrIntExpression(&ArgStr[2], Int16, &OK);
if (OK)
BuildLXI(DReg, Val);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeLD(Word Index)
* \brief handle LD instruction
* ------------------------------------------------------------------------ */
static void DecodeLD(Word Index)
{
UNUSED(Index);
if (ChkArgCnt(2, 2)
&& ChkZ80Syntax(eSyntaxZ80))
{
tAdrVals DestAdrVals, SrcAdrVals;
switch (DecodeAdr_Z80(&ArgStr[1], MModReg8 | MModReg16 | MModIHL, &DestAdrVals))
{
case eModReg8:
switch (DecodeAdr_Z80(&ArgStr[2], MModReg8 | MModReg16 | MModIHL | MModImm, &SrcAdrVals))
{
case eModReg8:
BAsmCode[CodeLen++] = 0xc0 | (DestAdrVals.Val << 3) | SrcAdrVals.Val;
break;
case eModIHL:
BAsmCode[CodeLen++] = 0xc7 | (DestAdrVals.Val << 3);
break;
case eModImm:
BAsmCode[CodeLen++] = 0x06 | (DestAdrVals.Val << 3);
BAsmCode[CodeLen++] = SrcAdrVals.Val;
break;
default:
break;
}
break;
case eModReg16:
{
Boolean OK;
Word Arg = EvalStrIntExpression(&ArgStr[2], Int16, &OK);
if (OK)
BuildLXI((DestAdrVals.Val << 1) + 1, Arg);
break;
}
case eModIHL:
switch (DecodeAdr_Z80(&ArgStr[2], MModReg8 | MModImm, &SrcAdrVals))
{
case eModReg8:
BAsmCode[CodeLen++] = 0xf8 | SrcAdrVals.Val;
break;
case eModImm:
BAsmCode[CodeLen++] = 0x3e;
BAsmCode[CodeLen++] = SrcAdrVals.Val;
break;
default:
break;
}
break;
default:
break;
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeADD(Word Code)
* \brief handle ADD instruction
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeADD(Word Code)
{
int MinArgCnt = (CurrZ80Syntax & eSyntax808x) ? ((MomCPU == CPU8008New) ? 1 : 0) : 2,
MaxArgCnt = (CurrZ80Syntax & eSyntaxZ80) ? 2 : ((MomCPU == CPU8008New) ? 1 : 0);
if (!ChkArgCnt(MinArgCnt, MaxArgCnt))
return;
switch (ArgCnt)
{
case 0: /* 8008 old style - src is implicit D, dst is implicitly ACC */
BAsmCode[CodeLen++] = Code | 0x03;
break;
case 1: /* 8008 (new) style - 8 bit register src only, dst is implicitly ACC */
if (MomCPU == CPU8008) (void)ChkArgCnt(0, 0);
else
{
Byte Reg;
if (!DecodeReg(ArgStr[1].str.p_str, eSyntax808x, &Reg)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
else
BAsmCode[CodeLen++] = Code | Reg;
}
break;
case 2: /* Z80 style - dst must be A and is first arg */
{
tAdrVals SrcAdrVals;
if (!CheckAcc_Z80(&ArgStr[1]))
return;
switch (DecodeAdr_Z80(&ArgStr[2], MModReg8 | MModIHL | MModImm, &SrcAdrVals))
{
case eModReg8:
BAsmCode[CodeLen++] = Code | SrcAdrVals.Val;
break;
case eModIHL:
BAsmCode[CodeLen++] = Code | 0x07;
break;
case eModImm:
BAsmCode[CodeLen++] = 0x04;
BAsmCode[CodeLen++] = SrcAdrVals.Val;
break;
default:
break;
}
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeADC(Word Code)
* \brief handle ADC instruction
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeADC(Word Code)
{
int MinArgCnt = (CurrZ80Syntax & eSyntax808x) ? ((MomCPU == CPU8008New) ? 1 : 0) : 2,
MaxArgCnt = (CurrZ80Syntax & eSyntaxZ80) ? 2 : ((MomCPU == CPU8008New) ? 1 : 0);
if (!ChkArgCnt(MinArgCnt, MaxArgCnt))
return;
switch (ArgCnt)
{
case 0: /* 8008 add(!) old style - src is implicit C, dst is implicitly ACC */
BAsmCode[CodeLen++] = 0x82;
break;
case 1: /* 8008 (new) style - 8 bit register src only, dst is implicitly ACC */
{
Byte Reg;
if (!DecodeReg(ArgStr[1].str.p_str, eSyntax808x, &Reg)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
else
BAsmCode[CodeLen++] = Code | Reg;
break;
}
case 2: /* Z80 style - dst must be A and is first arg */
{
tAdrVals SrcAdrVals;
if (!CheckAcc_Z80(&ArgStr[1]))
return;
switch (DecodeAdr_Z80(&ArgStr[2], MModReg8 | MModIHL | MModImm, &SrcAdrVals))
{
case eModReg8:
BAsmCode[CodeLen++] = Code | SrcAdrVals.Val;
break;
case eModIHL:
BAsmCode[CodeLen++] = Code | 0x07;
break;
case eModImm:
BAsmCode[CodeLen++] = 0x0c;
BAsmCode[CodeLen++] = SrcAdrVals.Val;
break;
default:
break;
}
break;
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeSUB(Word Code)
* \brief handle SUB instruction
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeSUB(Word Code)
{
Byte Reg;
int MinArgCnt, MaxArgCnt;
tAdrVals SrcAdrVals;
if (CurrZ80Syntax & eSyntaxZ80)
MaxArgCnt = 2;
else
MaxArgCnt = (MomCPU == CPU8008New) ? 1 : 0;
/* dest operand is always A and also optional for Z80 mode, so min arg cnt is
also 1 for pure Z80 mode: */
if ((CurrZ80Syntax & eSyntax808x) && (MomCPU == CPU8008))
MinArgCnt = 0;
else
MinArgCnt = 1;
if (!ChkArgCnt(MinArgCnt, MaxArgCnt))
return;
/* For Z80, optionally allow A as dest */
if ((ArgCnt == 2) && !CheckAcc_Z80(&ArgStr[1]))
return;
/* no arg (SUB -> B register) */
if (!ArgCnt)
{
BAsmCode[CodeLen++] = Code | 0x01;
return;
}
/* 8 bit register as source
808x style incl. M, Z80 style excl. (HL) */
if (DecodeReg(ArgStr[ArgCnt].str.p_str, CurrZ80Syntax, &Reg)) /* 808x style incl. M, Z80 style excl. (HL) */
{
BAsmCode[CodeLen++] = Code | Reg;
return;
}
/* rest is Z80 style ( (HL) or immediate) */
if (!(CurrZ80Syntax & eSyntaxZ80))
{
WrError(ErrNum_InvAddrMode);
return;
}
switch (DecodeAdr_Z80(&ArgStr[ArgCnt], MModImm | MModIHL, &SrcAdrVals))
{
case eModIHL:
BAsmCode[CodeLen++] = Code | 0x07;
break;
case eModImm:
BAsmCode[CodeLen++] = 0x14;
BAsmCode[CodeLen++] = SrcAdrVals.Val;
break;
default:
break;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeSBC(Word Code)
* \brief handle SBC instruction
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeSBC(Word Code)
{
tAdrVals SrcAdrVals;
/* special case of 8008 SBC: */
if ((CurrZ80Syntax & eSyntax808x) && (ArgCnt == 0) && (MomCPU == CPU8008))
{
BAsmCode[CodeLen++] = Code | 0x02;
return;
}
/* everything else is Z80-specific: */
if (!ChkArgCnt(1, 2) || !ChkZ80Syntax(eSyntaxZ80))
return;
/* dest operand is always A and also optional, since 8008 can only SUB from A: */
if ((ArgCnt == 2) && !CheckAcc_Z80(&ArgStr[1]))
return;
switch (DecodeAdr_Z80(&ArgStr[ArgCnt], MModImm | MModReg8 | MModIHL, &SrcAdrVals))
{
case eModReg8:
BAsmCode[CodeLen++] = Code | SrcAdrVals.Val;
break;
case eModIHL:
BAsmCode[CodeLen++] = Code | 0x07;
break;
case eModImm:
BAsmCode[CodeLen++] = 0x1c;
BAsmCode[CodeLen++] = SrcAdrVals.Val;
break;
default:
break;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeALU8_Z80(Word Code)
* \brief arithmetic instructions only available in Z80 style
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeALU8_Z80(Word Code)
{
tAdrVals SrcAdrVals;
if (!ChkZ80Syntax(eSyntaxZ80)
|| !ChkArgCnt(1, 2))
return;
if ((ArgCnt == 2) /* A as dest */
&& !CheckAcc_Z80(&ArgStr[1]))
return;
switch (DecodeAdr_Z80(&ArgStr[ArgCnt], MModImm | MModIHL | MModReg8, &SrcAdrVals))
{
case eModReg8:
BAsmCode[CodeLen++] = Lo(Code) | SrcAdrVals.Val;
break;
case eModIHL:
BAsmCode[CodeLen++] = Lo(Code) | 0x07;
break;
case eModImm:
BAsmCode[CodeLen++] = Hi(Code);
BAsmCode[CodeLen++] = SrcAdrVals.Val;
break;
default:
break;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeCP(Word Code)
* \brief handle CP instruction
* ------------------------------------------------------------------------ */
static void DecodeCP(Word Code)
{
tAdrVals SrcAdrVals;
Boolean IsCall;
UNUSED(Code);
if (!ChkArgCnt(1, (CurrZ80Syntax & eSyntaxZ80) ? 2 : 1))
return;
/* 2 arguments -> check for A as dest, and compare is meant
(syntax is either Z80 or Z80+808x implicitly due to previous check) */
if (ArgCnt == 2) /* A as dest */
{
if (!CheckAcc_Z80(&ArgStr[1]))
return;
IsCall = False;
}
/* 1 argument -> must be compare anyway in pure Z80 syntax mode, otherwise assume 808x call-on-positive */
else
IsCall = CurrZ80Syntax != eSyntaxZ80;
if (IsCall)
{
DecodeJmpCore((MomCPU == CPU8008New) ? 0x52 : 0x7a);
return;
}
switch (DecodeAdr_Z80(&ArgStr[ArgCnt], MModImm | MModIHL | MModReg8, &SrcAdrVals))
{
case eModReg8:
BAsmCode[CodeLen++] = 0xb8 | SrcAdrVals.Val;
break;
case eModIHL:
BAsmCode[CodeLen++] = 0xbf;
break;
case eModImm:
BAsmCode[CodeLen++] = 0x3c;
BAsmCode[CodeLen++] = SrcAdrVals.Val;
break;
default:
break;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeINCDEC(Word Code)
* \brief handle (Z80 style) INC/DEC
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeINCDEC(Word Code)
{
/* INC aka INC C on old 8008: */
if ((MomCPU == CPU8008) && (CurrZ80Syntax & eSyntax808x) && (!ArgCnt) && !Code)
{
BAsmCode[CodeLen++] = Code | (0x02 << 3);
return;
}
if (ChkZ80Syntax(eSyntaxZ80)
&& ChkArgCnt(1, 1))
{
tAdrVals AdrVals;
switch (DecodeAdr_Z80(&ArgStr[1], MModReg8, &AdrVals))
{
case eModReg8:
if (AdrVals.Val == AccReg) WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
else
BAsmCode[CodeLen++] = Code | (AdrVals.Val << 3);
break;
default:
break;
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeSingleReg(Word Index)
* \brief handle instructions taking a single register as argument
* \param Index machine code
* ------------------------------------------------------------------------ */
static void DecodeSingleReg(Word Index)
{
Byte Reg, Opcode = Lo(Index), Shift = Hi(Index) & 7;
Boolean NoAM = (Index & 0x8000) || False;
if (!ChkArgCnt(1, 1));
else if (!ChkZ80Syntax(eSyntax808x));
else if (!DecodeReg(ArgStr[1].str.p_str, eSyntax808x, &Reg)) WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
else if (NoAM && ((Reg == 0) || (Reg == 7))) WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
else
{
BAsmCode[0] = Opcode | (Reg << Shift);
CodeLen = 1;
}
}
/*!------------------------------------------------------------------------
* \fn DecodePORT(Word Index)
* \brief handle PORT instruction
* ------------------------------------------------------------------------ */
static void DecodePORT(Word Index)
{
UNUSED(Index);
CodeEquate(SegIO, 0, 0x7);
}
/*---------------------------------------------------------------------------*/
/* Codetabellenverwaltung */
static const char FlagNames[] = "CZSP";
static void AddFixed(const char *NName, Byte NCode, Word SyntaxMask)
{
AddInstTable(InstTable, NName, (SyntaxMask << 8) | NCode, DecodeFixed);
}
static void AddFixeds(const char *NName, Byte NCode, int Shift, Byte RegMask)
{
char Memo[10], *p;
int Reg;
for (Reg = 0; Reg < 8; Reg++)
if ((1 << Reg) & RegMask)
{
*p = RegNames[Reg];
AddFixed(Memo, NCode + (Reg << Shift), eSyntax808x);
}
}
static void AddImm(const char *NName, Byte NCode, Word SyntaxMask)
{
AddInstTable(InstTable, NName, (SyntaxMask << 8) | NCode, DecodeImm);
}
static void AddImms(const char *NName, Byte NCode, int Pos)
{
char Memo[10], *p;
int z;
for (z = 0; z < 8; z++)
{
*p = RegNames[z];
AddImm(Memo, NCode + (z << Pos), eSyntax808x);
}
}
static void AddJmp(const char *NName, Byte NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeJmp);
}
static void AddJmps(const char *NName, Byte NCode, int Pos)
{
char Memo[10], *p;
int z;
for (z = 0; z < 4; z++)
{
*p = FlagNames[z];
AddJmp(Memo, NCode + (z << Pos));
}
}
static void InitFields(void)
{
Boolean New = (MomCPU == CPU8008New);
SetDynamicInstTable(InstTable = CreateInstTable(503));
AddFixed("HLT" , 0x00, eSyntax808x);
AddFixed("HALT", 0x00, eSyntaxZ80);
AddFixed("NOP" , 0xc0, eSyntaxBoth); /* = MOV A,A */
if (!New)
AddInstTable(InstTable, "INP", True, DecodeINP_OUT);
AddInstTable(InstTable, "IN" , True , DecodeINP_OUT);
AddInstTable(InstTable, "OUT", False, DecodeINP_OUT);
AddInstTable(InstTable, "JP", 0, DecodeJP);
AddJmp ("JMP", 0x44);
if (New)
{
AddJmp("JNC", 0x40);
AddJmp("JNZ", 0x48);
AddJmp("JPO", 0x58);
AddJmp("JM" , 0x70);
AddJmp("JPE", 0x78);
}
else
{
AddJmp("JS" , 0x70);
AddJmps("JF*", 0x40, 3);
AddJmps("JT*", 0x60, 3);
}
AddJmp("JC" , 0x60);
AddJmp("JZ" , 0x68);
AddInstTable(InstTable, "CALL", 0, DecodeCALL);
AddInstTable(InstTable, "CP", 0, DecodeCP);
if (New)
{
AddJmp("CNC", 0x42);
AddJmp("CNZ", 0x4a);
AddJmp("CPO", 0x5a);
AddJmp("CM" , 0x72);
AddJmp("CPE", 0x7a);
}
else
{
AddJmp("CAL", 0x46);
AddJmp("CS" , 0x72);
AddJmps("CF*", 0x42, 3);
AddJmps("CT*", 0x62, 3);
}
AddJmp ("CC" , 0x62);
AddJmp ("CZ" , 0x6a);
AddInstTable(InstTable, "RET", 0x07, DecodeRET);
if (New)
{
AddFixed("RNC", 0x03, eSyntax808x);
AddFixed("RNZ", 0x0b, eSyntax808x);
AddFixed("RP" , 0x13, eSyntax808x);
AddFixed("RPO", 0x1b, eSyntax808x);
AddFixed("RM" , 0x33, eSyntax808x);
AddFixed("RPE", 0x3b, eSyntax808x);
}
else
{
AddFixed("RFC", 0x03, eSyntax808x);
AddFixed("RFZ", 0x0b, eSyntax808x);
AddFixed("RFS", 0x13, eSyntax808x);
AddFixed("RFP", 0x1b, eSyntax808x);
AddFixed("RS" , 0x33, eSyntax808x);
AddFixed("RP" , 0x3b, eSyntax808x);
AddFixed("RTC", 0x23, eSyntax808x);
AddFixed("RTZ", 0x2b, eSyntax808x);
AddFixed("RTS", 0x33, eSyntax808x);
AddFixed("RTP", 0x3b, eSyntax808x);
}
AddFixed("RC" , 0x23, eSyntax808x);
AddFixed("RZ" , 0x2b, eSyntax808x);
AddInstTable(InstTable, "RST", 0, DecodeRST); /* TODO: Z80 */
if (New)
AddInstTable(InstTable, "MOV", 0, DecodeMOV);
else
{
AddFixeds("L*A", 0xc0, 3, 0xff);
AddFixeds("L*B", 0xc1, 3, 0xff);
AddFixeds("L*C", 0xc2, 3, 0xff);
AddFixeds("L*D", 0xc3, 3, 0xff);
AddFixeds("L*E", 0xc4, 3, 0xff);
AddFixeds("L*H", 0xc5, 3, 0xff);
AddFixeds("L*L", 0xc6, 3, 0xff);
AddFixeds("L*M", 0xc7, 3, 0x7f); /* forbid LMM - would be opcode for HLT */
}
if (New)
{
AddInstTable(InstTable, "MVI", 0, DecodeMVI);
AddInstTable(InstTable, "LXI", 0, DecodeLXI);
}
else
AddImms("L*I", 0x06, 3);
AddInstTable(InstTable, "LD", 0, DecodeLD);
AddInstTable(InstTable, "ADD", 0x0080, DecodeADD);
AddInstTable(InstTable, "ADC", 0x0088, DecodeADC);
AddInstTable(InstTable, "SUB", 0x0090, DecodeSUB);
AddInstTable(InstTable, "SBC", 0x0098, DecodeSBC);
AddInstTable(InstTable, "AND", 0x24a0, DecodeALU8_Z80);
AddInstTable(InstTable, "XOR", 0x2ca8, DecodeALU8_Z80);
AddInstTable(InstTable, "OR" , 0x34b0, DecodeALU8_Z80);
AddInstTable(InstTable, "INC", 0x00, DecodeINCDEC);
AddInstTable(InstTable, "DEC", 0x01, DecodeINCDEC);
if (New)
{
AddInstTable(InstTable, "SBB", 0x0098, DecodeSingleReg);
AddInstTable(InstTable, "ANA", 0x00a0, DecodeSingleReg);
AddInstTable(InstTable, "XRA", 0x00a8, DecodeSingleReg);
AddInstTable(InstTable, "ORA", 0x00b0, DecodeSingleReg);
AddInstTable(InstTable, "CMP", 0x00b8, DecodeSingleReg);
AddInstTable(InstTable, "INR", 0x8300, DecodeSingleReg);
AddInstTable(InstTable, "DCR", 0x8301, DecodeSingleReg);
}
else
{
AddFixeds("AD*", 0x80, 0, 0xf3); /* ADC/ADD handled separately */
AddFixeds("AC*", 0x88, 0, 0xff);
AddFixeds("SU*", 0x90, 0, 0xfd); /* SUB handled separately */
AddFixeds("SB*", 0x98, 0, 0xfb); /* SBC handled separately */
AddFixeds("NR*", 0xa0, 0, 0xff);
AddFixeds("ND*", 0xa0, 0, 0xff);
AddFixeds("XR*", 0xa8, 0, 0xff);
AddFixeds("OR*", 0xb0, 0, 0xff);
AddFixeds("CP*", 0xb8, 0, 0xff);
AddFixeds("IN*", 0x00, 3, 0x7a); /* no INA/INM, INC handled separately */
AddFixeds("DC*", 0x01, 3, 0x7e); /* no DCA/DCM */
}
AddImm ("ADI", 0x04, eSyntax808x);
AddImm ("ACI", 0x0c, eSyntax808x);
AddImm ("SUI", 0x14, eSyntax808x);
AddImm ("SBI", 0x1c, eSyntax808x);
AddImm (New ? "ANI" : "NDI", 0x24, eSyntax808x);
AddImm ("XRI", 0x2c, eSyntax808x);
AddImm ("ORI", 0x34, eSyntax808x);
AddImm ("CPI", 0x3c, eSyntax808x);
AddFixed ("RLC" , 0x02, eSyntax808x);
AddFixed ("RLCA", 0x02, eSyntaxZ80);
AddFixed ("RRC" , 0x0a, eSyntax808x);
AddFixed ("RRCA", 0x0a, eSyntaxZ80);
AddFixed ("RAL" , 0x12, eSyntax808x);
AddFixed ("RLA" , 0x12, eSyntaxZ80);
AddFixed ("RAR" , 0x1a, eSyntax808x);
AddFixed ("RRA" , 0x1a, eSyntaxZ80);
AddInstTable(InstTable, "PORT", 0, DecodePORT);
AddZ80Syntax(InstTable);
}
static void DeinitFields(void)
{
DestroyInstTable(InstTable);
}
/*---------------------------------------------------------------------------*/
/* Callbacks */
static void MakeCode_8008(void)
{
CodeLen = 0; DontPrint = False;
/* zu ignorierendes */
if (Memo("")) return;
/* Pseudoanweisungen */
if (DecodeIntelPseudo(False)) return;
/* der Rest */
if (!LookupInstTable(InstTable, OpPart.str.p_str))
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
}
static Boolean IsDef_8008(void)
{
return Memo("PORT");
}
static void SwitchFrom_8008(void)
{
DeinitFields();
}
static void SwitchTo_8008(void)
{
const TFamilyDescr *FoundDescr;
FoundDescr = FindFamilyByName("8008");
TurnWords = False;
SetIntConstMode(eIntConstModeIntel);
PCSymbol = "$"; HeaderID = FoundDescr->Id; NOPCode = 0xc0;
DivideChars = ","; HasAttrs = False;
ValidSegs = (1 << SegCode) | (1 << SegIO);
Grans[SegCode ] = 1; ListGrans[SegCode ] = 1; SegInits[SegCode ] = 0;
SegLimits[SegCode] = 0x3fff;
Grans[SegIO ] = 1; ListGrans[SegIO ] = 1; SegInits[SegIO ] = 0;
SegLimits[SegIO] = 7;
MakeCode = MakeCode_8008;
IsDef = IsDef_8008;
SwitchFrom = SwitchFrom_8008;
InitFields();
}
/*---------------------------------------------------------------------------*/
/* Initialisierung */
void code8008_init(void)
{
CPU8008 = AddCPU("8008" , SwitchTo_8008);
CPU8008New = AddCPU("8008NEW", SwitchTo_8008);
}