1661 lines
69 KiB
C
1661 lines
69 KiB
C
/* ______ ______ ______
|
|
/\___ \ /\ __ \ /\ \
|
|
\/__/ /__\ \ __ \\ \ \ \
|
|
/\_____\\ \_____\\ \_____\
|
|
Zilog \/_____/ \/_____/ \/_____/ CPU Emulator v0.1
|
|
Copyright (C) 1999-2018 Manuel Sainz de Baranda y Goñi.
|
|
|
|
This library is free software: you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free Software
|
|
Foundation, either version 3 of the License, or (at your option) any later
|
|
version.
|
|
|
|
This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
this library. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include <Z/macros/value.h>
|
|
#include <Z/macros/pointer.h>
|
|
|
|
#if defined(CPU_Z80_HIDE_API)
|
|
# define CPU_Z80_API static
|
|
#elif defined(CPU_Z80_STATIC)
|
|
# define CPU_Z80_API
|
|
#else
|
|
# define CPU_Z80_API Z_API_EXPORT
|
|
#endif
|
|
|
|
#if defined(CPU_Z80_BUILD_ABI) || defined(CPU_Z80_BUILD_MODULE_ABI)
|
|
# ifndef CPU_Z80_USE_ABI
|
|
# define CPU_Z80_USE_ABI
|
|
# endif
|
|
|
|
# if defined(CPU_Z80_HIDE_ABI)
|
|
# define CPU_Z80_ABI static
|
|
# elif defined(CPU_Z80_STATIC)
|
|
# define CPU_Z80_ABI
|
|
# else
|
|
# define CPU_Z80_ABI Z_API_EXPORT
|
|
# endif
|
|
#endif
|
|
|
|
#if defined(CPU_Z80_USE_LOCAL_HEADER)
|
|
# include "Z80.h"
|
|
#else
|
|
# include <emulation/CPU/Z80.h>
|
|
#endif
|
|
|
|
|
|
/* MARK: - Types */
|
|
|
|
typedef zuint8 (* Instruction)(Z80 *object);
|
|
|
|
|
|
/* MARK: - Macros: External */
|
|
|
|
#define O(member) Z_OFFSET_OF(Z80, member)
|
|
#define ROL(value) value = (zuint8)Z_8BIT_ROTATE_LEFT( value, 1)
|
|
#define ROR(value) value = (zuint8)Z_8BIT_ROTATE_RIGHT(value, 1)
|
|
|
|
|
|
/* MARK: - Macros & Functions: Callback */
|
|
|
|
#define READ_8(address) object->read (object->context, (zuint16)(address))
|
|
#define WRITE_8(address, value) object->write (object->context, (zuint16)(address), (zuint8)(value))
|
|
#define IN(port) object->in (object->context, (zuint16)(port ))
|
|
#define OUT(port, value) object->out (object->context, (zuint16)(port ), (zuint8)(value))
|
|
#define INT_DATA object->int_data(object->context)
|
|
#define READ_OFFSET(address) ((zsint8)READ_8(address))
|
|
#define SET_HALT if (object->halt != NULL) object->halt(object->context, TRUE )
|
|
#define CLEAR_HALT if (object->halt != NULL) object->halt(object->context, FALSE)
|
|
|
|
|
|
static Z_INLINE zuint16 read_16bit(Z80 *object, zuint16 address)
|
|
{return (zuint16)(READ_8(address) | (zuint16)READ_8(address + 1) << 8);}
|
|
|
|
|
|
static Z_INLINE void write_16bit(Z80 *object, zuint16 address, zuint16 value)
|
|
{
|
|
WRITE_8(address, (zuint8)value);
|
|
WRITE_8(address + 1, value >> 8);
|
|
}
|
|
|
|
|
|
#define READ_16( address) read_16bit (object, (zuint16)(address))
|
|
#define WRITE_16(address, value) write_16bit(object, (zuint16)(address), (zuint16)(value))
|
|
|
|
|
|
/* MARK: - Macros: Registers */
|
|
|
|
#define AF object->state.Z_Z80_STATE_MEMBER_AF
|
|
#define BC object->state.Z_Z80_STATE_MEMBER_BC
|
|
#define DE object->state.Z_Z80_STATE_MEMBER_DE
|
|
#define HL object->state.Z_Z80_STATE_MEMBER_HL
|
|
#define IX object->state.Z_Z80_STATE_MEMBER_IX
|
|
#define IY object->state.Z_Z80_STATE_MEMBER_IY
|
|
#define PC object->state.Z_Z80_STATE_MEMBER_PC
|
|
#define SP object->state.Z_Z80_STATE_MEMBER_SP
|
|
#define AF_ object->state.Z_Z80_STATE_MEMBER_AF_
|
|
#define BC_ object->state.Z_Z80_STATE_MEMBER_BC_
|
|
#define DE_ object->state.Z_Z80_STATE_MEMBER_DE_
|
|
#define HL_ object->state.Z_Z80_STATE_MEMBER_HL_
|
|
|
|
#define A object->state.Z_Z80_STATE_MEMBER_A
|
|
#define F object->state.Z_Z80_STATE_MEMBER_F
|
|
#define B object->state.Z_Z80_STATE_MEMBER_B
|
|
#define C object->state.Z_Z80_STATE_MEMBER_C
|
|
#define L object->state.Z_Z80_STATE_MEMBER_L
|
|
#define I object->state.Z_Z80_STATE_MEMBER_I
|
|
#define R object->state.Z_Z80_STATE_MEMBER_R
|
|
#define R_ALL ((R & 127) | (R7 & 128))
|
|
|
|
|
|
/* MARK: - Macros: Internal State */
|
|
|
|
#define R7 object->r7
|
|
#define HALT object->state.Z_Z80_STATE_MEMBER_HALT
|
|
#define IFF1 object->state.Z_Z80_STATE_MEMBER_IFF1
|
|
#define IFF2 object->state.Z_Z80_STATE_MEMBER_IFF2
|
|
#define EI object->state.Z_Z80_STATE_MEMBER_EI
|
|
#define IM object->state.Z_Z80_STATE_MEMBER_IM
|
|
#define NMI object->state.Z_Z80_STATE_MEMBER_NMI
|
|
#define INT object->state.Z_Z80_STATE_MEMBER_IRQ
|
|
#define CYCLES object->cycles
|
|
|
|
|
|
/* MARK: - Macros: Cached Instruction Data */
|
|
|
|
#define BYTE(index) object->data.array_uint8[index]
|
|
#define BYTE0 BYTE(0)
|
|
#define BYTE1 BYTE(1)
|
|
#define BYTE2 BYTE(2)
|
|
#define BYTE3 BYTE(3)
|
|
|
|
|
|
/* MARK: - Macros: Memory Addressing */
|
|
|
|
#define XY object->xy.value_uint16
|
|
#define XY_ADDRESS ((zuint16)(XY + object->data.array_sint8[2]))
|
|
|
|
|
|
/* MARK: - Macros: Flags */
|
|
|
|
#define SF 128
|
|
#define ZF 64
|
|
#define YF 32
|
|
#define HF 16
|
|
#define XF 8
|
|
#define PF 4
|
|
#define NF 2
|
|
#define CF 1
|
|
|
|
#define SZPF (SF | ZF | PF)
|
|
#define SYXF (SF | YF | XF)
|
|
#define ZPF (ZF | PF )
|
|
#define YXCF (YF | XF | CF)
|
|
#define YXF (YF | XF )
|
|
#define PNF (PF | NF )
|
|
#define HCF (HF | CF )
|
|
|
|
#define F_H (F & HF)
|
|
#define F_N (F & NF)
|
|
#define F_C (F & CF)
|
|
#define F_SZP (F & SZPF)
|
|
#define A_SYX (A & SYXF)
|
|
#define A_YX (A & YXF)
|
|
|
|
#define ZF_ZERO(value) (!(value) << 6)
|
|
|
|
|
|
/* MARK: - P/V Flag Computation */
|
|
|
|
static zuint8 const pf_parity_table[256] = {
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
/* 0 */ 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
|
|
/* 1 */ 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
|
|
/* 2 */ 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
|
|
/* 3 */ 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
|
|
/* 4 */ 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
|
|
/* 5 */ 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
|
|
/* 6 */ 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
|
|
/* 7 */ 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
|
|
/* 8 */ 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
|
|
/* 9 */ 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
|
|
/* A */ 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
|
|
/* B */ 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
|
|
/* C */ 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
|
|
/* D */ 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
|
|
/* E */ 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
|
|
/* F */ 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4
|
|
};
|
|
|
|
#define PF_PARITY(value) pf_parity_table[value]
|
|
|
|
#define VF(function, operand) \
|
|
static Z_INLINE zuint8 pf_overflow_##function##8(zuint8 a, zuint8 b) \
|
|
{ \
|
|
zsint total = ((zsint)((zsint8)a)) operand ((zsint)((zsint8)b)); \
|
|
\
|
|
return total < -128 || total > 127 ? PF : 0; \
|
|
}
|
|
|
|
VF(add, +)
|
|
VF(sub, -)
|
|
|
|
#undef VF
|
|
#define VF(function, bits, type, operand, minimum, maximum) \
|
|
static Z_INLINE zuint8 pf_overflow_##function##bits(zuint##bits a, zuint##bits b, zuint8 carry) \
|
|
{ \
|
|
type total = ((type)((zsint##bits)a)) operand ((type)((zsint##bits)b)) operand carry; \
|
|
\
|
|
return total < minimum || total > maximum ? PF : 0; \
|
|
}
|
|
|
|
VF(adc, 8, zsint, +, -128, 127)
|
|
VF(sbc, 8, zsint, -, -128, 127)
|
|
VF(adc, 16, zsint32, +, -32768, 32767)
|
|
VF(sbc, 16, zsint32, -, -32768, 32767)
|
|
|
|
|
|
/* MARK: - 8-Bit Register Resolution
|
|
|
|
.----------. .---------. .-----------. .-----------.
|
|
| 76543210 | | X / Y | | J / K | | P / Q |
|
|
|----------| |---------| |-----------| |-----------|
|
|
| __xxx___ | | 000 = b | | 000 = b | | 000 = b |
|
|
| _____yyy | | 001 = c | | 001 = c | | 001 = c |
|
|
| __jjj___ | | 010 = d | | 010 = d | | 010 = d |
|
|
| _____kkk | | 011 = e | | 011 = e | | 011 = e |
|
|
| __ppp___ | | 100 = h | | 100 = ixh | | 100 = iyh |
|
|
| _____qqq | | 101 = l | | 101 = ixl | | 101 = iyl |
|
|
'----------' | 111 = a | | 111 = a | | 111 = a |
|
|
'---------' '-----------' '----------*/
|
|
|
|
static zuint8 const x_y_table[8] = {
|
|
O(state.Z_Z80_STATE_MEMBER_B),
|
|
O(state.Z_Z80_STATE_MEMBER_C),
|
|
O(state.Z_Z80_STATE_MEMBER_D),
|
|
O(state.Z_Z80_STATE_MEMBER_E),
|
|
O(state.Z_Z80_STATE_MEMBER_H),
|
|
O(state.Z_Z80_STATE_MEMBER_L),
|
|
0,
|
|
O(state.Z_Z80_STATE_MEMBER_A)
|
|
};
|
|
|
|
static zuint8 const j_k_p_q_table[8] = {
|
|
O(state.Z_Z80_STATE_MEMBER_B),
|
|
O(state.Z_Z80_STATE_MEMBER_C),
|
|
O(state.Z_Z80_STATE_MEMBER_D),
|
|
O(state.Z_Z80_STATE_MEMBER_E),
|
|
O(xy.values_uint8.index1 ),
|
|
O(xy.values_uint8.index0 ),
|
|
0,
|
|
O(state.Z_Z80_STATE_MEMBER_A)
|
|
};
|
|
|
|
#define R_8(name, table, offset, mask, shift) \
|
|
static Z_INLINE zuint8 *name(Z80 *object) \
|
|
{return ((zuint8 *)object) + table[(BYTE(offset) & mask) shift];}
|
|
|
|
R_8(__xxx___0, x_y_table, 0, 56, >> 3 )
|
|
R_8(__xxx___1, x_y_table, 1, 56, >> 3 )
|
|
R_8(_____yyy0, x_y_table, 0, 7, Z_EMPTY)
|
|
R_8(_____yyy1, x_y_table, 1, 7, Z_EMPTY)
|
|
R_8(_____yyy3, x_y_table, 3, 7, Z_EMPTY)
|
|
R_8(__jjj___ , j_k_p_q_table, 1, 56, >> 3 )
|
|
R_8(_____kkk , j_k_p_q_table, 1, 7, Z_EMPTY)
|
|
|
|
|
|
/* MARK: - 16-Bit Register Resolution
|
|
|
|
.----------. .---------. .---------. .---------.
|
|
| 76543210 | | S | | T | | W |
|
|
|----------| |---------| |---------| |---------|
|
|
| __ss____ | | 00 = bc | | 00 = bc | | 00 = bc |
|
|
| __tt____ | | 01 = de | | 01 = de | | 01 = de |
|
|
'----------' | 10 = hl | | 10 = hl | | 10 = XY |
|
|
| 11 = sp | | 11 = af | | 11 = sp |
|
|
'---------' '---------' '--------*/
|
|
|
|
static zuint8 const s_table[4] = {
|
|
O(state.Z_Z80_STATE_MEMBER_BC),
|
|
O(state.Z_Z80_STATE_MEMBER_DE),
|
|
O(state.Z_Z80_STATE_MEMBER_HL),
|
|
O(state.Z_Z80_STATE_MEMBER_SP)
|
|
};
|
|
|
|
static zuint8 const t_table[4] = {
|
|
O(state.Z_Z80_STATE_MEMBER_BC),
|
|
O(state.Z_Z80_STATE_MEMBER_DE),
|
|
O(state.Z_Z80_STATE_MEMBER_HL),
|
|
O(state.Z_Z80_STATE_MEMBER_AF)
|
|
};
|
|
|
|
static zuint8 const w_table[4] = {
|
|
O(state.Z_Z80_STATE_MEMBER_BC),
|
|
O(state.Z_Z80_STATE_MEMBER_DE),
|
|
O(xy ),
|
|
O(state.Z_Z80_STATE_MEMBER_SP)
|
|
};
|
|
|
|
#define R_16(name, table, offset) \
|
|
static Z_INLINE zuint16 *name(Z80 *object) \
|
|
{return Z_BOP(zuint16 *, object, table[(BYTE(offset) & 48) >> 4]);}
|
|
|
|
R_16(__ss____0, s_table, 0)
|
|
R_16(__ss____1, s_table, 1)
|
|
R_16(__tt____ , t_table, 0)
|
|
|
|
|
|
/* MARK: - Condition Resolution
|
|
|
|
.----------. .----------.
|
|
| 76543210 | | Z |
|
|
|----------| |----------|
|
|
| __zzz___ | | 000 = nz |
|
|
| ___zz___ | | 001 = z |
|
|
'----------' | 010 = nc |
|
|
| 011 = c |
|
|
| 100 = po |
|
|
| 101 = pe |
|
|
| 110 = p |
|
|
| 111 = m |
|
|
'---------*/
|
|
|
|
static zuint8 const z_table[8] = {ZF, ZF, CF, CF, PF, PF, SF, SF};
|
|
|
|
static Z_INLINE zboolean __zzz___(Z80 *object)
|
|
{
|
|
zuint8 z = (BYTE0 & 56) >> 3;
|
|
|
|
return (F & (z_table[z]))
|
|
? (z & 1) /* Flag is 1 */
|
|
: !(z & 1); /* Flag is 0 */
|
|
}
|
|
|
|
|
|
/* MARK: - 8-Bit Arithmetic and Logical Operation Resolution and Execution
|
|
|
|
.----------. .-----------. .-------------------------------.
|
|
| 76543210 | | U | | S | Z | Y | H | X | P | N | C |
|
|
|----------| |-----------| .-----+---+---+---+---+---+---+---+---|
|
|
| __uuu___ | | 000 = add | | add | S | Z | 5 | H | 3 | V | 0 | C |
|
|
| _____vvv | | 001 = adc | |-----+---+---+---+---+---+---+---+---|
|
|
'----------' | 010 = sub | | adc | S | Z | 5 | H | 3 | V | 0 | C |
|
|
| 011 = sbc | |-----+---+---+---+---+---+---+---+---|
|
|
| 100 = and | | sub | S | Z | 5 | H | 3 | V | 1 | C |
|
|
| 101 = xor | |-----+---+---+---+---+---+---+---+---|
|
|
| 110 = or | | sbc | S | Z | 5 | H | 3 | V | 1 | C |
|
|
| 111 = cp | |-----+---+---+---+---+---+---+---+---|
|
|
|-----------| | and | S | Z | 5 | 1 | 3 | P | 0 | 0 |
|
|
| V | |-----+---+---+---+---+---+---+---+---|
|
|
|-----------| | xor | S | Z | 5 | 0 | 3 | P | 0 | 0 |
|
|
| 100 = inc | |-----+---+---+---+---+---+---+---+---|
|
|
| 101 = dec | | or | S | Z | 5 | 0 | 3 | P | 0 | 0 |
|
|
'-----------' |-----+---+---+---+---+---+---+---+---|
|
|
| cp | S | Z |v.5| H |v.3| V | 1 | C |
|
|
|-----+---+---+---+---+---+---+---+---|
|
|
| inc | S | Z |v.5| H |v.3| V | 0 | . |
|
|
|-----+---+---+---+---+---+---+---+---|
|
|
| dec | S | Z |v.5| H |v.3| V | 1 | . |
|
|
'------------------------------------*/
|
|
|
|
static void __uuu___(Z80 *object, zuint8 offset, zuint8 value)
|
|
{
|
|
zuint8 t;
|
|
|
|
switch ((object->data.array_uint8[offset] >> 3) & 7)
|
|
{
|
|
case 0: /* ADD */
|
|
t = A + value;
|
|
|
|
F = ((zuint)A + value > 255) /* CF = Carry */
|
|
| pf_overflow_add8(A, value) /* PF = Overflow */
|
|
| ((A ^ value ^ t) & HF); /* HF = Half-carry */
|
|
A = t; /* NF = 0 */
|
|
break;
|
|
|
|
case 1: /* ADC */
|
|
t = F_C;
|
|
|
|
F = ((zuint)A + value + t > 255) /* CF = Carry */
|
|
| pf_overflow_adc8(A, value, t) /* PF = Overflow */
|
|
| (((A & 0xF) + (value & 0xF) + t) & HF); /* HF = Half-carry */
|
|
/* NF = 0 */
|
|
A += value + t;
|
|
break;
|
|
|
|
case 2: /* SUB */
|
|
t = A - value;
|
|
|
|
F = (A < value) /* CF = Borrow */
|
|
| NF /* NF = 1 */
|
|
| pf_overflow_sub8(A, value) /* PF = Overflow */
|
|
| ((A ^ value ^ t) & HF); /* HF = Half-Borrow */
|
|
A = t;
|
|
break;
|
|
|
|
case 3: /* SBC */
|
|
t = F_C;
|
|
|
|
F = ((zsint)A - (zsint)value - (zsint)t < 0) /* CF = Borrow */
|
|
| NF /* NF = 1 */
|
|
| pf_overflow_sbc8(A, value, t) /* PF = Overflow */
|
|
| (((A & 0xF) - (value & 0xF) - t) & HF); /* HF = Half-Borrow */
|
|
|
|
A -= value + t;
|
|
break;
|
|
|
|
case 4: /* AND */
|
|
A &= value;
|
|
F = HF | PF_PARITY(A); /* HF = 1; PF = Parity */
|
|
break; /* NF, CF = 0 */
|
|
|
|
case 5: /* XOR */
|
|
A ^= value;
|
|
F = PF_PARITY(A); /* PF = Parity */
|
|
break; /* HF, NF, CF = 0 */
|
|
|
|
case 6: /* OR */
|
|
A |= value;
|
|
F = PF_PARITY(A); /* PF = Parity */
|
|
break; /* HF, NF, CF = 0 */
|
|
|
|
case 7: /* CP */
|
|
t = A - value;
|
|
|
|
F = (zuint8)
|
|
((A < value) /* CF = Borrow */
|
|
| NF /* NF = 1 */
|
|
| pf_overflow_sub8(A, value) /* PF = Overflow */
|
|
| ((A ^ value ^ t) & HF) /* HF = Half-Borrow */
|
|
| (value & YXF) /* YF = v.5, XF = v.3 */
|
|
| ZF_ZERO(t) /* ZF = !(A - v) */
|
|
| (t & SF)); /* SF = (A - v).7 */
|
|
return;
|
|
}
|
|
|
|
F = (zuint8)
|
|
((F & (HF | PF | NF | CF)) /* CF, NF, PF and HF already changed */
|
|
| A_SYX /* SF = A.7; YF = A.5; XF = A.3 */
|
|
| ZF_ZERO(A)); /* ZF = !A */
|
|
}
|
|
|
|
|
|
static zuint8 _____vvv(Z80 *object, zuint8 offset, zuint8 value)
|
|
{
|
|
zuint8 t, pn;
|
|
|
|
/* DEC */
|
|
if (object->data.array_uint8[offset] & 1)
|
|
{ /* PF = Overflow */
|
|
pn = value == 128 ? PNF : NF; /* NF = 1 */
|
|
t = value - 1;
|
|
}
|
|
|
|
/* INC */
|
|
else { /* PF = Overflow */
|
|
pn = value == 127 ? PF : 0; /* NF = 0 */
|
|
t = value + 1;
|
|
}
|
|
|
|
F = (zuint8)
|
|
((F & CF) /* CF unchanged */
|
|
| pn /* PF and NF already calculated */
|
|
| (t & SYXF) /* SF = v.7; YF = v.5; XF = v.3 */
|
|
| ((value ^ 1 ^ t) & HF) /* HF = Half-Borrow */
|
|
| ZF_ZERO(t)); /* ZF = !v */
|
|
|
|
return t;
|
|
}
|
|
|
|
|
|
/* MARK: - Rotation and Shift Operation Resolution and Execution
|
|
|
|
.----------. .-----------.
|
|
| 76543210 | | G |
|
|
|----------| |-----------|
|
|
| __ggg___ | | 000 = rlc |
|
|
'----------' | 001 = rrc |
|
|
| 010 = rl |
|
|
| 011 = rr |
|
|
| 100 = sla |
|
|
| 101 = sra |
|
|
| 110 = sll |
|
|
| 111 = srl |
|
|
'----------*/
|
|
|
|
static zuint8 __ggg___(Z80 *object, zuint8 offset, zuint8 value)
|
|
{
|
|
zuint8 c;
|
|
|
|
switch ((object->data.array_uint8[offset] >> 3) & 7)
|
|
{
|
|
/* RLC .----------------.
|
|
.----. | .---------. |
|
|
| CF |<-----| 7 <-- 0 |<--'
|
|
'----' '--------*/
|
|
case 0:
|
|
ROL(value);
|
|
c = value & CF;
|
|
break;
|
|
|
|
/* RRC .----------------.
|
|
| .---------. | .----.
|
|
'-->| 7 --> 0 |----->| CF |
|
|
'---------' '---*/
|
|
case 1:
|
|
c = value & CF;
|
|
ROR(value);
|
|
break;
|
|
|
|
/* RL .-------------------------.
|
|
| .----. .---------. |
|
|
'--| CF |<--| 7 <-- 0 |<--'
|
|
'----' '--------*/
|
|
case 2:
|
|
c = value >> 7;
|
|
value = (zuint8)((value << 1) | F_C);
|
|
break;
|
|
|
|
/* RR .-------------------------.
|
|
| .---------. .----. |
|
|
'-->| 7 --> 0 |-->| CF |--'
|
|
'---------' '---*/
|
|
case 3:
|
|
c = value & CF;
|
|
value = (zuint8)((value >> 1) | (F_C << 7));
|
|
break;
|
|
|
|
/* SLA .----. .---------.
|
|
| CF |<--| 7 <-- 0 |<-- 0
|
|
'----' '--------*/
|
|
case 4:
|
|
c = value >> 7;
|
|
value <<= 1;
|
|
break;
|
|
|
|
/* SRA .---------. .----.
|
|
.-->| 7 --> 0 |-->| CF |
|
|
| '---------' '----'
|
|
| |
|
|
'----*/
|
|
case 5:
|
|
c = value & CF;
|
|
value = (value & 128) | (value >> 1);
|
|
break;
|
|
|
|
/* SLL .----. .---------.
|
|
| CF |<--| 7 <-- 0 |<-- 1
|
|
'----' '--------*/
|
|
case 6:
|
|
c = value >> 7;
|
|
value = (value << 1) & 1;
|
|
break;
|
|
|
|
/* SRL .---------. .----.
|
|
0 -->| 7 --> 0 |-->| CF |
|
|
'---------' '---*/
|
|
case 7:
|
|
c = value & CF;
|
|
value >>= 1;
|
|
break;
|
|
|
|
/* Uncoment to Avoid a compiler warning */
|
|
/*default: c = 0; break;*/
|
|
}
|
|
|
|
F = (zuint8)((value & SYXF) | ZF_ZERO(value) | PF_PARITY(value) | c);
|
|
return value;
|
|
}
|
|
|
|
|
|
/* MARK: - Bit Set and Reset Operation Resolution and Execution
|
|
|
|
.----------. .---------.
|
|
| 76543210 | | M |
|
|
|----------| |---------|
|
|
| _m______ | | 0 = res |
|
|
'----------' | 1 = set |
|
|
'--------*/
|
|
|
|
static Z_INLINE zuint8 _m______(Z80 *object, zuint8 offset, zuint8 value)
|
|
{
|
|
zuint8 t = object->data.array_uint8[offset];
|
|
|
|
return (zuint8)((t & 64)
|
|
? value | (1 << ((t & 56) >> 3)) /* SET */
|
|
: value & ~(1 << ((t & 56) >> 3))); /* RES */
|
|
}
|
|
|
|
|
|
/* MARK: - Macros: Shortening */
|
|
|
|
#define N(x) ((BYTE##x & 56) >> 3)
|
|
#define X0 (*__xxx___0(object))
|
|
#define X1 (*__xxx___1(object))
|
|
#define Y0 (*_____yyy0(object))
|
|
#define Y1 (*_____yyy1(object))
|
|
#define Y3 (*_____yyy3(object))
|
|
#define JP (*__jjj___ (object))
|
|
#define KQ (*_____kkk (object))
|
|
#define SS0 (*__ss____0(object))
|
|
#define SS1 (*__ss____1(object))
|
|
#define TT (*__tt____ (object))
|
|
#define Z __zzz___ (object)
|
|
#define U0(value) __uuu___ (object, 0, value)
|
|
#define U1(value) __uuu___ (object, 1, value)
|
|
#define V0(value) _____vvv (object, 0, value)
|
|
#define V1(value) _____vvv (object, 1, value)
|
|
#define G1(value) __ggg___ (object, 1, value)
|
|
#define G3(value) __ggg___ (object, 3, value)
|
|
#define M1(value) _m______ (object, 1, value)
|
|
#define M3(value) _m______ (object, 3, value)
|
|
#define WW (*Z_BOP(zuint16 *, object, w_table[(BYTE1 >> 4) & 3]))
|
|
|
|
|
|
/* MARK: - Macros & Functions: Reusable Code */
|
|
|
|
#define INSTRUCTION(name) static zuint8 name(Z80 *object)
|
|
#define EXIT_HALT if (HALT) {PC++; HALT = FALSE; CLEAR_HALT;}
|
|
#define PUSH(value) WRITE_16(SP -= 2, value)
|
|
|
|
|
|
#define LD_A_I_LD_A_R \
|
|
F = (zuint8) /* HF = 0 / NF = 0 */ \
|
|
(A_SYX /* SF = A.7; YF = A.5; XF = A.3 */ \
|
|
| ZF_ZERO(A) /* ZF = !A */ \
|
|
| (IFF2 << 2) /* PF = IFF2 */ \
|
|
| F_C); /* CF unchanged */
|
|
|
|
|
|
#define EX(a, b) t = a; a = b; b = t;
|
|
|
|
|
|
#define EX_VSP_X(register) \
|
|
t = READ_16(SP); \
|
|
WRITE_16(SP, register); \
|
|
register = t;
|
|
|
|
|
|
#define LDX(operator) \
|
|
zuint8 n; \
|
|
\
|
|
PC += 2; \
|
|
WRITE_8(DE operator, n = READ_8(HL operator)); \
|
|
n += A; \
|
|
\
|
|
F = (zuint8) /* HF = 0, NF = 0 */ \
|
|
((F & (SF | ZF | CF)) /* SF, ZF, CF unchanged */ \
|
|
| ((n & 2) << 4) /* YF = ([HL] + A).1 */ \
|
|
| (n & XF) /* XF = ([HL] + A).3 */ \
|
|
| (!!(--BC) << 2)); /* PF = 1 if BC != 0, else PF = 0 */
|
|
|
|
|
|
#define LDXR(operator) \
|
|
LDX(operator) \
|
|
if (!BC) return 16; \
|
|
PC -= 2; return 21;
|
|
|
|
|
|
#define CPX(operator) \
|
|
zuint8 v, n0, n1; \
|
|
\
|
|
PC += 2; \
|
|
n1 = (n0 = A - (v = READ_8(HL operator))) - !!F_H; \
|
|
\
|
|
F = (zuint8) \
|
|
((n0 & SF) /* SF = (A - [HL]).7 */ \
|
|
| ZF_ZERO(n0) /* ZF = !(A - [HL]) */ \
|
|
| ((A ^ v ^ n0) & HF) /* HF = borrow from bit 5 */ \
|
|
| ((n1 & 2) << 4) /* YF = (A - [HL] - HF).1 */ \
|
|
| (n1 & XF) /* XF = (A - [HL] - HF).3 */ \
|
|
| (!!(--BC) << 2) /* PF = !!BC */ \
|
|
| NF /* NF = 1 */ \
|
|
| F_C); /* CF unchanged */
|
|
|
|
|
|
#define CPXR(operator) \
|
|
CPX(operator) \
|
|
if (!BC || !n0) return 16; \
|
|
PC -= 2; return 21;
|
|
|
|
|
|
static Z_INLINE void add_RR_NN(Z80 *object, zuint16 *r, zuint16 v)
|
|
{
|
|
zuint16 t = *r + v;
|
|
|
|
F = F_SZP /* SF, ZF, PF unchanged */
|
|
| ((t >> 8) & YXF) /* YF = RR.13; XF = RR.11 */
|
|
| (((*r ^ v ^ t) >> 8) & HF) /* HF = RRh half-carry */
|
|
| ((zuint32)*r + v > 65535); /* CF = Carry */
|
|
*r = t; /* NF = 0 */
|
|
}
|
|
|
|
|
|
#define ADD_RR_NN(register, value) \
|
|
add_RR_NN(object, (zuint16 *)®ister, value);
|
|
|
|
|
|
#define ADC_SBC_HL_SS(function, sign, cf_test, set_nf) \
|
|
zuint8 c = F_C; \
|
|
zuint16 v = SS1, t = HL sign v sign c; \
|
|
\
|
|
F = (zuint8) \
|
|
(((t >> 8) & SYXF) /* SF = HL.15; YF = HL.13; XF = HL.11 */ \
|
|
| ZF_ZERO(t) /* ZF = !HL */ \
|
|
| ((((HL & 0xFFF) sign (v & 0xFFF) sign c) >> 8) & HF) /* HF = Half-carry of H */ \
|
|
| pf_overflow_##function##16(HL, v, c) /* PF = Overflow */ \
|
|
| !!(cf_test) /* CF = Carry */ \
|
|
set_nf); /* ADC: NF = 0; SBC: NF = 1 */ \
|
|
\
|
|
HL = t; \
|
|
PC += 2; \
|
|
return 15;
|
|
|
|
|
|
#define RXA \
|
|
F = F_SZP /* SF, ZF, PF unchanged */ \
|
|
| A_YX /* YF = A.5; XF = A.3 */ \
|
|
| c; /* CF = Ai.7 (rla) / Ai.0 (rra) */
|
|
|
|
|
|
#define RXD(a, b, c) \
|
|
zuint8 t; \
|
|
\
|
|
PC += 2; \
|
|
WRITE_8(HL, ((t = READ_8(HL)) a 4) | (A b)); \
|
|
A = (A & 0xF0) | (t c); \
|
|
\
|
|
F = (zuint8) \
|
|
(A_SYX /* SF = A.7; YF = A.5; XF = A.3 */ \
|
|
| ZF_ZERO(A) /* ZF = !A */ \
|
|
| PF_PARITY(A) /* PF = Parity of A */ \
|
|
| F_C); /* CF unchanged */ \
|
|
/* HF = 0, NF = 0; */
|
|
|
|
|
|
#define BIT_N_VALUE(value) \
|
|
zuint8 n = value & (1 << N(1)); /* SF = value.N && N == 7 */ \
|
|
/* ZF, PF = !value.N */ \
|
|
F = (n ? n & SYXF : ZPF) /* YF = value.N && N == 5 */ \
|
|
| HF /* HF = 1; NF = 0; CF unchanged */ \
|
|
| F_C; /* XF = value.N && N == 3 */
|
|
|
|
|
|
#define BIT_N_VADDRESS(address) \
|
|
Z16Bit a; \
|
|
zuint8 n = READ_8(a.value_uint16 = address) & (1 << N(3)); \
|
|
\
|
|
F = (n ? (n & SF) : ZPF) \
|
|
| (a.values_uint8.index1 & YXF) \
|
|
| HF \
|
|
| F_C;
|
|
|
|
|
|
#define IN_VC \
|
|
zuint8 t; \
|
|
\
|
|
PC += 2; \
|
|
t = IN(BC); \
|
|
\
|
|
F = (zuint8) \
|
|
((t & SYXF) \
|
|
| ZF_ZERO(t) \
|
|
| PF_PARITY(t) \
|
|
| F_C);
|
|
|
|
|
|
#define INX(hl_operator, c_operator) \
|
|
zuint8 v; \
|
|
zuint t; \
|
|
\
|
|
PC += 2; \
|
|
t = (zuint)(v = IN(BC)) + ((C c_operator 1) & 255); \
|
|
WRITE_8(HL, v); \
|
|
HL hl_operator; \
|
|
B--; \
|
|
\
|
|
F = (zuint8) \
|
|
((B & SYXF) /* SF = (B - 1).7; YF = (B - 1).5; XF = (B - 1).3 */ \
|
|
| ZF_ZERO(B) /* ZF = !(B - 1) */ \
|
|
| PF_PARITY((t & 7) ^ B) /* PF = Parity of (([HL] + ((C +/- 1) & 255)) and 7) xor B */ \
|
|
| (v & 128)); /* NF = IN(BC).7 */ \
|
|
/* if (([HL] + ((C +/- 1) & 255)) > 255) HF = 1; else HF = 0 */ \
|
|
if (t > 255) F |= HCF; /* if (([HL] + ((C +/- 1) & 255)) > 255) HF = 1; else HF = 0 */
|
|
|
|
|
|
#define INXR(hl_operator, c_operator) \
|
|
INX(hl_operator, c_operator); \
|
|
if (!B) return 16; \
|
|
PC -= 2; return 21;
|
|
|
|
|
|
#define OUTX(operator) \
|
|
zuint8 t; \
|
|
\
|
|
PC += 2; \
|
|
OUT(BC, t = READ_8(HL)); \
|
|
HL operator; \
|
|
B--; \
|
|
\
|
|
F = (zuint8) \
|
|
((B & SYXF) /* SF = (B - 1).7; YF = (B - 1).5; XF = (B - 1).3 */ \
|
|
| ZF_ZERO(B) /* ZF = !(B - 1) */ \
|
|
| PF_PARITY(((L + t) & 7) ^ B) /* PF = Parity of ((L + [HL]) and 7) xor B */ \
|
|
| (t & 128)); /* NF = IN(BC).7 */ \
|
|
/* if (L + [HL] > 255) HF = 1; else HF = 0 */ \
|
|
if ((zuint)t + L > 255) F |= HCF; /* if (L + [HL] > 255) CF = 1; else CF = 0 */
|
|
|
|
|
|
#define OTXR(operator) \
|
|
OUTX(operator); \
|
|
if (!B) return 16; \
|
|
PC -= 2; return 21;
|
|
|
|
|
|
#define RET PC = READ_16(SP); SP += 2;
|
|
|
|
|
|
/* MARK: - Instructions: 8-Bit Load Group
|
|
.---------------------------------------------------------------------------.
|
|
| 0 1 2 3 Flags |
|
|
| Assembly 76543210765432107654321076543210 szyhxpnc Cycles |
|
|
| ----------------------------------------------------------------------- |
|
|
| ld X,Y 01xxxyyy ........ 1 / 4 |
|
|
| ld J,K < DD >01jjjkkk ........ 2 / 8 |
|
|
| ld P,Q < FD >01pppqqq ........ 2 / 8 |
|
|
| ld X,BYTE 00xxx110< BYTE > ........ 2 / 7 |
|
|
| ld J,BYTE < DD >00jjj110< BYTE > ........ 3 / 11 |
|
|
| ld P,BYTE < FD >00ppp110< BYTE > ........ 3 / 11 |
|
|
| ld X,(hl) 01xxx110 ........ 2 / 7 |
|
|
| ld X,(ix+OFFSET) < DD >01xxx110<OFFSET> ........ 5 / 19 |
|
|
| ld X,(iy+OFFSET) < FD >01xxx110<OFFSET> ........ 5 / 19 |
|
|
| ld (hl),Y 01110yyy ........ 2 / 7 |
|
|
| ld (ix+OFFSET),Y < DD >01110yyy<OFFSET> ........ 5 / 19 |
|
|
| ld (iy+OFFSET),Y < FD >01110yyy<OFFSET> ........ 5 / 19 |
|
|
| ld (hl),BYTE < 36 >< BYTE > ........ 3 / 10 |
|
|
| ld (ix+OFFSET),BYTE < DD >< 36 ><OFFSET>< BYTE > ........ 5 / 19 |
|
|
| ld (iy+OFFSET),BYTE < FD >< 36 ><OFFSET>< BYTE > ........ 5 / 19 |
|
|
| ld a,(bc) < 0A > ........ 2 / 7 |
|
|
| ld a,(de) < 1A > ........ 2 / 7 |
|
|
| ld a,(WORD) < 3A >< WORD > ........ 4 / 13 |
|
|
| ld (bc),a < 02 > ........ 2 / 7 |
|
|
| ld (de),a < 12 > ........ 2 / 7 |
|
|
| ld (WORD),a < 32 >< WORD > ........ 4 / 13 |
|
|
| ld a,i < ED >< 57 > szy0xi0. 2 / 9 |
|
|
| ld a,r < ED >< 5F > szy0xi0. 2 / 9 |
|
|
| ld i,a < ED >< 47 > ........ 2 / 9 |
|
|
| ld r,a < ED >< 4F > ........ 2 / 9 |
|
|
'--------------------------------------------------------------------------*/
|
|
|
|
INSTRUCTION(ld_X_Y) {PC++; X0 = Y0; return 4;}
|
|
INSTRUCTION(ld_JP_KQ) {PC += 2; JP = KQ; return 8;}
|
|
INSTRUCTION(ld_X_BYTE) {X0 = READ_8((PC += 2) - 1); return 7;}
|
|
INSTRUCTION(ld_JP_BYTE) {JP = READ_8((PC += 3) - 1); return 11;}
|
|
INSTRUCTION(ld_X_vhl) {PC++; X0 = READ_8(HL); return 7;}
|
|
INSTRUCTION(ld_X_vXYOFFSET) {X1 = READ_8(XY + READ_OFFSET((PC += 3) - 1)); return 19;}
|
|
INSTRUCTION(ld_vhl_Y) {PC++; WRITE_8(HL, Y0); return 7;}
|
|
INSTRUCTION(ld_vXYOFFSET_Y) {WRITE_8(XY + READ_OFFSET((PC += 3) - 1), Y1); return 19;}
|
|
INSTRUCTION(ld_vhl_BYTE) {WRITE_8(HL, READ_8((PC += 2) - 1)); return 10;}
|
|
INSTRUCTION(ld_vXYOFFSET_BYTE) {PC += 4; WRITE_8(XY + READ_OFFSET(PC - 2), READ_8(PC - 1)); return 19;}
|
|
INSTRUCTION(ld_a_vbc) {PC++; A = READ_8(BC); return 7;}
|
|
INSTRUCTION(ld_a_vde) {PC++; A = READ_8(DE); return 7;}
|
|
INSTRUCTION(ld_a_vWORD) {A = READ_8(READ_16((PC += 3) - 2)); return 13;}
|
|
INSTRUCTION(ld_vbc_a) {PC++; WRITE_8(BC, A); return 7;}
|
|
INSTRUCTION(ld_vde_a) {PC++; WRITE_8(DE, A); return 7;}
|
|
INSTRUCTION(ld_vWORD_a) {WRITE_8(READ_16((PC += 3) - 2), A); return 13;}
|
|
INSTRUCTION(ld_a_i) {PC += 2; A = I; LD_A_I_LD_A_R; return 9;}
|
|
INSTRUCTION(ld_a_r) {PC += 2; A = R_ALL; LD_A_I_LD_A_R; return 9;}
|
|
INSTRUCTION(ld_i_a) {PC += 2; I = A; return 9;}
|
|
INSTRUCTION(ld_r_a) {PC += 2; R = R7 = A; return 9;}
|
|
|
|
|
|
/* MARK: - Instructions: 16-Bit Load Group
|
|
.---------------------------------------------------------------------------.
|
|
| 0 1 2 3 Flags |
|
|
| Assembly 76543210765432107654321076543210 szyhxpnc Cycles |
|
|
| ----------------------------------------------------------------------- |
|
|
| ld SS,WORD 00ss0001< WORD > ........ 3 / 10 |
|
|
| ld ix,WORD < DD >< 21 >< WORD > ........ 4 / 14 |
|
|
| ld iy,WORD < FD >< 21 >< WORD > ........ 4 / 14 |
|
|
| ld hl,(WORD) < 2A >< WORD > ........ 5 / 16 |
|
|
| ld SS,(WORD) < ED >01ss1011< WORD > ........ 6 / 20 |
|
|
| ld ix,(WORD) < DD >< 2A >< WORD > ........ 6 / 20 |
|
|
| ld iy,(WORD) < FD >< 2A >< WORD > ........ 6 / 20 |
|
|
| ld (WORD),hl < 22 >< WORD > ........ 5 / 16 |
|
|
| ld (WORD),SS < ED >01ss0011< WORD > ........ 6 / 20 |
|
|
| ld (WORD),ix < DD >< 22 >< WORD > ........ 6 / 20 |
|
|
| ld (WORD),iy < FD >< 22 >< WORD > ........ 6 / 20 |
|
|
| ld sp,hl < F9 > ........ 1 / 6 |
|
|
| ld sp,ix < DD >< F9 > ........ 2 / 10 |
|
|
| ld sp,iy < FD >< F9 > ........ 2 / 10 |
|
|
| push TT 11tt0101 ........ 3 / 11 |
|
|
| push ix < DD >< E5 > ........ 4 / 15 |
|
|
| push iy < FD >< E5 > ........ 4 / 15 |
|
|
| pop TT 11tt0001 ........ 3 / 10 |
|
|
| pop ix < DD >< E1 > ........ 4 / 14 |
|
|
| pop iy < FD >< E1 > ........ 4 / 14 |
|
|
'--------------------------------------------------------------------------*/
|
|
|
|
INSTRUCTION(ld_SS_WORD) {SS0 = READ_16((PC += 3) - 2); return 10;}
|
|
INSTRUCTION(ld_XY_WORD) {XY = READ_16((PC += 4) - 2); return 14;}
|
|
INSTRUCTION(ld_hl_vWORD) {HL = READ_16(READ_16((PC += 3) - 2)); return 16;}
|
|
INSTRUCTION(ld_SS_vWORD) {SS1 = READ_16(READ_16((PC += 4) - 2)); return 20;}
|
|
INSTRUCTION(ld_XY_vWORD) {XY = READ_16(READ_16((PC += 4) - 2)); return 20;}
|
|
INSTRUCTION(ld_vWORD_hl) {WRITE_16(READ_16((PC += 3) - 2), HL); return 16;}
|
|
INSTRUCTION(ld_vWORD_SS) {WRITE_16(READ_16((PC += 4) - 2), SS1); return 20;}
|
|
INSTRUCTION(ld_vWORD_XY) {WRITE_16(READ_16((PC += 4) - 2), XY); return 20;}
|
|
INSTRUCTION(ld_sp_hl) {PC++; SP = HL; return 6;}
|
|
INSTRUCTION(ld_sp_XY) {PC += 2; SP = XY; return 10;}
|
|
INSTRUCTION(push_TT) {PC++; WRITE_16(SP -= 2, TT); return 11;}
|
|
INSTRUCTION(push_XY) {PC += 2; WRITE_16(SP -= 2, XY); return 15;}
|
|
INSTRUCTION(pop_TT) {PC++; TT = READ_16(SP); SP += 2; return 10;}
|
|
INSTRUCTION(pop_XY) {PC += 2; XY = READ_16(SP); SP += 2; return 14;}
|
|
|
|
|
|
/* MARK: - Instructions: Exchange, Block Transfer and Search Groups
|
|
.--------------------------------------------------------------------------------.
|
|
| 0 1 2 3 Flags |
|
|
| Assembly 76543210765432107654321076543210 szyhxpnc Cycles |
|
|
| ---------------------------------------------------------------------------- |
|
|
| ex de,hl < EB > ........ 1 / 4 |
|
|
| ex af,af' < 08 > ........ 1 / 4 |
|
|
| exx < D9 > ........ 1 / 4 |
|
|
| ex (sp),hl < E3 > ........ 5 / 19 |
|
|
| ex (sp),ix < DD >< E3 > ........ 6 / 23 |
|
|
| ex (sp),iy < FD >< E3 > ........ 6 / 23 |
|
|
| ldi < ED >< A0 > ..*0**0. 4 / 16 |
|
|
| ldir < ED >< B0 > ..*0*00. 5,4 / 21,16 |
|
|
| ldd < ED >< A8 > ..*0**0. 4 / 16 |
|
|
| lddr < ED >< B8 > ..*0*00. 5,4 / 21,16 |
|
|
| cpi < ED >< A1 > ******1. 4 / 16 |
|
|
| cpir < ED >< B1 > ******1. 5,4 / 21,16 |
|
|
| cpd < ED >< A9 > ******1. 4 / 16 |
|
|
| cpdr < ED >< B9 > ******1. 5,4 / 21,16 |
|
|
'-------------------------------------------------------------------------------*/
|
|
|
|
INSTRUCTION(ex_de_hl) {zuint16 t; PC++; EX(DE, HL) return 4;}
|
|
INSTRUCTION(ex_af_af_) {zuint16 t; PC++; EX(AF, AF_) return 4;}
|
|
INSTRUCTION(exx) {zuint16 t; PC++; EX(BC, BC_) EX(DE, DE_) EX(HL, HL_) return 4;}
|
|
INSTRUCTION(ex_vsp_hl) {zuint16 t; PC++; EX_VSP_X(HL) return 19;}
|
|
INSTRUCTION(ex_vsp_XY) {zuint16 t; PC += 2; EX_VSP_X(XY) return 23;}
|
|
INSTRUCTION(ldi) {LDX (++) return 16;}
|
|
INSTRUCTION(ldir) {LDXR(++) }
|
|
INSTRUCTION(ldd) {LDX (--) return 16;}
|
|
INSTRUCTION(lddr) {LDXR(--) }
|
|
INSTRUCTION(cpi) {CPX (++) return 16;}
|
|
INSTRUCTION(cpir) {CPXR(++) }
|
|
INSTRUCTION(cpd) {CPX (--) return 16;}
|
|
INSTRUCTION(cpdr) {CPXR(--) }
|
|
|
|
|
|
/* MARK: - Instructions: 8-Bit Arithmetic and Logical Group
|
|
.---------------------------------------------------------------------------.
|
|
| 0 1 2 3 Flags |
|
|
| Assembly 76543210765432107654321076543210 szyhxpnc Cycles |
|
|
| ----------------------------------------------------------------------- |
|
|
| U [a,]Y 10uuuyyy sz5h3*** 1 / 4 |
|
|
| U [a,]K < DD >10uuukkk sz5h3*** 2 / 8 |
|
|
| U [a,]Q < FD >10uuuqqq sz5h3*** 2 / 8 |
|
|
| U [a,]BYTE 11uuu110< BYTE > sz5h3*** 2 / 7 |
|
|
| U [a,](hl) 10uuu110 sz5h3*** 2 / 7 |
|
|
| U [a,](ix+OFFSET) < DD >10uuu110<OFFSET> sz5h3*** 5 / 19 |
|
|
| U [a,](iy+OFFSET) < FD >10uuu110<OFFSET> sz5h3*** 5 / 19 |
|
|
| V X 00xxxvvv sz5h3v0. 1 / 4 |
|
|
| V J < DD >00jjjvvv sz5h3v0. 2 / 8 |
|
|
| V P < FD >00pppvvv sz5h3v0. 2 / 8 |
|
|
| V (hl) 00110vvv sz5h3v*. 3 / 11 |
|
|
| V (ix+OFFSET) < DD >00110vvv<OFFSET> sz5h3v*. 6 / 23 |
|
|
| V (iy+OFFSET) < FD >00110vvv<OFFSET> sz5h3v*. 6 / 23 |
|
|
'--------------------------------------------------------------------------*/
|
|
|
|
INSTRUCTION(U_a_Y) {PC++; U0(Y0); return 4;}
|
|
INSTRUCTION(U_a_KQ) {PC += 2; U1(KQ); return 8;}
|
|
INSTRUCTION(U_a_BYTE) {U0(READ_8((PC += 2) - 1)); return 7;}
|
|
INSTRUCTION(U_a_vhl) {PC++; U0(READ_8(HL)); return 7;}
|
|
INSTRUCTION(U_a_vXYOFFSET) {U1(READ_8(XY + READ_OFFSET((PC += 3) - 1))); return 19;}
|
|
INSTRUCTION(V_X) {zuint8 *r; PC++; r = __xxx___0(object); *r = V0(*r); return 4;}
|
|
INSTRUCTION(V_JP) {zuint8 *r; PC += 2; r = __jjj___ (object); *r = V1(*r); return 8;}
|
|
INSTRUCTION(V_vhl) {PC++; WRITE_8(HL, V0(READ_8(HL))); return 11;}
|
|
INSTRUCTION(V_vXYOFFSET) {zuint16 a = (zuint16)(XY + READ_OFFSET((PC += 3) - 1));
|
|
WRITE_8(a, V1(READ_8(a))); return 23;}
|
|
|
|
|
|
/* MARK: - Instructions: General-Purpose Arithmetic and CPU Control Group
|
|
.---------------------------------------------------------------------------.
|
|
| 0 1 2 3 Flags |
|
|
| Assembly 76543210765432107654321076543210 szyhxpnc Cycles |
|
|
| ----------------------------------------------------------------------- |
|
|
| nop < 00 > ........ 1 / 4 |
|
|
| halt < 76 > ........ 1 / 4 |
|
|
| di < F3 > ........ 1 / 4 |
|
|
| ei < FB > ........ 1 / 4 |
|
|
| im 0 < ED >< 46 > ........ 2 / 8 |
|
|
| < ED >< 4E > |
|
|
| < ED >< 66 > |
|
|
| < ED >< 6E > |
|
|
| im 1 < ED >< 56 > ........ 2 / 8 |
|
|
| < ED >< 76 > |
|
|
| im 2 < ED >< 5E > ........ 2 / 8 |
|
|
| < ED >< 7E > |
|
|
| daa < 27 > szyhxp.c 1 / 4 |
|
|
| cpl < 2F > ..y1x.1. 1 / 4 |
|
|
| neg < ED >< 44 > szyhxv1c 2 / 8 |
|
|
| < ED >< 4C > |
|
|
| < ED >< 54 > |
|
|
| < ED >< 5C > |
|
|
| < ED >< 64 > |
|
|
| < ED >< 6C > |
|
|
| < ED >< 74 > |
|
|
| < ED >< 7C > |
|
|
| ccf < 3F > ..***.0c 1 / 4 |
|
|
| scf < 37 > ..*0*.01 1 / 4 |
|
|
'--------------------------------------------------------------------------*/
|
|
|
|
INSTRUCTION(nop) {PC++; return 4;}
|
|
INSTRUCTION(halt) {HALT = 1; SET_HALT; return 4;}
|
|
INSTRUCTION(di) {PC++; IFF1 = IFF2 = 0; EI = TRUE; return 4;}
|
|
INSTRUCTION(ei) {PC++; IFF1 = IFF2 = 1; EI = TRUE; return 4;}
|
|
INSTRUCTION(im_0) {PC += 2; IM = 0; return 8;}
|
|
INSTRUCTION(im_1) {PC += 2; IM = 1; return 8;}
|
|
INSTRUCTION(im_2) {PC += 2; IM = 2; return 8;}
|
|
|
|
|
|
INSTRUCTION(daa)
|
|
{
|
|
zuint8 t = (F_H || (A & 0xF ) > 9) ? 6 : 0;
|
|
|
|
if (F_C || A > 0x99) t |= 0x60;
|
|
t = (F_N) ? A - t : A + t;
|
|
PC++;
|
|
|
|
F = (zuint8)
|
|
((F_N) /* NF unchanged */
|
|
| (t & SYXF) /* SF = A.7; YF = A.5; XF = A.3 */
|
|
| ZF_ZERO(t) /* ZF = !Af */
|
|
| ((A & HF) ^ (t & HF)) /* HF = Ai.4 xor Af.4 */
|
|
| PF_PARITY(t) /* PF = Parity of Af */
|
|
| (F_C | (A > 0x99))); /* CF = CF | (Ai > 0x99) */
|
|
|
|
A = t;
|
|
return 4;
|
|
}
|
|
|
|
|
|
INSTRUCTION(cpl)
|
|
{
|
|
PC++; A = ~A;
|
|
|
|
F = (F & (SF | ZF | PF | CF)) /* SF, ZF, PF, CF unchanged */
|
|
| HF /* HF = 1 */
|
|
| NF /* NF = 1 */
|
|
| A_YX; /* YF = A.5; XF = A.3 */
|
|
|
|
return 4;
|
|
}
|
|
|
|
|
|
INSTRUCTION(neg)
|
|
{
|
|
zuint8 t = -A; PC += 2;
|
|
|
|
F = (zuint8)
|
|
((t & SYXF) /* SF = -A.7; YF = -A.5; XF = -A.3 */
|
|
| ZF_ZERO(t) /* ZF = !-A */
|
|
| ((0 ^ A ^ t) & HF) /* HF = Half-borrow */
|
|
| ((t == 128) << 2) /* PF = Overflow */
|
|
| NF /* NF = 1 */
|
|
| !!A); /* CF = !!A */
|
|
|
|
A = t;
|
|
return 8;
|
|
}
|
|
|
|
|
|
INSTRUCTION(ccf)
|
|
{
|
|
PC++;
|
|
|
|
F = (zuint8)
|
|
(F_SZP /* SF, ZF, PF unchanged */
|
|
| A_YX /* YF = A.5; XF = A.3 */
|
|
| (F_C << 4) /* HF = CF */
|
|
| (~F & CF)); /* CF = ~CF */
|
|
/* NF = 0 */
|
|
return 4;
|
|
}
|
|
|
|
|
|
INSTRUCTION(scf)
|
|
{
|
|
PC++;
|
|
|
|
F = F_SZP /* SF, ZF, PF unchanged */
|
|
| A_YX /* YF = A.5; XF = A.3 */
|
|
| CF; /* CF = 1 */
|
|
/* HF = 0; NF = 0 */
|
|
return 4;
|
|
}
|
|
|
|
|
|
/* MARK: - Instructions: 16-Bit Arithmetic Group
|
|
.---------------------------------------------------------------------------.
|
|
| 0 1 2 3 Flags |
|
|
| Assembly 76543210765432107654321076543210 szyhxpnc Cycles |
|
|
| ----------------------------------------------------------------------- |
|
|
| add hl,SS 00ss1001 ..***.0* 3 / 11 |
|
|
| adc hl,SS < ED >01ss1010 *****v0* 4 / 15 |
|
|
| sbc hl,SS < ED >01ss0010 *****v0* 4 / 15 |
|
|
| add ix,WW < DD >00ww1001 ..***.0* 4 / 15 |
|
|
| add iy,WW < FD >00ww1001 ..***.0* 4 / 15 |
|
|
| inc SS 00ss0011 ........ 1 / 6 |
|
|
| inc ix < DD >< 23 > ........ 2 / 10 |
|
|
| inc iy < FD >< 23 > ........ 2 / 10 |
|
|
| dec SS 00ss1011 ........ 1 / 6 |
|
|
| dec ix < DD >< 2B > ........ 2 / 10 |
|
|
| dec iy < FD >< 2B > ........ 2 / 10 |
|
|
'--------------------------------------------------------------------------*/
|
|
|
|
INSTRUCTION(add_hl_SS) {PC++; ADD_RR_NN(HL, SS0) return 11;}
|
|
INSTRUCTION(adc_hl_SS) {ADC_SBC_HL_SS(adc, +, (zuint32)v + c + HL > 65535, Z_EMPTY)}
|
|
INSTRUCTION(sbc_hl_SS) {ADC_SBC_HL_SS(sbc, -, (zuint32)v + c > HL, | NF) }
|
|
INSTRUCTION(add_XY_WW) {PC += 2; ADD_RR_NN(XY, WW) return 15;}
|
|
INSTRUCTION(inc_SS) {PC++; SS0++; return 6;}
|
|
INSTRUCTION(inc_XY) {PC += 2; XY++; return 10;}
|
|
INSTRUCTION(dec_SS) {PC++; SS0--; return 6;}
|
|
INSTRUCTION(dec_XY) {PC += 2; XY--; return 15;}
|
|
|
|
|
|
/* MARK: - Instructions: Rotate and Shift Group
|
|
.---------------------------------------------------------------------------.
|
|
| 0 1 2 3 Flags |
|
|
| Assembly 76543210765432107654321076543210 szyhxpnc Cycles |
|
|
| ----------------------------------------------------------------------- |
|
|
| rlca < 07 > ..y0x.0c 1 / 4 |
|
|
| rla < 17 > ..y0x.0c 1 / 4 |
|
|
| rrca < 0F > ..y0x.0c 1 / 4 |
|
|
| rra < 1F > ..y0x.0c 1 / 4 |
|
|
| G Y < CB >00gggyyy szy0xp0c 2 / 8 |
|
|
| G (hl) < CB >00ggg110 szy0xp0c 4 / 15 |
|
|
| G (ix+OFFSET) < DD >< CB ><OFFSET>00ggg110 szy0xp0c 6 / 23 |
|
|
| G (iy+OFFSET) < FD >< CB ><OFFSET>00ggg110 szy0xp0c 6 / 23 |
|
|
| G (ix+OFFSET),Y < DD >< CB ><OFFSET>00gggyyy szy0xp0c 6 / 23 |
|
|
| G (iy+OFFSET),Y < FD >< CB ><OFFSET>00gggyyy szy0xp0c 6 / 23 |
|
|
| rld < ED >< 6F > szy0xp0. 5 / 18 |
|
|
| rrd < ED >< 67 > szy0xp0. 5 / 18 |
|
|
'--------------------------------------------------------------------------*/
|
|
|
|
INSTRUCTION(rlca) {PC++; ROL(A); F = F_SZP | (A & YXCF); return 4;}
|
|
INSTRUCTION(rla) {zuint8 c; PC++; c = A >> 7; A = (zuint8)((A << 1) | F_C); RXA return 4;}
|
|
INSTRUCTION(rrca) {PC++; ROR(A); F = F_SZP | A_YX | (A >> 7); return 4;}
|
|
INSTRUCTION(rra) {zuint8 c; PC++; c = A & 1; A = (zuint8)((A >> 1) | (F << 7)); RXA return 4;}
|
|
INSTRUCTION(G_Y) {zuint8 *r = _____yyy1(object); *r = G1(*r); return 8;}
|
|
INSTRUCTION(G_vhl) {WRITE_8(HL, G1(READ_8(HL))); return 15;}
|
|
INSTRUCTION(G_vXYOFFSET) {zuint16 a = XY_ADDRESS; WRITE_8(a, G3(READ_8(a))); return 23;}
|
|
INSTRUCTION(G_vXYOFFSET_Y) {zuint16 a = XY_ADDRESS; WRITE_8(a, Y3 = G3(READ_8(a))); return 23;}
|
|
INSTRUCTION(rld) {RXD(<<, & 0xF, >> 4) return 18;}
|
|
INSTRUCTION(rrd) {RXD(>>, << 4, & 0xF) return 18;}
|
|
|
|
|
|
/* MARK: - Instructions: Bit Set, Reset and Test Group
|
|
.---------------------------------------------------------------------------.
|
|
| 0 1 2 3 Flags |
|
|
| Assembly 76543210765432107654321076543210 szyhxpnc Cycles |
|
|
| ----------------------------------------------------------------------- |
|
|
| bit N,Y < CB >01nnnyyy szy1xz0. 2 / 8 |
|
|
| bit N,(hl) < CB >01nnn110 sz?1?z0. 3 / 12 |
|
|
| bit N,(ix+OFFSET) < DD >< CB ><OFFSET>01nnn*** sz*1*z0. 5 / 20 |
|
|
| bit N,(iy+OFFSET) < FD >< CB ><OFFSET>01nnn*** sz*1*z0. 5 / 20 |
|
|
| M N,Y < CB >1mnnnyyy ........ 2 / 8 |
|
|
| M N,(hl) < CB >1mnnn110 ........ 4 / 15 |
|
|
| M N,(ix+OFFSET) < DD >< CB ><OFFSET>1mnnn110 ........ 6 / 23 |
|
|
| M N,(iy+OFFSET) < FD >< CB ><OFFSET>1mnnn110 ........ 6 / 23 |
|
|
| M N,(ix+OFFSET),Y < DD >< CB ><OFFSET>1mnnnyyy ........ 6 / 23 |
|
|
| M N,(iy+OFFSET),Y < FD >< CB ><OFFSET>1mnnnyyy ........ 6 / 23 |
|
|
'--------------------------------------------------------------------------*/
|
|
|
|
INSTRUCTION(bit_N_Y) {BIT_N_VALUE(Y1) return 8;}
|
|
INSTRUCTION(bit_N_vhl) {BIT_N_VALUE(READ_8(HL)) return 12;}
|
|
INSTRUCTION(bit_N_vXYOFFSET) {BIT_N_VADDRESS(XY_ADDRESS) return 20;}
|
|
INSTRUCTION(M_N_Y) {zuint8 *t = _____yyy1(object); *t = M1(*t); return 8;}
|
|
INSTRUCTION(M_N_vhl) {WRITE_8(HL, M1(READ_8(HL))); return 15;}
|
|
INSTRUCTION(M_N_vXYOFFSET) {zuint16 a = XY_ADDRESS; WRITE_8(a, M3(READ_8(a))); return 23;}
|
|
INSTRUCTION(M_N_vXYOFFSET_Y) {zuint16 a = XY_ADDRESS; WRITE_8(a, Y3 = M3(READ_8(a))); return 23;}
|
|
|
|
|
|
/* MARK: - Instructions: Jump Group
|
|
.-------------------------------------------------------------------------------.
|
|
| 0 1 2 3 Flags |
|
|
| Assembly 76543210765432107654321076543210 szyhxpnc Cycles |
|
|
| --------------------------------------------------------------------------- |
|
|
| jp WORD < C3 >< WORD > ........ 3 / 10 |
|
|
| jp Z,WORD 11zzz010< WORD > ........ 3 / 10 |
|
|
| jr OFFSET < 18 ><OFFSET> ........ 3 / 12 |
|
|
| jr Z,OFFSET 001zz000<OFFSET> ........ 3,2 / 12,7 |
|
|
| jp (hl) < E9 > ........ 1 / 4 |
|
|
| jp (ix) < DD >< E9 > ........ 2 / 8 |
|
|
| jp (iy) < FD >< E9 > ........ 2 / 8 |
|
|
| djnz OFFSET < 10 ><OFFSET> ........ 3,2 / 13,8 |
|
|
'------------------------------------------------------------------------------*/
|
|
|
|
INSTRUCTION(jp_WORD) {PC = READ_16(PC + 1); return 10;}
|
|
INSTRUCTION(jp_Z_WORD) {PC = Z ? READ_16(PC + 1) : PC + 3; return 10;}
|
|
INSTRUCTION(jr_OFFSET) {PC += (2 + READ_OFFSET(PC + 1)); return 12;}
|
|
INSTRUCTION(jr_Z_OFFSET) {BYTE0 &= 223; PC += 2; if (Z) {PC += READ_OFFSET(PC - 1); return 12;} return 7;}
|
|
INSTRUCTION(jp_hl) {PC = HL; return 4;}
|
|
INSTRUCTION(jp_XY) {PC = XY; return 8;}
|
|
INSTRUCTION(djnz_OFFSET) {PC += 2; if (--B) {PC += READ_OFFSET(PC - 1); return 13;} return 8;}
|
|
|
|
|
|
/* MARK: - Instructions: Call and Return Group
|
|
.--------------------------------------------------------------------------------.
|
|
| 0 1 2 3 Flags |
|
|
| Assembly 76543210765432107654321076543210 szyhxpnc Cycles |
|
|
| ---------------------------------------------------------------------------- |
|
|
| call WORD < CD >< WORD > ........ 5 / 17 |
|
|
| call Z,WORD 11zzz100< WORD > ........ 3,5 / 10,17 |
|
|
| ret < C9 > ........ 3 / 10 |
|
|
| ret Z 11zzz000 ........ 1,3 / 5,11 |
|
|
| reti < ED >< 4D > ........ 4 / 14 |
|
|
| retn < ED >< 45 > ........ 4 / 14 |
|
|
| < ED >< 55 > |
|
|
| < ED >< 5D > |
|
|
| < ED >< 65 > |
|
|
| < ED >< 6D > |
|
|
| < ED >< 75 > |
|
|
| < ED >< 7D > |
|
|
| rst N 11nnn111 ........ 3 / 11 |
|
|
'-------------------------------------------------------------------------------*/
|
|
|
|
INSTRUCTION(call_WORD) {PUSH(PC + 3); PC = READ_16(PC + 1); return 17;}
|
|
INSTRUCTION(call_Z_WORD) {if (Z) return call_WORD(object); PC += 3; return 10;}
|
|
INSTRUCTION(ret) {RET; return 10;}
|
|
INSTRUCTION(ret_Z) {if (Z) {RET; return 11;} PC++; return 5;}
|
|
INSTRUCTION(reti) {IFF1 = IFF2; RET; return 14;}
|
|
INSTRUCTION(retn) {IFF1 = IFF2; RET; return 14;}
|
|
INSTRUCTION(rst_N) {PUSH(PC + 1); PC = BYTE0 & 56; return 11;}
|
|
|
|
|
|
/* MARK: - Instructions: Input and Output Group
|
|
.--------------------------------------------------------------------------------.
|
|
| 0 1 2 3 Flags |
|
|
| Assembly 76543210765432107654321076543210 szyhxpnc Cycles |
|
|
| ---------------------------------------------------------------------------- |
|
|
| in a,(BYTE) < DB >< BYTE > ........ 3 / 11 |
|
|
| in X,(c) < ED >01xxx000 szy0xp0. 3 / 12 |
|
|
| in 0,(c) < ED >< 70 > szy0xp0. 3 / 12 |
|
|
| ini < ED >< A2 > ******** 4 / 16 |
|
|
| inir < ED >< B2 > 010*0*** 5,4 / 21,16 |
|
|
| ind < ED >< AA > ******** 4 / 16 |
|
|
| indr < ED >< BA > 010*0*** 5,4 / 21,16 |
|
|
| out (BYTE),a < D3 >< BYTE > ........ 3 / 11 |
|
|
| out (c),X < ED >01xxx001 ........ 3 / 12 |
|
|
| out (c),0 < ED >< 71 > ........ 3 / 12 |
|
|
| outi < ED >< A3 > ******** 4 / 16 |
|
|
| otir < ED >< B3 > 010*0_** 5,4 / 21,16 |
|
|
| outd < ED >< AB > ******** 4 / 16 |
|
|
| otdr < ED >< BB > 010*0*** 5,4 / 21,16 |
|
|
'-------------------------------------------------------------------------------*/
|
|
|
|
INSTRUCTION(in_a_BYTE) {A = IN((A << 8) | READ_8((PC += 2) - 1)); return 11;}
|
|
INSTRUCTION(in_X_vc) {IN_VC; X1 = t; return 12;}
|
|
INSTRUCTION(in_0_vc) {IN_VC; return 16;}
|
|
INSTRUCTION(ini) {INX (++, +) return 16;}
|
|
INSTRUCTION(inir) {INXR(++, +) }
|
|
INSTRUCTION(ind) {INX (--, -) return 16;}
|
|
INSTRUCTION(indr) {INXR(--, -) }
|
|
INSTRUCTION(out_vBYTE_a) {OUT((A << 8) | READ_8((PC += 2) - 1), A); return 11;}
|
|
INSTRUCTION(out_vc_X) {PC += 2; OUT(BC, X1); return 12;}
|
|
INSTRUCTION(out_vc_0) {PC += 2; OUT(BC, 0); return 12;}
|
|
INSTRUCTION(outi) {OUTX(++) return 16;}
|
|
INSTRUCTION(otir) {OTXR(++) }
|
|
INSTRUCTION(outd) {OUTX(--) return 16;}
|
|
INSTRUCTION(otdr) {OTXR(--) }
|
|
|
|
|
|
/* MARK: - Opcode Selector Prototypes */
|
|
|
|
INSTRUCTION(CB);
|
|
INSTRUCTION(DD);
|
|
INSTRUCTION(ED);
|
|
INSTRUCTION(FD);
|
|
INSTRUCTION(XY_CB);
|
|
INSTRUCTION(ED_illegal);
|
|
INSTRUCTION(XY_illegal);
|
|
|
|
|
|
/* MARK: - Instruction Function Tables */
|
|
|
|
static Instruction const instruction_table[256] = {
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
/* 0 */ nop, ld_SS_WORD, ld_vbc_a, inc_SS, V_X, V_X, ld_X_BYTE, rlca, ex_af_af_, add_hl_SS, ld_a_vbc, dec_SS, V_X, V_X, ld_X_BYTE, rrca,
|
|
/* 1 */ djnz_OFFSET, ld_SS_WORD, ld_vde_a, inc_SS, V_X, V_X, ld_X_BYTE, rla, jr_OFFSET, add_hl_SS, ld_a_vde, dec_SS, V_X, V_X, ld_X_BYTE, rra,
|
|
/* 2 */ jr_Z_OFFSET, ld_SS_WORD, ld_vWORD_hl, inc_SS, V_X, V_X, ld_X_BYTE, daa, jr_Z_OFFSET, add_hl_SS, ld_hl_vWORD, dec_SS, V_X, V_X, ld_X_BYTE, cpl,
|
|
/* 3 */ jr_Z_OFFSET, ld_SS_WORD, ld_vWORD_a, inc_SS, V_vhl, V_vhl, ld_vhl_BYTE, scf, jr_Z_OFFSET, add_hl_SS, ld_a_vWORD, dec_SS, V_X, V_X, ld_X_BYTE, ccf,
|
|
/* 4 */ ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_vhl, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_vhl, ld_X_Y,
|
|
/* 5 */ ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_vhl, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_vhl, ld_X_Y,
|
|
/* 6 */ ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_vhl, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_vhl, ld_X_Y,
|
|
/* 7 */ ld_vhl_Y, ld_vhl_Y, ld_vhl_Y, ld_vhl_Y, ld_vhl_Y, ld_vhl_Y, halt, ld_vhl_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_Y, ld_X_vhl, ld_X_Y,
|
|
/* 8 */ U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_vhl, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_vhl, U_a_Y,
|
|
/* 9 */ U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_vhl, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_vhl, U_a_Y,
|
|
/* A */ U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_vhl, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_vhl, U_a_Y,
|
|
/* B */ U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_vhl, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_Y, U_a_vhl, U_a_Y,
|
|
/* C */ ret_Z, pop_TT, jp_Z_WORD, jp_WORD, call_Z_WORD, push_TT, U_a_BYTE, rst_N, ret_Z, ret, jp_Z_WORD, CB, call_Z_WORD, call_WORD, U_a_BYTE, rst_N,
|
|
/* D */ ret_Z, pop_TT, jp_Z_WORD, out_vBYTE_a, call_Z_WORD, push_TT, U_a_BYTE, rst_N, ret_Z, exx, jp_Z_WORD, in_a_BYTE, call_Z_WORD, DD, U_a_BYTE, rst_N,
|
|
/* E */ ret_Z, pop_TT, jp_Z_WORD, ex_vsp_hl, call_Z_WORD, push_TT, U_a_BYTE, rst_N, ret_Z, jp_hl, jp_Z_WORD, ex_de_hl, call_Z_WORD, ED, U_a_BYTE, rst_N,
|
|
/* F */ ret_Z, pop_TT, jp_Z_WORD, di, call_Z_WORD, push_TT, U_a_BYTE, rst_N, ret_Z, ld_sp_hl, jp_Z_WORD, ei, call_Z_WORD, FD, U_a_BYTE, rst_N
|
|
};
|
|
|
|
static Instruction const instruction_table_CB[256] = {
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
/* 0 */ G_Y, G_Y, G_Y, G_Y, G_Y, G_Y, G_vhl, G_Y, G_Y, G_Y, G_Y, G_Y, G_Y, G_Y, G_vhl, G_Y,
|
|
/* 1 */ G_Y, G_Y, G_Y, G_Y, G_Y, G_Y, G_vhl, G_Y, G_Y, G_Y, G_Y, G_Y, G_Y, G_Y, G_vhl, G_Y,
|
|
/* 2 */ G_Y, G_Y, G_Y, G_Y, G_Y, G_Y, G_vhl, G_Y, G_Y, G_Y, G_Y, G_Y, G_Y, G_Y, G_vhl, G_Y,
|
|
/* 3 */ G_Y, G_Y, G_Y, G_Y, G_Y, G_Y, G_vhl, G_Y, G_Y, G_Y, G_Y, G_Y, G_Y, G_Y, G_vhl, G_Y,
|
|
/* 4 */ bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_vhl, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_vhl, bit_N_Y,
|
|
/* 5 */ bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_vhl, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_vhl, bit_N_Y,
|
|
/* 6 */ bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_vhl, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_vhl, bit_N_Y,
|
|
/* 7 */ bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_vhl, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_Y, bit_N_vhl, bit_N_Y,
|
|
/* 8 */ M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y,
|
|
/* 9 */ M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y,
|
|
/* A */ M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y,
|
|
/* B */ M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y,
|
|
/* C */ M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y,
|
|
/* D */ M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y,
|
|
/* E */ M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y,
|
|
/* F */ M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_Y, M_N_vhl, M_N_Y
|
|
};
|
|
|
|
static Instruction const instruction_table_XY_CB[256] = {
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
/* 0 */ G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET, G_vXYOFFSET_Y,
|
|
/* 1 */ G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET, G_vXYOFFSET_Y,
|
|
/* 2 */ G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET, G_vXYOFFSET_Y,
|
|
/* 3 */ G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET_Y, G_vXYOFFSET, G_vXYOFFSET_Y,
|
|
/* 4 */ bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET,
|
|
/* 5 */ bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET,
|
|
/* 6 */ bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET,
|
|
/* 7 */ bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET, bit_N_vXYOFFSET,
|
|
/* 8 */ M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y,
|
|
/* 9 */ M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y,
|
|
/* A */ M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y,
|
|
/* B */ M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y,
|
|
/* C */ M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y,
|
|
/* D */ M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y,
|
|
/* E */ M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y,
|
|
/* F */ M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET_Y, M_N_vXYOFFSET, M_N_vXYOFFSET_Y
|
|
};
|
|
|
|
static Instruction const instruction_table_XY[256] = {
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
/* 0 */ XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, add_XY_WW, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal,
|
|
/* 1 */ XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, add_XY_WW, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal,
|
|
/* 2 */ XY_illegal, ld_XY_WORD, ld_vWORD_XY, inc_XY, V_JP, V_JP, ld_JP_BYTE, XY_illegal, XY_illegal, add_XY_WW, ld_XY_vWORD, dec_XY, V_JP, V_JP, ld_JP_BYTE, XY_illegal,
|
|
/* 3 */ XY_illegal, XY_illegal, XY_illegal, XY_illegal, V_vXYOFFSET, V_vXYOFFSET, ld_vXYOFFSET_BYTE, XY_illegal, XY_illegal, add_XY_WW, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal,
|
|
/* 4 */ XY_illegal, XY_illegal, XY_illegal, XY_illegal, ld_JP_KQ, ld_JP_KQ, ld_X_vXYOFFSET, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, ld_JP_KQ, ld_JP_KQ, ld_X_vXYOFFSET, XY_illegal,
|
|
/* 5 */ XY_illegal, XY_illegal, XY_illegal, XY_illegal, ld_JP_KQ, ld_JP_KQ, ld_X_vXYOFFSET, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, ld_JP_KQ, ld_JP_KQ, ld_X_vXYOFFSET, XY_illegal,
|
|
/* 6 */ ld_JP_KQ, ld_JP_KQ, ld_JP_KQ, ld_JP_KQ, ld_JP_KQ, ld_JP_KQ, ld_X_vXYOFFSET, ld_JP_KQ, ld_JP_KQ, ld_JP_KQ, ld_JP_KQ, ld_JP_KQ, ld_JP_KQ, ld_JP_KQ, ld_X_vXYOFFSET, ld_JP_KQ,
|
|
/* 7 */ ld_vXYOFFSET_Y, ld_vXYOFFSET_Y, ld_vXYOFFSET_Y, ld_vXYOFFSET_Y, ld_vXYOFFSET_Y, ld_vXYOFFSET_Y, XY_illegal, ld_vXYOFFSET_Y, XY_illegal, XY_illegal, XY_illegal, XY_illegal, ld_JP_KQ, ld_JP_KQ, ld_X_vXYOFFSET, XY_illegal,
|
|
/* 8 */ XY_illegal, XY_illegal, XY_illegal, XY_illegal, U_a_KQ, U_a_KQ, U_a_vXYOFFSET, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, U_a_KQ, U_a_KQ, U_a_vXYOFFSET, XY_illegal,
|
|
/* 9 */ XY_illegal, XY_illegal, XY_illegal, XY_illegal, U_a_KQ, U_a_KQ, U_a_vXYOFFSET, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, U_a_KQ, U_a_KQ, U_a_vXYOFFSET, XY_illegal,
|
|
/* A */ XY_illegal, XY_illegal, XY_illegal, XY_illegal, U_a_KQ, U_a_KQ, U_a_vXYOFFSET, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, U_a_KQ, U_a_KQ, U_a_vXYOFFSET, XY_illegal,
|
|
/* B */ XY_illegal, XY_illegal, XY_illegal, XY_illegal, U_a_KQ, U_a_KQ, U_a_vXYOFFSET, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, U_a_KQ, U_a_KQ, U_a_vXYOFFSET, XY_illegal,
|
|
/* C */ XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_CB, XY_illegal, XY_illegal, XY_illegal, XY_illegal,
|
|
/* D */ XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal,
|
|
/* E */ XY_illegal, pop_XY, XY_illegal, ex_vsp_XY, XY_illegal, push_XY, XY_illegal, XY_illegal, XY_illegal, jp_XY, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal,
|
|
/* F */ XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, ld_sp_XY, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal, XY_illegal
|
|
};
|
|
|
|
static Instruction const instruction_table_ED[256] = {
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
/* 0 */ ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal,
|
|
/* 1 */ ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal,
|
|
/* 2 */ ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal,
|
|
/* 3 */ ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal,
|
|
/* 4 */ in_X_vc, out_vc_X, sbc_hl_SS, ld_vWORD_SS, neg, retn, im_0, ld_i_a, in_X_vc, out_vc_X, adc_hl_SS, ld_SS_vWORD, neg, reti, im_0, ld_r_a,
|
|
/* 5 */ in_X_vc, out_vc_X, sbc_hl_SS, ld_vWORD_SS, neg, retn, im_1, ld_a_i, in_X_vc, out_vc_X, adc_hl_SS, ld_SS_vWORD, neg, retn, im_2, ld_a_r,
|
|
/* 6 */ in_X_vc, out_vc_X, sbc_hl_SS, ld_vWORD_SS, neg, retn, im_0, rrd, in_X_vc, out_vc_X, adc_hl_SS, ld_SS_vWORD, neg, retn, im_0, rld,
|
|
/* 7 */ in_0_vc, out_vc_0, sbc_hl_SS, ld_vWORD_SS, neg, retn, im_1, ED_illegal, in_X_vc, out_vc_X, adc_hl_SS, ld_SS_vWORD, neg, retn, im_2, ED_illegal,
|
|
/* 8 */ ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal,
|
|
/* 9 */ ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal,
|
|
/* A */ ldi, cpi, ini, outi, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ldd, cpd, ind, outd, ED_illegal, ED_illegal, ED_illegal, ED_illegal,
|
|
/* B */ ldir, cpir, inir, otir, ED_illegal, ED_illegal, ED_illegal, ED_illegal, lddr, cpdr, indr, otdr, ED_illegal, ED_illegal, ED_illegal, ED_illegal,
|
|
/* C */ ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal,
|
|
/* D */ ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal,
|
|
/* E */ ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal,
|
|
/* F */ ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal, ED_illegal
|
|
};
|
|
|
|
|
|
/* MARK: - Prefixed Instruction Set Selection and Execution */
|
|
|
|
#define DD_FD(register) \
|
|
zuint8 cycles; \
|
|
\
|
|
XY = register; \
|
|
R++; \
|
|
cycles = instruction_table_XY[BYTE1 = READ_8(PC + 1)](object); \
|
|
register = XY; \
|
|
return cycles;
|
|
|
|
|
|
INSTRUCTION(DD) {DD_FD(IX)}
|
|
INSTRUCTION(FD) {DD_FD(IY)}
|
|
INSTRUCTION(CB) {R++; return instruction_table_CB[BYTE1 = READ_8((PC += 2) - 1)](object);}
|
|
INSTRUCTION(ED) {R++; return instruction_table_ED[BYTE1 = READ_8( PC + 1)](object);}
|
|
|
|
|
|
INSTRUCTION(XY_CB)
|
|
{
|
|
PC += 4;
|
|
BYTE2 = READ_8(PC - 2);
|
|
return instruction_table_XY_CB[BYTE3 = READ_8(PC - 1)](object);
|
|
}
|
|
|
|
|
|
/* MARK: - Illegal Instruction Handling */
|
|
|
|
INSTRUCTION(XY_illegal) {PC += 1; return instruction_table[BYTE0 = BYTE1](object) + 4;}
|
|
INSTRUCTION(ED_illegal) {PC += 2; return 8;}
|
|
|
|
|
|
/* MARK: - Main Functions */
|
|
|
|
CPU_Z80_API void z80_power(Z80 *object, zboolean state)
|
|
{
|
|
if (state)
|
|
{
|
|
# ifdef Z_Z80_RESET_IS_EQUAL_TO_POWER_ON
|
|
z80_reset(object);
|
|
# else
|
|
PC = Z_Z80_VALUE_AFTER_POWER_ON_PC;
|
|
SP = Z_Z80_VALUE_AFTER_POWER_ON_SP;
|
|
IX = Z_Z80_VALUE_AFTER_POWER_ON_IX;
|
|
IY = Z_Z80_VALUE_AFTER_POWER_ON_IY;
|
|
AF = Z_Z80_VALUE_AFTER_POWER_ON_AF;
|
|
BC = Z_Z80_VALUE_AFTER_POWER_ON_BC;
|
|
DE = Z_Z80_VALUE_AFTER_POWER_ON_DE;
|
|
HL = Z_Z80_VALUE_AFTER_POWER_ON_HL;
|
|
AF_ = Z_Z80_VALUE_AFTER_POWER_ON_AF_;
|
|
BC_ = Z_Z80_VALUE_AFTER_POWER_ON_BC_;
|
|
DE_ = Z_Z80_VALUE_AFTER_POWER_ON_DE_;
|
|
HL_ = Z_Z80_VALUE_AFTER_POWER_ON_HL_;
|
|
R = Z_Z80_VALUE_AFTER_POWER_ON_R;
|
|
I = Z_Z80_VALUE_AFTER_POWER_ON_I;
|
|
IFF1 = Z_Z80_VALUE_AFTER_POWER_ON_IFF1;
|
|
IFF2 = Z_Z80_VALUE_AFTER_POWER_ON_IFF2;
|
|
IM = Z_Z80_VALUE_AFTER_POWER_ON_IM;
|
|
|
|
EI = HALT = INT = NMI = 0;
|
|
# endif
|
|
}
|
|
|
|
else PC = SP = IX = IY = AF = BC = DE = HL = AF_ = BC_ = DE_ = HL_ = I = R =
|
|
IFF1 = IFF2 = IM = EI = HALT = INT = NMI = 0;
|
|
}
|
|
|
|
|
|
CPU_Z80_API void z80_reset(Z80 *object)
|
|
{
|
|
PC = Z_Z80_VALUE_AFTER_RESET_PC;
|
|
SP = Z_Z80_VALUE_AFTER_RESET_SP;
|
|
IX = Z_Z80_VALUE_AFTER_RESET_IX;
|
|
IY = Z_Z80_VALUE_AFTER_RESET_IY;
|
|
AF = Z_Z80_VALUE_AFTER_RESET_AF;
|
|
BC = Z_Z80_VALUE_AFTER_RESET_BC;
|
|
DE = Z_Z80_VALUE_AFTER_RESET_DE;
|
|
HL = Z_Z80_VALUE_AFTER_RESET_HL;
|
|
AF_ = Z_Z80_VALUE_AFTER_RESET_AF_;
|
|
BC_ = Z_Z80_VALUE_AFTER_RESET_BC_;
|
|
DE_ = Z_Z80_VALUE_AFTER_RESET_DE_;
|
|
HL_ = Z_Z80_VALUE_AFTER_RESET_HL_;
|
|
R = Z_Z80_VALUE_AFTER_RESET_R;
|
|
I = Z_Z80_VALUE_AFTER_RESET_I;
|
|
IFF1 = Z_Z80_VALUE_AFTER_RESET_IFF1;
|
|
IFF2 = Z_Z80_VALUE_AFTER_RESET_IFF2;
|
|
IM = Z_Z80_VALUE_AFTER_RESET_IM;
|
|
|
|
EI = HALT = INT = NMI = 0;
|
|
}
|
|
|
|
|
|
CPU_Z80_API zusize z80_run(Z80 *object, zusize cycles)
|
|
{
|
|
zuint32 data;
|
|
|
|
/*-------------.
|
|
| Clear cycles |
|
|
'-------------*/
|
|
CYCLES = 0;
|
|
|
|
/*--------------.
|
|
| Backup R7 bit |
|
|
'--------------*/
|
|
R7 = R;
|
|
|
|
/*------------------------------.
|
|
| Execute until cycles consumed |
|
|
'------------------------------*/
|
|
while (CYCLES < cycles)
|
|
{
|
|
/*--------------------------------------.
|
|
| Jump to NMI handler if NMI pending... |
|
|
'--------------------------------------*/
|
|
if (NMI)
|
|
{
|
|
EXIT_HALT; /* Resume CPU if halted. */
|
|
R++; /* Consume memory refresh. */
|
|
NMI = FALSE; /* Clear the NMI pulse. */
|
|
/*IFF2 = IFF1;*/ /* Backup IFF1 (it doesn't occur, acording to Sean Young). */
|
|
IFF1 = 0; /* Reset IFF1 to don't bother the NMI routine. */
|
|
PUSH(PC); /* Save return addres in the stack. */
|
|
PC = Z_Z80_ADDRESS_NMI_POINTER; /* Make PC point to the NMI routine. */
|
|
CYCLES += 11; /* Accepting a NMI consumes 11 cycles. */
|
|
continue;
|
|
}
|
|
|
|
/*--------------------------.
|
|
| Execute INT if pending... |
|
|
'--------------------------*/
|
|
if (INT && IFF1 && !EI)
|
|
{
|
|
EXIT_HALT; /* Resume CPU on halt. */
|
|
R++; /* Consume memory refresh. */
|
|
IFF1 = IFF2 = 0; /* Clear interrupt flip-flops. */
|
|
|
|
switch (IM)
|
|
{
|
|
/*------------------------------.
|
|
| IM 0: Execute bus instruction |
|
|
'------------------------------*/
|
|
case 0:
|
|
|
|
if ((data = INT_DATA)) switch (data & Z_UINT32(0xFF000000))
|
|
{
|
|
case Z_UINT32(0xC3000000): /* JP */
|
|
PC = (zuint16)(data >> 8);
|
|
CYCLES += 10;
|
|
break;
|
|
|
|
case Z_UINT32(0xCD000000): /* CALL */
|
|
PUSH(PC);
|
|
PC = (zuint16)(data >> 8);
|
|
CYCLES += 17;
|
|
break;
|
|
|
|
default: /* RST (and possibly others) */
|
|
PUSH(PC);
|
|
PC = (zuint16)((data >> 8) & 0x38);
|
|
CYCLES += 11;
|
|
}
|
|
|
|
CYCLES += 2;
|
|
break;
|
|
|
|
/*----------------------.
|
|
| IM 1: Execute rst 38h |
|
|
'----------------------*/
|
|
case 1:
|
|
PUSH(PC);
|
|
PC = 0x38;
|
|
CYCLES += (11 + 2);
|
|
break;
|
|
|
|
/*---------------------------.
|
|
| IM 2: Execute rst [i:byte] |
|
|
'---------------------------*/
|
|
case 2:
|
|
PUSH(PC);
|
|
PC = READ_16(((zuint16)(I << 8)) | (INT_DATA & 0xFF));
|
|
CYCLES += (17 + 2);
|
|
break;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
/*---------------------------------------.
|
|
| Consume memory refresh and update bits |
|
|
'---------------------------------------*/
|
|
R++;
|
|
EI = FALSE;
|
|
|
|
/*-----------------------------------------------.
|
|
| Execute instruction and update consumed cycles |
|
|
'-----------------------------------------------*/
|
|
CYCLES += instruction_table[BYTE0 = READ_8(PC)](object);
|
|
}
|
|
|
|
/*---------------.
|
|
| Restore R7 bit |
|
|
'---------------*/
|
|
R = R_ALL;
|
|
|
|
/*-----------------------.
|
|
| Return consumed cycles |
|
|
'-----------------------*/
|
|
return CYCLES;
|
|
}
|
|
|
|
|
|
CPU_Z80_API void z80_nmi(Z80 *object) {NMI = TRUE ;}
|
|
CPU_Z80_API void z80_int(Z80 *object, zboolean state) {INT = state;}
|
|
|
|
|
|
/* MARK: - ABI */
|
|
|
|
#if defined(CPU_Z80_BUILD_ABI) || defined(CPU_Z80_BUILD_MODULE_ABI)
|
|
|
|
static void will_read_state(Z80 *object) {R = R_ALL;}
|
|
static void did_write_state(Z80 *object) {R7 = R; }
|
|
|
|
static ZCPUEmulatorExport const exports[7] = {
|
|
{Z_EMULATOR_FUNCTION_POWER, {(void (*)(void))z80_power }},
|
|
{Z_EMULATOR_FUNCTION_RESET, {(void (*)(void))z80_reset }},
|
|
{Z_EMULATOR_FUNCTION_RUN, {(void (*)(void))z80_run }},
|
|
{Z_EMULATOR_FUNCTION_WILL_READ_STATE, {(void (*)(void))will_read_state}},
|
|
{Z_EMULATOR_FUNCTION_DID_WRITE_STATE, {(void (*)(void))did_write_state}},
|
|
{Z_EMULATOR_FUNCTION_NMI, {(void (*)(void))z80_nmi }},
|
|
{Z_EMULATOR_FUNCTION_IRQ, {(void (*)(void))z80_int }}
|
|
};
|
|
|
|
static ZCPUEmulatorInstanceImport const instance_imports[6] = {
|
|
{Z_EMULATOR_FUNCTION_READ_8BIT, O(read )},
|
|
{Z_EMULATOR_FUNCTION_WRITE_8BIT, O(write )},
|
|
{Z_EMULATOR_FUNCTION_IN_8BIT, O(in )},
|
|
{Z_EMULATOR_FUNCTION_OUT_8BIT, O(out )},
|
|
{Z_EMULATOR_FUNCTION_IRQ_DATA, O(int_data)},
|
|
{Z_EMULATOR_FUNCTION_HALT, O(halt )}
|
|
};
|
|
|
|
CPU_Z80_ABI ZCPUEmulatorABI const abi_emulation_cpu_z80 = {
|
|
/* dependency_count */ 0,
|
|
/* dependencies */ NULL,
|
|
/* export_count */ 7,
|
|
/* exports */ exports,
|
|
/* instance_size */ sizeof(Z80),
|
|
/* instance_state_offset */ O(state),
|
|
/* instance_state_size */ sizeof(ZZ80State),
|
|
/* instance_import_count */ 6,
|
|
/* instance_imports */ instance_imports
|
|
};
|
|
|
|
#endif
|
|
|
|
#if defined(CPU_Z80_BUILD_MODULE_ABI)
|
|
|
|
# include <Z/ABIs/generic/module.h>
|
|
|
|
static ZModuleUnit const unit = {"Z80", "Z80", Z_VERSION(0, 1, 0), &abi_emulation_cpu_z80};
|
|
static ZModuleDomain const domain = {"Emulation.CPU", Z_VERSION(1, 0, 0), 1, &unit};
|
|
Z_API_WEAK_EXPORT ZModuleABI const __module_abi__ = {1, &domain};
|
|
|
|
#endif
|
|
|
|
|
|
/* Z80.c EOF */
|