/* code78c10.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Codegenerator NEC uPD78(C)(0|1)x */
/* */
/*****************************************************************************/
#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 "asmstructs.h"
#include "asmitree.h"
#include "asmcode.h"
#include "codepseudo.h"
#include "intpseudo.h"
#include "codevars.h"
#include "errmsg.h"
#include "headids.h"
#include "code78c10.h"
/*---------------------------------------------------------------------------*/
typedef struct
{
const char *p_name;
Byte code;
} intflag_t;
typedef struct
{
const char name[5];
Byte code, flags;
} reg_t;
typedef struct
{
const char *p_name;
Byte code, flags, core_mask;
} sreg_t;
typedef struct
{
const char *pName;
Byte Code;
Byte MayIndirect;
} tAdrMode;
typedef enum
{
eCoreNone,
eCore7800Low,
eCore7800High,
eCore7807,
eCore7810
} tCore;
#define core_mask_no_low ((1 << eCore7800High) | (1 << eCore7807) | (1 << eCore7810))
#define core_mask_7800 ((1 << eCore7800Low) | (1 << eCore7800High))
#define core_mask_7800_low (1 << eCore7800Low)
#define core_mask_7800_high (1 << eCore7800High)
#define core_mask_7807 (1 << eCore7807)
#define core_mask_7810 (1 << eCore7810)
#define core_mask_7807_7810 ((1 << eCore7807) | (1 << eCore7810))
#define core_mask_all ((1 << eCore7800Low) | (1 << eCore7800High) | (1 << eCore7807) | (1 << eCore7810))
#define core_mask_cmos 0x80
enum
{
eFlagHasV = 1 << 0,
eFlagCMOS = 1 << 1,
eFlagSR = 1 << 2, /* sr -> may be written from A */
eFlagSR1 = 1 << 3, /* sr1 -> may be read to A */
eFlagSR2 = 1 << 4, /* sr2 -> load or read/modify/write with immediate */
eFlagSR3 = 1 << 5, /* sr3 -> may be written from EA */
eFlagSR4 = 1 << 6 /* sr4 -> may be read to EA */
};
/* Flags in high byte of ALU operations: */
#define ALUImm_SR (1 << 0)
#define ALUReg_Src (1 << 1)
#define ALUReg_Dest (1 << 2)
#define ALUReg_MayZ80 (1 << 3)
typedef struct
{
char Name[6];
Byte Core;
Byte Flags;
} tCPUProps;
typedef enum { e_decode_reg_unknown, e_decode_reg_ok, e_decode_reg_error } decode_reg_res_t;
typedef struct
{
Word code;
unsigned core_mask;
} order_t;
typedef enum
{
e_mod_none = -1,
e_mod_reg8 = 0,
e_mod_reg16 = 1,
e_mod_imm = 2,
e_mod_indir = 3,
e_mod_wa = 4,
e_mod_abs = 5,
e_mod_sreg8 = 6,
e_mod_sreg16 = 7
} z80_adr_mode_t;
#define MModReg8 (1 << e_mod_reg8)
#define MModReg16 (1 << e_mod_reg16)
#define MModImm (1 << e_mod_imm)
#define MModIndir (1 << e_mod_indir)
#define MModWA (1 << e_mod_wa)
#define MModAbs (1 << e_mod_abs)
#define MModSReg8 (1 << e_mod_sreg8)
#define MModSReg16 (1 << e_mod_sreg16)
#define REG_V 0
#define REG_A 1
#define REG_B 2
#define REG_C 3
#define REG_D 4
#define REG_H 6
#define REG_EAH 8
#define REG_BC 1
#define REG_DE 2
#define REG_HL 3
#define REG_EA 4
typedef struct
{
z80_adr_mode_t mode;
unsigned count;
Boolean force_long;
Byte val, vals[2];
} z80_adr_vals_t;
static Boolean is_7807_781x;
static LongInt WorkArea;
static const tCPUProps *pCurrCPUProps;
static order_t *fixed_orders, *reg2_orders;
static sreg_t *s_regs8, *s_regs16;
static intflag_t *int_flags;
static tSymbolSize z80_op_size, z80_def_op_size;
/*--------------------------------------------------------------------------------*/
/*!------------------------------------------------------------------------
* \fn check_core(unsigned core_mask)
* \brief check whether active target uses given core
* \param core_mask list of allowed cores
* \return True if OK
* ------------------------------------------------------------------------ */
static Boolean check_core(unsigned core_mask)
{
if ((core_mask & core_mask_cmos) && !(pCurrCPUProps->Flags & eFlagCMOS))
return False;
return !!((core_mask >> pCurrCPUProps->Core) & 1);
}
/*!------------------------------------------------------------------------
* \fn decode_reg8(const char *p_arg, Byte *p_res)
* \brief decode 8 bit register
* \param p_arg source argument
* \param p_res encoded name
* \return True if valid name
* ------------------------------------------------------------------------ */
static Boolean decode_reg8(const char *p_arg, Byte *p_res)
{
{
case 1:
{
static const char names[] = "VABCDEHL";
const char *p;
int no_v = !(pCurrCPUProps->Flags & eFlagHasV);
p
= strchr(&names
[no_v
], as_toupper
(*p_arg
));
if (!p)
return False;
*p_res = p - names;
return True;
}
case 3:
if (!is_7807_781x
|| (as_toupper(p_arg[0]) != 'E')
|| (as_toupper(p_arg[1]) != 'A'))
return False;
if (as_toupper(p_arg[2]) == 'L')
*p_res = REG_EAH + 1;
else if (as_toupper(p_arg[2]) == 'H')
*p_res = REG_EAH;
else
return False;
return True;
default:
return False;
}
}
/*!------------------------------------------------------------------------
* \fn decode_r(const tStrComp *p_arg, Byte *p_res)
* \brief decode name of 8 bit register
* \param p_arg source argument
* \param p_res return buffer
* \return e_decode_reg_ok -> register known & OK
* ------------------------------------------------------------------------ */
static decode_reg_res_t decode_r(const tStrComp *p_arg, Byte *p_res)
{
if (!decode_reg8(p_arg->str.p_str, p_res))
return e_decode_reg_unknown;
if (*p_res >= 8)
{
WrStrErrorPos(ErrNum_InvReg, p_arg);
return e_decode_reg_error;
}
else
return e_decode_reg_ok;
}
/*!------------------------------------------------------------------------
* \fn decode_r1(const tStrComp *p_arg, Byte *p_res)
* \brief decode name of 8 bit register, plus EAL/H on 78C1x
* \param p_arg source argument
* \param p_res return buffer
* \return e_decode_reg_ok -> register known & OK
* ------------------------------------------------------------------------ */
static decode_reg_res_t decode_r1(const tStrComp *p_arg, Byte *p_res)
{
if (!decode_reg8(p_arg->str.p_str, p_res))
return e_decode_reg_unknown;
if (*p_res < 2)
{
WrStrErrorPos(ErrNum_InvReg, p_arg);
return e_decode_reg_error;
}
*p_res &= 7;
return e_decode_reg_ok;
}
/*!------------------------------------------------------------------------
* \fn decode_r2(const tStrComp *p_arg, Byte *p_res)
* \brief decode name of 8 bit register A, B, or C
* \param p_arg source argument
* \param p_res return buffer
* \return e_decode_reg_ok -> register known & OK
* ------------------------------------------------------------------------ */
static decode_reg_res_t decode_r2(const tStrComp *p_arg, Byte *p_res)
{
if (!decode_reg8(p_arg->str.p_str, p_res))
return e_decode_reg_unknown;
if ((*p_res == 0) || (*p_res >= 4))
{
WrStrErrorPos(ErrNum_InvReg, p_arg);
return e_decode_reg_error;
}
return e_decode_reg_ok;
}
/*!------------------------------------------------------------------------
* \fn decode_reg16(char *p_arg, Byte *p_res, Boolean allow_single_letter)
* \brief decode 16 bit register argument
* \param p_arg source argument
* \param p_res result value
* \param allow_single_letter allow register names with single letters (not for Z80 syntax)
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean decode_reg16(char *p_arg, Byte *p_res, Boolean allow_single_letter)
{
static const reg_t regs[] =
{
{ "SP" , 0, 0 },
{ "B" , REG_BC, 0 },
{ "BC" , REG_BC, 0 },
{ "D" , REG_DE, 0 },
{ "DE" , REG_DE, 0 },
{ "H" , REG_HL, 0 },
{ "HL" , REG_HL, 0 },
{ "EA" , REG_EA, 0 },
{ "" , 0, 0 },
};
for (*p_res = 0; regs[*p_res].name[0]; (*p_res)++)
if (!as_strcasecmp(p_arg, regs[*p_res].name))
{
if (!p_arg[1] && !allow_single_letter)
return False;
*p_res = regs[*p_res].code;
return True;
}
return False;
}
/*!------------------------------------------------------------------------
* \fn Decode_rp(char *Asc, Byte *Erg)
* \brief decode rp2 argument (SP/BC/DE/HL/EA)
* \param Asc source argument
* \param Erg resulting register #
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean Decode_rp2(char *p_arg, Byte *p_res)
{
return decode_reg16(p_arg, p_res, True);
}
/*!------------------------------------------------------------------------
* \fn Decode_rp(char *Asc, Byte *Erg)
* \brief decode rp argument (SP/BC/DE/HL)
* \param Asc source argument
* \param Erg resulting register #
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean Decode_rp(char *Asc, Byte *Erg)
{
if (!Decode_rp2(Asc, Erg)) return False;
return (*Erg < 4);
}
/*!------------------------------------------------------------------------
* \fn Decode_rp1(char *Asc, Byte *Erg)
* \brief decode rp1 argument (VA/BC/DE/HL/EA)
* \param Asc source argument
* \param Erg resulting register #
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean Decode_rp1(char *Asc, Byte *Erg)
{
if (!as_strcasecmp(Asc, "V")) *Erg = 0;
else
{
if (!Decode_rp2(Asc, Erg)) return False;
return (*Erg != 0);
}
return True;
}
/*!------------------------------------------------------------------------
* \fn Decode_rp3(char *Asc, Byte *Erg)
* \brief decode rp3 argument (BC/DE/HL)
* \param Asc source argument
* \param Erg resulting register #
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean Decode_rp3(char *Asc, Byte *Erg)
{
if (!Decode_rp2(Asc, Erg)) return False;
return ((*Erg < 4) && (*Erg > 0));
}
/*!------------------------------------------------------------------------
* \fn parse_rpa(const tStrComp *p_arg, z80_adr_vals_t *p_vals, unsigned mode_mask, int *p_auto_val, Boolean force)
* \brief parse indirect address expression
* \param p_arg source argument
* \param p_vals buffer for parse result
* \param mode_mask allowed addressing modes
* \param p_auto_val returns auto-in/decrement value
* \param force assume expression is indirect, even without outer (...)
* \return True if expression was detected as indirect (parsing may still have failed)
* ------------------------------------------------------------------------ */
static int split_auto_val(tStrComp *p_arg)
{
int l
= strlen(p_arg
->str.
p_str);
if (l >= 2)
{
if (!strcmp(p_arg
->str.
p_str + l
- 2, "--"))
{
StrCompShorten(p_arg, 2);
return - 2;
}
if (!strcmp(p_arg
->str.
p_str + l
- 2, "++"))
{
StrCompShorten(p_arg, 2);
return + 2;
}
}
if (l >= 1)
{
if (p_arg->str.p_str[l - 1] == '-')
{
StrCompShorten(p_arg, 1);
return -1;
}
if (p_arg->str.p_str[l - 1] == '+')
{
StrCompShorten(p_arg, 1);
return +1;
}
}
return 0;
}
static void parse_indirect_list(z80_adr_vals_t *p_vals, const tStrComp *p_arg, unsigned mode_mask, int auto_val)
{
char *p;
tStrComp rem, arg;
Byte reg, base = 0, index = 0;
LongInt disp_acc = 0;
Boolean bad_reg, first_unknown = False, this_minus, next_minus;
StrCompRefRight(&arg, p_arg, 0);
KillPostBlanksStrComp(&arg);
this_minus = False;
do
{
/* split off one component */
KillPrefBlanksStrCompRef(&arg);
next_minus = False;
p = indir_split_pos(arg.str.p_str); /* TODO: parentheses */
if (p)
{
next_minus = (*p == '-');
StrCompSplitRef(&arg, &rem, &arg, p);
KillPostBlanksStrComp(&arg);
}
bad_reg = False;
/* 8 bit register? Note that a B/D/H may actually mean BC/DE/HL
in 'old syntax': */
if (decode_reg8(arg.str.p_str, ®))
{
if (this_minus)
bad_reg = True;
else switch (reg)
{
case REG_A:
if (index)
bad_reg = True;
else
index = reg;
break;
case REG_B:
if (!index)
index = reg;
else if (!base)
base = REG_BC;
else
bad_reg = True;
break;
case REG_D:
if (!base)
base = REG_DE;
else
bad_reg = True;
break;
case REG_H:
if (!base)
base = REG_HL;
else
bad_reg = True;
break;
default:
bad_reg = True;
}
}
/* 16 bit register? */
else if (decode_reg16(arg.str.p_str, ®, False))
{
if (this_minus)
bad_reg = True;
else switch (reg)
{
case REG_EA:
if (index)
bad_reg = True;
else
index = reg;
break;
case REG_BC:
case REG_DE:
case REG_HL:
if (base)
bad_reg = True;
else
base = reg;
break;
default:
bad_reg = True;
}
}
else
{
tEvalResult eval_result;
Word value;
value = EvalStrIntExpressionWithResult(&arg, UInt16, &eval_result);
if (!eval_result.OK)
return;
if (mFirstPassUnknownOrQuestionable(eval_result.Flags))
first_unknown = True;
disp_acc = this_minus ? (disp_acc - value) : (disp_acc + value);
}
if (bad_reg)
{
WrStrErrorPos(ErrNum_InvReg, &arg);
return;
}
if (p)
{
arg = rem;
this_minus = next_minus;
}
}
while (p);
/* Dissolve ambiguities */
if ((index == REG_B) && !base)
{
index = 0;
base = REG_BC;
}
/* For auto-in/decrement, only a plain base register DE/HL is allowed.
Furthermore, (..)-- is not implemented: */
if (auto_val)
{
if (index || (base < REG_BC) || (base > REG_HL) || disp_acc || (auto_val == -2))
WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
else
{
p_vals->val = (base + 2) + (2 * !!(auto_val < 0));
p_vals->mode = e_mod_indir;
}
}
else
{
/* (BC) (DE) (HL) */
if ((base >= REG_BC) && (base <= REG_HL) && !index && !disp_acc)
{
p_vals->val = base;
p_vals->mode = e_mod_indir;
}
/* (DE+byte) (HL+byte) */
else if ((base >= REG_DE) && (base <= REG_HL) && !index)
{
if (first_unknown)
disp_acc &= 0xff;
if ((disp_acc > 0xff) || (disp_acc < -0x80))
{
WrStrErrorPos(ErrNum_OverRange, p_arg);
return;
}
p_vals->val = (base << 2) + 3;
p_vals->mode = e_mod_indir;
p_vals->vals[p_vals->count++] = Lo(disp_acc);
}
/* (HL+A) (HL+B) */
else if ((base == REG_HL) && (index >= REG_A) && (index <= REG_B) && !disp_acc)
{
p_vals->val = index + 11;
p_vals->mode = e_mod_indir;
}
/* (HL+EA) */
else if ((base == REG_HL) && (index == REG_EA) && !disp_acc)
{
p_vals->val = 14;
p_vals->mode = e_mod_indir;
}
/* abs/wa */
else if (!base && !index)
{
Boolean is_wa = (Hi(disp_acc) == WorkArea),
may_wa = !!(mode_mask & MModWA);
p_vals->vals[p_vals->count++] = Lo(disp_acc);
if ((may_wa && is_wa) || (!may_wa && first_unknown))
p_vals->mode = e_mod_wa;
else
{
p_vals->vals[p_vals->count++] = Hi(disp_acc);
p_vals->mode = e_mod_abs;
}
}
else
WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
}
}
static Boolean parse_rpa(const tStrComp *p_arg, z80_adr_vals_t *p_vals, unsigned mode_mask, int *p_auto_val, Boolean force)
{
tStrComp arg;
Boolean is_indirect;
/* split off auto-in/decrement */
StrCompRefRight(&arg, p_arg, 0);
*p_auto_val = split_auto_val(&arg);
/* Indirect? */
is_indirect = IsIndirect(arg.str.p_str);
if (is_indirect)
{
StrCompIncRefLeft(&arg, 1);
StrCompShorten(&arg, 1);
KillPostBlanksStrComp(&arg);
if (!*p_auto_val)
*p_auto_val = split_auto_val(&arg);
}
/* Auto-in/decrement enforces indirect parsing: */
if (is_indirect || *p_auto_val || force)
{
parse_indirect_list(p_vals, &arg, mode_mask, *p_auto_val);
return True;
}
else
return False;
}
/*!------------------------------------------------------------------------
* \fn reset_z80_adr_vals(z80_adr_vals_t *p_vals)
* \brief clear encoded addressing mode container
* \param p_vals container to clear
* ------------------------------------------------------------------------ */
static void reset_z80_adr_vals(z80_adr_vals_t *p_vals)
{
p_vals->mode = e_mod_none;
p_vals->force_long = 0;
p_vals->val = 0;
p_vals->count = 0;
}
/*!------------------------------------------------------------------------
* \fn Decode_rpa2(const tStrComp *pArg, Byte *Erg, Byte *Disp)
* \brief Decode rpa2 argument (indirect 8 bit argument in memory)
* \param pArg source argument
* \param Erg resulting addressing mode
* \param Disp resulting addressing displacement
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean Decode_rpa2(const tStrComp *pArg, Byte *Erg, Byte *Disp)
{
z80_adr_vals_t vals;
int auto_val;
/* We force parsing as indirect, so the return value is always true: */
reset_z80_adr_vals(&vals);
(void)parse_rpa(pArg, &vals, MModIndir, &auto_val, True);
switch (vals.mode)
{
case e_mod_indir:
if ((auto_val < -1) || (auto_val > 1))
goto bad_mode;
*Erg = vals.val;
*Disp = (vals.count > 0) ? vals.vals[0] : 0;
return True;
case e_mod_wa:
case e_mod_abs:
bad_mode:
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
return False;
default:
return False;
}
}
/*!------------------------------------------------------------------------
* \fn Decode_rpa(const tStrComp *pArg, Byte *Erg)
* \brief Decode rpa argument (indirect 8 bit argument in memory, without index)
* \param pArg source argument
* \param Erg resulting addressing mode
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean is_rpa(Byte value)
{
return (value >= 1) && (value <= 7);
}
static Boolean Decode_rpa(const tStrComp *pArg, Byte *Erg)
{
Byte Dummy;
if (!Decode_rpa2(pArg, Erg, &Dummy)) return False;
if (!is_rpa(*Erg))
{
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
return False;
}
return True;
}
/*!------------------------------------------------------------------------
* \fn Decode_rpa1(const tStrComp *pArg, Byte *Erg)
* \brief Decode rpa1 argument (indirect 8 bit argument in memory, without index or auto-in/decrement)
* \param pArg source argument
* \param Erg resulting addressing mode
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean is_rpa1(Byte value)
{
return (value >= 1) && (value <= 3);
}
static Boolean Decode_rpa1(const tStrComp *pArg, Byte *Erg)
{
Byte Dummy;
if (!Decode_rpa2(pArg, Erg, &Dummy)) return False;
if (!is_rpa1(*Erg))
{
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
return False;
}
return True;
}
/*!------------------------------------------------------------------------
* \fn Decode_rpa3(const tStrComp *pArg, Byte *Erg, ShortInt *Disp)
* \brief Decode rpa3 argument (indirect 16 bit argument in memory)
* \param pArg source argument
* \param Erg resulting addressing mode
* \param Disp resulting addressing displacement
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean is_rpa3(Byte value)
{
return ((value >= 2) && (value <= 5))
|| ((value >= 11) && (value <= 15));
}
static Boolean Decode_rpa3(const tStrComp *pArg, Byte *Erg, Byte *Disp)
{
z80_adr_vals_t vals;
int auto_val;
/* We force parsing as indirect, so the return value is always true: */
reset_z80_adr_vals(&vals);
(void)parse_rpa(pArg, &vals, MModIndir, &auto_val, True);
switch (vals.mode)
{
case e_mod_indir:
if ((auto_val != -2) && (auto_val != 0) && (auto_val != 2))
goto bad_mode;
if (!is_rpa3(vals.val))
goto bad_mode;
*Erg = vals.val;
*Disp = (vals.count > 0) ? vals.vals[0] : 0;
return True;
case e_mod_wa:
case e_mod_abs:
bad_mode:
WrStrErrorPos(ErrNum_InvAddrMode, pArg);
return False;
default:
return False;
}
}
/*!------------------------------------------------------------------------
* \fn Decode_f(char *Asc, Byte *Erg)
* \brief descode status flag
* \param Asc source argument
* \param Erg returns encoded flag
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean Decode_f(char *Asc, Byte *Erg)
{
#define FlagCnt 3
static const char Flags[FlagCnt][3] = {"CY", "HC", "Z"};
for (*Erg = 0; *Erg < FlagCnt; (*Erg)++)
if (!as_strcasecmp(Flags[*Erg], Asc)) break;
*Erg += 2; return (*Erg <= 4);
}
/*!------------------------------------------------------------------------
* \fn decode_sr_core(const tStrComp *p_arg)
* \brief core register list decode
* \param p_arg source argument
* \return * to record of decoded register
* ------------------------------------------------------------------------ */
static const sreg_t *decode_sr_core(const sreg_t *p_sregs, const tStrComp *p_arg)
{
for (; p_sregs->p_name; p_sregs++)
if (check_core(p_sregs->core_mask) && !as_strcasecmp(p_arg->str.p_str, p_sregs->p_name))
return p_sregs;
return NULL;
}
/*!------------------------------------------------------------------------
* \fn check_sr_flag(Byte reg_flags, Byte req_flag, const tStrComp *p_arg)
* \brief check whether special register's flags fulfill requirement, and
issue error if not
* \param reg_flags register's suppoerted flags
* \param req_flag required flag
* \param p_arg source argument
* \return True if OK
* ------------------------------------------------------------------------ */
static Boolean check_sr_flag(Byte reg_flags, Byte req_flag, const tStrComp *p_arg)
{
if (reg_flags & req_flag)
return True;
WrStrErrorPos(reg_flags ? ErrNum_InvOpOnReg : ErrNum_InvReg, p_arg);
return False;
}
static decode_reg_res_t decode_sr_flag(const tStrComp *p_arg, const sreg_t *p_sregs, Byte *p_res, Byte flag)
{
const sreg_t *p_reg = decode_sr_core(p_sregs, p_arg);
if (p_reg)
{
if (check_sr_flag(p_reg->flags, flag, p_arg))
{
*p_res = p_reg->code;
return e_decode_reg_ok;
}
else
return e_decode_reg_error;
}
else
return e_decode_reg_unknown;
}
#define decode_sr1(p_arg, p_res) decode_sr_flag(p_arg, s_regs8, p_res, eFlagSR1)
#define decode_sr(p_arg, p_res) decode_sr_flag(p_arg, s_regs8, p_res, eFlagSR)
#define decode_sr2(p_arg, p_res) decode_sr_flag(p_arg, s_regs8, p_res, eFlagSR2)
/*!------------------------------------------------------------------------
* \fn Decode_irf(const tStrComp *p_arg, ShortInt *p_res)
* \brief decode interrupt flag argument
* \param p_arg source argument
* \param p_res resulting flag #
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean Decode_irf(const tStrComp *p_arg, ShortInt *p_res)
{
for (*p_res = 0; int_flags[*p_res].p_name; (*p_res)++)
if (!as_strcasecmp(int_flags[*p_res].p_name, p_arg->str.p_str))
{
*p_res = int_flags[*p_res].code;
return True;
}
WrStrErrorPos(ErrNum_UnknownInt, p_arg);
return False;
}
/*!------------------------------------------------------------------------
* \fn Decode_wa(const tStrComp *pArg, Byte *Erg, Byte max_address)
* \brief decode working area address argument
* \param pArg source argument
* \param Erg resulting (short) address
* \param max_address range limit
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean Decode_wa(const tStrComp *pArg, Byte *Erg, Byte max_address)
{
Word Adr;
Boolean OK;
tSymbolFlags Flags;
Adr = EvalStrIntExpressionWithFlags(pArg, Int16, &OK, &Flags);
if (!OK)
return False;
if (!mFirstPassUnknown(Flags) && (Hi(Adr) != WorkArea)) WrStrErrorPos(ErrNum_InAccPage, pArg);
*Erg = Lo(Adr);
if (mFirstPassUnknownOrQuestionable(Flags))
*Erg &= max_address;
return ChkRangePos(*Erg, 0, max_address, pArg);
}
static Boolean HasDisp(ShortInt Mode)
{
return ((Mode & 11) == 11);
}
/*!------------------------------------------------------------------------
* \fn set_op_size(tSymbolSize new_op_size, const tStrComp *p_arg)
* \brief Set operand size and throw error in case of conflict
* \param new_op_size operand size to set
* \param p_arg source argument carrying this size
* ------------------------------------------------------------------------ */
static Boolean set_op_size(tSymbolSize new_op_size, const tStrComp *p_arg)
{
if (z80_op_size == eSymbolSizeUnknown)
z80_op_size = new_op_size;
else if (z80_op_size != new_op_size)
{
WrStrErrorPos(ErrNum_ConfOpSizes, p_arg);
return False;
}
return True;
}
/*!------------------------------------------------------------------------
* \fn decode_z80_adr(const tStrComp *p_arg, z80_adr_vals_t *p_vals, unsigned mode_mask)
* \brief decode Z80 style address expression
* \param p_arg source argument
* \param p_vals encoded values
* \param mode_mask bit mask of allowe daddressing modes
* \return resulting addressing mode
* ------------------------------------------------------------------------ */
static z80_adr_mode_t decode_z80_adr(const tStrComp *p_arg, z80_adr_vals_t *p_vals, unsigned mode_mask)
{
Boolean ok;
int auto_val;
const sreg_t *p_sreg;
reset_z80_adr_vals(p_vals);
/* Registers: */
if (!as_strcasecmp(p_arg->str.p_str, ">A"))
{
if (set_op_size(eSymbolSize8Bit, p_arg))
{
p_vals->force_long = True;
p_vals->val = REG_A;
p_vals->mode = e_mod_reg8;
}
goto found;
}
if (decode_reg8(p_arg->str.p_str, &p_vals->val))
{
/* No V register on low function core */
if ((pCurrCPUProps->Core == eCore7800Low) && (p_vals->val == REG_V));
/* EA register only on 7807++ */
else if ((pCurrCPUProps->Core < eCore7807) && (p_vals->val >= REG_EAH));
else
{
if (set_op_size(eSymbolSize8Bit, p_arg))
p_vals->mode = e_mod_reg8;
goto found;
}
}
if (decode_reg16(p_arg->str.p_str, &p_vals->val, False))
{
/* EA register only on 7807++ */
if ((pCurrCPUProps->Core < eCore7807) && (p_vals->val >= REG_EA));
else
{
if (set_op_size(eSymbolSize16Bit, p_arg))
p_vals->mode = e_mod_reg16;
goto found;
}
}
p_sreg = decode_sr_core(s_regs8, p_arg);
if (p_sreg)
{
if (set_op_size(eSymbolSize8Bit, p_arg))
{
p_vals->mode = e_mod_sreg8;
p_vals->val = p_sreg->code;
p_vals->vals[0] = p_sreg->flags;
}
goto found;
}
p_sreg = decode_sr_core(s_regs16, p_arg);
if (p_sreg)
{
if (set_op_size(eSymbolSize16Bit, p_arg))
{
p_vals->mode = e_mod_sreg16;
p_vals->val = p_sreg->code;
p_vals->vals[0] = p_sreg->flags;
}
goto found;
}
/* indirect stuff: */
if (parse_rpa(p_arg, p_vals, mode_mask, &auto_val, False))
{
/* single or double auto-in/decrement implicitly describes operand size: */
if (auto_val)
{
if (!set_op_size(((auto_val == 1) || (auto_val == -1)) ? eSymbolSize8Bit : eSymbolSize16Bit, p_arg))
reset_z80_adr_vals(p_vals);
}
goto found;
}
/* Immediate: */
if (!(mode_mask & MModImm))
{
WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
goto found;
}
if (z80_op_size == eSymbolSizeUnknown)
{
z80_op_size = z80_def_op_size;
z80_def_op_size = eSymbolSizeUnknown;
}
switch (z80_op_size)
{
case eSymbolSize8Bit:
p_vals->vals[0] = EvalStrIntExpression(p_arg, Int8, &ok);
if (ok)
{
p_vals->count = 1;
p_vals->mode = e_mod_imm;
}
break;
case eSymbolSize16Bit:
{
Word tmp = EvalStrIntExpression(p_arg, Int16, &ok);
if (ok)
{
p_vals->vals[p_vals->count++] = Lo(tmp);
p_vals->vals[p_vals->count++] = Hi(tmp);
p_vals->mode = e_mod_imm;
}
break;
}
default:
WrStrErrorPos(ErrNum_UndefOpSizes, p_arg);
}
found:
if ((p_vals->mode != e_mod_none) && !((mode_mask >> p_vals->mode) & 1))
{
WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
reset_z80_adr_vals(p_vals);
}
return p_vals->mode;
}
/*!------------------------------------------------------------------------
* \fn append_adr_vals(const z80_adr_vals_t *p_vals)
* \brief append encoded addess extension bytes to instruction
* \param p_vals contains bytes to append
* ------------------------------------------------------------------------ */
static void append_adr_vals(const z80_adr_vals_t *p_vals)
{
memcpy(&BAsmCode
[CodeLen
], p_vals
->vals
, p_vals
->count
);
CodeLen += p_vals->count;
}
/*--------------------------------------------------------------------------*/
/* Bit Symbol Handling (uPD7807...7809 only) */
/*
* Compact representation of bits in symbol table:
* bits 0..2: bit position
* bits 3...6/18: address in I/O or memory space
* bit 19: 0 for memory space, 1 for I/O space
* bits 20..23: core type
*/
/*!------------------------------------------------------------------------
* \fn eval_bit_position(const tStrComp *p_arg, Boolean *p_ok)
* \brief evaluate bit position
* \param bit position argument
* \param p_ok parsing OK?
* \return numeric bit position
* ------------------------------------------------------------------------ */
static LongWord eval_bit_position(const tStrComp *p_arg, Boolean *p_ok)
{
return EvalStrIntExpression(p_arg, UInt3, p_ok);
}
/*!------------------------------------------------------------------------
* \fn assemble_bit_symbol(Byte core, Boolean is_io, Word address, Byte bit_pos)
* \brief transform bit symbol components into compact representation
* \param core core used to define this bit
* \param is_io special register or memory bit?
* \param address (I/O) register address
* \param bit_pos bit position
* \return compact storage value
* ------------------------------------------------------------------------ */
static LongWord assemble_bit_symbol(Byte core, Boolean is_io, Word address, Byte bit_pos)
{
LongWord result = bit_pos | ((LongWord)address << 3);
if (is_io)
result |= 1ul << 19;
result |= ((LongWord)core) << 20;
return result;
}
/*!------------------------------------------------------------------------
* \fn decode_bit_arg_2(LongWord *p_result, const tStrComp *p_reg_arg, const tStrComp *p_bit_arg)
* \brief encode a bit symbol, address & bit position separated
* \param p_result resulting encoded bit
* \param p_reg_arg register argument
* \param p_bit_arg bit argument
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean decode_bit_arg_2(LongWord *p_result, const tStrComp *p_reg_arg, const tStrComp *p_bit_arg)
{
Boolean ok;
LongWord addr;
Boolean is_io;
Byte bit_pos;
Byte s_reg;
bit_pos = eval_bit_position(p_bit_arg, &ok);
if (!ok)
return False;
if (decode_sr_flag(p_reg_arg, s_regs8, &s_reg, eFlagSR2) == e_decode_reg_ok)
{
if (s_reg > 0x0f)
{
WrStrErrorPos(ErrNum_InvReg, p_reg_arg);
return False;
}
is_io = True;
addr = s_reg;
}
else
{
addr = EvalStrIntExpression(p_reg_arg, UInt16, &ok);
if (!ok)
return False;
is_io = False;
}
*p_result = assemble_bit_symbol(pCurrCPUProps->Core, is_io, addr, bit_pos);
return True;
}
/*!------------------------------------------------------------------------
* \fn decode_bit_arg(LongWord *p_result, int start, int stop)
* \brief encode a bit symbol from instruction argument(s)
* \param p_result resulting encoded bit
* \param start first argument
* \param stop last argument
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean decode_bit_arg(LongWord *p_result, int start, int stop)
{
*p_result = 0;
/* Just one argument -> parse as bit argument */
if (start == stop)
{
char *p_sep = RQuotPos(ArgStr[start].str.p_str, '.');
if (p_sep)
{
tStrComp reg_comp, bit_comp;
StrCompSplitRef(®_comp, &bit_comp, &ArgStr[start], p_sep);
return decode_bit_arg_2(p_result, ®_comp, &bit_comp);
}
else
{
tEvalResult eval_result;
*p_result = EvalStrIntExpressionWithResult(&ArgStr[start], UInt24, &eval_result);
if (eval_result.OK)
ChkSpace(SegBData, eval_result.AddrSpaceMask);
return eval_result.OK;
}
}
/* register & bit position are given as separate arguments */
else if (stop == start + 1)
return decode_bit_arg_2(p_result, &ArgStr[start], &ArgStr[stop]);
/* other # of arguments not allowed */
else
{
WrError(ErrNum_WrongArgCnt);
return False;
}
}
/*!------------------------------------------------------------------------
* \fn dissect_bit_symbol(LongWord bit_symbol, Byte *p_core, Boolean *p_is_io, Word *p_address, Byte *p_bit_pos)
* \brief transform compact representation of bit (field) symbol into components
* \param bit_symbol compact storage
* \param p_core core used to define bit
* \param p_is_io special register or memory bit?
* \param p_address (I/O) register address
* \param p_bit_pos (start) bit position
* \return constant True
* ------------------------------------------------------------------------ */
static Boolean dissect_bit_symbol(LongWord bit_symbol, Byte *p_core, Boolean *p_is_io, Word *p_address, Byte *p_bit_pos)
{
*p_core = (bit_symbol >> 20) & 15;
*p_is_io = (bit_symbol >> 19) & 1;
*p_address = (bit_symbol >> 3) & (*p_is_io ? 0xf : 0xffff);
*p_bit_pos = bit_symbol & 7;
return True;
}
/*!------------------------------------------------------------------------
* \fn dissect_bit_7807(char *p_dest, size_t dest_size, LargeWord inp)
* \brief dissect compact storage of bit (field) into readable form for listing
* \param p_dest destination for ASCII representation
* \param dest_size destination buffer size
* \param inp compact storage
* ------------------------------------------------------------------------ */
static void dissect_bit_7807(char *p_dest, size_t dest_size, LargeWord inp)
{
Byte bit_pos, core;
Word address;
Boolean is_io;
dissect_bit_symbol(inp, &core, &is_io, &address, &bit_pos);
if (is_io)
{
const sreg_t *p_sreg;
for (p_sreg = s_regs8; p_sreg->p_name; p_sreg++)
{
if (!((p_sreg->core_mask >> core) & 1))
continue;
if (address == p_sreg->code)
{
as_snprintf(p_dest, dest_size, "%s.%u", p_sreg->p_name, (unsigned)bit_pos);
return;
}
}
as_snprintf(p_dest, dest_size, "SR%u.%u", address, (unsigned)bit_pos);
}
else
as_snprintf(p_dest, dest_size, "%~.*u%s.%u",
ListRadixBase, (unsigned)address, GetIntConstIntelSuffix(ListRadixBase),
(unsigned)bit_pos);
}
/*!------------------------------------------------------------------------
* \fn expand_bit_7807(const tStrComp *p_var_name, const struct sStructElem *p_struct_elem, LargeWord base)
* \brief expands bit definition when a structure is instantiated
* \param p_var_name desired symbol name
* \param p_struct_elem element definition
* \param base base address of instantiated structure
* ------------------------------------------------------------------------ */
static void expand_bit_7807(const tStrComp *p_var_name, const struct sStructElem *p_struct_elem, LargeWord base)
{
LongWord address = base + p_struct_elem->Offset;
if (pInnermostNamedStruct)
{
PStructElem p_elem = CloneStructElem(p_var_name, p_struct_elem);
if (!p_elem)
return;
p_elem->Offset = address;
AddStructElem(pInnermostNamedStruct->StructRec, p_elem);
}
else
{
if (!ChkRange(address, 0, 0xffff)
|| !ChkRange(p_struct_elem->BitPos, 0, 7))
return;
PushLocHandle(-1);
EnterIntSymbol(p_var_name, assemble_bit_symbol(pCurrCPUProps->Core, False, address, p_struct_elem->BitPos), SegBData, False);
PopLocHandle();
/* TODO: MakeUseList? */
}
}
/*--------------------------------------------------------------------------------*/
static Boolean check_core_and_error(unsigned core_mask)
{
Boolean ret = check_core(core_mask);
if (!ret)
WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
return ret;
}
static void PutCode(Word Code)
{
if (Hi(Code) != 0)
BAsmCode[CodeLen++] = Hi(Code);
BAsmCode[CodeLen++] = Lo(Code);
}
/*!------------------------------------------------------------------------
* \fn decode_bit_7807_core(const tStrComp *p_arg, Byte code)
* \brief core routine for uPD7807 bit-oriented instructions
* \param p_arg source bit argument
* \param code machine code of instruction
* ------------------------------------------------------------------------ */
static void decode_bit_7807_core(int arg_idx, Byte code)
{
LongWord packed_bit;
Boolean is_io;
Word address;
Byte bit_pos, core;
if (!decode_bit_arg(&packed_bit, arg_idx, arg_idx))
return;
dissect_bit_symbol(packed_bit, &core, &is_io, &address, &bit_pos);
if (!is_io)
{
if ((Hi(address) != WorkArea) || (Lo(address) > 15))
WrStrErrorPos(ErrNum_InAccPage, &ArgStr[arg_idx]);
}
BAsmCode[1] = (is_io ? 0x80 : 0x00)
| ((address & 15) << 3)
| (bit_pos & 7);
BAsmCode[0] = code;
CodeLen = 2;
}
/*!------------------------------------------------------------------------
* \fn DecodeFixed(Word Code)
* \brief Handle instructions without arguments
* \param index index into instruction table
* ------------------------------------------------------------------------ */
static void DecodeFixed(Word index)
{
const order_t *p_order = &fixed_orders[index];
if (ChkArgCnt(0, 0) && check_core_and_error(p_order->core_mask))
PutCode(p_order->code);
}
/*!------------------------------------------------------------------------
* \fn DecodeMOV(Word Code)
* \brief handle MOV instruction
* ------------------------------------------------------------------------ */
static void DecodeMOV(Word Code)
{
Boolean OK;
Byte HReg;
Integer AdrInt;
decode_reg_res_t res1;
UNUSED(Code);
if (!ChkArgCnt(2, 2));
else if (!as_strcasecmp(ArgStr[1].str.p_str, "A"))
{
decode_reg_res_t res2;
if ((res2 = decode_sr1(&ArgStr[2], &HReg)) != e_decode_reg_unknown)
{
if (res2 == e_decode_reg_ok)
{
CodeLen = 2;
BAsmCode[0] = 0x4c;
BAsmCode[1] = 0xc0 + HReg;
}
}
else if ((res2 = decode_r1(&ArgStr[2], &HReg)) != e_decode_reg_unknown)
{
if (res2 == e_decode_reg_ok)
{
CodeLen = 1;
BAsmCode[0] = 0x08 + HReg;
}
}
else
{
AdrInt = EvalStrIntExpression(&ArgStr[2], Int16, &OK);
if (OK)
{
CodeLen = 4;
BAsmCode[0] = 0x70;
BAsmCode[1] = 0x69;
BAsmCode[2] = Lo(AdrInt);
BAsmCode[3] = Hi(AdrInt);
}
}
}
else if (!as_strcasecmp(ArgStr[2].str.p_str, "A"))
{
decode_reg_res_t res2;
if ((res2 = decode_sr(&ArgStr[1], &HReg)) != e_decode_reg_unknown)
{
if (res2 == e_decode_reg_ok)
{
CodeLen = 2;
BAsmCode[0] = 0x4d;
BAsmCode[1] = 0xc0 + HReg;
}
}
else if ((res2 = decode_r1(&ArgStr[1], &HReg)) != e_decode_reg_unknown)
{
if (res2 == e_decode_reg_ok)
{
CodeLen = 1;
BAsmCode[0] = 0x18 + HReg;
}
}
else
{
AdrInt = EvalStrIntExpression(&ArgStr[1], Int16, &OK);
if (OK)
{
CodeLen = 4;
BAsmCode[0] = 0x70;
BAsmCode[1] = 0x79;
BAsmCode[2] = Lo(AdrInt);
BAsmCode[3] = Hi(AdrInt);
}
}
}
else if ((pCurrCPUProps->Core == eCore7807) && !as_strcasecmp(ArgStr[1].str.p_str, "CY"))
decode_bit_7807_core(2, 0x5f);
else if ((pCurrCPUProps->Core == eCore7807) && !as_strcasecmp(ArgStr[2].str.p_str, "CY"))
decode_bit_7807_core(1, 0x5a);
else if ((res1 = decode_r(&ArgStr[1], &HReg)) != e_decode_reg_unknown)
{
if (res1 == e_decode_reg_ok)
{
AdrInt = EvalStrIntExpression(&ArgStr[2], Int16, &OK);
if (OK)
{
CodeLen = 4;
BAsmCode[0] = 0x70;
BAsmCode[1] = 0x68 + HReg;
BAsmCode[2] = Lo(AdrInt);
BAsmCode[3] = Hi(AdrInt);
}
}
}
else if ((res1 = decode_r(&ArgStr[2], &HReg)) != e_decode_reg_unknown)
{
if (res1 == e_decode_reg_ok)
{
AdrInt = EvalStrIntExpression(&ArgStr[1], Int16, &OK);
if (OK)
{
CodeLen = 4;
BAsmCode[0] = 0x70;
BAsmCode[1] = 0x78 + HReg;
BAsmCode[2] = Lo(AdrInt);
BAsmCode[3] = Hi(AdrInt);
}
}
}
/* Cannot say in this case if src or dest is invalid register: */
else
WrError(ErrNum_InvReg);
}
/*!------------------------------------------------------------------------
* \fn DecodeMVI(Word Code)
* \brief handle MVI instruction
* ------------------------------------------------------------------------ */
static void DecodeMVI(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(2, 2))
{
Byte HReg;
Boolean OK;
BAsmCode[1] = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
if (OK)
{
decode_reg_res_t res;
if ((res = decode_r(&ArgStr[1], &HReg)) != e_decode_reg_unknown)
{
if (res == e_decode_reg_ok)
{
CodeLen = 2;
BAsmCode[0] = 0x68 + HReg;
}
}
else if ((res = decode_sr2(&ArgStr[1], &HReg)) != e_decode_reg_unknown)
{
if (res == e_decode_reg_ok)
{
if (!is_7807_781x) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
CodeLen = 3;
BAsmCode[2] = BAsmCode[1];
BAsmCode[0] = 0x64;
BAsmCode[1] = (HReg & 7) + ((HReg & 8) << 4);
}
}
}
else WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeMVIW(Word Code)
* \brief handle MVIW instruction
* ------------------------------------------------------------------------ */
static void DecodeMVIW(Word Code)
{
Boolean OK;
UNUSED(Code);
if (!ChkArgCnt(2, 2) || !check_core_and_error(core_mask_no_low));
else if (Decode_wa(&ArgStr[1], BAsmCode + 1, 0xff))
{
BAsmCode[2] = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
if (OK)
{
CodeLen = 3;
BAsmCode[0] = 0x71;
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeMVIX(Word Code)
* \brief handle MVIX instruction
* ------------------------------------------------------------------------ */
static void DecodeMVIX(Word Code)
{
Boolean OK;
Byte HReg;
UNUSED(Code);
if (!ChkArgCnt(2, 2) || !check_core_and_error(core_mask_no_low));
else if (Decode_rpa1(&ArgStr[1], &HReg))
{
BAsmCode[1] = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
if (OK)
{
BAsmCode[0] = 0x48 + HReg;
CodeLen = 2;
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeLDAX_STAX(Word Code)
* \brief handle LDAX/STAX instructions
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeLDAX_STAX(Word Code)
{
Byte HReg;
if (ChkArgCnt(1, 1))
{
Boolean ok = is_7807_781x
? Decode_rpa2(&ArgStr[1], &HReg, &BAsmCode[1])
: Decode_rpa(&ArgStr[1], &HReg);
if (ok)
{
CodeLen = 1 + Ord(HasDisp(HReg));
BAsmCode[0] = Code + ((HReg & 8) << 4) + (HReg & 7);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeLDEAX_STEAX(Word Code)
* \brief handle LDEAX/STEAX instructions
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeLDEAX_STEAX(Word Code)
{
Byte HReg;
if (ChkArgCnt(1, 1)
&& check_core_and_error(core_mask_7807_7810)
&& Decode_rpa3(&ArgStr[1], &HReg, &BAsmCode[2]))
{
CodeLen = 2 + Ord(HasDisp(HReg));
BAsmCode[0] = 0x48;
BAsmCode[1] = Code + HReg;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeLXI(Word Code)
* \brief Handle LXI instruction
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeLXI(Word Code)
{
Byte HReg;
Integer AdrInt;
Boolean OK;
UNUSED(Code);
if (!ChkArgCnt(2, 2))
return;
OK = (pCurrCPUProps->Core >= eCore7807)
? Decode_rp2(ArgStr[1].str.p_str, &HReg)
: Decode_rp(ArgStr[1].str.p_str, &HReg);
if (!OK) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
AdrInt = EvalStrIntExpression(&ArgStr[2], Int16, &OK);
if (OK)
{
CodeLen = 3;
BAsmCode[0] = 0x04 + (HReg << 4);
BAsmCode[1] = Lo(AdrInt);
BAsmCode[2] = Hi(AdrInt);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodePUSH_POP(Word Code)
* \brief Handle PUSH/POP instruction
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodePUSH_POP(Word Code)
{
Byte HReg;
if (!ChkArgCnt(1, 1));
else if (!Decode_rp1(ArgStr[1].str.p_str, &HReg)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
PutCode(Code | (HReg << (Hi(Code) ? 4 : 0)));
}
/*!------------------------------------------------------------------------
* \fn DecodeDMOV(Word Code)
* \brief Handle DMOV instruction
* ------------------------------------------------------------------------ */
static void DecodeDMOV(Word Code)
{
Byte HReg, SReg;
UNUSED(Code);
if (ChkArgCnt(2, 2) && check_core_and_error(core_mask_7807_7810))
{
Boolean Swap = as_strcasecmp(ArgStr[1].str.p_str, "EA") || False;
const tStrComp *pArg1 = Swap ? &ArgStr[2] : &ArgStr[1],
*pArg2 = Swap ? &ArgStr[1] : &ArgStr[2];
if (as_strcasecmp(pArg1->str.p_str, "EA")) WrStrErrorPos(ErrNum_InvAddrMode, pArg1);
else if (Decode_rp3(pArg2->str.p_str, &HReg))
{
CodeLen = 1;
BAsmCode[0] = 0xa4 + HReg;
if (Swap)
BAsmCode[0] += 0x10;
}
else switch (decode_sr_flag(pArg2, s_regs16, &SReg, Swap ? eFlagSR3 : eFlagSR4))
{
case e_decode_reg_ok:
CodeLen = 2;
BAsmCode[0] = 0x48;
BAsmCode[1] = 0xc0 + SReg;
if (Swap)
BAsmCode[1] += 0x12;
break;
case e_decode_reg_error:
WrStrErrorPos(ErrNum_InvCtrlReg, pArg2);
break;
default:
WrStrErrorPos(ErrNum_InvAddrMode, pArg2);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_alu_z80(Word code)
* \brief handle ALU instruction, Z80-style
* \param code machine code & flags
* ------------------------------------------------------------------------ */
static void decode_alu_z80(Word code)
{
if (ChkArgCnt(2, 2)
&& ChkZ80Syntax(eSyntaxZ80))
{
const Byte flags = Hi(code);
z80_adr_vals_t src_adr_vals, dest_adr_vals;
code = Lo(code);
switch (decode_z80_adr(&ArgStr[1], &dest_adr_vals,
MModReg8 | MModReg16 | MModSReg8
| ((code & 1) ? MModWA : 0)))
{
case e_mod_reg8:
switch (decode_z80_adr(&ArgStr[2], &src_adr_vals,
MModReg8
| MModImm
| ((dest_adr_vals.val == REG_A) ? MModIndir : 0)
| (((dest_adr_vals.val == REG_A) && (pCurrCPUProps->Core >= eCore7800High)) ? MModWA : 0)))
{
case e_mod_reg8:
if ((dest_adr_vals.val == REG_A) && !dest_adr_vals.force_long && (src_adr_vals.val < 8) && (flags & ALUReg_Src))
{
BAsmCode[CodeLen++] = 0x60;
BAsmCode[CodeLen++] = 0x80 | (code << 3) | src_adr_vals.val;
}
else if ((src_adr_vals.val == REG_A) && !src_adr_vals.force_long && (dest_adr_vals.val < 8) && (flags & ALUReg_Dest))
{
BAsmCode[CodeLen++] = 0x60;
BAsmCode[CodeLen++] = (code << 3) | dest_adr_vals.val;
/* ONA/OFFA only exist as A,r, but since binary AND is commutative, we can just swap operands: */
if ((code == 9) || (code == 11))
BAsmCode[CodeLen - 1] |= 0x80;
}
else
WrError(ErrNum_InvAddrMode);
break;
case e_mod_imm:
if ((dest_adr_vals.val == REG_A) && !dest_adr_vals.force_long)
BAsmCode[CodeLen++] = 0x06 | ((code & 14) << 3) | (code & 1);
else if (pCurrCPUProps->Core < eCore7800High) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
BAsmCode[CodeLen++] = 0x74;
BAsmCode[CodeLen++] = (code << 3) | dest_adr_vals.val;
}
if (CodeLen > 0)
BAsmCode[CodeLen++] = src_adr_vals.vals[0];
break;
case e_mod_indir:
if (!is_rpa(src_adr_vals.val)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[CodeLen++] = 0x70;
BAsmCode[CodeLen++] = 0x80 | (code << 3) | src_adr_vals.val;
}
break;
case e_mod_wa:
BAsmCode[CodeLen++] = 0x74;
BAsmCode[CodeLen++] = 0x80 | (code << 3);
BAsmCode[CodeLen++] = src_adr_vals.vals[0];
break;
default:
break;
}
break;
case e_mod_reg16:
{
unsigned mask = MModReg16;
if (dest_adr_vals.val != REG_EA)
{
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
return;
}
if ((code == 8) || (code == 12))
{
mask |= MModReg8;
z80_op_size = eSymbolSizeUnknown;
}
switch (decode_z80_adr(&ArgStr[2], &src_adr_vals, mask))
{
case e_mod_reg8:
if ((src_adr_vals.val < REG_A) || (src_adr_vals.val > REG_C)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[CodeLen++] = 0x70;
BAsmCode[CodeLen++] = (code << 3) | src_adr_vals.val;
}
break;
case e_mod_reg16:
if ((src_adr_vals.val < REG_BC) || (src_adr_vals.val > REG_HL)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[CodeLen++] = 0x74;
BAsmCode[CodeLen++] = 0x84 | (code << 3) | src_adr_vals.val;
}
break;
default:
break;
}
break;
}
case e_mod_sreg8:
switch (decode_z80_adr(&ArgStr[2], &src_adr_vals, (flags & ALUImm_SR) ? MModImm : 0))
{
case e_mod_imm:
if (check_sr_flag(dest_adr_vals.vals[0], eFlagSR2, &ArgStr[1]))
{
BAsmCode[CodeLen++] = 0x64;
BAsmCode[CodeLen++] = (code << 3)
| ((pCurrCPUProps->Core < eCore7800High) ? 0x80 : 0x00)
| (dest_adr_vals.val & 7)
| ((dest_adr_vals.val & 8) << 4);
BAsmCode[CodeLen++] = src_adr_vals.vals[0];
}
break;
default:
break;
}
break;
case e_mod_wa:
z80_def_op_size = eSymbolSize8Bit;
switch (decode_z80_adr(&ArgStr[2], &src_adr_vals, MModImm))
{
case e_mod_imm:
BAsmCode[CodeLen++] = ((code & 0x0e) << 3) | 0x05;
BAsmCode[CodeLen++] = dest_adr_vals.vals[0];
BAsmCode[CodeLen++] = src_adr_vals.vals[0];
break;
default:
break;
}
break;
default:
break;
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeALUImm(Word Code)
* \brief handle 8 Bit ALU instructions with immediate source
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeALUImm(Word Code)
{
ShortInt HVal8;
Byte HReg;
Boolean OK;
Byte Flags;
Flags = Hi(Code);
Code = Lo(Code);
if (ChkArgCnt(2, 2))
{
HVal8 = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
if (OK)
{
tStrComp Arg1;
decode_reg_res_t res;
/* allow >A to enforce long addressing */
StrCompRefRight(&Arg1, &ArgStr[1], as_strcasecmp(ArgStr[1].str.p_str, ">A") ? 0 : 1);
if (!as_strcasecmp(ArgStr[1].str.p_str, "A"))
{
CodeLen = 2;
BAsmCode[0] = 0x06 + ((Code & 14) << 3) + (Code & 1);
BAsmCode[1] = HVal8;
}
else if ((res = decode_r(&Arg1, &HReg)) != e_decode_reg_unknown)
{
if (res != e_decode_reg_ok);
else if (pCurrCPUProps->Core == eCore7800Low) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
CodeLen = 3;
BAsmCode[0] = is_7807_781x ? 0x74 : 0x64;
BAsmCode[2] = HVal8;
BAsmCode[1] = HReg + (Code << 3);
}
}
else if ((res = decode_sr2(&ArgStr[1], &HReg)) != e_decode_reg_unknown)
{
if (res != e_decode_reg_ok);
else if (!(Flags & ALUImm_SR)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
CodeLen = 3;
BAsmCode[0] = 0x64;
BAsmCode[1] = (HReg & 7) | (Code << 3)
| (is_7807_781x ? ((HReg & 8) << 4) : 0x80);
BAsmCode[2] = HVal8;
}
}
else WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeALUReg(Word Code)
* \brief Handle ALU instructions with A and register as argument
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeALUReg(Word Code)
{
Byte HReg;
Byte Flags;
Flags = Hi(Code);
if ((CurrZ80Syntax & eSyntaxZ80) && (Flags & ALUReg_MayZ80))
{
decode_alu_z80(Code);
return;
}
Code = Lo(Code);
if (ChkArgCnt(2, 2))
{
Boolean NoSwap = !as_strcasecmp(ArgStr[1].str.p_str, "A");
tStrComp *pArg1 = NoSwap ? &ArgStr[1] : &ArgStr[2],
*pArg2 = NoSwap ? &ArgStr[2] : &ArgStr[1],
Arg2;
decode_reg_res_t res;
/* allow >A to enforce <op> r,A instrad of <op> A,r */
StrCompRefRight(&Arg2, pArg2, as_strcasecmp(pArg2->str.p_str, ">A") ? 0 : 1);
if (as_strcasecmp(pArg1->str.p_str, "A")) WrStrErrorPos(ErrNum_InvAddrMode, pArg1);
else if ((res = decode_r(&Arg2, &HReg)) == e_decode_reg_unknown) WrStrErrorPos(ErrNum_InvReg, &Arg2);
else if (res == e_decode_reg_ok)
{
if (NoSwap && !(Flags & ALUReg_Src)) WrStrErrorPos(ErrNum_InvAddrMode, &Arg2);
else if (!NoSwap && !(Flags & ALUReg_Dest)) WrStrErrorPos(ErrNum_InvAddrMode, &Arg2);
else
{
CodeLen = 2;
BAsmCode[0] = 0x60;
BAsmCode[1] = (Code << 3) + HReg;
if ((NoSwap) || (Memo("ONA")) || (Memo("OFFA")))
BAsmCode[1] += 0x80;
}
}
}
}
static void DecodeALURegW(Word Code)
{
if (ChkArgCnt(1, 1)
&& check_core_and_error(core_mask_no_low)
&& Decode_wa(&ArgStr[1], BAsmCode + 2, 0xff))
{
CodeLen = 3;
BAsmCode[0] = 0x74;
BAsmCode[1] = 0x80 + (Code << 3);
}
}
static void DecodeALURegX(Word Code)
{
Byte HReg;
if (!ChkArgCnt(1, 1));
else if (Decode_rpa(&ArgStr[1], &HReg))
{
CodeLen = 2;
BAsmCode[0] = 0x70;
BAsmCode[1] = 0x80 + (Code << 3) + HReg;
}
}
static void DecodeALUEA(Word Code)
{
Byte HReg;
if (!ChkArgCnt(2, 2));
else if (!check_core_and_error(core_mask_7807_7810));
else if (as_strcasecmp(ArgStr[1].str.p_str, "EA")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else if (!Decode_rp3(ArgStr[2].str.p_str, &HReg)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
CodeLen = 2;
BAsmCode[0] = 0x74;
BAsmCode[1] = 0x84 + (Code << 3) + HReg;
}
}
static void DecodeALUImmW(Word Code)
{
Boolean OK;
if (!ChkArgCnt(2, 2));
else if (Decode_wa(&ArgStr[1], BAsmCode + 1, 0xff))
{
BAsmCode[2] = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
if (OK)
{
CodeLen = 3;
BAsmCode[0] = 0x05 + ((Code >> 1) << 4);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeAbs(Word Code)
* \brief Handle instructions with absolute address as argument
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeAbs(Word Code)
{
if (!ChkArgCnt(1, 1));
else
{
Boolean OK;
Integer AdrInt;
AdrInt = EvalStrIntExpression(&ArgStr[1], Int16, &OK);
if (OK)
{
PutCode(Code);
BAsmCode[CodeLen++] = Lo(AdrInt);
BAsmCode[CodeLen++] = Hi(AdrInt);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeReg2(Word index)
* \brief Handle instructions with r2 as argument
* \param index index into instruction table
* ------------------------------------------------------------------------ */
static void DecodeReg2(Word index)
{
const order_t *p_order = ®2_orders[index];
Byte HReg;
decode_reg_res_t res;
if (!ChkArgCnt(1, 1) || !check_core_and_error(p_order->core_mask));
else if ((res = decode_r2(&ArgStr[1], &HReg)) == e_decode_reg_unknown) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else if (res == e_decode_reg_ok)
PutCode(p_order->code + HReg);
}
/*!------------------------------------------------------------------------
* \fn DecodeWA(Word Code)
* \brief Handle instructions with work area address as argument
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeWork(Word Code)
{
if (ChkArgCnt(1, 1)
&& Decode_wa(&ArgStr[1], BAsmCode + 1, 0xff))
{
CodeLen = 2;
BAsmCode[0] = Code;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeA(Word Code)
* \brief Handle instructions with A as argument
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeA(Word Code)
{
if (!ChkArgCnt(1, 1));
else if (as_strcasecmp(ArgStr[1].str.p_str, "A")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
PutCode(Code);
}
/*!------------------------------------------------------------------------
* \fn DecodeEA(Word Code)
* \brief Handle instructions with EA as argument
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeEA(Word Code)
{
if (!ChkArgCnt(1, 1) || !check_core_and_error(core_mask_7807_7810));
else if (as_strcasecmp(ArgStr[1].str.p_str, "EA")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
CodeLen = 2;
BAsmCode[0] = Hi(Code);
BAsmCode[1] = Lo(Code);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeDCX_INX(Word Code)
* \brief Handle INX/DCX Instructions
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeDCX_INX(Word Code)
{
Byte HReg;
if (!ChkArgCnt(1, 1));
else if (check_core(core_mask_7807_7810) && !as_strcasecmp(ArgStr[1].str.p_str, "EA"))
{
CodeLen = 1;
BAsmCode[0] = 0xa8 + Code;
}
else if (Decode_rp(ArgStr[1].str.p_str, &HReg))
{
CodeLen = 1;
BAsmCode[0] = 0x02 + Code + (HReg << 4);
}
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
}
/*!------------------------------------------------------------------------
* \fn decode_inc_dec(word code)
* \brief Handle Z80-style INC/DEC instructions
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_inc_dec(Word code)
{
if (ChkArgCnt(1, 1)
&& ChkZ80Syntax(eSyntaxZ80))
{
z80_adr_vals_t adr_vals;
switch (decode_z80_adr(&ArgStr[1], &adr_vals, MModReg8 | MModReg16 | MModWA))
{
case e_mod_reg8:
if ((adr_vals.val < REG_A) || (adr_vals.val > REG_C)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
BAsmCode[CodeLen++] = 0x40 | (code << 4) | adr_vals.val;
break;
case e_mod_reg16:
BAsmCode[CodeLen++] = (adr_vals.val == REG_EA)
? 0xa8 | code
: 0x02 | code | (adr_vals.val << 4);
break;
case e_mod_wa:
BAsmCode[CodeLen++] = 0x20 | (code << 4);
BAsmCode[CodeLen++] = adr_vals.vals[0];
break;
default:
break;
}
}
}
static void DecodeEADD_ESUB(Word Code)
{
Byte HReg;
decode_reg_res_t res;
if (!ChkArgCnt(2, 2) || !check_core_and_error(core_mask_7807_7810));
else if (as_strcasecmp(ArgStr[1].str.p_str, "EA")) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else if ((res = decode_r2(&ArgStr[2], &HReg)) == e_decode_reg_unknown) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else if (res == e_decode_reg_ok)
{
CodeLen = 2;
BAsmCode[0] = 0x70;
BAsmCode[1] = Code + HReg;
}
}
static void DecodeJ_JR_JRE(Word Type)
{
Boolean OK;
Integer AdrInt;
tSymbolFlags Flags;
if (!ChkArgCnt(1, 1))
return;
AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[1], Int16, &OK, &Flags) - (EProgCounter() + 1);
if (!OK)
return;
if (!Type) /* generic J */
Type = RangeCheck(AdrInt, SInt6) ? 1 : 2;
switch (Type)
{
case 1: /* JR */
if (!mSymbolQuestionable(Flags) && !RangeCheck(AdrInt, SInt6)) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
else
{
CodeLen = 1;
BAsmCode[0] = 0xc0 + (AdrInt & 0x3f);
}
break;
case 2:
AdrInt--; /* JRE is 2 bytes long */
if (!mSymbolQuestionable(Flags) && !RangeCheck(AdrInt, SInt9)) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
else
{
CodeLen = 2;
BAsmCode[0] = 0x4e + (Hi(AdrInt) & 1);
BAsmCode[1] = Lo(AdrInt);
}
break;
}
}
static void DecodeCALF(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 1))
{
Boolean OK;
Integer AdrInt;
tSymbolFlags Flags;
AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[1], Int16, &OK, &Flags);
if (OK)
{
if (!mFirstPassUnknown(Flags) && ((AdrInt >> 11) != 1)) WrStrErrorPos(ErrNum_NotFromThisAddress, &ArgStr[1]);
else
{
CodeLen = 2;
BAsmCode[0] = Hi(AdrInt) + 0x70;
BAsmCode[1] = Lo(AdrInt);
}
}
}
}
static void DecodeCALT(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(1, 1))
{
Boolean OK;
Integer AdrInt;
tSymbolFlags Flags;
AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[1], Int16, &OK, &Flags);
if (OK)
{
Word AdrMask = is_7807_781x ? 0xffc1 : 0xff81;
if (!mFirstPassUnknown(Flags) && ((AdrInt & AdrMask) != 0x80)) WrStrErrorPos(ErrNum_NotFromThisAddress, &ArgStr[1]);
else
{
CodeLen = 1;
BAsmCode[0] = 0x80 + ((AdrInt & ~AdrMask) >> 1);
}
}
}
}
static void DecodeBIT(Word Code)
{
UNUSED(Code);
if (ChkArgCnt(2, 2) && check_core_and_error(core_mask_no_low))
{
Boolean OK;
ShortInt HReg;
HReg = EvalStrIntExpression(&ArgStr[1], UInt3, &OK);
if (OK)
if (Decode_wa(&ArgStr[2], BAsmCode + 1, 0xff))
{
CodeLen = 2; BAsmCode[0] = 0x58 + HReg;
}
}
}
static void DecodeSK_SKN(Word Code)
{
Byte HReg;
if (!ChkArgCnt(1, 1) || !check_core_and_error(Hi(Code)));
else if (Decode_f(ArgStr[1].str.p_str, &HReg))
{
CodeLen = 2;
BAsmCode[0] = 0x48;
BAsmCode[1] = Lo(Code) + HReg;
}
else if (pCurrCPUProps->Core == eCore7807)
decode_bit_7807_core(1, (Code & 0x10) ? 0x50 :0x5d);
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
}
static void DecodeSKIT_SKNIT(Word Code)
{
ShortInt HReg;
if (ChkArgCnt(1, 1)
&& check_core_and_error(Hi(Code))
&& Decode_irf(&ArgStr[1], &HReg))
{
CodeLen = 2;
BAsmCode[0] = 0x48;
BAsmCode[1] = Lo(Code) + HReg;
}
}
static void DecodeIN_OUT(Word Code)
{
const tStrComp *p_port_arg;
switch (ArgCnt)
{
case 2:
{
const tStrComp *p_acc_arg = &ArgStr[(Code & 1) + 1];
if (as_strcasecmp(p_acc_arg->str.p_str, "A"))
{
WrStrErrorPos(ErrNum_InvAddrMode, p_acc_arg);
return;
}
p_port_arg = &ArgStr[2 - (Code & 1)];
goto common;
}
case 1:
p_port_arg = &ArgStr[1];
/* fall-thru */
common:
{
Boolean OK;
BAsmCode[1] = EvalStrIntExpression(p_port_arg, UInt8, &OK);
if (OK)
{
BAsmCode[0] = Code;
CodeLen = 2;
}
break;
}
default:
(void)ChkArgCnt(1, 2);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeBLOCK_7807(Word code)
* \brief Handle 7807-style BLOCK instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeBLOCK_7807(Word code)
{
if (ChkArgCnt(1, 1))
{
Byte mode;
if (Decode_rpa(&ArgStr[1], &mode))
{
if ((mode != 4) && (mode != 6)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
BAsmCode[0] = code | ((mode >> 1) & 1);
CodeLen = 1;
}
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeBit1_7807(Word code)
* \brief handle 7807-specific bit operations with one operand
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeBit1_7807(Word code)
{
if (!ChkArgCnt(1, 1));
else if (!check_core_and_error(core_mask_7807));
else
decode_bit_7807_core(1, code);
}
/*!------------------------------------------------------------------------
* \fn DecodeBit2_7807(Word code)
* \brief handle 7807-specific bit operations with two operands,
and Z80-style logical instructions
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeBit2_7807(Word code)
{
if (!ChkArgCnt(2, 2));
else if (!as_strcasecmp(ArgStr[1].str.p_str, "CY"))
{
if (check_core_and_error(core_mask_7807))
decode_bit_7807_core(2, Lo(code));
}
else if (CurrZ80Syntax & eSyntaxZ80)
{
Word Flags = ALUReg_Src;
if (pCurrCPUProps->Core != eCore7800Low)
Flags |= ALUReg_Dest | ALUImm_SR;
else if (Hi(code) != 2)
Flags |= ALUImm_SR;
decode_alu_z80((Flags << 8) | Hi(code));
}
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
}
/*!------------------------------------------------------------------------
* \fn DecodeDEFBIT(Word code)
* \brief handle DEFBIT instruction (7807...7809 only)
* ------------------------------------------------------------------------ */
static void DecodeDEFBIT(Word code)
{
LongWord BitSpec;
UNUSED(code);
/* if in structure definition, add special element to structure */
if (ActPC == StructSeg)
{
Boolean OK;
Byte BitPos;
PStructElem pElement;
if (!ChkArgCnt(2, 2))
return;
BitPos = eval_bit_position(&ArgStr[2], &OK);
if (!OK)
return;
pElement = CreateStructElem(&LabPart);
if (!pElement)
return;
pElement->pRefElemName = as_strdup(ArgStr[1].str.p_str);
pElement->OpSize = eSymbolSize8Bit;
pElement->BitPos = BitPos;
pElement->ExpandFnc = expand_bit_7807;
AddStructElem(pInnermostNamedStruct->StructRec, pElement);
}
else
{
if (decode_bit_arg(&BitSpec, 1, ArgCnt))
{
*ListLine = '=';
dissect_bit_7807(ListLine + 1, STRINGSIZE - 3, BitSpec);
PushLocHandle(-1);
EnterIntSymbol(&LabPart, BitSpec, SegBData, False);
PopLocHandle();
/* TODO: MakeUseList? */
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_ld(Word code)
* \brief handle LD (Z80 style) instruction
* ------------------------------------------------------------------------ */
static void decode_ld(Word code)
{
UNUSED(code);
if (ChkArgCnt(2, 2)
&& ChkZ80Syntax(eSyntaxZ80))
{
z80_adr_vals_t dest_adr_vals, src_adr_vals;
switch (decode_z80_adr(&ArgStr[1], &dest_adr_vals, MModReg8 | MModReg16 | MModAbs | MModWA | MModIndir | MModSReg8 | MModSReg16))
{
case e_mod_reg8:
switch (decode_z80_adr(&ArgStr[2], &src_adr_vals,
MModReg8
| ((dest_adr_vals.val < 8) ? MModImm : 0)
| ((dest_adr_vals.val < 8) ? MModAbs : 0)
| ((dest_adr_vals.val == REG_A) ? MModWA : 0)
| ((dest_adr_vals.val == REG_A) ? MModIndir : 0)
| ((dest_adr_vals.val == REG_A) ? MModSReg8 : 0)))
{
case e_mod_imm:
BAsmCode[CodeLen++] = 0x68 + dest_adr_vals.val;
BAsmCode[CodeLen++] = src_adr_vals.vals[0];
break;
case e_mod_abs:
BAsmCode[CodeLen++] = 0x70;
BAsmCode[CodeLen++] = 0x68 + dest_adr_vals.val;
BAsmCode[CodeLen++] = src_adr_vals.vals[0];
BAsmCode[CodeLen++] = src_adr_vals.vals[1];
break;
case e_mod_wa:
BAsmCode[CodeLen++] = (pCurrCPUProps->Core >= eCore7800High) ? 0x01 : 0x28;
BAsmCode[CodeLen++] = src_adr_vals.vals[0];
break;
case e_mod_reg8:
if ((src_adr_vals.val == REG_A) && (dest_adr_vals.val >= 2))
BAsmCode[CodeLen++] = 0x18 | (dest_adr_vals.val & 7);
else if ((dest_adr_vals.val == REG_A) && (src_adr_vals.val >= 2))
BAsmCode[CodeLen++] = 0x08 | (src_adr_vals.val & 7);
else
WrError(ErrNum_InvAddrMode);
break;
case e_mod_indir:
if ((pCurrCPUProps->Core <= eCore7800High) && !is_rpa(src_adr_vals.val)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[CodeLen++] = 0x28 | (src_adr_vals.val & 0x07) | ((src_adr_vals.val & 0x08) << 4);
append_adr_vals(&src_adr_vals);
}
break;
case e_mod_sreg8:
if (check_sr_flag(src_adr_vals.vals[0], eFlagSR1, &ArgStr[2]))
{
BAsmCode[CodeLen++] = 0x4c;
BAsmCode[CodeLen++] = 0xc0 | src_adr_vals.val;
}
break;
default:
break;
}
break;
case e_mod_reg16:
switch (decode_z80_adr(&ArgStr[2], &src_adr_vals,
MModImm
| MModReg16
| ((dest_adr_vals.val < REG_EA) ? MModAbs : 0)
| ((dest_adr_vals.val == REG_EA) ? MModIndir : 0)
| ((dest_adr_vals.val == REG_EA) ? MModSReg16 : 0)))
{
case e_mod_imm:
BAsmCode[CodeLen++] = 0x04 | (dest_adr_vals.val << 4);
BAsmCode[CodeLen++] = src_adr_vals.vals[0];
BAsmCode[CodeLen++] = src_adr_vals.vals[1];
break;
case e_mod_reg16:
if ((dest_adr_vals.val == REG_EA) && (src_adr_vals.val >= REG_BC) && (src_adr_vals.val <= REG_HL))
BAsmCode[CodeLen++] = 0xa4 | src_adr_vals.val;
else if ((src_adr_vals.val == REG_EA) && (dest_adr_vals.val >= REG_BC) && (dest_adr_vals.val <= REG_HL))
BAsmCode[CodeLen++] = 0xb4 | dest_adr_vals.val;
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
break;
case e_mod_abs:
BAsmCode[CodeLen++] = 0x70;
BAsmCode[CodeLen++] = 0x0f | (dest_adr_vals.val << 4);
BAsmCode[CodeLen++] = src_adr_vals.vals[0];
BAsmCode[CodeLen++] = src_adr_vals.vals[1];
break;
case e_mod_indir:
if (!is_rpa3(src_adr_vals.val)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[CodeLen++] = 0x48;
BAsmCode[CodeLen++] = 0x80 | src_adr_vals.val;
append_adr_vals(&src_adr_vals);
}
break;
case e_mod_sreg16:
if (check_sr_flag(src_adr_vals.vals[0], eFlagSR4, &ArgStr[2]))
{
BAsmCode[CodeLen++] = 0x48;
BAsmCode[CodeLen++] = 0xc0 | src_adr_vals.val;
}
break;
default:
break;
}
break;
case e_mod_abs:
switch (decode_z80_adr(&ArgStr[2], &src_adr_vals, MModReg8 | MModReg16))
{
case e_mod_reg8:
if (src_adr_vals.val > 7) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[CodeLen++] = 0x70;
BAsmCode[CodeLen++] = 0x78 | src_adr_vals.val;
append_adr_vals(&dest_adr_vals);
}
break;
case e_mod_reg16:
if (src_adr_vals.val >= REG_EA) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[CodeLen++] = 0x70;
BAsmCode[CodeLen++] = 0x0e | (src_adr_vals.val << 4);
append_adr_vals(&dest_adr_vals);
}
break;
default:
break;
}
break;
case e_mod_wa:
z80_def_op_size = eSymbolSize8Bit;
switch (decode_z80_adr(&ArgStr[2], &src_adr_vals, MModReg8 | MModReg16
| ((pCurrCPUProps->Core >= eCore7800High) ? MModImm : 0)
))
{
case e_mod_reg8:
if (src_adr_vals.val == REG_A)
{
BAsmCode[CodeLen++] = (pCurrCPUProps->Core >= eCore7800High) ? 0x63 : 0x38;
BAsmCode[CodeLen++] = dest_adr_vals.vals[0];
}
else if (src_adr_vals.val <= 7) /* map to absolute addressing */
{
BAsmCode[CodeLen++] = 0x70;
BAsmCode[CodeLen++] = 0x78 | src_adr_vals.val;
BAsmCode[CodeLen++] = dest_adr_vals.vals[0];
BAsmCode[CodeLen++] = WorkArea;
}
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
break;
case e_mod_reg16: /* map to absolute addressing */
if (src_adr_vals.val >= REG_EA) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else
{
BAsmCode[CodeLen++] = 0x70;
BAsmCode[CodeLen++] = 0x0e | (src_adr_vals.val << 4);
BAsmCode[CodeLen++] = dest_adr_vals.vals[0];
BAsmCode[CodeLen++] = WorkArea;
}
break;
case e_mod_imm:
BAsmCode[CodeLen++] = 0x71;
BAsmCode[CodeLen++] = dest_adr_vals.vals[0];
BAsmCode[CodeLen++] = src_adr_vals.vals[0];
break;
default:
break;
}
break;
case e_mod_indir:
z80_def_op_size = eSymbolSize8Bit;
switch (decode_z80_adr(&ArgStr[2], &src_adr_vals, MModReg8 | MModReg16
| ((pCurrCPUProps->Core >= eCore7800High) ? MModImm : 0)))
{
case e_mod_reg8:
if (src_adr_vals.val != REG_A) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else if ((pCurrCPUProps->Core <= eCore7800High) && !is_rpa(dest_adr_vals.val)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
BAsmCode[CodeLen++] = 0x38 | (dest_adr_vals.val & 0x07) | ((dest_adr_vals.val & 0x08) << 4);
append_adr_vals(&dest_adr_vals);
}
break;
case e_mod_reg16:
if (src_adr_vals.val != REG_EA) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else if (!is_rpa3(dest_adr_vals.val)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
BAsmCode[CodeLen++] = 0x48;
BAsmCode[CodeLen++] = 0x90 | dest_adr_vals.val;
append_adr_vals(&dest_adr_vals);
}
break;
case e_mod_imm:
if (!is_rpa1(dest_adr_vals.val)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
{
BAsmCode[CodeLen++] = 0x48 | dest_adr_vals.val;
BAsmCode[CodeLen++] = src_adr_vals.vals[0];
}
break;
default:
break;
}
break;
case e_mod_sreg8:
switch (decode_z80_adr(&ArgStr[2], &src_adr_vals, MModReg8 | MModImm))
{
case e_mod_reg8:
if (src_adr_vals.val != REG_A) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else if (check_sr_flag(dest_adr_vals.vals[0], eFlagSR, &ArgStr[1]))
{
BAsmCode[CodeLen++] = 0x4d;
BAsmCode[CodeLen++] = 0xc0 | dest_adr_vals.val;
}
break;
case e_mod_imm:
if (check_sr_flag(dest_adr_vals.vals[0], eFlagSR2, &ArgStr[1]))
{
BAsmCode[CodeLen++] = 0x64;
BAsmCode[CodeLen++] = (dest_adr_vals.val & 0x07) | ((dest_adr_vals.val & 0x08) << 4);
BAsmCode[CodeLen++] = src_adr_vals.vals[0];
}
default:
break;
}
break;
case e_mod_sreg16:
switch (decode_z80_adr(&ArgStr[2], &src_adr_vals, MModReg16))
{
case e_mod_reg16:
if (src_adr_vals.val != REG_EA) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
else if (check_sr_flag(dest_adr_vals.vals[0], eFlagSR3, &ArgStr[1]))
{
BAsmCode[CodeLen++] = 0x48;
BAsmCode[CodeLen++] = 0xd2 | dest_adr_vals.val;
}
break;
default:
break;
}
break;
default:
break;
}
}
}
/*--------------------------------------------------------------------------------*/
/* Dynamic Code Table Handling */
static void AddFixed(const char *p_name, Word code, unsigned core_mask)
{
order_array_rsv_end(fixed_orders, order_t);
fixed_orders[InstrZ].code = code;
fixed_orders[InstrZ].core_mask = core_mask;
AddInstTable(InstTable, p_name, InstrZ++, DecodeFixed);
}
static void AddIntFlag(const char *p_name, Byte code)
{
order_array_rsv_end(int_flags, intflag_t);
int_flags[InstrZ].p_name = p_name;
int_flags[InstrZ++].code = code;
}
static void AddALU(Byte NCode, Word Flags, const char *NNameI, const char *NNameReg, const char *NNameEA, const char *NNameZ80)
{
char Name[20];
AddInstTable(InstTable, NNameI, ((Flags & ALUImm_SR) << 8) | NCode, DecodeALUImm);
AddInstTable(InstTable, NNameReg, ((Flags & (ALUReg_Src | ALUReg_Dest | ALUImm_SR | ALUReg_MayZ80)) << 8) | NCode, DecodeALUReg);
AddInstTable(InstTable, NNameEA, NCode, DecodeALUEA);
as_snprintf(Name, sizeof(Name), "%sW", NNameReg);
AddInstTable(InstTable, Name, NCode, DecodeALURegW);
as_snprintf(Name, sizeof(Name), "%sX", NNameReg);
AddInstTable(InstTable, Name, NCode, DecodeALURegX);
if (NCode & 1)
{
as_snprintf(Name, sizeof(Name), "%sW", NNameI);
AddInstTable(InstTable, Name, NCode, DecodeALUImmW);
}
if (NNameZ80)
AddInstTable(InstTable, NNameZ80, NCode, decode_alu_z80);
}
static void add_alu_z80(const char *p_name, Byte code, Word flags)
{
AddInstTable(InstTable, p_name, (flags << 8) | code, decode_alu_z80);
}
static void AddAbs(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeAbs);
}
static void AddReg2(const char *p_name, Word code, unsigned core_mask)
{
order_array_rsv_end(reg2_orders, order_t);
reg2_orders[InstrZ].code = code;
reg2_orders[InstrZ].core_mask = core_mask;
AddInstTable(InstTable, p_name, InstrZ++, DecodeReg2);
}
static void add_sreg8(const char *p_name, Byte code, Byte flags, Byte core_mask)
{
order_array_rsv_end(s_regs8, sreg_t);
s_regs8[InstrZ].p_name = p_name;
s_regs8[InstrZ].code = code;
s_regs8[InstrZ].flags = flags;
s_regs8[InstrZ].core_mask = core_mask;
InstrZ++;
}
static void add_sreg16(const char *p_name, Byte code, Byte flags, Byte core_mask)
{
order_array_rsv_end(s_regs16, sreg_t);
s_regs16[InstrZ].p_name = p_name;
s_regs16[InstrZ].code = code;
s_regs16[InstrZ].flags = flags;
s_regs16[InstrZ].core_mask = core_mask;
InstrZ++;
}
static void AddWork(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeWork);
}
static void AddA(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeA);
}
static void AddEA(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeEA);
}
static void InitFields(void)
{
Boolean IsLow = pCurrCPUProps->Core == eCore7800Low,
IsHigh = pCurrCPUProps->Core == eCore7800High,
Is7807 = pCurrCPUProps->Core == eCore7807,
Is781x = pCurrCPUProps->Core == eCore7810;
InstTable = CreateInstTable(301);
SetDynamicInstTable(InstTable);
AddInstTable(InstTable, "MOV", 0, DecodeMOV);
AddInstTable(InstTable, "MVI", 0, DecodeMVI);
AddInstTable(InstTable, "MVIW", 0, DecodeMVIW);
AddInstTable(InstTable, "MVIX", 0, DecodeMVIX);
AddInstTable(InstTable, "LDAX", 0x28, DecodeLDAX_STAX);
AddInstTable(InstTable, "STAX", 0x38, DecodeLDAX_STAX);
AddInstTable(InstTable, "LDEAX", 0x80, DecodeLDEAX_STEAX);
AddInstTable(InstTable, "STEAX", 0x90, DecodeLDEAX_STEAX);
AddInstTable(InstTable, "LXI", 0, DecodeLXI);
AddInstTable(InstTable, "PUSH", is_7807_781x ? 0xb0 : 0x480e, DecodePUSH_POP);
AddInstTable(InstTable, "POP", is_7807_781x ? 0xa0 : 0x480f, DecodePUSH_POP);
AddInstTable(InstTable, "DMOV", 0, DecodeDMOV);
AddInstTable(InstTable, "DCX", 1, DecodeDCX_INX);
AddInstTable(InstTable, "INX", 0, DecodeDCX_INX);
AddInstTable(InstTable, "EADD", 0x40, DecodeEADD_ESUB);
AddInstTable(InstTable, "ESUB", 0x60, DecodeEADD_ESUB);
AddInstTable(InstTable, "JR", 1, DecodeJ_JR_JRE);
AddInstTable(InstTable, "JRE", 2, DecodeJ_JR_JRE);
AddInstTable(InstTable, "J", 0, DecodeJ_JR_JRE);
AddInstTable(InstTable, "CALF", 0, DecodeCALF);
AddInstTable(InstTable, "CALT", 0, DecodeCALT);
AddInstTable(InstTable, "BIT", 0, DecodeBIT);
AddInstTable(InstTable, "SK" , (core_mask_no_low << 8) | 0x08, DecodeSK_SKN);
AddInstTable(InstTable, "SKN", (core_mask_all << 8) | 0x18, DecodeSK_SKN);
AddInstTable(InstTable, "SKIT" , (core_mask_no_low << 8) | (is_7807_781x ? 0x40 : 0x00), DecodeSKIT_SKNIT);
AddInstTable(InstTable, "SKNIT", (core_mask_all << 8) | (is_7807_781x ? 0x60 : 0x10), DecodeSKIT_SKNIT);
InstrZ = 0;
AddFixed("EX" , 0x0010 , (1 << eCore7800High));
AddFixed("PEN" , 0x482c , (1 << eCore7800High));
AddFixed("RCL" , 0x4832 , (1 << eCore7800High));
AddFixed("RCR" , 0x4833 , (1 << eCore7800High));
AddFixed("SHAL" , 0x4834 , (1 << eCore7800High));
AddFixed("SHAR" , 0x4835 , (1 << eCore7800High));
AddFixed("SHCL" , 0x4836 , (1 << eCore7800High));
AddFixed("SHCR" , 0x4837 , (1 << eCore7800High));
AddFixed("EXX" , Is7807 ? 0x48af : 0x0011 , core_mask_no_low);
AddFixed("EXA" , Is7807 ? 0x48ac : 0x0010 , core_mask_all);
AddFixed("EXH" , Is7807 ? 0x48ae : 0x0050 , core_mask_all);
AddFixed("EXR" , 0x48ad , core_mask_7807);
if (Is7807)
AddInstTable(InstTable, "BLOCK", 0x0010, DecodeBLOCK_7807);
else
AddFixed("BLOCK", 0x0031 , core_mask_no_low);
AddFixed("TABLE", is_7807_781x ? 0x48a8 : 0x0021 , core_mask_no_low);
AddFixed("DAA" , 0x0061 , core_mask_all);
AddFixed("STC" , 0x482b , core_mask_all);
AddFixed("CLC" , 0x482a , core_mask_all);
AddFixed("CMC" , 0x48aa , core_mask_7807);
AddFixed("NEGA" , 0x483a , core_mask_all);
AddFixed("RLD" , 0x4838 , core_mask_all);
AddFixed("RRD" , 0x4839 , core_mask_all);
AddFixed("JB" , is_7807_781x ? 0x0021 : 0x0073 , core_mask_all);
AddFixed("JEA" , 0x4828 , core_mask_all);
AddFixed("CALB" , is_7807_781x ? 0x4829 : 0x0063 , core_mask_no_low);
AddFixed("SOFTI", 0x0072 , core_mask_no_low);
AddFixed("RET" , is_7807_781x ? 0x00b8 : 0x0008 , core_mask_all);
AddFixed("RETS" , is_7807_781x ? 0x00b9 : 0x0018 , core_mask_all);
AddFixed("RETI" , 0x0062 , core_mask_all);
AddFixed("NOP" , 0x0000 , core_mask_all);
AddFixed("EI" , is_7807_781x ? 0x00aa : 0x4820 , core_mask_all);
AddFixed("DI" , is_7807_781x ? 0x00ba : 0x4824 , core_mask_all);
AddFixed("HLT" , is_7807_781x ? 0x483b : 0x0001 , core_mask_no_low);
AddFixed("SIO" , 0x0009 , core_mask_7800);
AddFixed("STM" , 0x0019 , core_mask_7800);
AddFixed("PEX" , 0x482d , core_mask_7800);
AddFixed("RAL" , is_7807_781x ? 0x4835 : 0x4830 , core_mask_all);
AddFixed("RAR" , 0x4831 , core_mask_all);
AddFixed("PER" , 0x483c , core_mask_7800);
if (pCurrCPUProps->Flags & eFlagCMOS)
AddFixed("STOP" , 0x48bb, core_mask_all);
if (is_7807_781x)
{
if (Is781x)
{
}
else
{
}
/* 0x28 eFlagSR ? */
}
else
{
}
InstrZ = 0;
if (is_7807_781x)
{
AddIntFlag("NMI" , 0);
AddIntFlag("FT0" , 1);
AddIntFlag("FT1" , 2);
AddIntFlag("F1" , 3);
AddIntFlag("F2" , 4);
AddIntFlag("FE0" , 5);
AddIntFlag("FE1" , 6);
AddIntFlag("FEIN", 7);
AddIntFlag("FSR" , 9);
AddIntFlag("FST" ,10);
AddIntFlag("ER" ,11);
AddIntFlag("OV" ,12);
AddIntFlag("SB" ,20);
if (Is781x)
{
AddIntFlag("FAD" , 8);
AddIntFlag("AN4" ,16);
AddIntFlag("AN5" ,17);
AddIntFlag("AN6" ,18);
AddIntFlag("AN7" ,19);
}
else
{
/* value yet unknown */
/* AddIntFlag("IFE2", ...); */
}
}
else
{
AddIntFlag("F0" , 0);
AddIntFlag("FT" , 1);
AddIntFlag("F1" , 2);
if (IsHigh)
AddIntFlag("F2" , 3);
AddIntFlag("FS" , 4);
}
AddIntFlag(NULL, 0);
AddALU(10, IsLow ? ALUReg_Src | ALUReg_MayZ80 : ALUImm_SR | ALUReg_Src | ALUReg_Dest | ALUReg_MayZ80, "ACI" , "ADC" , "DADC" , NULL );
AddALU( 4, IsLow ? ALUReg_Src | ALUReg_MayZ80 : ALUImm_SR | ALUReg_Src | ALUReg_Dest | ALUReg_MayZ80, "ADINC", "ADDNC", "DADDNC", NULL );
AddALU( 8, IsLow ? ALUReg_Src | ALUReg_MayZ80 : ALUImm_SR | ALUReg_Src | ALUReg_Dest | ALUReg_MayZ80, "ADI" , "ADD" , "DADD" , NULL );
AddALU( 1, IsLow ? ALUImm_SR | ALUReg_Src : ALUImm_SR | ALUReg_Src | ALUReg_Dest , "ANI" , "ANA" , "DAN" , NULL );
AddALU(15, IsLow ? ALUReg_Src : ALUImm_SR | ALUReg_Src | ALUReg_Dest , "EQI" , "EQA" , "DEQ" , NULL );
AddALU( 5, IsLow ? ALUReg_Src : ALUImm_SR | ALUReg_Src | ALUReg_Dest , "GTI" , "GTA" , "DGT" , NULL );
AddALU( 7, IsLow ? ALUReg_Src : ALUImm_SR | ALUReg_Src | ALUReg_Dest , "LTI" , "LTA" , "DLT" , NULL );
AddALU(13, IsLow ? ALUReg_Src : ALUImm_SR | ALUReg_Src | ALUReg_Dest , "NEI" , "NEA" , "DNE" , NULL );
AddALU(11, IsLow ? ALUImm_SR : ALUImm_SR | ALUReg_Src | ALUReg_Dest , "OFFI" , "OFFA" , "DOFF" , NULL );
AddALU( 9, IsLow ? ALUImm_SR : ALUImm_SR | ALUReg_Src | ALUReg_Dest , "ONI" , "ONA" , "DON" , NULL );
AddALU( 3, IsLow ? ALUImm_SR | ALUReg_Src : ALUImm_SR | ALUReg_Src | ALUReg_Dest , "ORI" , "ORA" , "DOR" , NULL );
AddALU(14, IsLow ? ALUReg_Src | ALUReg_MayZ80 : ALUImm_SR | ALUReg_Src | ALUReg_Dest | ALUReg_MayZ80, "SBI" , "SBB" , "DSBB" , NULL );
AddALU( 6, IsLow ? ALUReg_Src | ALUReg_MayZ80 : ALUImm_SR | ALUReg_Src | ALUReg_Dest | ALUReg_MayZ80, "SUINB", "SUBNB", "DSUBNB", NULL );
AddALU(12, IsLow ? ALUReg_Src | ALUReg_MayZ80 : ALUImm_SR | ALUReg_Src | ALUReg_Dest | ALUReg_MayZ80, "SUI" , "SUB" , "DSUB" , NULL );
AddALU( 2, IsLow ? ALUReg_Src : ALUImm_SR | ALUReg_Src | ALUReg_Dest , "XRI" , "XRA" , "DXR" , NULL );
AddAbs("CALL", is_7807_781x ? 0x0040 : 0x0044);
AddAbs("JMP" , 0x0054);
AddAbs("LBCD", 0x701f);
AddAbs("LDED", 0x702f);
AddAbs("LHLD", 0x703f);
AddAbs("LSPD", 0x700f);
AddAbs("SBCD", 0x701e);
AddAbs("SDED", 0x702e);
AddAbs("SHLD", 0x703e);
AddAbs("SSPD", 0x700e);
InstrZ = 0;
AddReg2("DCR" , 0x0050, core_mask_all);
AddReg2("DIV" , 0x483c, core_mask_7807_7810);
AddReg2("INR" , 0x0040, core_mask_all);
AddReg2("MUL" , 0x482c, core_mask_7807_7810);
if (is_7807_781x)
{
AddReg2("RLL" , 0x4834, core_mask_7807_7810);
AddReg2("RLR" , 0x4830, core_mask_7807_7810);
}
else
{
AddA("RLL", 0x4830);
AddA("RLR", 0x4831);
}
AddReg2("SLL" , 0x4824, core_mask_7807_7810);
AddReg2("SLR" , 0x4820, core_mask_7807_7810);
AddReg2("SLLC", 0x4804, core_mask_7807_7810);
AddReg2("SLRC", 0x4800, core_mask_7807_7810);
AddWork("DCRW", 0x30);
AddWork("INRW", 0x20);
AddWork("LDAW", is_7807_781x ? 0x01 : 0x28);
AddWork("STAW", is_7807_781x ? 0x63 : 0x38);
AddEA("DRLL", 0x48b4); AddEA("DRLR", 0x48b0);
AddEA("DSLL", 0x48a4); AddEA("DSLR", 0x48a0);
if (!is_7807_781x)
{
AddInstTable(InstTable, "IN" , 0x4c, DecodeIN_OUT);
AddInstTable(InstTable, "OUT", 0x4d, DecodeIN_OUT);
}
AddInstTable(InstTable, "AND" , 0x0131, DecodeBit2_7807);
AddInstTable(InstTable, "OR" , 0x035c, DecodeBit2_7807);
AddInstTable(InstTable, "XOR" , 0x025e, DecodeBit2_7807);
AddInstTable(InstTable, "SETB", 0x58, DecodeBit1_7807);
AddInstTable(InstTable, "CLR" , 0x5b, DecodeBit1_7807);
AddInstTable(InstTable, "NOT" , 0x59, DecodeBit1_7807);
/* Array with special regs is created upon first usage and remains
allocated, because we need it in dissect_bit_7807(), which may
be called after we switched away fro mtarget (e.g. when printing
symbol table: */
if (!s_regs8)
{
InstrZ = 0;
add_sreg8("PA" , 0x00, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_all);
add_sreg8("PB" , 0x01, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_all);
add_sreg8("PC" , 0x02, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_7807_7810);
add_sreg8("PD" , 0x03, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_7807_7810);
add_sreg8("PF" , 0x05, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_7807_7810);
add_sreg8("MKH" , 0x06, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_7807_7810);
add_sreg8("MKL" , 0x07, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_7807_7810);
add_sreg8("SMH" , 0x09, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_7807_7810);
add_sreg8("SML" , 0x0a, eFlagSR , core_mask_7807_7810);
add_sreg8("EOM" , 0x0b, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_7807_7810);
add_sreg8("ETMM", 0x0c, eFlagSR , core_mask_7807_7810);
add_sreg8("TMM" , 0x0d, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_7807_7810);
add_sreg8("MM" , 0x10, eFlagSR , core_mask_7807_7810);
add_sreg8("MCC" , 0x11, eFlagSR , core_mask_7807_7810);
add_sreg8("MA" , 0x12, eFlagSR , core_mask_7807_7810);
add_sreg8("MB" , 0x13, eFlagSR , core_mask_7807_7810);
add_sreg8("MC" , 0x14, eFlagSR , core_mask_7807_7810);
add_sreg8("MF" , 0x17, eFlagSR , core_mask_7807_7810);
add_sreg8("TXB" , 0x18, eFlagSR , core_mask_7807_7810);
add_sreg8("RXB" , 0x19, eFlagSR1 , core_mask_7807_7810);
add_sreg8("TM0" , 0x1a, eFlagSR , core_mask_7807_7810);
add_sreg8("TM1" , 0x1b, eFlagSR , core_mask_7807_7810);
add_sreg8("ZCM" , 0x28, eFlagSR , core_mask_7807_7810 | core_mask_cmos);
add_sreg8("ANM" , 0x08, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_7810 );
add_sreg8("CR0" , 0x20, eFlagSR1 , core_mask_7810 );
add_sreg8("CR1" , 0x21, eFlagSR1 , core_mask_7810 );
add_sreg8("CR2" , 0x22, eFlagSR1 , core_mask_7810 );
add_sreg8("CR3" , 0x23, eFlagSR1 , core_mask_7810 );
add_sreg8("PT" , 0x0e, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_7807 );
add_sreg8("WDM" , 0x20, eFlagSR | eFlagSR1 , core_mask_7807 );
add_sreg8("MT" , 0x21, eFlagSR | eFlagSR1 , core_mask_7807 );
add_sreg8("MK" , 0x03, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_7800 );
add_sreg8("MB" , 0x04, eFlagSR , core_mask_7800 );
add_sreg8("PC" , 0x02, eFlagSR | eFlagSR1 | eFlagSR2, core_mask_7800_high);
add_sreg8("PC" , 0x02, eFlagSR1 | eFlagSR2 , core_mask_7800_low );
add_sreg8("MC" , 0x05, eFlagSR , core_mask_7800_high);
add_sreg8("MC" , 0x05, 0 , core_mask_7800_low );
add_sreg8("TM0" , 0x06, eFlagSR , core_mask_7800_high);
add_sreg8("TM0" , 0x06, 0 , core_mask_7800_low );
add_sreg8("TM1" , 0x07, eFlagSR , core_mask_7800_high);
add_sreg8("TM1" , 0x07, 0 , core_mask_7800_low );
add_sreg8("TM" , 0x06, eFlagSR , core_mask_7800_low );
add_sreg8("TM" , 0x06, 0 , core_mask_7800_high);
add_sreg8("SM" , 0x0a, eFlagSR | eFlagSR1 , core_mask_7800_low );
add_sreg8("SM" , 0x0a, 0 , core_mask_7800_high);
add_sreg8("SC" , 0x0b, eFlagSR | eFlagSR1 , core_mask_7800_low );
add_sreg8("SC" , 0x0b, 0 , core_mask_7800_high);
add_sreg8("S" , 0x08, eFlagSR | eFlagSR1 , core_mask_7800 );
add_sreg8("TMM" , 0x09, eFlagSR | eFlagSR1 , core_mask_7800 );
add_sreg8(NULL , 0x00, 0 , 0 );
}
InstrZ = 0;
add_sreg16("ETM0" , 0x00, eFlagSR3, core_mask_all );
add_sreg16("ETM1" , 0x01, eFlagSR3, core_mask_all );
add_sreg16("ECNT" , 0x00, eFlagSR4, core_mask_all );
add_sreg16("ECPT" , 0x01, eFlagSR4, core_mask_7810);
add_sreg16("ECPT0", 0x01, eFlagSR4, core_mask_7807);
add_sreg16("ECPT1", 0x02, eFlagSR4, core_mask_7807);
add_sreg16(NULL , 0x00, 0 , 0 );
if (Is7807)
AddInstTable(InstTable, "DEFBIT", 0, DecodeDEFBIT);
AddZ80Syntax(InstTable);
AddInstTable(InstTable, "LD", 0, decode_ld);
AddInstTable(InstTable, "INC", 0, decode_inc_dec);
AddInstTable(InstTable, "DEC", 1, decode_inc_dec);
add_alu_z80("SKGT", 5, IsLow ? ALUReg_Src : ALUImm_SR | ALUReg_Src | ALUReg_Dest);
add_alu_z80("SKLT", 7, IsLow ? ALUReg_Src : ALUImm_SR | ALUReg_Src | ALUReg_Dest);
add_alu_z80("SKNE",13, IsLow ? ALUReg_Src : ALUImm_SR | ALUReg_Src | ALUReg_Dest);
add_alu_z80("SKEQ",15, IsLow ? ALUReg_Src : ALUImm_SR | ALUReg_Src | ALUReg_Dest);
add_alu_z80("SKON", 9, IsLow ? ALUImm_SR : ALUImm_SR | ALUReg_Src | ALUReg_Dest);
add_alu_z80("SKOFF",11, IsLow ? ALUImm_SR : ALUImm_SR | ALUReg_Src | ALUReg_Dest);
}
static void DeinitFields(void)
{
DestroyInstTable(InstTable);
order_array_free(int_flags);
order_array_free(fixed_orders);
order_array_free(reg2_orders);
/* See above why s_regs8 does not get freed upon deinit: */
/*order_array_free(s_regs8);*/
order_array_free(s_regs16);
}
/*--------------------------------------------------------------------------*/
/*!------------------------------------------------------------------------
* \fn MakeCode_78C10(void)
* \brief generate code from source code line
* ------------------------------------------------------------------------ */
static void MakeCode_78C10(void)
{
CodeLen = 0;
DontPrint = False;
z80_op_size =
z80_def_op_size = eSymbolSizeUnknown;
/* zu ignorierendes */
if (Memo("")) return;
/* Pseudoanweisungen */
if (DecodeIntelPseudo(False)) return;
if (!LookupInstTable(InstTable, OpPart.str.p_str))
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
}
/*!------------------------------------------------------------------------
* \fn InitCode_78C10(void)
* \brief target-specific initializations at begin of pass
* ------------------------------------------------------------------------ */
static void InitCode_78C10(void)
{
WorkArea = 0x100;
}
/*!------------------------------------------------------------------------
* \fn IsDef_78C10(void)
* \brief check whether instruction consumes label field itself
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean IsDef_78C10(void)
{
return (pCurrCPUProps->Core == eCore7807) && Memo("DEFBIT");
}
/*!------------------------------------------------------------------------
* \fn SwitchFrom_78C10(void)
* \brief cleanups when switching away from target
* ------------------------------------------------------------------------ */
static void SwitchFrom_78C10(void)
{
DeinitFields();
}
/*!------------------------------------------------------------------------
* \fn SwitchTo_78C10(void *pUser)
* \brief initializations when switching to target
* \param pUser * to target details
* ------------------------------------------------------------------------ */
static void SwitchTo_78C10(void *pUser)
{
const TFamilyDescr *pDescr = FindFamilyByName("78(C)xx");
pCurrCPUProps = (const tCPUProps*)pUser;
TurnWords = False;
SetIntConstMode(eIntConstModeIntel);
PCSymbol = "$"; HeaderID = pDescr->Id; NOPCode = 0x00;
DivideChars = ","; HasAttrs = False;
ValidSegs = 1 << SegCode;
Grans[SegCode] = 1; ListGrans[SegCode] = 1; SegInits[SegCode] = 0;
SegLimits[SegCode] = 0xffff;
if (pCurrCPUProps->Flags & eFlagHasV)
{
static ASSUMERec ASSUME78C10s[] =
{
{"V" , &WorkArea, 0, 0xff, 0x100, NULL}
};
pASSUMERecs = ASSUME78C10s;
ASSUMERecCnt = sizeof(ASSUME78C10s) / sizeof(*ASSUME78C10s);
}
else
WorkArea = 0xff;
is_7807_781x = (pCurrCPUProps->Core == eCore7807) || (pCurrCPUProps->Core == eCore7810);
MakeCode = MakeCode_78C10; IsDef = IsDef_78C10;
SwitchFrom = SwitchFrom_78C10;
if (pCurrCPUProps->Core == eCore7807)
DissectBit = dissect_bit_7807;
InitFields();
}
/*!------------------------------------------------------------------------
* \fn code78c10_init(void)
* \brief Attach 78Cxx target
* ------------------------------------------------------------------------ */
static const tCPUProps CPUProps[] =
{
{ "7800" , eCore7800High, eFlagHasV }, /* ROMless , 128B RAM */
{ "7801" , eCore7800High, eFlagHasV }, /* 4KB ROM , 128B RAM */
{ "7802" , eCore7800High, eFlagHasV }, /* 6KB ROM , 128B RAM */
{ "78C05", eCore7800Low, 0 }, /* ROMless , 128B RAM */
{ "78C06", eCore7800Low, 0 }, /* 4KB ROM , 128B RAM */
{ "7807" , eCore7807, eFlagHasV }, /* ROMless , 256B RAM */
{ "7808" , eCore7807, eFlagHasV }, /* 4KB ROM , 256B RAM */
{ "7809" , eCore7807, eFlagHasV }, /* 8KB ROM , 256B RAM */
{ "7810" , eCore7810, eFlagHasV }, /* ROMless , 256B RAM */
{ "78C10", eCore7810, eFlagHasV | eFlagCMOS }, /* ROMless , 256B RAM */
{ "78C11", eCore7810, eFlagHasV | eFlagCMOS }, /* 4KB ROM , 256B RAM */
{ "78C12", eCore7810, eFlagHasV | eFlagCMOS }, /* 8KB ROM , 256B RAM */
{ "78C14", eCore7810, eFlagHasV | eFlagCMOS }, /* 16KB ROM, 256B RAM */
{ "78C17", eCore7810, eFlagHasV | eFlagCMOS }, /* ROMless , 1KB RAM */
{ "78C18", eCore7810, eFlagHasV | eFlagCMOS }, /* 32KB ROM, 1KB RAM */
{ "" , eCoreNone, 0 },
};
void code78c10_init(void)
{
const tCPUProps *pProp;
for (pProp = CPUProps; pProp->Name[0]; pProp++)
(void)AddCPUUserWithArgs(pProp->Name, SwitchTo_78C10, (void*)pProp, NULL, NULL);
AddInitPassProc(InitCode_78C10);
}