/* codez80.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Codegenerator Zilog Z80/180/380 */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <ctype.h>
#include <string.h>
#include "nls.h"
#include "strutil.h"
#include "bpemu.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmcode.h"
#include "asmallg.h"
#include "onoff_common.h"
#include "asmitree.h"
#include "codepseudo.h"
#include "intpseudo.h"
#include "codevars.h"
#include "cpu2phys.h"
#include "function.h"
#include "errmsg.h"
#include "codez80.h"
/*-------------------------------------------------------------------------*/
/* Instruktionsgruppendefinitionen */
typedef struct
{
CPUVar MinCPU;
Byte Len;
Word Code;
} BaseOrder;
typedef struct
{
const char *Name;
Byte Code;
} Condition;
/*-------------------------------------------------------------------------*/
/* Praefixtyp */
typedef enum
{
Pref_IN_N,Pref_IN_W ,Pref_IB_W ,Pref_IW_W ,Pref_IB_N ,
Pref_IN_LW,Pref_IB_LW,Pref_IW_LW,Pref_IW_N
} PrefType;
typedef enum
{
ePrefixNone,
ePrefixW, /* word processing */
ePrefixLW, /* long word processing */
ePrefixIB, /* one byte more in argument */
ePrefixIW /* one word more in argument */
} tOpPrefix;
#ifdef __cplusplus
# include "codez80.hpp"
#endif
#define LWordFlagName "INLWORDMODE"
#define ModNone (-1)
#define ModReg8 1
#define ModReg16 2
#define ModIndReg16 3
#define ModImm 4
#define ModAbs 5
#define ModRef 6
#define ModInt 7
#define ModSPRel 8
#define ModIndReg8 9
#define ModSPAdd 10
#define ModHLInc 11
#define ModHLDec 12
#define ModIOAbs 13
#define ModImmIsAbs 14
#define MModReg8 (1 << ModReg8)
#define MModReg16 (1 << ModReg16)
#define MModIndReg16 (1 << ModIndReg16)
#define MModImm (1 << ModImm)
#define MModAbs (1 << ModAbs)
#define MModRef (1 << ModRef)
#define MModInt (1 << ModInt)
#define MModSPRel (1 << ModSPRel)
#define MModIndReg8 (1 << ModIndReg8)
#define MModSPAdd (1 << ModSPAdd)
#define MModHLInc (1 << ModHLInc)
#define MModHLDec (1 << ModHLDec)
#define MModIOAbs (1 << ModIOAbs)
#define MModImmIsAbs (1 << ModImmIsAbs)
/* These masks deliberately omit the (special)
Sharp/Gameboy addressing modes: */
#define MModNoImm (MModReg8 | MModReg16 | MModIndReg16 | MModAbs | MModRef | MModInt | MModSPRel)
#define MModAll (MModReg8 | MModReg16 | MModIndReg16 | MModImm | MModAbs | MModRef | MModInt | MModSPRel)
#define IXPrefix 0xdd
#define IYPrefix 0xfd
#define AccReg 7
#define DEReg 1
#define HLReg 2
#define SPReg 3
/*-------------------------------------------------------------------------*/
static Byte PrefixCnt;
static Byte AdrPart,OpSize;
static Byte AdrVals[4];
static ShortInt AdrMode;
static BaseOrder *FixedOrders;
static BaseOrder *AccOrders;
static BaseOrder *HLOrders;
static Condition *Conditions;
static CPUVar CPULR35902, CPUGBZ80,
CPUZ80, CPUZ80U, CPUZ180,
CPUR2000, CPUZ380;
static Boolean MayLW, /* Instruktion erlaubt 32 Bit */
ExtFlag, /* Prozessor im 4GByte-Modus ? */
LWordFlag; /* 32-Bit-Verarbeitung ? */
static PrefType CurrPrefix, /* mom. explizit erzeugter Praefix */
LastPrefix; /* von der letzten Anweisung generierter Praefix */
static LongInt Reg_CBAR,
Reg_BBR,
Reg_CBR;
static const char Reg8Names[] = "BCDEHL*A";
static int Reg16Cnt;
static const char Reg16Names[][3] = { "BC", "DE", "HL", "SP", "IX", "IY" };
/*==========================================================================*/
/* Aux Functions */
static Boolean is_sharp(void)
{
return (MomCPU == CPULR35902) || (MomCPU == CPUGBZ80);
}
/*--------------------------------------------------------------------------*/
/* Praefix dazuaddieren */
static tOpPrefix DecodePrefix(const char *pArg)
{
const char *pPrefNames[] = { "W", "LW", "IB", "IW", NULL };
tOpPrefix Result;
for (Result = ePrefixW; pPrefNames[Result - 1]; Result++)
if (!as_strcasecmp(pArg, pPrefNames[Result - 1]))
return Result;
return ePrefixNone;
}
static Boolean ExtendPrefix(PrefType *Dest, tOpPrefix AddPrefix)
{
Byte SPart,IPart;
switch (*Dest)
{
case Pref_IB_N:
case Pref_IB_W:
case Pref_IB_LW:
IPart = 1;
break;
case Pref_IW_N:
case Pref_IW_W:
case Pref_IW_LW:
IPart = 2;
break;
default:
IPart = 0;
}
switch (*Dest)
{
case Pref_IN_W:
case Pref_IB_W:
case Pref_IW_W:
SPart = 1;
break;
case Pref_IN_LW:
case Pref_IB_LW:
case Pref_IW_LW:
SPart = 2;
break;
default:
SPart = 0;
}
switch (AddPrefix)
{
case ePrefixW:
SPart = 1; break;
case ePrefixLW:
SPart = 2; break;
case ePrefixIB:
IPart = 1; break;
case ePrefixIW:
IPart = 2; break;
default:
return False;
}
switch ((IPart << 4) | SPart)
{
case 0x00:
*Dest = Pref_IN_N;
break;
case 0x01:
*Dest = Pref_IN_W;
break;
case 0x02:
*Dest = Pref_IN_LW;
break;
case 0x10:
*Dest = Pref_IB_N;
break;
case 0x11:
*Dest = Pref_IB_W;
break;
case 0x12:
*Dest = Pref_IB_LW;
break;
case 0x20:
*Dest = Pref_IW_N;
break;
case 0x21:
*Dest = Pref_IW_W;
break;
case 0x22:
*Dest = Pref_IW_LW;
break;
}
return True;
}
/*--------------------------------------------------------------------------*/
/* Code fuer Praefix bilden */
static void GetPrefixCode(PrefType inp, Byte *b1 ,Byte *b2)
{
int z;
z = ((int)inp) - 1;
*b1 = 0xdd + ((z & 4) << 3);
*b2 = 0xc0 + (z & 3);
}
/*--------------------------------------------------------------------------*/
/* DD-Praefix addieren, nur EINMAL pro Instruktion benutzen! */
static void ChangeDDPrefix(tOpPrefix Prefix)
{
PrefType ActPrefix;
int z;
ActPrefix = LastPrefix;
if (ExtendPrefix(&ActPrefix, Prefix))
if (LastPrefix != ActPrefix)
{
if (LastPrefix != Pref_IN_N) RetractWords(2);
for (z = PrefixCnt - 1; z >= 0; z--) BAsmCode[2 + z] = BAsmCode[z];
PrefixCnt += 2;
GetPrefixCode(ActPrefix, BAsmCode + 0, BAsmCode + 1);
}
}
/*--------------------------------------------------------------------------*/
/* IX/IY used ? */
static Boolean IndexPrefix(void)
{
return ((PrefixCnt > 0)
&& ((BAsmCode[PrefixCnt - 1] == IXPrefix)
|| (BAsmCode[PrefixCnt - 1] == IYPrefix)));
}
/*--------------------------------------------------------------------------*/
/* Wortgroesse ? */
static Boolean InLongMode(void)
{
switch (LastPrefix)
{
case Pref_IN_W:
case Pref_IB_W:
case Pref_IW_W:
return False;
case Pref_IN_LW:
case Pref_IB_LW:
case Pref_IW_LW:
return MayLW;
default:
return LWordFlag && MayLW;
}
}
/*--------------------------------------------------------------------------*/
/* absolute Adresse */
static LongWord EvalAbsAdrExpression(const tStrComp *pArg, tEvalResult *pEvalResult)
{
return EvalStrIntExpressionWithResult(pArg, ExtFlag ? Int32 : UInt16, pEvalResult);
}
/*==========================================================================*/
/* Adressparser */
/*!------------------------------------------------------------------------
* \fn DecodeReg8Core(const char *p_asc, Byte *p_ret)
* \brief parse 8 bit register
* \param p_asc source argument
* \param p_ret return buffer
* \return true if valid register name
* ------------------------------------------------------------------------ */
static Boolean DecodeReg8Core(const char *p_asc, Byte *p_ret)
{
const char *p_pos;
{
case 1:
p_pos
= strchr(Reg8Names
, as_toupper
(p_asc
[0]));
if (!p_pos)
return False;
*p_ret = p_pos - Reg8Names;
return (*p_ret != 6);
case 3:
{
|| ((ix != 'X') && (ix != 'Y')))
return False;
{
case 'L':
*p_ret = 5 | (((ix == 'X') ? IXPrefix : IYPrefix) & 0xf0);
return True;
case 'H':
if (MomCPU != CPUZ80U) /* do not allow IXH/IYH on Z380 */
return False;
/* else fall-through */
case 'U':
*p_ret = 4 | (((ix == 'X') ? IXPrefix : IYPrefix) & 0xf0);
return True;
default:
return False;
}
}
default:
return False;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeReg16Core(const char *p_asc, Byte *p_ret)
* \brief parse 16 bit register
* \param p_asc source argument
* \param p_ret return buffer
* \return true if valid register name
* ------------------------------------------------------------------------ */
static Boolean DecodeReg16Core(const char *p_asc, Byte *p_ret)
{
int z;
for (z = 0; z < Reg16Cnt; z++)
if (!as_strcasecmp(p_asc, Reg16Names[z]))
{
if (z <= 3)
*p_ret = z;
else
*p_ret = 2 /* = HL */ | (((z == 4) ? IXPrefix : IYPrefix) & 0xf0);
return True;
}
return False;
}
/*!------------------------------------------------------------------------
* \fn DecodeReg(const tStrComp *p_arg, Byte *p_ret, tSymbolSize *p_size, tSymbolSize req_size, Boolean must_be_reg)
* \brief check whether argument is a CPU register or user-defined register alias
* \param p_arg argument
* \param p_value resulting register # if yes
* \param p_size resulting register size if yes
* \param req_size requested register size
* \param must_be_reg expecting register or maybe not?
* \return reg eval result
* ------------------------------------------------------------------------ */
static Boolean chk_reg_size(tSymbolSize req_size, tSymbolSize act_size)
{
return (req_size == eSymbolSizeUnknown)
|| (req_size == act_size);
}
static tRegEvalResult DecodeReg(const tStrComp *p_arg, Byte *p_ret, tSymbolSize *p_size, tSymbolSize req_size, Boolean must_be_reg)
{
tRegEvalResult reg_eval_result;
tEvalResult eval_result;
tRegDescr reg_descr;
if (DecodeReg8Core(p_arg->str.p_str, p_ret))
{
eval_result.DataSize = eSymbolSize8Bit;
reg_eval_result = eIsReg;
}
else if (DecodeReg16Core(p_arg->str.p_str, p_ret))
{
eval_result.DataSize = eSymbolSize16Bit;
reg_eval_result = eIsReg;
}
else
{
reg_eval_result = EvalStrRegExpressionAsOperand(p_arg, ®_descr, &eval_result, eSymbolSizeUnknown, must_be_reg);
if (reg_eval_result == eIsReg)
*p_ret = reg_descr.Reg;
}
if (reg_eval_result == eIsReg)
{
if (!chk_reg_size(req_size, eval_result.DataSize))
{
WrStrErrorPos(ErrNum_InvOpSize, p_arg);
reg_eval_result = must_be_reg ? eIsNoReg : eRegAbort;
}
}
if (p_size) *p_size = eval_result.DataSize;
return reg_eval_result;
}
static Boolean IsSym(char ch)
{
return ((ch == '_')
|| ((ch >= '0') && (ch <= '9'))
|| ((ch >= 'A') && (ch <= 'Z'))
|| ((ch >= 'a') && (ch <= 'z')));
}
static ShortInt DecodeAdr(const tStrComp *pArg, unsigned ModeMask)
{
Integer AdrInt;
#if 0
int z, l;
LongInt AdrLong;
#endif
Boolean OK, is_indirect;
tEvalResult EvalResult;
AdrMode = ModNone;
AdrCnt = 0;
AdrPart = 0;
/* 0. Sonderregister */
if (!as_strcasecmp(pArg->str.p_str, "R"))
{
AdrMode = ModRef;
goto found;
}
if (!as_strcasecmp(pArg->str.p_str, "I"))
{
AdrMode = ModInt;
goto found;
}
/* 1. 8/16 bit registers ? */
switch (DecodeReg(pArg, &AdrPart, &EvalResult.DataSize, eSymbolSizeUnknown, False))
{
case eRegAbort:
goto found;
case eIsReg:
if (AdrPart & 0xf0)
BAsmCode[PrefixCnt++] = (AdrPart & 0xf0) | 0x0d;
AdrPart &= (EvalResult.DataSize == eSymbolSize8Bit) ? 7 : 3;
AdrMode = (EvalResult.DataSize == eSymbolSize8Bit) ? ModReg8 : ModReg16;
goto found;
default:
break;
}
/* 2. SP+d8 (Gameboy specific) */
if ((ModeMask & MModSPAdd)
&& (strlen(pArg
->str.
p_str) >= 4)
&& !as_strncasecmp(pArg->str.p_str, "SP", 2)
&& !IsSym(pArg->str.p_str[2]))
{
AdrVals[0] = EvalStrIntExpressionOffs(pArg, 2, SInt8, &OK);
if (OK)
{
AdrCnt = 1;
AdrMode = ModSPAdd;
}
goto found;
}
/* all types of indirect expressions (...): */
is_indirect = IsIndirect(pArg->str.p_str);
if (is_indirect || (ModeMask & MModImmIsAbs))
{
tStrComp arg, remainder;
char *p_split_pos;
Boolean neg_flag, next_neg_flag;
tEvalResult disp_eval_result;
LongInt disp_acc;
Byte addr_reg, this_reg;
tSymbolSize addr_reg_size, this_reg_size;
/* strip outer braces and spaces */
StrCompRefRight(&arg, pArg, !!is_indirect);
StrCompShorten(&arg, !!is_indirect);
KillPrefBlanksStrCompRef(&arg);
KillPostBlanksStrComp(&arg);
/* special cases: */
if ((ModeMask & MModHLInc) && (!as_strcasecmp(arg.str.p_str, "HL+") || !as_strcasecmp(arg.str.p_str, "HLI")))
{
AdrMode = ModHLInc;
goto found;
}
if ((ModeMask & MModHLDec) && (!as_strcasecmp(arg.str.p_str, "HL-") || !as_strcasecmp(arg.str.p_str, "HLD")))
{
AdrMode = ModHLDec;
goto found;
}
/* otherwise, walk through the components : */
disp_eval_result.Flags = eSymbolFlag_None;
disp_eval_result.AddrSpaceMask = 0;
disp_acc = 0;
neg_flag = False;
addr_reg = 0xff;
addr_reg_size = eSymbolSizeUnknown;
do
{
/* Split off one component: */
p_split_pos = indir_split_pos(arg.str.p_str);
next_neg_flag = p_split_pos && (*p_split_pos == '-');
if ((p_split_pos
== arg.
str.
p_str) || (p_split_pos
== arg.
str.
p_str + strlen(arg.
str.
p_str) - 1))
{
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
return AdrMode;
}
if (p_split_pos)
StrCompSplitRef(&arg, &remainder, &arg, p_split_pos);
KillPrefBlanksStrCompRef(&arg);
KillPostBlanksStrComp(&arg);
/* register or displacement? */
switch (DecodeReg(&arg, &this_reg, &this_reg_size, eSymbolSizeUnknown, False))
{
case eIsReg:
if (addr_reg != 0xff)
{
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
return AdrMode;
}
addr_reg = this_reg;
addr_reg_size = this_reg_size;
break;
case eRegAbort:
return AdrMode;
default:
{
tEvalResult eval_result;
LongInt this_disp;
/* special case for GameBoy/Sharp: FF00 always allowed, independent of radix: */
if (!as_strcasecmp(arg.str.p_str, "FF00"))
{
this_disp = 0xff00;
eval_result.OK = True;
eval_result.Flags = eSymbolFlag_None;
eval_result.AddrSpaceMask = 0;
}
else
this_disp = EvalStrIntExpressionWithResult(&arg, Int32, &eval_result);
if (!eval_result.OK)
return AdrMode;
disp_eval_result.Flags |= eval_result.Flags;
disp_eval_result.AddrSpaceMask |= eval_result.AddrSpaceMask;
if (neg_flag)
disp_acc -= this_disp;
else
disp_acc += this_disp;
}
}
/* sign of next component */
neg_flag = next_neg_flag;
if (p_split_pos)
arg = remainder;
}
while (p_split_pos);
/* now we have parsed the expression, see what we can do with it: */
switch (addr_reg)
{
/* no register: absolute */
case 0xff:
{
LongWord address = disp_acc;
if (ModeMask & MModAbs)
{
/* no range checking if address range is 32 bits - disp_acc is only a 32 bit value */
if (!mFirstPassUnknownOrQuestionable(disp_eval_result.Flags)
&& !ExtFlag
&& !ChkRangeByType(disp_acc, UInt16, pArg))
return AdrMode;
ChkSpace(SegCode, disp_eval_result.AddrSpaceMask);
AdrVals[0] = address & 0xff;
AdrVals[1] = (address >> 8) & 0xff;
AdrCnt = 2;
if (address > 0xfffful)
{
AdrVals[AdrCnt++] = (address >> 16) & 0xff;
if (address <= 0xfffffful)
ChangeDDPrefix(ePrefixIB);
else
{
AdrVals[AdrCnt++] = ((address >> 24) & 0xff);
ChangeDDPrefix(ePrefixIW);
}
}
AdrMode = ModAbs;
goto found;
}
else if (ModeMask & MModIOAbs)
{
if (!mFirstPassUnknownOrQuestionable(disp_eval_result.Flags) && !ChkRangeByType(disp_acc, UInt8, pArg))
return AdrMode;
ChkSpace(SegIO, disp_eval_result.AddrSpaceMask);
AdrVals[0] = address & 0xff;
AdrCnt = 1;
AdrMode = ModIOAbs;
goto found;
}
else
goto inv_mode;
}
case 0:
if ((addr_reg_size != eSymbolSize16Bit) || disp_acc) /* no (B), (BC+d) */
goto wrong;
else /* (BC) */
{
AdrMode = ModIndReg16;
AdrPart = 0;
goto found;
}
case 1:
if (addr_reg_size == eSymbolSize16Bit) /* (DE) */
{
if (disp_acc)
goto wrong;
AdrMode = ModIndReg16;
AdrPart = 1;
goto found;
}
else /* (C), (FF00+C) on Sharp/GB */
{
if (!disp_acc || (is_sharp() && (disp_acc == 0xff00)))
{
AdrMode = ModIndReg8;
goto found;
}
else
goto wrong;
}
case 2:
if ((addr_reg_size != eSymbolSize16Bit) || disp_acc) /* no (D), (HL+d) */
goto wrong;
else /* (HL) */
{
AdrMode = ModReg8; /* (HL) is M-Reg */
AdrPart = 6;
goto found;
}
case (IXPrefix & 0xf0) | 2: /* (IX+d) */
case (IYPrefix & 0xf0) | 2: /* (IY+d) */
case 3: /* (SP+d) */
if (!mFirstPassUnknownOrQuestionable(disp_eval_result.Flags) && !ChkRangeByType(disp_acc, (MomCPU >= CPUZ380) ? SInt24 : SInt8, pArg))
return AdrMode;
if (addr_reg == 3)
AdrMode = ModSPRel;
else
{
AdrMode = ModReg8;
AdrPart = 6;
BAsmCode[PrefixCnt++] = 0x0d | (addr_reg & 0xf0);
}
AdrVals[0] = disp_acc & 0xff;
AdrCnt = 1;
if (((disp_acc < -0x80l) || (disp_acc > 0x7fl)) && (MomCPU >= CPUZ380))
{
AdrVals[AdrCnt++] = (disp_acc >> 8) & 0xff;
if ((disp_acc >= -0x8000l) && (disp_acc <= 0x7fffl))
ChangeDDPrefix(ePrefixIB);
else
{
AdrVals[AdrCnt++] = (disp_acc >> 16) & 0xff;
ChangeDDPrefix(ePrefixIW);
}
}
goto found;
wrong:
default:
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
return AdrMode;
}
}
/* ...immediate */
if (!(ModeMask & MModImm))
goto inv_mode;
switch (OpSize)
{
case 0xff:
if (ModeMask & MModImm)
WrError(ErrNum_UndefOpSizes);
else
AdrMode = ModImm; /* will fail on test @ label found */
break;
case 0:
AdrVals[0] = EvalStrIntExpression(pArg, Int8, &OK);
if (OK)
{
AdrMode = ModImm;
AdrCnt = 1;
}
break;
case 1:
if (InLongMode())
{
LongWord ImmVal = EvalStrIntExpression(pArg, Int32, &OK);
if (OK)
{
AdrVals[0] = Lo(ImmVal);
AdrVals[1] = Hi(ImmVal);
AdrMode = ModImm;
AdrCnt = 2;
if (ImmVal <= 0xfffful);
else
{
AdrVals[AdrCnt++] = (ImmVal >> 16) & 0xff;
if (ImmVal <= 0xfffffful)
ChangeDDPrefix(ePrefixIB);
else
{
AdrVals[AdrCnt++] = (ImmVal >> 24) & 0xff;
ChangeDDPrefix(ePrefixIW);
}
}
}
}
else
{
AdrInt = EvalStrIntExpression(pArg, Int16, &OK);
if (OK)
{
AdrVals[0] = Lo(AdrInt);
AdrVals[1] = Hi(AdrInt);
AdrMode = ModImm;
AdrCnt = 2;
}
}
break;
}
found:
if ((AdrMode != ModNone) && !(ModeMask & (1 << AdrMode)))
goto inv_mode;
return AdrMode;
inv_mode:
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
AdrMode = ModNone;
return AdrMode;
}
/*!------------------------------------------------------------------------
* \fn DecodeAdr_A(const tStrComp *p_arg)
* \brief check whether argument is accumulator (including possible register aliases)
* \param p_arg source argument
* \return True if it is
* ------------------------------------------------------------------------ */
static Boolean DecodeAdr_A(const tStrComp *p_arg)
{
if (DecodeAdr(p_arg, MModReg8) != ModReg8)
return False;
if (AdrPart != AccReg)
{
WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
return False;
}
else
return True;
}
/*!------------------------------------------------------------------------
* \fn DecodeAdr_HL(const tStrComp *p_arg)
* \brief check whether argument is HL (including possible register aliases)
* \param p_arg source argument
* \return True if it is
* ------------------------------------------------------------------------ */
static Boolean DecodeAdr_HL(const tStrComp *p_arg)
{
if (DecodeAdr(p_arg, MModReg16) != ModReg16)
return False;
if ((AdrPart != HLReg) || (PrefixCnt > 0))
{
WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
return False;
}
else
return True;
}
/*!------------------------------------------------------------------------
* \fn DecodeAdrWithF(const tStrComp *pArg, Boolean AllowF)
* \brief Handle address expression, treating F as 8th register
* \param pArg source argument
* \param allow 'F' at all?
* ------------------------------------------------------------------------ */
static void DecodeAdrWithF(const tStrComp *pArg, Boolean AllowF)
{
Boolean applies_to_cpu = (MomCPU == CPUZ80U) || (MomCPU == CPUZ180) || (MomCPU == CPUZ380);
if (applies_to_cpu
&& AllowF
&& !as_strcasecmp(pArg->str.p_str, "F"))
{
AdrMode = ModReg8;
AdrPart = 6;
return;
}
DecodeAdr(pArg, MModAll);
/* if 110 denotes F, it cannot denote (HL) */
if (applies_to_cpu
&& (AdrMode == ModReg8)
&& (AdrPart == 6))
{
AdrMode = ModNone;
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
}
}
static Boolean ImmIs8(void)
{
Word tmp;
if (AdrCnt < 2)
return True;
tmp = (Word) AdrVals[AdrCnt - 2];
return ((tmp <= 255) || (tmp >= 0xff80));
}
static Boolean ImmIsS8(void)
{
Word tmp;
if (AdrCnt < 2)
return True;
tmp = AdrVals[1];
tmp = (tmp << 8) | AdrVals[0];
return ((tmp <= 127) || (tmp >= 0xff80));
}
static void AppendVals(const Byte *pVals, unsigned ValLen)
{
memcpy(BAsmCode
+ CodeLen
, pVals
, ValLen
);
CodeLen += ValLen;
}
static void AppendAdrVals(void)
{
AppendVals(AdrVals, AdrCnt);
}
static Boolean ParPair(const char *Name1, const char *Name2)
{
return (((!as_strcasecmp(ArgStr[1].str.p_str, Name1)) && (!as_strcasecmp(ArgStr[2].str.p_str, Name2))) ||
((!as_strcasecmp(ArgStr[1].str.p_str, Name2)) && (!as_strcasecmp(ArgStr[2].str.p_str, Name1))));
}
/*-------------------------------------------------------------------------*/
/* Bedingung entschluesseln */
static Boolean DecodeCondition(const char *Name, int *Erg)
{
int z;
for (z = 0; Conditions[z].Name; z++)
if (!as_strcasecmp(Conditions[z].Name, Name))
{
*Erg = Conditions[z].Code;
return True;
}
*Erg = 0;
return False;
}
/*-------------------------------------------------------------------------*/
/* Sonderregister dekodieren */
static Boolean DecodeSFR(char *Inp, Byte *Erg)
{
if (!as_strcasecmp(Inp, "SR"))
*Erg = 1;
else if (!as_strcasecmp(Inp, "XSR"))
*Erg = 5;
else if (!as_strcasecmp(Inp, "DSR"))
*Erg = 6;
else if (!as_strcasecmp(Inp, "YSR"))
*Erg = 7;
else
return False;
return True;
}
/*==========================================================================*/
/* Adressbereiche */
static LargeWord PortEnd(void)
{
return (LargeWord)IntTypeDefs[ExtFlag ? UInt32 : UInt16].Max;
}
/*==========================================================================*/
/* instruction decoders */
static void DecodeFixed(Word Index)
{
BaseOrder *POrder = FixedOrders + Index;
if (ChkArgCnt(0, 0)
&& ChkMinCPU(POrder->MinCPU))
{
if (POrder->Len == 2)
{
BAsmCode[PrefixCnt++] = Hi(POrder->Code);
BAsmCode[PrefixCnt++] = Lo(POrder->Code);
}
else
BAsmCode[PrefixCnt++] = Lo(POrder->Code);
CodeLen = PrefixCnt;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeSTOP(Word Code)
* \brief handle STOP machine instruction
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeSTOP(Word Code)
{
if (ChkArgCnt(0, 0) && (ChkExactCPUList(ErrNum_InstructionNotSupported, CPUGBZ80, CPULR35902, CPUNone) >= 0))
{
BAsmCode[PrefixCnt++] = Lo(Code);
CodeLen = PrefixCnt;
}
}
static void DecodeAcc(Word Index)
{
BaseOrder *POrder = AccOrders + Index;
if (!ChkArgCnt(0, 1)
|| !ChkMinCPU(POrder->MinCPU))
return;
if (ArgCnt && !DecodeAdr_A(&ArgStr[1]))
return;
if (POrder->Len == 2)
{
BAsmCode[PrefixCnt++] = Hi(POrder->Code);
BAsmCode[PrefixCnt++] = Lo(POrder->Code);
}
else
BAsmCode[PrefixCnt++] = Lo(POrder->Code);
CodeLen = PrefixCnt;
}
static void DecodeHL(Word Index)
{
BaseOrder *POrder = HLOrders + Index;
if (!ChkArgCnt(0, 1)
|| !ChkMinCPU(POrder->MinCPU))
return;
if (ArgCnt && !DecodeAdr_HL(&ArgStr[1]))
return;
if (POrder->Len == 2)
{
BAsmCode[PrefixCnt++] = Hi(POrder->Code);
BAsmCode[PrefixCnt++] = Lo(POrder->Code);
}
else
BAsmCode[PrefixCnt++] = Lo(POrder->Code);
CodeLen = PrefixCnt;
}
static void DecodeLD(Word IsLDW)
{
Byte AdrByte,HLen;
int z;
Byte HVals[5];
if (ChkArgCnt(2, 2))
{
DecodeAdr(&ArgStr[1], MModReg8 | MModReg16 | MModIndReg16 | MModAbs | MModSPRel
| (is_sharp() ? (MModIndReg8 | MModHLInc | MModHLDec) : (MModRef | MModInt)));
switch (AdrMode)
{
case ModReg8:
if (AdrPart == AccReg) /* LD A, ... */
{
OpSize = 0; DecodeAdr(&ArgStr[2], MModReg8 | MModReg16 | MModIndReg16 | MModImm | MModAbs | MModSPRel
| (is_sharp() ? (MModIndReg8 | MModHLInc | MModHLDec) : (MModRef | MModInt)));
switch (AdrMode)
{
case ModReg8: /* LD A, R8/RX8/(HL)/(XY+D) */
BAsmCode[PrefixCnt] = 0x78 + AdrPart;
memcpy(BAsmCode
+ PrefixCnt
+ 1, AdrVals
, AdrCnt
);
CodeLen = PrefixCnt + 1 + AdrCnt;
break;
case ModIndReg8: /* LD A,(FF00+C) */
BAsmCode[0] = 0xf2;
CodeLen = 1;
break;
case ModHLInc: /* LD A,(HLI) */
BAsmCode[0] = 0x2a;
CodeLen = 1;
break;
case ModHLDec: /* LD A,(HLD) */
BAsmCode[0] = 0x3a;
CodeLen = 1;
break;
case ModIndReg16: /* LD A, (BC)/(DE) */
BAsmCode[PrefixCnt++] = 0x0a + (AdrPart << 4);
CodeLen = PrefixCnt;
break;
case ModImm: /* LD A, imm8 */
BAsmCode[PrefixCnt++] = 0x3e;
BAsmCode[PrefixCnt++] = AdrVals[0];
CodeLen = PrefixCnt;
break;
case ModAbs: /* LD a, (adr) */
if (is_sharp() && (AdrVals[1] == 0xff))
{
BAsmCode[0] = 0xf0;
BAsmCode[1] = AdrVals[0];
CodeLen = 2;
}
else
{
BAsmCode[PrefixCnt] = is_sharp() ? 0xfa : 0x3a;
memcpy(BAsmCode
+ PrefixCnt
+ 1, AdrVals
, AdrCnt
);
CodeLen = PrefixCnt + 1 + AdrCnt;
}
break;
case ModRef: /* LD A, R */
BAsmCode[PrefixCnt++] = 0xed;
BAsmCode[PrefixCnt++] = 0x5f;
CodeLen = PrefixCnt;
break;
case ModInt: /* LD A, I */
BAsmCode[PrefixCnt++] = 0xed;
BAsmCode[PrefixCnt++] = 0x57;
CodeLen = PrefixCnt;
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
else if ((AdrPart != 6) && (PrefixCnt == 0)) /* LD R8, ... */
{
AdrByte = AdrPart; OpSize = 0; DecodeAdr(&ArgStr[2], MModReg8 | MModImm);
switch (AdrMode)
{
case ModReg8: /* LD R8, R8/RX8/(HL)/(XY+D) */
/* if (I(XY)+d) as source, cannot use H/L as target ! */
if (((AdrByte == 4) || (AdrByte == 5)) && IndexPrefix() && (AdrCnt == 0)) WrError(ErrNum_InvAddrMode);
else
{
BAsmCode[PrefixCnt] = 0x40 + (AdrByte << 3) + AdrPart;
memcpy(BAsmCode
+ PrefixCnt
+ 1, AdrVals
, AdrCnt
);
CodeLen = PrefixCnt + 1 + AdrCnt;
}
break;
case ModImm: /* LD R8, imm8 */
BAsmCode[0] = 0x06 + (AdrByte << 3); BAsmCode[1] = AdrVals[0];
CodeLen = 2;
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
else if ((AdrPart == 4) || (AdrPart == 5)) /* LD RX8, ... */
{
AdrByte = AdrPart; OpSize = 0; DecodeAdr(&ArgStr[2], MModAll);
switch (AdrMode)
{
case ModReg8: /* LD RX8, R8/RX8 */
if (AdrPart == 6) WrError(ErrNum_InvAddrMode); /* stopped here */
else if ((AdrPart >= 4) && (AdrPart <= 5) && (PrefixCnt != 2)) WrError(ErrNum_InvAddrMode);
else if ((AdrPart >= 4) && (AdrPart <= 5) && (BAsmCode[0] != BAsmCode[1])) WrError(ErrNum_InvAddrMode);
else
{
if (PrefixCnt == 2) PrefixCnt--;
BAsmCode[PrefixCnt] = 0x40 + (AdrByte << 3) + AdrPart;
CodeLen = PrefixCnt + 1;
}
break;
case ModImm: /* LD RX8,imm8 */
BAsmCode[PrefixCnt]=0x06+(AdrByte << 3);
BAsmCode[PrefixCnt+1]=AdrVals[0];
CodeLen=PrefixCnt+2;
break;
default:
if (AdrMode!=ModNone) WrError(ErrNum_InvAddrMode);
}
}
else /* LD (HL)/(XY+d),... */
{
HLen = AdrCnt;
memcpy(HVals
, AdrVals
, AdrCnt
);
z = PrefixCnt;
if ((z == 0) && (IsLDW))
{
OpSize = 1;
MayLW = True;
}
else
OpSize = 0;
DecodeAdr(&ArgStr[2], MModAll);
switch (AdrMode)
{
case ModReg8: /* LD (HL)/(XY+D),R8 */
if ((PrefixCnt != z) || (AdrPart == 6)) WrError(ErrNum_InvAddrMode);
else
{
BAsmCode[PrefixCnt] = 0x70 + AdrPart;
memcpy(BAsmCode
+ PrefixCnt
+ 1, HVals
, HLen
);
CodeLen=PrefixCnt + 1 + HLen;
}
break;
case ModImm: /* LD (HL)/(XY+D),imm8:16:32 */
if ((z == 0) && (IsLDW))
{
if (ChkMinCPU(CPUZ380))
{
BAsmCode[PrefixCnt] = 0xed;
BAsmCode[PrefixCnt + 1] = 0x36;
memcpy(BAsmCode
+ PrefixCnt
+ 2, AdrVals
, AdrCnt
);
CodeLen = PrefixCnt + 2 + AdrCnt;
}
}
else
{
BAsmCode[PrefixCnt] = 0x36;
memcpy(BAsmCode
+ 1 + PrefixCnt
, HVals
, HLen
);
BAsmCode[PrefixCnt + 1 + HLen] = AdrVals[0];
CodeLen = PrefixCnt + 1 + HLen + AdrCnt;
}
break;
case ModReg16: /* LD (HL)/(XY+D),R16/XY */
if (!ChkMinCPU(CPUZ380));
else if (AdrPart == 3) WrError(ErrNum_InvAddrMode);
else if (HLen == 0)
{
if (PrefixCnt == z) /* LD (HL),R16 */
{
if (AdrPart == 2)
AdrPart = 3;
BAsmCode[0] = 0xfd;
BAsmCode[1] = 0x0f + (AdrPart << 4);
CodeLen = 2;
}
else /* LD (HL),XY */
{
CodeLen = PrefixCnt + 1;
BAsmCode[PrefixCnt] = 0x31;
CodeLen = 1 + PrefixCnt;
}
}
else
{
if (PrefixCnt == z) /* LD (XY+D),R16 */
{
if (AdrPart == 2)
AdrPart = 3;
BAsmCode[PrefixCnt] = 0xcb;
memcpy(BAsmCode
+ PrefixCnt
+ 1, HVals
, HLen
);
BAsmCode[PrefixCnt + 1 + HLen] = 0x0b + (AdrPart << 4);
CodeLen = PrefixCnt + 1 + HLen + 1;
}
else if (BAsmCode[0] == BAsmCode[1]) WrError(ErrNum_InvAddrMode);
else
{
PrefixCnt--;
BAsmCode[PrefixCnt] = 0xcb;
memcpy(BAsmCode
+PrefixCnt
+ 1, HVals
, HLen
);
BAsmCode[PrefixCnt + 1 + HLen] = 0x2b;
CodeLen = PrefixCnt + 1 + HLen + 1;
}
}
break;
default:
if (AdrMode!=ModNone) WrError(ErrNum_InvAddrMode);
}
}
break;
case ModReg16:
if (AdrPart == 3) /* LD SP,... */
{
OpSize = 1;
MayLW = True;
DecodeAdr(&ArgStr[2], MModAll);
switch (AdrMode)
{
case ModReg16: /* LD SP,HL/XY */
if (AdrPart != 2) WrError(ErrNum_InvAddrMode);
else
{
BAsmCode[PrefixCnt] = 0xf9;
CodeLen = PrefixCnt + 1;
}
break;
case ModImm: /* LD SP,imm16:32 */
BAsmCode[PrefixCnt] = 0x31;
memcpy(BAsmCode
+ PrefixCnt
+ 1, AdrVals
, AdrCnt
);
CodeLen = PrefixCnt + 1 + AdrCnt;
break;
case ModAbs: /* LD SP,(adr) */
if (AChkMinCPUPos(CPUZ80, &ArgStr[2]))
{
BAsmCode[PrefixCnt] = 0xed;
BAsmCode[PrefixCnt + 1] = 0x7b;
memcpy(BAsmCode
+ PrefixCnt
+ 2, AdrVals
, AdrCnt
);
CodeLen = PrefixCnt + 2 + AdrCnt;
}
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
else if (PrefixCnt == 0) /* LD R16,... */
{
unsigned ModeMask = MModAll;
AdrByte = (AdrPart == 2) ? 3 : AdrPart;
OpSize = 1;
MayLW = True;
if (is_sharp() && (AdrPart == 2))
ModeMask |= MModSPAdd;
DecodeAdr(&ArgStr[2], ModeMask);
switch (AdrMode)
{
case ModInt: /* LD HL,I */
if (!ChkMinCPU(CPUZ380));
else if (AdrByte != 3) WrError(ErrNum_InvAddrMode);
else
{
BAsmCode[0] = 0xdd;
BAsmCode[1] = 0x57;
CodeLen = 2;
}
break;
case ModReg8:
if (AdrPart != 6) WrError(ErrNum_InvAddrMode);
else if (!ChkMinCPU(CPUZ380));
else if (PrefixCnt == 0) /* LD R16,(HL) */
{
BAsmCode[0] = 0xdd;
BAsmCode[1] = 0x0f + (AdrByte << 4);
CodeLen = 2;
}
else /* LD R16,(XY+d) */
{
BAsmCode[PrefixCnt] = 0xcb;
memcpy(BAsmCode
+PrefixCnt
+ 1, AdrVals
, AdrCnt
);
BAsmCode[PrefixCnt + 1 + AdrCnt] = 0x03 + (AdrByte << 4);
CodeLen = PrefixCnt + 1 + AdrCnt + 1;
}
break;
case ModReg16:
if (AdrPart == 3) WrError(ErrNum_InvAddrMode);
else if (!ChkMinCPU(CPUZ380));
else if (PrefixCnt == 0) /* LD R16,R16 */
{
if (AdrPart == 2)
AdrPart = 3;
else if (AdrPart == 0)
AdrPart = 2;
BAsmCode[0] = 0xcd + (AdrPart << 4);
BAsmCode[1] = 0x02 + (AdrByte << 4);
CodeLen = 2;
}
else /* LD R16,XY */
{
BAsmCode[PrefixCnt] = 0x0b + (AdrByte << 4);
CodeLen=PrefixCnt + 1;
}
break;
case ModIndReg16: /* LD R16,(R16) */
if (ChkMinCPU(CPUZ380))
{
CodeLen = 2;
BAsmCode[0] = 0xdd;
BAsmCode[1] = 0x0c + (AdrByte << 4) + AdrPart;
}
break;
case ModImm: /* LD R16,imm */
if (AdrByte == 3)
AdrByte = 2;
CodeLen=PrefixCnt + 1 + AdrCnt;
BAsmCode[PrefixCnt] = 0x01 + (AdrByte << 4);
memcpy(BAsmCode
+ PrefixCnt
+ 1, AdrVals
, AdrCnt
);
break;
case ModAbs: /* LD R16,(adr) */
if (!AChkMinCPUPos(CPUZ80, &ArgStr[2]));
else if (AdrByte == 3)
{
BAsmCode[PrefixCnt] = 0x2a;
memcpy(BAsmCode
+ PrefixCnt
+ 1, AdrVals
, AdrCnt
);
CodeLen = 1 + PrefixCnt + AdrCnt;
}
else
{
BAsmCode[PrefixCnt] = 0xed;
BAsmCode[PrefixCnt+1] = 0x4b + (AdrByte << 4);
memcpy(BAsmCode
+ PrefixCnt
+ 2, AdrVals
, AdrCnt
);
CodeLen = PrefixCnt + 2 + AdrCnt;
}
break;
case ModSPAdd:
BAsmCode[0] = 0xf8;
BAsmCode[1] = AdrVals[0];
CodeLen = 2;
break;
case ModSPRel: /* LD R16,(SP+D) */
if (ChkMinCPU(CPUZ380))
{
BAsmCode[PrefixCnt] = 0xdd;
BAsmCode[PrefixCnt + 1] = 0xcb;
memcpy(BAsmCode
+ PrefixCnt
+ 2, AdrVals
, AdrCnt
);
BAsmCode[PrefixCnt + 2 + AdrCnt] = 0x01 + (AdrByte << 4);
CodeLen=PrefixCnt + 3 + AdrCnt;
}
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
else /* LD XY,... */
{
OpSize = 1;
MayLW = True;
DecodeAdr(&ArgStr[2], MModAll);
switch (AdrMode)
{
case ModReg8:
if (AdrPart != 6) WrError(ErrNum_InvAddrMode);
else if (!ChkMinCPU(CPUZ380));
else if (AdrCnt == 0) /* LD XY,(HL) */
{
BAsmCode[PrefixCnt] = 0x33;
CodeLen = PrefixCnt + 1;
}
else if (BAsmCode[0] == BAsmCode[1]) WrError(ErrNum_InvAddrMode);
else /* LD XY,(XY+D) */
{
BAsmCode[0] = BAsmCode[1];
PrefixCnt--;
BAsmCode[PrefixCnt] = 0xcb;
memcpy(BAsmCode
+ PrefixCnt
+ 1, AdrVals
, AdrCnt
);
BAsmCode[PrefixCnt + 1 + AdrCnt] = 0x23;
CodeLen = PrefixCnt + 1 + AdrCnt + 1;
}
break;
case ModReg16:
if (!ChkMinCPU(CPUZ380));
else if (AdrPart == 3) WrError(ErrNum_InvAddrMode);
else if (PrefixCnt == 1) /* LD XY,R16 */
{
if (AdrPart == 2) AdrPart = 3;
CodeLen = 1 + PrefixCnt;
BAsmCode[PrefixCnt] = 0x07 + (AdrPart << 4);
}
else if (BAsmCode[0] == BAsmCode[1]) WrError(ErrNum_InvAddrMode);
else /* LD XY,XY */
{
BAsmCode[--PrefixCnt] = 0x27;
CodeLen = 1 + PrefixCnt;
}
break;
case ModIndReg16:
if (ChkMinCPU(CPUZ380)) /* LD XY,(R16) */
{
BAsmCode[PrefixCnt] = 0x03 + (AdrPart << 4);
CodeLen = PrefixCnt + 1;
}
break;
case ModImm: /* LD XY,imm16:32 */
BAsmCode[PrefixCnt] = 0x21;
memcpy(BAsmCode
+PrefixCnt
+ 1, AdrVals
, AdrCnt
);
CodeLen = PrefixCnt + 1 + AdrCnt;
break;
case ModAbs: /* LD XY,(adr) */
BAsmCode[PrefixCnt] = 0x2a;
memcpy(BAsmCode
+ PrefixCnt
+ 1, AdrVals
, AdrCnt
);
CodeLen = PrefixCnt + 1 + AdrCnt;
break;
case ModSPRel: /* LD XY,(SP+D) */
if (ChkMinCPU(CPUZ380))
{
BAsmCode[PrefixCnt] = 0xcb;
memcpy(BAsmCode
+ PrefixCnt
+ 1, AdrVals
, AdrCnt
);
BAsmCode[PrefixCnt + 1 + AdrCnt] = 0x21;
CodeLen = PrefixCnt + 1 + AdrCnt + 1;
}
break;
default:
if (AdrMode!=ModNone) WrError(ErrNum_InvAddrMode);
}
}
break;
case ModIndReg8:
DecodeAdr(&ArgStr[2], MModReg8);
switch (AdrMode)
{
case ModReg8:
if (AdrPart != AccReg) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[0] = 0xe2;
CodeLen = 1;
}
break;
default:
break;
}
break;
case ModHLInc:
DecodeAdr(&ArgStr[2], MModReg8);
switch (AdrMode)
{
case ModReg8:
if (AdrPart != AccReg) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[0] = 0x22;
CodeLen = 1;
}
break;
default:
break;
}
break;
case ModHLDec:
DecodeAdr(&ArgStr[2], MModReg8);
switch (AdrMode)
{
case ModReg8:
if (AdrPart != AccReg) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[0] = 0x32;
CodeLen = 1;
}
break;
default:
break;
}
break;
case ModIndReg16:
AdrByte = AdrPart;
if (IsLDW)
{
OpSize = 1;
MayLW = True;
}
else
OpSize = 0;
DecodeAdr(&ArgStr[2], MModAll);
switch (AdrMode)
{
case ModReg8: /* LD (R16),A */
if (AdrPart != AccReg) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
CodeLen = 1;
BAsmCode[0] = 0x02 + (AdrByte << 4);
}
break;
case ModReg16:
if (AdrPart == 3) WrError(ErrNum_InvAddrMode);
else if (!ChkMinCPU(CPUZ380));
else if (PrefixCnt == 0) /* LD (R16),R16 */
{
if (AdrPart == 2)
AdrPart = 3;
BAsmCode[0] = 0xfd;
BAsmCode[1] = 0x0c + AdrByte + (AdrPart << 4);
CodeLen = 2;
}
else /* LD (R16),XY */
{
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0x01 + (AdrByte << 4);
}
break;
case ModImm:
if (!IsLDW) WrError(ErrNum_InvAddrMode);
else if (ChkMinCPU(CPUZ380))
{
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xed;
BAsmCode[CodeLen++] = 0x06 + (AdrByte << 4);
AppendAdrVals();
}
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
break;
case ModAbs:
HLen = AdrCnt;
memcpy(HVals
, AdrVals
, AdrCnt
);
OpSize = 0;
DecodeAdr(&ArgStr[2], MModReg8 | MModReg16);
switch (AdrMode)
{
case ModReg8: /* LD (adr),A */
if (AdrPart != AccReg) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else if (is_sharp() && (HVals[1] == 0xff))
{
BAsmCode[0] = 0xe0;
BAsmCode[1] = HVals[0];
CodeLen = 2;
}
else
{
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = is_sharp() ? 0xea : 0x32;
AppendVals(HVals, HLen);
}
break;
case ModReg16:
if ((AdrPart == 3) && is_sharp())
{
BAsmCode[0] = 0x08;
CodeLen = 1;
}
else if (!AChkMinCPUPos(CPUZ80, &ArgStr[1]));
else if (AdrPart == 2) /* LD (adr),HL/XY */
{
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0x22;
AppendVals(HVals, HLen);
}
else /* LD (adr),R16 */
{
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xed;
BAsmCode[CodeLen++] = 0x43 + (AdrPart << 4);
AppendVals(HVals, HLen);
}
break;
default:
if (AdrMode!=ModNone) WrError(ErrNum_InvAddrMode);
}
break;
case ModInt:
switch (DecodeAdr(&ArgStr[2], MModReg8 | MModReg16))
{
case ModReg8: /* LD I,A */
if (AdrPart != AccReg) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
CodeLen = 2;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x47;
}
break;
case ModReg16: /* LD I,HL */
if ((AdrPart != HLReg) || PrefixCnt) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else if (ChkMinCPU(CPUZ380))
{
CodeLen = 2;
BAsmCode[0] = 0xdd;
BAsmCode[1] = 0x47;
}
break;
default:
break;
}
break;
case ModRef:
if (DecodeAdr_A(&ArgStr[2])) /* LD R,A */
{
CodeLen = 2;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x4f;
}
else WrError(ErrNum_InvAddrMode);
break;
case ModSPRel:
if (ChkMinCPU(CPUZ380))
{
HLen = AdrCnt;
memcpy(HVals
, AdrVals
, AdrCnt
);
OpSize = 0;
DecodeAdr(&ArgStr[2], MModAll);
switch (AdrMode)
{
case ModReg16:
if (AdrPart == 3) WrError(ErrNum_InvAddrMode);
else if (PrefixCnt == 0) /* LD (SP+D),R16 */
{
if (AdrPart == 2)
AdrPart = 3;
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xdd;
BAsmCode[CodeLen++] = 0xcb;
AppendVals(HVals, HLen);
BAsmCode[CodeLen++] = 0x09 + (AdrPart << 4);
}
else /* LD (SP+D),XY */
{
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xcb;
AppendVals(HVals, HLen);
BAsmCode[CodeLen++] = 0x29;
}
break;
default:
if (AdrMode!=ModNone) WrError(ErrNum_InvAddrMode);
}
}
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
} /* outer switch */
}
}
/*!------------------------------------------------------------------------
* \fn DecodeLDHL(Word Code)
* \brief decode LDHL instruction (Sharp cores only)
* ------------------------------------------------------------------------ */
static void DecodeLDHL(Word Code)
{
Boolean OK;
UNUSED(Code);
if (!ChkArgCnt(2, 2)
|| (ChkExactCPUList(ErrNum_InstructionNotSupported, CPULR35902, CPUGBZ80, CPUNone) < 0))
return;
DecodeAdr(&ArgStr[1], MModReg16);
if (AdrMode != ModReg16)
return;
if (AdrPart != 3)
{
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
return;
}
BAsmCode[1] = EvalStrIntExpression(&ArgStr[2], SInt8, &OK);
if (OK)
{
BAsmCode[0] = 0xf8;
CodeLen = 2;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeLDH(Word code)
* \brief Decode LDH instruction (Sharp cores only)
* ------------------------------------------------------------------------ */
static Boolean ChkAbsUpperPage(Byte *p_dest)
{
/* allow just lower byte (00..ff) or full address (ff00..ffff): */
if ((AdrCnt == 2) && ((AdrVals[1] == 0x00) || (AdrVals[1] == 0xff)))
{
*p_dest = AdrVals[0];
return True;
}
else
return False;
}
static void DecodeLDH(Word code)
{
UNUSED(code);
if (!ChkArgCnt(2, 2)
|| (ChkExactCPUList(ErrNum_InstructionNotSupported, CPULR35902, CPUGBZ80, CPUNone) < 0))
return;
OpSize = 0;
switch (DecodeAdr(&ArgStr[1], MModReg8 | MModIndReg8 | MModAbs))
{
case ModReg8:
if (AdrPart != AccReg) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else switch (DecodeAdr(&ArgStr[2], MModIndReg8 | MModAbs))
{
case ModIndReg8:
BAsmCode[0] = 0xf2;
CodeLen = 1;
break;
case ModAbs:
if (ChkAbsUpperPage(&BAsmCode[1]))
{
BAsmCode[0] = 0xf0;
CodeLen = 2;
}
break;
default:
break;
}
break;
case ModIndReg8:
if (DecodeAdr_A(&ArgStr[2]))
{
BAsmCode[0] = 0xe2;
CodeLen = 1;
}
break;
case ModAbs:
if (ChkAbsUpperPage(&BAsmCode[1]))
{
if (DecodeAdr_A(&ArgStr[2]))
{
BAsmCode[0] = 0xe0;
CodeLen = 2;
}
}
break;
default:
break;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeLDX(Word Code)
* \brief decode LDX instruction (Sharp cores only)
* ------------------------------------------------------------------------ */
static void DecodeLDX(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(2, 2)
|| (ChkExactCPUList(ErrNum_InstructionNotSupported, CPULR35902, CPUGBZ80, CPUNone) < 0))
return;
DecodeAdr(&ArgStr[1], MModReg8 | MModAbs);
switch (AdrMode)
{
case ModReg8:
if (AdrPart != AccReg) WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
else
{
DecodeAdr(&ArgStr[2], MModAbs);
if (AdrMode == ModAbs)
{
BAsmCode[0] = 0xfa;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
CodeLen = 1 + AdrCnt;
}
}
break;
case ModAbs:
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
DecodeAdr(&ArgStr[2], MModReg8);
if (AdrMode == ModReg8)
{
if (AdrPart != AccReg) WrStrErrorPos(ErrNum_InvReg, &ArgStr[2]);
else
{
BAsmCode[0] = 0xea;
CodeLen = 3;
}
}
break;
default:
break;
}
}
static void DecodeALU8(Word Code)
{
switch (ArgCnt)
{
case 1:
AdrMode = ModReg8;
AdrPart = AccReg;
AdrCnt = 0;
break;
case 2:
DecodeAdr(&ArgStr[1], MModReg8 | (MomCPU == CPUZ380? MModReg16 : 0));
break;
default:
(void)ChkArgCnt(1, 2);
return;
}
switch (AdrMode)
{
case ModReg16:
if (Code != 2) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else if (AdrPart == HLReg)
{
OpSize = 1;
if (DecodeAdr(&ArgStr[ArgCnt], MModAbs) == ModAbs)
{
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xed;
BAsmCode[CodeLen++] = 0xd6;
AppendAdrVals();
}
}
else if (AdrPart == SPReg)
{
OpSize = 1;
if (DecodeAdr(&ArgStr[ArgCnt], MModImm) == ModImm)
{
CodeLen = 0;
BAsmCode[CodeLen++] = 0xed;
BAsmCode[CodeLen++] = 0x92;
AppendAdrVals();
break;
}
}
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
break;
case ModReg8:
if (AdrPart != AccReg) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
OpSize = 0;
switch (DecodeAdr(&ArgStr[ArgCnt], MModReg8 | MModImm))
{
case ModReg8:
CodeLen = PrefixCnt + 1 + AdrCnt;
BAsmCode[PrefixCnt] = 0x80 + (Code << 3) + AdrPart;
memcpy(BAsmCode
+ PrefixCnt
+ 1, AdrVals
, AdrCnt
);
break;
case ModImm:
if (!ImmIs8()) WrStrErrorPos(ErrNum_OverRange, &ArgStr[ArgCnt]);
else
{
CodeLen = 2;
BAsmCode[0] = 0xc6 + (Code << 3);
BAsmCode[1] = AdrVals[0];
}
break;
default:
break;
}
break;
default:
break;
}
}
}
static void DecodeALU16(Word Code)
{
if (ChkArgCnt(1, 2)
&& ChkMinCPU(CPUZ380)
&& ((ArgCnt == 1) || DecodeAdr_HL(&ArgStr[1])))
{
OpSize = 1; DecodeAdr(&ArgStr[ArgCnt], MModAll);
switch (AdrMode)
{
case ModReg16:
if (PrefixCnt > 0) /* wenn Register, dann nie DDIR! */
{
BAsmCode[PrefixCnt] = 0x87 + (Code << 3);
CodeLen = 1 + PrefixCnt;
}
else if (AdrPart == 3) WrError(ErrNum_InvAddrMode);
else
{
if (AdrPart == 2)
AdrPart = 3;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x84 + (Code << 3) + AdrPart;
CodeLen = 2;
}
break;
case ModReg8:
if ((AdrPart != 6) || (AdrCnt == 0)) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xc6 + (Code << 3);
AppendAdrVals();
}
break;
case ModImm:
CodeLen = 0;
BAsmCode[CodeLen++] = 0xed;
BAsmCode[CodeLen++] = 0x86 + (Code << 3);
AppendAdrVals();
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
}
static void DecodeADD(Word Index)
{
UNUSED(Index);
if (ChkArgCnt(2, 2))
{
DecodeAdr(&ArgStr[1], MModNoImm);
switch (AdrMode)
{
case ModReg8:
if (AdrPart != AccReg) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
OpSize = 0; DecodeAdr(&ArgStr[2], MModReg8 | MModImm);
switch (AdrMode)
{
case ModReg8:
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0x80 + AdrPart;
AppendAdrVals();
break;
case ModImm:
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xc6;
AppendAdrVals();
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
break;
case ModReg16:
if (AdrPart == 3) /* SP */
{
OpSize = (MomCPU == CPUZ380) ? 1 : 0;
DecodeAdr(&ArgStr[2], MModAll);
switch (AdrMode)
{
case ModImm:
switch (ChkExactCPUList(ErrNum_InstructionNotSupported, CPUZ380, CPUR2000, CPULR35902, CPUGBZ80, CPUNone))
{
case 0:
BAsmCode[0] = 0xed; BAsmCode[1] = 0x82;
memcpy(BAsmCode
+ 2, AdrVals
, AdrCnt
);
CodeLen = 2 + AdrCnt;
break;
case 1:
BAsmCode[0] = 0x27; BAsmCode[1] = 0[AdrVals];
CodeLen = 2;
break;
case 2:
case 3:
if (!ImmIsS8()) WrStrErrorPos(ErrNum_OverRange, &ArgStr[2]);
else
{
BAsmCode[0] = 0xe8;
BAsmCode[1] = 0[AdrVals];
CodeLen = 2;
}
break;
}
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
else if (AdrPart != 2) WrError(ErrNum_InvAddrMode);
else
{
Boolean HasPrefixes = (PrefixCnt> 0);
OpSize = 1; DecodeAdr(&ArgStr[2], MModAll);
switch (AdrMode)
{
case ModReg16:
if ((AdrPart == 2) && (PrefixCnt != 0) && ((PrefixCnt != 2) || (BAsmCode[0] != BAsmCode[1]))) WrError(ErrNum_InvAddrMode);
else
{
if (PrefixCnt == 2)
PrefixCnt--;
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0x09 + (AdrPart << 4);
}
break;
case ModAbs:
if (HasPrefixes) WrError(ErrNum_InvAddrMode);
else if (ChkMinCPU(CPUZ380))
{
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xed;
BAsmCode[CodeLen++] = 0xc2;
AppendAdrVals();
}
break;
default:
if (AdrMode!=ModNone) WrError(ErrNum_InvAddrMode);
}
}
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
}
static void DecodeADDW(Word Index)
{
UNUSED(Index);
if (ChkArgCnt(1, 2)
&& ChkMinCPU(CPUZ380)
&& ((ArgCnt == 1) || DecodeAdr_HL(&ArgStr[1])))
{
OpSize = 1; DecodeAdr(&ArgStr[ArgCnt], MModAll);
switch (AdrMode)
{
case ModReg16:
if (PrefixCnt > 0) /* wenn Register, dann nie DDIR! */
{
BAsmCode[PrefixCnt] = 0x87;
CodeLen = 1 + PrefixCnt;
}
else if (AdrPart == 3) WrError(ErrNum_InvAddrMode);
else
{
if (AdrPart == 2)
AdrPart = 3;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x84 + AdrPart;
CodeLen = 2;
}
break;
case ModReg8:
if ((AdrPart != 6) || (AdrCnt == 0)) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xc6;
AppendAdrVals();
}
break;
case ModImm:
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x86;
memcpy(BAsmCode
+ 2, AdrVals
, AdrCnt
);
CodeLen = 2 + AdrCnt;
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
}
static void DecodeADC_SBC(Word IsSBC)
{
if (ChkArgCnt(2, 2))
{
DecodeAdr(&ArgStr[1], MModReg8 | (is_sharp() ? 0 : MModReg16));
switch (AdrMode)
{
case ModReg8:
if (AdrPart != AccReg) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
OpSize = 0; DecodeAdr(&ArgStr[2], MModReg8 | MModImm);
switch (AdrMode)
{
case ModReg8:
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0x88 + AdrPart;
AppendAdrVals();
break;
case ModImm:
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xce;
AppendAdrVals();
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
if ((IsSBC) && (CodeLen != 0))
BAsmCode[PrefixCnt] += 0x10;
}
break;
case ModReg16:
if ((AdrPart != 2) || (PrefixCnt != 0)) WrError(ErrNum_InvAddrMode);
else
{
OpSize = 1; DecodeAdr(&ArgStr[2], MModAll);
switch (AdrMode)
{
case ModReg16:
if (PrefixCnt != 0) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x42 + (AdrPart << 4);
if (!IsSBC)
BAsmCode[1] += 8;
}
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
}
static void DecodeADCW_SBCW(Word Code)
{
if (ChkArgCnt(1, 2)
&& ChkMinCPU(CPUZ380)
&& ((ArgCnt == 1) || DecodeAdr_HL(&ArgStr[1])))
{
OpSize = 1; DecodeAdr(&ArgStr[ArgCnt], MModAll);
switch (AdrMode)
{
case ModReg16:
if (PrefixCnt > 0) /* wenn Register, dann nie DDIR! */
{
BAsmCode[PrefixCnt] = 0x8f + Code;
CodeLen = 1 + PrefixCnt;
}
else if (AdrPart == 3) WrError(ErrNum_InvAddrMode);
else
{
if (AdrPart == 2)
AdrPart = 3;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x8c + Code + AdrPart;
CodeLen = 2;
}
break;
case ModReg8:
if ((AdrPart != 6) || (AdrCnt == 0)) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xce + Code; /* ANSI :-0 */
AppendAdrVals();
}
break;
case ModImm:
CodeLen = 0;
BAsmCode[CodeLen++] = 0xed;
BAsmCode[CodeLen++] = 0x8e + Code;
AppendAdrVals();
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
}
static void DecodeINC_DEC(Word Index)
{
Word IsDEC = (Index & 1), IsWord = (Index & 2);
if (ChkArgCnt(1, 1))
{
DecodeAdr(&ArgStr[1], MModReg8 | MModReg16);
switch (AdrMode)
{
case ModReg8:
if (IsWord) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0x04 + (AdrPart << 3) + IsDEC;
AppendAdrVals();
}
break;
case ModReg16:
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0x03 + (AdrPart << 4) + (IsDEC << 3);
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
}
static void DecodeShift8(Word Code)
{
Byte reg_num = 0;
int mem_arg_index;
if (!ChkArgCnt(1, (MomCPU == CPUZ80U) ? 2 : 1))
return;
if ((Code == 6) && !ChkExactCPU(CPUZ80U)) /* SLI(A)/SL1/SLS undok. Z80 */
return;
/* dual arg (Z80 undoc): which is the extra destination register? This must be a 'simple' register (A,B,C,D,E,H,L): */
if (ArgCnt >= 2)
{
if (DecodeReg8Core(ArgStr[1].str.p_str, ®_num) && !(reg_num & 0xc0))
mem_arg_index = 2;
else if (DecodeReg8Core(ArgStr[2].str.p_str, ®_num) && !(reg_num & 0xc0))
mem_arg_index = 1;
else
{
WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
return;
}
}
/* single arg (documented version): */
else
mem_arg_index = 1;
/* now decode the 'official argument': */
OpSize = 0;
DecodeAdr(&ArgStr[mem_arg_index], MModReg8);
if (AdrMode != ModReg8)
return;
/* forbid IXL..IYU: */
if ((PrefixCnt > 0) && (AdrPart != 6))
{
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[mem_arg_index]);
return;
}
/* replace AdrPart for undocumented version. Addressing mode must be IXd/IYd: */
if (ArgCnt >= 2)
{
if ((AdrPart != 6) || (PrefixCnt != 1))
{
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[mem_arg_index]);
return;
}
AdrPart = reg_num;
}
/* assemble instruction: */
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xcb;
AppendAdrVals();
BAsmCode[CodeLen++] = (Code << 3) | AdrPart;
}
static void DecodeShift16(Word Code)
{
if (!ChkArgCnt(1, 1));
else if (ChkMinCPU(CPUZ380))
{
OpSize = 1; DecodeAdr(&ArgStr[1], MModNoImm);
switch (AdrMode)
{
case ModReg16:
if (PrefixCnt > 0)
{
BAsmCode[2] = 0x04 + (Code << 3) + ((BAsmCode[0] >> 5) & 1);
BAsmCode[0] = 0xed;
BAsmCode[1] = 0xcb;
CodeLen = 3;
}
else if (AdrPart == 3) WrError(ErrNum_InvAddrMode);
else
{
if (AdrPart == 2)
AdrPart = 3;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0xcb;
BAsmCode[2] = (Code << 3) + AdrPart;
CodeLen = 3;
}
break;
case ModReg8:
if (AdrPart != 6) WrError(ErrNum_InvAddrMode);
else
{
if (AdrCnt == 0)
{
BAsmCode[0] = 0xed;
PrefixCnt = 1;
}
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xcb;
AppendAdrVals();
BAsmCode[CodeLen++] = 0x02 + (Code << 3);
}
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
}
static void DecodeBit(Word Code)
{
Byte reg_num = 0;
int mem_arg_index, bit_arg_index;
Boolean ok;
/* extra undocumented dest register is not allowed for BIT */
if (!ChkArgCnt(1, ((MomCPU == CPUZ80U) && (Code != 0)) ? 3 : 2))
return;
/* triple arg (Z80 undoc): which is the extra destination register? This must be a 'simple' register (A,B,C,D,E,H,L): */
if (ArgCnt >= 3)
{
if (DecodeReg8Core(ArgStr[1].str.p_str, ®_num) && !(reg_num & 0xc0))
{
mem_arg_index = 3;
bit_arg_index = 2;
}
else if (DecodeReg8Core(ArgStr[3].str.p_str, ®_num) && !(reg_num & 0xc0))
{
mem_arg_index = 2;
bit_arg_index = 1;
}
else
{
WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
return;
}
}
/* single arg (documented version): */
else
{
mem_arg_index = 2;
bit_arg_index = 1;
}
/* now decode the 'official arguments': */
OpSize = 0;
DecodeAdr(&ArgStr[mem_arg_index], MModReg8);
if (AdrMode != ModReg8)
return;
/* forbid IXL..IYU: */
if ((PrefixCnt > 0) && (AdrPart != 6))
{
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[mem_arg_index]);
return;
}
/* parse bit # and form machine code: */
Code = ((Code + 1) << 6) | (EvalStrIntExpression(&ArgStr[bit_arg_index], UInt3, &ok) << 3);
if (!ok)
return;
/* replace AdrPart for undocumented version. Addressing mode must be IXd/IYd: */
if (ArgCnt >= 3)
{
if ((AdrPart != 6) || (PrefixCnt != 1))
{
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[mem_arg_index]);
return;
}
AdrPart = reg_num;
}
/* assemble instruction: */
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xcb;
AppendAdrVals();
BAsmCode[CodeLen++] = Code | AdrPart;
}
static void DecodeMLT(Word Index)
{
UNUSED(Index);
if (!ChkArgCnt(1, 1));
else if (ChkMinCPU(CPUZ180))
{
DecodeAdr(&ArgStr[1], MModAll);
if ((AdrMode != ModReg16) || (PrefixCnt != 0)) WrError(ErrNum_InvAddrMode);
else
{
BAsmCode[CodeLen] = 0xed;
BAsmCode[CodeLen + 1] = 0x4c + (AdrPart << 4);
CodeLen = 2;
}
}
}
static void DecodeMULT_DIV(Word Code)
{
const tStrComp *pSrcArg;
if (!ChkMinCPU(CPUZ380)
|| !ChkArgCnt(1, 2))
return;
if (2 == ArgCnt)
{
if (!DecodeAdr_HL(&ArgStr[1]))
return;
}
OpSize = 1;
pSrcArg = &ArgStr[ArgCnt];
switch (DecodeAdr(pSrcArg, MModReg8 | MModReg16 | MModImm))
{
case ModReg8:
if ((AdrPart != 6) || (PrefixCnt == 0)) WrStrErrorPos(ErrNum_InvAddrMode, pSrcArg);
else
{
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xcb;
AppendAdrVals();
BAsmCode[CodeLen++] = 0x92 | Code;
}
break;
case ModReg16:
if (AdrPart == SPReg) WrStrErrorPos(ErrNum_InvAddrMode, pSrcArg);
else if (PrefixCnt == 0)
{
if (AdrPart == 2)
AdrPart = 3;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0xcb;
BAsmCode[2] = 0x90 + AdrPart + Code;
CodeLen = 3;
}
else
{
BAsmCode[2] = 0x94 + ((BAsmCode[0] >> 5) & 1) + Code;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0xcb;
CodeLen = 3;
}
break;
case ModImm:
CodeLen = 0;
BAsmCode[CodeLen++] = 0xed;
BAsmCode[CodeLen++] = 0xcb;
BAsmCode[CodeLen++] = 0x97 + Code;
AppendAdrVals();
break;
default:
break;
}
}
static void DecodeTST(Word Index)
{
UNUSED(Index);
if (!ChkArgCnt(1, 1));
else if (ChkMinCPU(CPUZ180))
{
OpSize = 0; DecodeAdr(&ArgStr[1], MModAll);
switch (AdrMode)
{
case ModReg8:
if (PrefixCnt != 0) WrError(ErrNum_InvAddrMode);
else
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 4 + (AdrPart << 3);
CodeLen = 2;
}
break;
case ModImm:
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x64;
BAsmCode[2] = AdrVals[0];
CodeLen = 3;
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
}
static void DecodeSWAP(Word Index)
{
UNUSED(Index);
if (!ChkArgCnt(1, 1));
else if (ChkExactCPUList(ErrNum_InstructionNotSupported, CPUZ380, CPUGBZ80, CPULR35902, CPUNone) >= 0)
{
DecodeAdr(&ArgStr[1], (MomCPU == CPUZ380) ? MModReg16 : MModReg8);
switch (AdrMode)
{
case ModReg16:
if (AdrPart == 3) WrError(ErrNum_InvAddrMode);
else if (PrefixCnt == 0)
{
if (AdrPart == 2)
AdrPart = 3;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x0e + (AdrPart << 4); /*?*/
CodeLen = 2;
}
else
{
BAsmCode[PrefixCnt] = 0x3e;
CodeLen = PrefixCnt + 1;
}
break;
case ModReg8:
BAsmCode[0] = 0xcb;
BAsmCode[1] = 0x30 | AdrPart;
CodeLen = 2;
break;
default:
break;
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodePUSH_POP(Word Code)
* \brief handle PUSH/POP instructions
* \param Code machine code (4 = PUSH family, 0 = POP family)
* ------------------------------------------------------------------------ */
static void DecodePUSH_POP(Word Code)
{
if (!ChkArgCnt(1, 1));
else if (!as_strcasecmp(ArgStr[1].str.p_str, "SR"))
{
if (ChkMinCPU(CPUZ380))
{
CodeLen = 2;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0xc1 + Code;
}
}
else
{
OpSize = 1; MayLW = True;
if (!as_strcasecmp(ArgStr[1].str.p_str, "AF"))
{
AdrPart = SPReg;
AdrMode = ModReg16;
}
else
DecodeAdr(&ArgStr[1], MModReg16 | (((Code == 4) && (MomCPU == CPUZ380)) ? MModImm : 0));
switch (AdrMode)
{
case ModReg16:
CodeLen = 1 + PrefixCnt;
BAsmCode[PrefixCnt] = 0xc1 + (AdrPart << 4) + Code;
break;
case ModImm:
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xfd;
BAsmCode[CodeLen++] = 0xf5;
AppendAdrVals();
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
}
static void DecodeEX(Word Index)
{
Boolean OK;
Byte AdrByte;
UNUSED(Index);
/* No EX at all on GBZ80 */
if (!ChkMinCPU(CPUZ80))
return;
/* work around the parser problem related to the ' character */
if (!as_strncasecmp(ArgStr[2].str.p_str, "AF\'", 3))
ArgStr[2].str.p_str[3] = '\0';
if (!ChkArgCnt(2, 2));
else if (ParPair("AF", "AF\'"))
{
BAsmCode[0] = 0x08;
CodeLen = 1;
}
else if (ParPair("AF", "AF`"))
{
BAsmCode[0] = 0x08;
CodeLen = 1;
}
else
{
if ((ArgStr
[2].
str.
p_str[0]) && (ArgStr
[2].
str.
p_str[strlen(ArgStr
[2].
str.
p_str) - 1] == '\''))
{
OK = True;
ArgStr
[2].
str.
p_str[strlen(ArgStr
[2].
str.
p_str) - 1] = '\0';
}
else
OK = False;
DecodeAdr(&ArgStr[1], MModReg8 | MModReg16 | MModSPRel | MModIndReg16);
switch (AdrMode)
{
case ModReg8:
if (AdrPart == 6)
{
if (PrefixCnt) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else if (DecodeAdr_A(&ArgStr[2]) && ChkMinCPU(CPUZ380)) /* (HL),A */
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x37;
CodeLen = 2;
}
}
else
{
AdrByte = AdrPart;
DecodeAdr(&ArgStr[2], MModReg8);
switch (AdrMode)
{
case ModReg8:
if (AdrPart == 6)
{
if ((AdrByte != AccReg) || PrefixCnt) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]); /* A<->(HL) */
else if (ChkMinCPU(CPUZ380))
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x37;
CodeLen = 2;
}
}
else if (!ChkMinCPU(CPUZ380));
else if ((AdrByte == AccReg) && !OK)
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x07 + (AdrPart << 3);
CodeLen = 2;
}
else if ((AdrPart == AccReg) && !OK)
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x07 + (AdrByte << 3);
CodeLen = 2;
}
else if (OK && (AdrPart == AdrByte))
{
BAsmCode[0] = 0xcb;
BAsmCode[1] = 0x30 + AdrPart;
CodeLen = 2;
}
else WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
break;
default:
break;
}
}
break;
case ModReg16:
if (AdrPart == 3) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else if (PrefixCnt == 0) /* EX R16,... */
{
AdrByte = (AdrPart == HLReg) ? SPReg : AdrPart;
DecodeAdr(&ArgStr[2], MModReg16 | ((AdrPart == HLReg) ? MModSPRel : 0));
switch (AdrMode)
{
case ModReg16:
/* For DE <-> IX/IY, use the DD/FD prefix and DE<->HL on Z80, but the newer coding on Z380 */
if (((AdrByte == DEReg) && (AdrPart == HLReg) && (!PrefixCnt || (MomCPU != CPUZ380))) /* DE <-> HL */
|| ((AdrByte == SPReg) && (AdrPart == DEReg) && (!PrefixCnt || (MomCPU != CPUZ380))))
{
BAsmCode[PrefixCnt] = 0xeb;
CodeLen = PrefixCnt + 1;
}
else if (AdrPart == 3) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else if (!ChkMinCPU(CPUZ380));
else if (OK)
{
if (AdrPart == 2)
AdrPart = 3;
if ((PrefixCnt != 0) || (AdrPart != AdrByte)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0xcb;
BAsmCode[2] = 0x30 + AdrByte;
CodeLen = 3;
}
}
else if (PrefixCnt == 0)
{
if (AdrByte == 0)
{
if (AdrPart == 2)
AdrPart = 3;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x01 + (AdrPart << 2);
CodeLen = 2;
}
else if (AdrPart == 0)
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x01 + (AdrByte << 2);
CodeLen = 2;
}
}
else
{
if (AdrPart == 2)
AdrPart = 3;
BAsmCode[1] = 0x03 + ((BAsmCode[0] >> 2) & 8) + (AdrByte << 4);
BAsmCode[0] = 0xed;
CodeLen = 2;
}
break;
case ModSPRel:
if ((AdrCnt == 1) && !AdrVals[0]) /* HL <-> (SP) */
{
BAsmCode[PrefixCnt] = 0xe3;
CodeLen = PrefixCnt + 1;
}
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
break;
default:
break;
}
}
else /* EX XY,... */
{
DecodeAdr(&ArgStr[2], MModReg16 | MModSPRel);
switch (AdrMode)
{
case ModReg16:
if (AdrPart == 3) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else if (!ChkMinCPU(CPUZ380));
else if (OK)
{
if ((PrefixCnt != 2) || (BAsmCode[0] != BAsmCode[1])) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[2] = ((BAsmCode[0] >> 5) & 1)+0x34;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0xcb;
CodeLen = 3;
}
}
else if (PrefixCnt == 1)
{
if (AdrPart == 2)
AdrPart = 3;
BAsmCode[1] = ((BAsmCode[0] >> 2) & 8) + 3 + (AdrPart << 4);
BAsmCode[0] = 0xed;
CodeLen = 2;
}
else if (BAsmCode[0] == BAsmCode[1]) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x2b;
CodeLen = 2;
}
break;
case ModSPRel:
if ((AdrCnt == 1) && !AdrVals[0]) /* IX/IX <-> (SP) */
{
BAsmCode[PrefixCnt] = 0xe3;
CodeLen = PrefixCnt + 1;
}
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
break;
default:
break;
}
}
break;
case ModSPRel:
if ((AdrCnt != 1) || AdrVals[0]) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else switch (DecodeAdr(&ArgStr[2], MModReg16))
{
case ModReg16: /* (SP) <-> HL/IX/IX */
if (AdrPart != HLReg) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[PrefixCnt] = 0xe3;
CodeLen = PrefixCnt + 1;
}
break;
default:
break;
}
break;
default:
break;
}
}
}
static void DecodeTSTI(Word Code)
{
UNUSED(Code);
if (ChkExactCPU(CPUZ80U)
&& ChkArgCnt(0, 0))
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x70;
CodeLen = 2;
}
}
static void DecodeIN_OUT(Word IsOUT)
{
if ((ArgCnt == 1) && !IsOUT)
{
if (ChkExactCPU(CPUZ80U)
&& (DecodeAdr(&ArgStr[1], MModIndReg8) == ModIndReg8))
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x70;
CodeLen = 2;
}
}
else if (ChkArgCnt(2, 2) && ChkMinCPU(CPUZ80))
{
const tStrComp *pPortArg = IsOUT ? &ArgStr[1] : &ArgStr[2],
*pRegArg = IsOUT ? &ArgStr[2] : &ArgStr[1];
/* allow absolute I/O address also without (...) */
OpSize = 0;
switch (DecodeAdr(pPortArg, MModIndReg8 | MModIOAbs | MModImm))
{
case ModIndReg8:
DecodeAdrWithF(pRegArg, !IsOUT);
switch (AdrMode)
{
case ModReg8:
if (PrefixCnt != 0) WrError(ErrNum_InvAddrMode);
else
{
CodeLen = 2;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x40 + (AdrPart << 3);
if (IsOUT)
BAsmCode[1]++;
}
break;
case ModImm:
if (!IsOUT) WrError(ErrNum_InvAddrMode);
else if ((MomCPU == CPUZ80U) && (AdrVals[0] == 0))
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x71;
CodeLen = 2;
}
else if (ChkMinCPU(CPUZ380))
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x71;
BAsmCode[2] = AdrVals[0];
CodeLen = 3;
}
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
break;
case ModIOAbs:
case ModImm:
if (DecodeAdr_A(pRegArg))
{
CodeLen = 2;
BAsmCode[0] = IsOUT ? 0xd3 : 0xdb;
BAsmCode[1] = AdrVals[0];
}
break;
default:
break;
}
}
}
static void DecodeINW_OUTW(Word IsOUTW)
{
const tStrComp *pPortArg, *pRegArg;
if (!ChkArgCnt(2, 2) || !ChkMinCPU(CPUZ380))
return;
pPortArg = IsOUTW ? &ArgStr[1] : &ArgStr[2];
pRegArg = IsOUTW ? &ArgStr[2] : &ArgStr[1];
if (DecodeAdr(pPortArg, MModIndReg8) != ModIndReg8)
return;
OpSize = 1;
switch (DecodeAdr(pRegArg, MModReg16 | (IsOUTW ? MModImm : 0)))
{
case ModReg16:
if ((AdrPart == 3) || (PrefixCnt > 0)) WrError(ErrNum_InvAddrMode);
else
{
switch (AdrPart)
{
case 1: AdrPart = 2; break;
case 2: AdrPart = 7; break;
}
BAsmCode[0] = 0xdd;
BAsmCode[1] = 0x40 + (AdrPart << 3);
if (IsOUTW)
BAsmCode[1]++;
CodeLen = 2;
}
break;
case ModImm:
CodeLen = 0;
BAsmCode[CodeLen++] = 0xfd;
BAsmCode[CodeLen++] = 0x79;
AppendAdrVals();
break;
default:
break;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeIN0_OUT0(Word IsOUT0)
* \brief Handle IN0/OUT0 instructions on Z180++
* \param IsOUT0 1 for OUT0, 0 for IN0
* ------------------------------------------------------------------------ */
static void DecodeIN0_OUT0(Word IsOUT0)
{
/* 'IN0 (C)' better should not be allowed at all, because it was a copy'n'waste from
the undocumented Z80 'IN (C)' which should better have been named 'IN F,(C)'. But
I will leave it in for upward compatibility, and not implicitly assume A as register: */
if (ChkArgCnt(IsOUT0 ? 2 : 1, 2)
&& ChkMinCPU(CPUZ180))
{
Boolean OK;
const tStrComp *pRegArg, *pPortArg;
if (IsOUT0)
{
pRegArg = (ArgCnt == 2) ? &ArgStr[2] : NULL;
pPortArg = &ArgStr[1];
}
else
{
pRegArg = (ArgCnt == 2) ? &ArgStr[1] : NULL;
pPortArg = &ArgStr[ArgCnt];
}
OpSize = 0;
if (!pRegArg)
{
AdrPart = 6;
OK = True;
}
else
{
DecodeAdrWithF(pRegArg, !IsOUT0);
if ((AdrMode == ModReg8) && (PrefixCnt == 0)) OK = True;
else
{
OK = False;
if (AdrMode != ModNone) WrStrErrorPos(ErrNum_InvAddrMode, pRegArg);
}
}
if (OK)
{
BAsmCode[2] = EvalStrIntExpression(pPortArg, UInt8, &OK);
if (OK)
{
BAsmCode[0] = 0xed;
BAsmCode[1] = AdrPart << 3;
if (IsOUT0)
BAsmCode[1]++;
CodeLen = 3;
}
}
}
}
static void DecodeINA_INAW_OUTA_OUTAW(Word Code)
{
Word IsIn = Code & 8;
LongWord AdrLong;
tStrComp *pRegArg, *pPortArg;
tEvalResult EvalResult;
if (!ChkArgCnt(2, 2) || !ChkMinCPU(CPUZ380))
return;
pRegArg = IsIn ? &ArgStr[1] : &ArgStr[2];
pPortArg = IsIn ? &ArgStr[2] : &ArgStr[1];
OpSize = Code & 1;
if (!(OpSize ? DecodeAdr_HL(pRegArg) : DecodeAdr_A(pRegArg)))
return;
AdrLong = EvalStrIntExpressionWithResult(pPortArg, ExtFlag ? Int32 : UInt8, &EvalResult);
if (EvalResult.OK)
{
ChkSpace(SegIO, EvalResult.AddrSpaceMask);
if (AdrLong > 0xfffffful)
ChangeDDPrefix(ePrefixIW);
else if (AdrLong > 0xfffful)
ChangeDDPrefix(ePrefixIB);
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xed + (OpSize << 4);
BAsmCode[CodeLen++] = 0xd3 + IsIn;
BAsmCode[CodeLen++] = AdrLong & 0xff;
BAsmCode[CodeLen++] = (AdrLong >> 8) & 0xff;
if (AdrLong > 0xfffful)
BAsmCode[CodeLen++] = (AdrLong >> 16) & 0xff;
if (AdrLong > 0xfffffful)
BAsmCode[CodeLen++] = (AdrLong >> 24) & 0xff;
}
}
static void DecodeTSTIO(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 1)
&& ChkMinCPU(CPUZ180))
{
Boolean OK;
BAsmCode[2] = EvalStrIntExpression(&ArgStr[1], Int8, &OK);
if (OK)
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x74;
CodeLen = 3;
}
}
}
static void DecodeRET(Word Code)
{
int Cond;
UNUSED(Code);
if (ArgCnt == 0)
{
CodeLen = 1;
BAsmCode[0] = 0xc9;
}
else if (!ChkArgCnt(0, 1));
else if (!DecodeCondition(ArgStr[1].str.p_str, &Cond)) WrStrErrorPos(ErrNum_UndefCond, &ArgStr[1]);
else
{
CodeLen = 1;
BAsmCode[0] = 0xc0 + (Cond << 3);
}
}
static void DecodeJP(Word Code)
{
int Cond;
UNUSED(Code);
switch (ArgCnt)
{
case 1:
Cond = 1;
break;
case 2:
if (!DecodeCondition(ArgStr[1].str.p_str, &Cond))
{
WrStrErrorPos(ErrNum_UndefCond, &ArgStr[1]);
return;
}
Cond <<= 3;
break;
default:
(void)ChkArgCnt(1, 2);
return;
}
switch (DecodeAdr(&ArgStr[ArgCnt], MModImmIsAbs | MModAbs | ((Cond == 1) ? MModReg8 : 0)))
{
case ModReg8:
if ((AdrPart != 6) || ((AdrCnt > 0) && AdrVals[0])) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[ArgCnt]);
else
{
BAsmCode[PrefixCnt] = 0xe9;
CodeLen = PrefixCnt + 1;
}
break;
case ModAbs:
{
BAsmCode[PrefixCnt] = 0xc2 + Cond;
CodeLen = PrefixCnt + 1;
AppendAdrVals();
break;
}
}
}
static void DecodeCALL(Word Code)
{
Boolean OK;
int Condition;
UNUSED(Code);
switch (ArgCnt)
{
case 1:
Condition = 9;
OK = True;
break;
case 2:
OK = DecodeCondition(ArgStr[1].str.p_str, &Condition);
if (OK)
Condition <<= 3;
else
WrStrErrorPos(ErrNum_UndefCond, &ArgStr[1]);
break;
default:
(void)ChkArgCnt(1, 2);
OK = False;
}
if (OK)
{
LongWord AdrLong;
tEvalResult EvalResult;
AdrLong = EvalAbsAdrExpression(&ArgStr[ArgCnt], &EvalResult);
if (EvalResult.OK)
{
if (AdrLong <= 0xfffful)
{
CodeLen = 3;
BAsmCode[0] = 0xc4 + Condition;
BAsmCode[1] = Lo(AdrLong);
BAsmCode[2] = Hi(AdrLong);
}
else if (AdrLong <= 0xfffffful)
{
ChangeDDPrefix(ePrefixIB);
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xc4 + Condition;
BAsmCode[CodeLen++] = Lo(AdrLong);
BAsmCode[CodeLen++] = Hi(AdrLong);
BAsmCode[CodeLen++] = Hi(AdrLong >> 8);
}
else
{
ChangeDDPrefix(ePrefixIW);
CodeLen = PrefixCnt;
BAsmCode[CodeLen++] = 0xc4 + Condition;
BAsmCode[CodeLen++] = Lo(AdrLong);
BAsmCode[CodeLen++] = Hi(AdrLong);
BAsmCode[CodeLen++] = Hi(AdrLong >> 8);
BAsmCode[CodeLen++] = Hi(AdrLong >> 16);
}
}
}
}
static void DecodeJR(Word Code)
{
Boolean OK;
int Condition;
UNUSED(Code);
switch (ArgCnt)
{
case 1:
Condition = 3;
OK = True;
break;
case 2:
OK = DecodeCondition(ArgStr[1].str.p_str, &Condition);
if ((OK) && (Condition > 3))
OK = False;
if (OK)
Condition += 4;
else
WrStrErrorPos(ErrNum_UndefCond, &ArgStr[1]);
break;
default:
(void)ChkArgCnt(1, 2);
OK = False;
}
if (OK)
{
LongInt AdrLInt;
tEvalResult EvalResult;
AdrLInt = EvalAbsAdrExpression(&ArgStr[ArgCnt], &EvalResult);
if (EvalResult.OK)
{
IntType dist_type;
AdrLInt -= EProgCounter() + 2;
if ((MomCPU < CPUZ380) || RangeCheck(AdrLInt, SInt8))
dist_type = SInt8;
else
{
AdrLInt -= 2;
if (RangeCheck(AdrLInt, SInt16))
dist_type = SInt16;
else
{
AdrLInt--;
dist_type = SInt24;
}
}
if (!mFirstPassUnknownOrQuestionable(EvalResult.Flags) && !RangeCheck(AdrLInt, dist_type)) WrError(ErrNum_JmpDistTooBig);
else switch (dist_type)
{
case SInt8:
CodeLen = 2;
BAsmCode[0] = Condition << 3;
BAsmCode[1] = AdrLInt & 0xff;
break;
case SInt16:
CodeLen = 4;
BAsmCode[0] = 0xdd;
BAsmCode[1] = Condition << 3;
BAsmCode[2] = AdrLInt & 0xff;
BAsmCode[3] = (AdrLInt >> 8) & 0xff;
break;
case SInt24:
CodeLen = 5;
BAsmCode[0] = 0xfd;
BAsmCode[1] = Condition << 3;
BAsmCode[2] = AdrLInt & 0xff;
BAsmCode[3] = (AdrLInt >> 8) & 0xff;
BAsmCode[4] = (AdrLInt >> 16) & 0xff;
break;
default:
break;
}
}
}
}
static void DecodeCALR(Word Code)
{
Boolean OK;
int Condition;
UNUSED(Code);
switch (ArgCnt)
{
case 1:
Condition = 9;
OK = True;
break;
case 2:
OK = DecodeCondition(ArgStr[1].str.p_str, &Condition);
if (OK)
Condition <<= 3;
else
WrStrErrorPos(ErrNum_UndefCond, &ArgStr[1]);
break;
default:
(void)ChkArgCnt(1, 2);
OK = False;
}
if (OK)
{
if (ChkMinCPU(CPUZ380))
{
LongInt AdrLInt;
tEvalResult EvalResult;
AdrLInt = EvalAbsAdrExpression(&ArgStr[ArgCnt], &EvalResult);
if (EvalResult.OK)
{
AdrLInt -= EProgCounter() + 3;
if ((AdrLInt <= 0x7fl) && (AdrLInt >= -0x80l))
{
CodeLen = 3;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0xc4 | Condition;
BAsmCode[2] = AdrLInt & 0xff;
}
else
{
AdrLInt--;
if ((AdrLInt <= 0x7fffl) && (AdrLInt >= -0x8000l))
{
CodeLen = 4;
BAsmCode[0] = 0xdd;
BAsmCode[1] = 0xc4 + Condition;
BAsmCode[2] = AdrLInt & 0xff;
BAsmCode[3] = (AdrLInt >> 8) & 0xff;
}
else
{
AdrLInt--;
if ((AdrLInt <= 0x7fffffl) && (AdrLInt >= -0x800000l))
{
CodeLen = 5;
BAsmCode[0] = 0xfd;
BAsmCode[1] = 0xc4 + Condition;
BAsmCode[2] = AdrLInt & 0xff;
BAsmCode[3] = (AdrLInt >> 8) & 0xff;
BAsmCode[4] = (AdrLInt >> 16) & 0xff;
}
else WrError(ErrNum_JmpDistTooBig);
}
}
}
}
}
}
static void DecodeDJNZ(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 1) && ChkMinCPU(CPUZ80))
{
tEvalResult EvalResult;
LongInt AdrLInt;
AdrLInt = EvalAbsAdrExpression(&ArgStr[1], &EvalResult);
if (EvalResult.OK)
{
AdrLInt -= EProgCounter() + 2;
if ((AdrLInt <= 0x7fl) & (AdrLInt >= -0x80l))
{
CodeLen = 2;
BAsmCode[0] = 0x10;
BAsmCode[1] = Lo(AdrLInt);
}
else if (MomCPU<CPUZ380) WrError(ErrNum_JmpDistTooBig);
else
{
AdrLInt -= 2;
if ((AdrLInt <= 0x7fffl) && (AdrLInt >= -0x8000l))
{
CodeLen = 4;
BAsmCode[0] = 0xdd;
BAsmCode[1] = 0x10;
BAsmCode[2] = AdrLInt & 0xff;
BAsmCode[3] = (AdrLInt >> 8) & 0xff;
}
else
{
AdrLInt--;
if ((AdrLInt <= 0x7fffffl) && (AdrLInt >= -0x800000l))
{
CodeLen = 5;
BAsmCode[0] = 0xfd;
BAsmCode[1] = 0x10;
BAsmCode[2] = AdrLInt & 0xff;
BAsmCode[3] = (AdrLInt >> 8) & 0xff;
BAsmCode[4] = (AdrLInt >> 16) & 0xff;
}
else WrError(ErrNum_JmpDistTooBig);
}
}
}
}
}
static void DecodeRST(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 1))
{
Boolean OK;
tSymbolFlags Flags;
Byte AdrByte;
int SaveRadixBase = RadixBase;
#if 0
/* some people like to regard the RST argument as a literal
and leave away the 'h' to mark 38 as a hex number... */
RadixBase = 16;
#endif
AdrByte = EvalStrIntExpressionWithFlags(&ArgStr[1], Int8, &OK, &Flags);
RadixBase = SaveRadixBase;
if (mFirstPassUnknown(Flags))
AdrByte = AdrByte & 0x38;
if (OK)
{
if ((AdrByte > 0x38) || (AdrByte & 7)) WrError(ErrNum_NotFromThisAddress);
else
{
CodeLen = 1;
BAsmCode[0] = 0xc7 + AdrByte;
}
}
}
}
static void DecodeEI_DI(Word Code)
{
if (ArgCnt == 0)
{
BAsmCode[0] = 0xf3 + Code;
CodeLen = 1;
}
else if (ChkArgCnt(1, 1)
&& ChkMinCPU(CPUZ380))
{
Boolean OK;
BAsmCode[2] = EvalStrIntExpression(&ArgStr[1], UInt8, &OK);
if (OK)
{
BAsmCode[0] = 0xdd;
BAsmCode[1] = 0xf3 + Code;
CodeLen = 3;
}
}
}
static void DecodeIM(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 1)
&& ChkMinCPU(CPUZ80))
{
Byte AdrByte;
Boolean OK;
AdrByte = EvalStrIntExpression(&ArgStr[1], UInt2, &OK);
if (OK)
{
if (AdrByte > 3) WrError(ErrNum_OverRange);
else if ((AdrByte == 3) && (!ChkMinCPU(CPUZ380)));
else
{
if (AdrByte == 3)
AdrByte = 1;
else if (AdrByte >= 1)
AdrByte++;
CodeLen = 2;
BAsmCode[0] = 0xed;
BAsmCode[1] = 0x46 + (AdrByte << 3);
}
}
}
}
static void DecodeLDCTL(Word Code)
{
Byte AdrByte;
UNUSED(Code);
OpSize = 0;
if (!ChkArgCnt(2, 2));
else if (!ChkMinCPU(CPUZ380));
else if (DecodeSFR(ArgStr[1].str.p_str, &AdrByte))
{
DecodeAdr(&ArgStr[2], MModAll);
switch (AdrMode)
{
case ModReg8:
if (AdrPart != AccReg) WrError(ErrNum_InvAddrMode);
else
{
BAsmCode[0] = 0xcd + ((AdrByte & 3) << 4);
BAsmCode[1] = 0xc8 + ((AdrByte & 4) << 2);
CodeLen = 2;
}
break;
case ModReg16:
if ((AdrByte != 1) || (AdrPart != 2) || (PrefixCnt != 0)) WrError(ErrNum_InvAddrMode);
else
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0xc8;
CodeLen = 2;
}
break;
case ModImm:
BAsmCode[0] = 0xcd +((AdrByte & 3) << 4);
BAsmCode[1] = 0xca +((AdrByte & 4) << 2);
BAsmCode[2] = AdrVals[0];
CodeLen = 3;
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
else if (DecodeSFR(ArgStr[2].str.p_str, &AdrByte))
{
DecodeAdr(&ArgStr[1], MModAll);
switch (AdrMode)
{
case ModReg8:
if ((AdrPart != 7) || (AdrByte == 1)) WrError(ErrNum_InvAddrMode);
else
{
BAsmCode[0] = 0xcd + ((AdrByte & 3) << 4);
BAsmCode[1] = 0xd0;
CodeLen = 2;
}
break;
case ModReg16:
if ((AdrByte != 1) || (AdrPart != 2) || (PrefixCnt != 0)) WrError(ErrNum_InvAddrMode);
else
{
BAsmCode[0] = 0xed;
BAsmCode[1] = 0xc0;
CodeLen = 2;
}
break;
default:
if (AdrMode != ModNone) WrError(ErrNum_InvAddrMode);
}
}
else
WrError(ErrNum_InvAddrMode);
}
static void DecodeRESC_SETC(Word Code)
{
if (ChkArgCnt(1, 1)
&& ChkMinCPU(CPUZ380))
{
Byte AdrByte = 0xff;
NLS_UpString(ArgStr[1].str.p_str);
if (!strcmp(ArgStr
[1].
str.
p_str, "LW")) AdrByte
= 1;
else if (!strcmp(ArgStr
[1].
str.
p_str, "LCK")) AdrByte
= 2;
else if (!strcmp(ArgStr
[1].
str.
p_str, "XM")) AdrByte
= 3;
else WrError(ErrNum_InvCtrlReg);
if (AdrByte != 0xff)
{
CodeLen = 2;
BAsmCode[0] = 0xcd + (AdrByte << 4);
BAsmCode[1] = 0xf7 + Code;
}
}
}
static void DecodeDDIR(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 2)
&& ChkMinCPU(CPUZ380))
{
Boolean OK;
int z;
OK = True;
for (z = 1; z <= ArgCnt; z++)
{
if (OK)
{
OK = ExtendPrefix(&CurrPrefix, DecodePrefix(ArgStr[z].str.p_str));
if (!OK) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[z]);
}
}
if (OK)
{
GetPrefixCode(CurrPrefix, BAsmCode + 0, BAsmCode + 1);
CodeLen = 2;
}
}
}
static void DecodePORT(Word Code)
{
UNUSED(Code);
CodeEquate(SegIO, 0, PortEnd());
}
static void DecodeLDI_LDD(Word Code)
{
if (ChkArgCnt(2,2) && (ChkExactCPUList(ErrNum_InstructionNotSupported, CPUGBZ80, CPULR35902, CPUNone) >= 0))
{
DecodeAdr(&ArgStr[1], MModReg8);
if (AdrMode == ModReg8)
switch (AdrPart)
{
case 7:
DecodeAdr(&ArgStr[2], MModReg8);
if (AdrMode == ModReg8)
{
if (AdrPart != 6) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[0] = Code | 0x08;
CodeLen = 1;
}
}
break;
case 6:
DecodeAdr(&ArgStr[2], MModReg8);
if (AdrMode == ModReg8)
{
if (AdrPart != AccReg) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[0] = Code;
CodeLen = 1;
}
}
break;
default:
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
}
}
}
static void DecodePRWINS(Word Code)
{
UNUSED(Code);
if (ChkExactCPU(CPUZ180))
{
printf("\nCBAR 0%02xh BBR 0%02xh CBR 0%02xh\n",
(unsigned)Reg_CBAR, (unsigned)Reg_BBR, (unsigned)Reg_CBR);
cpu_2_phys_area_dump(SegCode, stdout);
}
}
static void ModIntel(Word Code)
{
UNUSED(Code);
/* M80 compatibility: DEFB->DB, DEFW->DW */
strmov(OpPart.str.p_str + 1, OpPart.str.p_str + 3);
DecodeIntelPseudo(False);
}
/*!------------------------------------------------------------------------
* \fn valid_cbar(void)
* \brief allowed CBAR value?
* \return True if valid
* ------------------------------------------------------------------------ */
static Boolean valid_cbar(void)
{
return ((Reg_CBAR & 0x0f) <= ((Reg_CBAR >> 4) & 0x0f));
}
/*!------------------------------------------------------------------------
* \fn update_z180_areas(void)
* \brief recompute Z180 mapped areas
* ------------------------------------------------------------------------ */
static void update_z180_areas(void)
{
if (valid_cbar())
{
Word common_area_start = ((Reg_CBAR >> 4) & 0x0f) << 12,
bank_area_start = (Reg_CBAR & 0x0f) << 12;
cpu_2_phys_area_clear(SegCode);
/* Common Area 0 */
if (bank_area_start > 0)
cpu_2_phys_area_add(SegCode, 0, 0, bank_area_start);
/* Bank Area */
if (common_area_start > bank_area_start)
cpu_2_phys_area_add(SegCode, bank_area_start, (Reg_BBR << 12) + bank_area_start, common_area_start - bank_area_start);
/* Common Area 1 - always present since upper nibble of CBAR is always < 0x10 */
cpu_2_phys_area_add(SegCode, common_area_start, (Reg_CBR << 12) + common_area_start, 0x10000ul - common_area_start);
/* this *SHOULD* be a NOP, since completely filled the 64K CPU space: */
cpu_2_phys_area_fill(SegCode, 0, 0xffff);
}
}
/*!------------------------------------------------------------------------
* \fn check_cbar(void)
* \brief check valid CBAR value
* ------------------------------------------------------------------------ */
static void check_cbar(void)
{
if (valid_cbar())
update_z180_areas();
else
WrError(ErrNum_InvCBAR);
}
/*==========================================================================*/
/* Codetabellenerzeugung */
static void AddFixed(const char *NewName, CPUVar NewMin, Byte NewLen, Word NewCode)
{
order_array_rsv_end(FixedOrders, BaseOrder);
FixedOrders[InstrZ].MinCPU = NewMin;
FixedOrders[InstrZ].Len = NewLen;
FixedOrders[InstrZ].Code = NewCode;
AddInstTable(InstTable, NewName, InstrZ++, DecodeFixed);
}
static void AddAcc(const char *NewName, CPUVar NewMin, Byte NewLen, Word NewCode)
{
order_array_rsv_end(AccOrders, BaseOrder);
AccOrders[InstrZ].MinCPU = NewMin;
AccOrders[InstrZ].Len = NewLen;
AccOrders[InstrZ].Code = NewCode;
AddInstTable(InstTable, NewName, InstrZ++, DecodeAcc);
}
static void AddHL(const char *NewName, CPUVar NewMin, Byte NewLen, Word NewCode)
{
order_array_rsv_end(HLOrders, BaseOrder);
HLOrders[InstrZ].MinCPU = NewMin;
HLOrders[InstrZ].Len = NewLen;
HLOrders[InstrZ].Code = NewCode;
AddInstTable(InstTable, NewName, InstrZ++, DecodeHL);
}
static void AddALU(const char *Name8, const char *Name16, Byte Code)
{
AddInstTable(InstTable, Name8 , Code, DecodeALU8);
AddInstTable(InstTable, Name16, Code, DecodeALU16);
}
static void AddShift(const char *Name8, const char *Name16, Byte Code)
{
AddInstTable(InstTable, Name8 , Code, DecodeShift8);
if (Name16)
AddInstTable(InstTable, Name16, Code, DecodeShift16);
}
static void AddBit(const char *NName, Word Code)
{
AddInstTable(InstTable, NName, Code, DecodeBit);
}
static void AddCondition(const char *NewName, Byte NewCode)
{
order_array_rsv_end(Conditions, Condition);
Conditions[InstrZ].Name = NewName;
Conditions[InstrZ++].Code = NewCode;
}
static void InitFields(void)
{
InstTable = CreateInstTable(203);
AddInstTable(InstTable, "LD" , 0, DecodeLD);
AddInstTable(InstTable, "LDW", 1, DecodeLD);
AddInstTable(InstTable, "LDHL", 0, DecodeLDHL);
AddInstTable(InstTable, "LDH", 0, DecodeLDH);
AddInstTable(InstTable, "LDX", 0, DecodeLDX);
AddInstTable(InstTable, "ADD", 0, DecodeADD);
AddInstTable(InstTable, "ADDW", 0, DecodeADDW);
AddInstTable(InstTable, "ADC" , 0, DecodeADC_SBC);
AddInstTable(InstTable, "SBC" , 1, DecodeADC_SBC);
AddInstTable(InstTable, "ADCW", 0, DecodeADCW_SBCW);
AddInstTable(InstTable, "SBCW",16, DecodeADCW_SBCW);
AddInstTable(InstTable, "INC" , 0, DecodeINC_DEC);
AddInstTable(InstTable, "DEC" , 1, DecodeINC_DEC);
AddInstTable(InstTable, "INCW", 2, DecodeINC_DEC);
AddInstTable(InstTable, "DECW", 3, DecodeINC_DEC);
AddInstTable(InstTable, "MLT" , 0, DecodeMLT);
AddInstTable(InstTable, "DIVUW" , 0x28, DecodeMULT_DIV);
AddInstTable(InstTable, "MULTW" , 0x00, DecodeMULT_DIV);
AddInstTable(InstTable, "MULTUW", 0x08, DecodeMULT_DIV);
AddInstTable(InstTable, "TST", 0, DecodeTST);
AddInstTable(InstTable, "SWAP", 0, DecodeSWAP);
AddInstTable(InstTable, "PUSH", 4, DecodePUSH_POP);
AddInstTable(InstTable, "POP" , 0, DecodePUSH_POP);
AddInstTable(InstTable, "EX" , 0, DecodeEX);
AddInstTable(InstTable, "TSTI", 0, DecodeTSTI);
AddInstTable(InstTable, "IN" , 0, DecodeIN_OUT);
AddInstTable(InstTable, "OUT" , 1, DecodeIN_OUT);
AddInstTable(InstTable, "INW" , 0, DecodeINW_OUTW);
AddInstTable(InstTable, "OUTW" , 1, DecodeINW_OUTW);
AddInstTable(InstTable, "IN0" , 0, DecodeIN0_OUT0);
AddInstTable(InstTable, "OUT0" , 1, DecodeIN0_OUT0);
AddInstTable(InstTable, "INA" , 8, DecodeINA_INAW_OUTA_OUTAW);
AddInstTable(InstTable, "INAW" , 9, DecodeINA_INAW_OUTA_OUTAW);
AddInstTable(InstTable, "OUTA" , 0, DecodeINA_INAW_OUTA_OUTAW);
AddInstTable(InstTable, "OUTAW", 1, DecodeINA_INAW_OUTA_OUTAW);
AddInstTable(InstTable, "TSTIO", 0, DecodeTSTIO);
AddInstTable(InstTable, "RET" , 0, DecodeRET);
AddInstTable(InstTable, "JP" , 0, DecodeJP);
AddInstTable(InstTable, "CALL", 0, DecodeCALL);
AddInstTable(InstTable, "JR" , 0, DecodeJR);
AddInstTable(InstTable, "CALR", 0, DecodeCALR);
AddInstTable(InstTable, "DJNZ", 0, DecodeDJNZ);
AddInstTable(InstTable, "RST", 0, DecodeRST);
AddInstTable(InstTable, "DI", 0, DecodeEI_DI);
AddInstTable(InstTable, "EI", 8, DecodeEI_DI);
AddInstTable(InstTable, "IM", 0, DecodeIM);
AddInstTable(InstTable, "LDCTL", 0, DecodeLDCTL);
AddInstTable(InstTable, "RESC", 8, DecodeRESC_SETC);
AddInstTable(InstTable, "SETC", 0, DecodeRESC_SETC);
AddInstTable(InstTable, "DDIR", 0, DecodeDDIR);
AddInstTable(InstTable, "PORT", 0, DecodePORT);
AddInstTable(InstTable, "DEFB", 0, ModIntel);
AddInstTable(InstTable, "DEFW", 0, ModIntel);
InstrZ = 0;
AddCondition("NZ", 0); AddCondition("Z" , 1);
AddCondition("NC", 2); AddCondition("C" , 3);
if (!is_sharp())
{
AddCondition("PO", 4); AddCondition("NV", 4);
AddCondition("PE", 5); AddCondition("V" , 5);
AddCondition("P" , 6); AddCondition("NS", 6);
AddCondition("M" , 7); AddCondition("S" , 7);
}
AddCondition(NULL, 0);
InstrZ = 0;
AddFixed("EXX" , CPUZ80 , 1, 0x00d9);
if (is_sharp())
{
AddInstTable(InstTable, "LDI", 0x22, DecodeLDI_LDD);
AddInstTable(InstTable, "LDD", 0x32, DecodeLDI_LDD);
}
else
{
AddFixed("LDI" , CPUZ80 , 2, 0xeda0);
AddFixed("LDD" , CPUZ80 , 2, 0xeda8);
}
AddFixed("LDIR" , CPUZ80 , 2, 0xedb0);
AddFixed("LDDR" , CPUZ80 , 2, 0xedb8);
AddFixed("CPI" , CPUZ80 , 2, 0xeda1);
AddFixed("CPIR" , CPUZ80 , 2, 0xedb1);
AddFixed("CPD" , CPUZ80 , 2, 0xeda9);
AddFixed("CPDR" , CPUZ80 , 2, 0xedb9);
AddFixed("RLCA" , CPUGBZ80 , 1, 0x0007);
AddFixed("RRCA" , CPUGBZ80 , 1, 0x000f);
AddFixed("RLA" , CPUGBZ80 , 1, 0x0017);
AddFixed("RRA" , CPUGBZ80 , 1, 0x001f);
AddFixed("RLD" , CPUZ80 , 2, 0xed6f);
AddFixed("RRD" , CPUZ80 , 2, 0xed67);
AddFixed("DAA" , CPUGBZ80 , 1, 0x0027);
AddFixed("CCF" , CPUGBZ80 , 1, 0x003f);
AddFixed("SCF" , CPUGBZ80 , 1, 0x0037);
AddFixed("NOP" , CPUGBZ80 , 1, 0x0000);
AddFixed("HALT" , CPUGBZ80 , 1, 0x0076);
AddFixed("RETI" , CPUGBZ80 ,
is_sharp() ? 1 : 2,
is_sharp() ? 0x00d9 : 0xed4d);
AddFixed("RETN" , CPUZ80 , 2, 0xed45);
AddFixed("INI" , CPUZ80 , 2, 0xeda2);
AddFixed("INIR" , CPUZ80 , 2, 0xedb2);
AddFixed("IND" , CPUZ80 , 2, 0xedaa);
AddFixed("INDR" , CPUZ80 , 2, 0xedba);
AddFixed("OUTI" , CPUZ80 , 2, 0xeda3);
AddFixed("OTIR" , CPUZ80 , 2, 0xedb3);
AddFixed("OUTD" , CPUZ80 , 2, 0xedab);
AddFixed("OTDR" , CPUZ80 , 2, 0xedbb);
AddFixed("EXA" , CPUZ80 , 1, 0x0008);
AddFixed("EXD" , CPUZ80 , 1, 0x00eb);
AddFixed("SLP" , CPUZ180 , 2, 0xed76);
AddFixed("OTIM" , CPUZ180 , 2, 0xed83);
AddFixed("OTIMR", CPUZ180 , 2, 0xed93);
AddFixed("OTDM" , CPUZ180 , 2, 0xed8b);
AddFixed("OTDMR", CPUZ180 , 2, 0xed9b);
AddFixed("BTEST", CPUZ380 , 2, 0xedcf);
AddFixed("EXALL", CPUZ380 , 2, 0xedd9);
AddFixed("EXXX" , CPUZ380 , 2, 0xddd9);
AddFixed("EXXY" , CPUZ380 , 2, 0xfdd9);
AddFixed("INDW" , CPUZ380 , 2, 0xedea);
AddFixed("INDRW", CPUZ380 , 2, 0xedfa);
AddFixed("INIW" , CPUZ380 , 2, 0xede2);
AddFixed("INIRW", CPUZ380 , 2, 0xedf2);
AddFixed("LDDW" , CPUZ380 , 2, 0xede8);
AddFixed("LDDRW", CPUZ380 , 2, 0xedf8);
AddFixed("LDIW" , CPUZ380 , 2, 0xede0);
AddFixed("LDIRW", CPUZ380 , 2, 0xedf0);
AddFixed("MTEST", CPUZ380 , 2, 0xddcf);
AddFixed("OTDRW", CPUZ380 , 2, 0xedfb);
AddFixed("OTIRW", CPUZ380 , 2, 0xedf3);
AddFixed("OUTDW", CPUZ380 , 2, 0xedeb);
AddFixed("OUTIW", CPUZ380 , 2, 0xede3);
AddFixed("RETB" , CPUZ380 , 2, 0xed55);
AddInstTable(InstTable, "STOP", 0x0010, DecodeSTOP);
InstrZ = 0;
AddAcc("CPL" , CPUGBZ80 , 1, 0x002f);
AddAcc("NEG" , CPUZ80 , 2, 0xed44);
AddAcc("EXTS" , CPUZ380 , 2, 0xed65);
InstrZ = 0;
AddHL("CPLW" , CPUZ380, 2, 0xdd2f);
AddHL("NEGW" , CPUZ380, 2, 0xed54);
AddHL("EXTSW", CPUZ380, 2, 0xed75);
AddALU("SUB", "SUBW", 2); AddALU("AND", "ANDW", 4);
AddALU("OR" , "ORW" , 6); AddALU("XOR", "XORW", 5);
AddALU("CP" , "CPW" , 7);
AddShift("RLC" , "RLCW" , 0); AddShift("RRC", "RRCW", 1);
AddShift("RL" , "RLW" , 2); AddShift("RR" , "RRW" , 3);
AddShift("SLA" , "SLAW" , 4); AddShift("SRA", "SRAW", 5);
AddShift("SLIA", NULL , 6); AddShift("SRL", "SRLW", 7);
AddShift("SLS" , NULL , 6); AddShift("SLI", NULL , 6);
AddShift("SL1" , NULL , 6);
AddBit("BIT", 0); AddBit("RES", 1); AddBit("SET", 2);
AddInstTable(InstTable, "REG" , 0, CodeREG);
AddInstTable(InstTable, "PRWINS", 0, DecodePRWINS);
}
static void DeinitFields(void)
{
order_array_free(Conditions);
order_array_free(FixedOrders);
order_array_free(AccOrders);
order_array_free(HLOrders);
DestroyInstTable(InstTable);
}
/*=========================================================================*/
static void StripPref(const char *Arg, Byte Opcode)
{
char *ptr, *ptr2;
int z;
/* do we have a prefix ? */
if (!strcmp(OpPart.
str.
p_str, Arg
))
{
/* add to code */
BAsmCode[PrefixCnt++] = Opcode;
StrCompReset(&OpPart);
/* cut true opcode out of next argument */
if (ArgCnt)
{
/* look for end of string */
for (ptr = ArgStr[1].str.p_str; *ptr; ptr++)
if (as_isspace(*ptr))
break;
/* look for beginning of next string */
for (ptr2 = ptr; *ptr2; ptr2++)
if (!as_isspace(*ptr2))
break;
/* copy out new opcode */
OpPart.Pos.StartCol = ArgStr[1].Pos.StartCol;
OpPart.Pos.Len = strmemcpy(OpPart.str.p_str, STRINGSIZE, ArgStr[1].str.p_str, ptr - ArgStr[1].str.p_str);
NLS_UpString(OpPart.str.p_str);
/* cut down arg or eliminate it completely */
if (*ptr2)
{
strmov(ArgStr[1].str.p_str, ptr2);
ArgStr[1].Pos.StartCol += ptr2 - ArgStr[1].str.p_str;
ArgStr[1].Pos.Len -= ptr2 - ArgStr[1].str.p_str;
}
else
{
for (z = 1; z < ArgCnt; z++)
StrCompCopy(&ArgStr[z], &ArgStr[z + 1]);
ArgCnt--;
}
}
/* if no further argument, that's all folks */
else
CodeLen = PrefixCnt;
}
}
static void MakeCode_Z80(void)
{
CodeLen = 0;
DontPrint = False;
PrefixCnt = 0;
OpSize = 0xff;
MayLW = False;
/*--------------------------------------------------------------------------*/
/* Rabbit 2000 prefixes */
if (MomCPU == CPUR2000)
{
StripPref("ALTD", 0x76);
}
/* zu ignorierendes */
if (Memo("")) return;
/* letzten Praefix umkopieren */
LastPrefix = CurrPrefix;
CurrPrefix = Pref_IN_N;
/* evtl. Datenablage */
if (DecodeIntelPseudo(False)) return;
if (!LookupInstTable(InstTable, OpPart.str.p_str))
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
}
static void InitCode_Z80(void)
{
Reg_CBAR = 0xf0;
Reg_CBR = Reg_BBR = 0x00;
}
static Boolean IsDef_Z80(void)
{
return Memo("PORT") || Memo("REG");
}
/* Treat special case of AF' which is no quoting: */
static Boolean QualifyQuote_Z80(const char *pStart, const char *pQuotePos)
{
if ((*pQuotePos == '\'')
&& (pQuotePos >= pStart + 2)
&& (as_toupper(*(pQuotePos - 2)) == 'A')
&& (as_toupper(*(pQuotePos - 1)) == 'F'))
return False;
return True;
}
/*!------------------------------------------------------------------------
* \fn DissectReg_Z80(char *p_dest, size_t dest_size, tRegInt value, tSymbolSize inp_size)
* \brief dissect register symbols - Z80 variant
* \param p_dest destination buffer
* \param dest_size destination buffer size
* \param value numeric register value
* \param inp_size register size
* ------------------------------------------------------------------------ */
static void DissectReg_Z80(char *p_dest, size_t dest_size, tRegInt value, tSymbolSize inp_size)
{
switch (inp_size)
{
case eSymbolSize8Bit:
if ((value & 0xf0) == (IXPrefix & 0xf0))
as_snprintf(p_dest, dest_size, "%s%c", Reg16Names[4], (value & 1) ? 'L' : ((MomCPU == CPUZ80U) ? 'H' : 'U'));
else if ((value & 0xf0) == (IYPrefix & 0xf0))
as_snprintf(p_dest, dest_size, "%s%c", Reg16Names[5], (value & 1) ? 'L' : ((MomCPU == CPUZ80U) ? 'H' : 'U'));
else if ((value < 8) && (value != 6))
as_snprintf(p_dest, dest_size, "%c", Reg8Names[value]);
else
goto none;
break;
case eSymbolSize16Bit:
if ((value & 0xf0) == (IXPrefix & 0xf0))
as_snprintf(p_dest, dest_size, Reg16Names[4]);
else if ((value & 0xf0) == (IYPrefix & 0xf0))
as_snprintf(p_dest, dest_size, Reg16Names[5]);
else if (value < 4)
as_snprintf(p_dest, dest_size, "%s", Reg16Names[value]);
else
goto none;
break;
none:
default:
as_snprintf(p_dest, dest_size, "%d-%u", (int)inp_size, (unsigned)value);
}
}
/*!------------------------------------------------------------------------
* \fn InternSymbol_Z80(char *p_arg, TempResult *p_result)
* \brief handle built-in (register) symbols for Z80
* \param p_arg source argument
* \param p_result result buffer
* ------------------------------------------------------------------------ */
static void InternSymbol_Z80(char *p_arg, TempResult *p_result)
{
Byte reg_num;
if (DecodeReg8Core(p_arg, ®_num))
{
p_result->Typ = TempReg;
p_result->DataSize = eSymbolSize8Bit;
p_result->Contents.RegDescr.Reg = reg_num;
p_result->Contents.RegDescr.Dissect = DissectReg_Z80;
p_result->Contents.RegDescr.compare = NULL;
}
else if (DecodeReg16Core(p_arg, ®_num))
{
p_result->Typ = TempReg;
p_result->DataSize = eSymbolSize16Bit;
p_result->Contents.RegDescr.Reg = reg_num;
p_result->Contents.RegDescr.Dissect = DissectReg_Z80;
p_result->Contents.RegDescr.compare = NULL;
}
}
static Boolean ChkMoreOneArg(void)
{
return (ArgCnt > 1);
}
static Boolean chk_pc_z380(LargeWord addr)
{
switch (ActPC)
{
case SegCode:
return (addr < (ExtFlag ? 0xfffffffful : 0xffffu));
default:
return True;
}
}
static void SwitchTo_Z80(void)
{
TurnWords = False;
SetIntConstMode(eIntConstModeIntel);
SetIsOccupiedFnc = ChkMoreOneArg;
PCSymbol = "$"; HeaderID = 0x51; NOPCode = 0x00;
DivideChars = ","; HasAttrs = False;
ValidSegs = 1 << SegCode;
Grans[SegCode] = 1; ListGrans[SegCode] = 1; SegInits[SegCode] = 0;
if (MomCPU == CPUZ380)
{
SegLimits[SegCode] = 0xfffffffful;
ChkPC = chk_pc_z380;
}
else if (MomCPU == CPUZ180)
SegLimits[SegCode] = 0x7fffful;
else if (MomCPU == CPUZ80U) SegLimits[SegCode] = 0xfffffffful;
else
SegLimits[SegCode] = 0xffffu;
/* Gameboy Z80 does not have I/O space, and no IX/IY, do not test for them and allow as normal symbols: */
if (!is_sharp())
{
ValidSegs |= 1 << SegIO;
Grans[SegIO ] = 1; ListGrans[SegIO ] = 1; SegInits[SegIO ] = 0;
SegLimits[SegIO ] = PortEnd();
Reg16Cnt = 6;
}
else
Reg16Cnt = 4;
MakeCode = MakeCode_Z80;
IsDef = IsDef_Z80;
QualifyQuote = QualifyQuote_Z80;
InternSymbol = InternSymbol_Z80;
SwitchFrom = DeinitFields; InitFields();
DissectReg = DissectReg_Z80;
/* Extended Modes only on Z380 */
if (MomCPU >= CPUZ380)
{
if (!onoff_test_and_set(e_onoff_reg_extmode))
SetFlag(&ExtFlag, ExtModeSymName, False);
AddONOFF(ExtModeCmdName, &ExtFlag, ExtModeSymName, False);
if (!onoff_test_and_set(e_onoff_reg_lwordmode))
SetFlag(&LWordFlag, LWordModeSymName, False);
AddONOFF(LWordModeCmdName, &LWordFlag , LWordModeSymName , False);
}
if (MomCPU == CPUZ180)
{
static const ASSUMERec ASSUMEZ180s[] =
{
{ "CBAR" , &Reg_CBAR , 0, 0xff, 0xf0, check_cbar },
{ "CBR" , &Reg_CBR , 0, 0xff, 0 , update_z180_areas },
{ "BBR" , &Reg_BBR , 0, 0xff, 0 , update_z180_areas },
};
pASSUMERecs = ASSUMEZ180s;
ASSUMERecCnt = as_array_size(ASSUMEZ180s);
update_z180_areas();
}
}
void codez80_init(void)
{
CPUGBZ80 = AddCPU("GBZ80" , SwitchTo_Z80);
CPULR35902 = AddCPU("LR35902" , SwitchTo_Z80);
CPUZ80 = AddCPU("Z80" , SwitchTo_Z80);
CPUZ80U = AddCPU("Z80UNDOC" , SwitchTo_Z80);
CPUZ180 = AddCPU("Z180" , SwitchTo_Z80);
CPUR2000 = AddCPU("RABBIT2000", SwitchTo_Z80);
CPUZ380 = AddCPU("Z380" , SwitchTo_Z80);
AddInitPassProc(InitCode_Z80);
}