diff --git a/software/FusionX/src/driver/Z80.c b/software/FusionX/src/driver/Z80.c deleted file mode 100644 index e9d713537..000000000 --- a/software/FusionX/src/driver/Z80.c +++ /dev/null @@ -1,2636 +0,0 @@ -/* Z80 v0.2 - ______ ______ ______ - /\___ \/\ __ \\ __ \ - ____ \/__/ /\_\ __ \\ \/\ \ ________________________________________________ -| /\_____\\_____\\_____\ | -| Zilog \/_____//_____//_____/ CPU Emulator | -| Copyright (C) 1999-2022 Manuel Sainz de Baranda y Goñi. | -| | -| This emulator is free software: you can redistribute it and/or modify it | -| under the terms of the GNU Lesser General Public License as published by | -| the Free Software Foundation, either version 3 of the License, or (at your | -| option) any later version. | -| | -| This emulator 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 Lesser General Public | -| License for more details. | -| | -| You should have received a copy of the GNU Lesser General Public License | -| along with this emulator. If not, see . | -| | -| -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | -| | -| A NOTE FROM THE ORIGINAL AUTHOR | -| | -| Those familiar with the official documentation of the Zilog Z80 CPU will | -| find this source code quite intuitive. The purpose has not been to write | -| the fastest possible emulator, although the speed aspect is not neglected, | -| but a portable, hackable and well | -| .----._.----. structured piece of software; | -| A11 <-01--|1 o|--40-> A10 something small, solid and elegant | -| A12 <-02--| |--39-> A09 that can stand the test of time | -| A13 <-03--| |--38-> A08 with no need for major changes. | -| A14 <-04--| |--37-> A07 | -| A15 <-05--| |--36-> A06 Some of the main design decisions | -| CLK --06->| |--35-> A05 have been the following: | -| D4 <-07->| |--34-> A04 | -| D3 <-08->|.---------.|--33-> A03 1. Opcode partial decoding keeps | -| D5 <-09->|| ZILOG ||--32-> A02 the code small and maintainable. | -| D6 <-10->|| Z80 ||--31-> A01 | -| +5V --11--|| CPU ||--30-> A00 2. Function pointer tables for | -| D2 <-12->|| ||--29-- GND opcode selection allow easy reuse | -| D7 <-13->|'---------'|--28-> RFSH of almost all instruction code | -| D0 <-14->| |--27-> M1 in the interrupt mode 0. | -| D1 <-15->| |<-26-- RESET | -| INT --16->| |<-25-- BUSREQ 3. Avoiding conditional statements | -| NMI --17->| |<-24-- WAIT as much as possible reduces the | -| HALT <-18--| |--23-> BUSACK branch penalty in modern pipelined | -| MREQ <-19--| |--22-> WR processors. | -| IORQ <-20--| |--21-> RD | -| '-----------' | -| Zilog Z80 CPU, May 1976 version | -| 40-pin ceramic DIP pinout Manuel | -| | -'=============================================================================*/ - -#ifndef Z80_DEPENDENCIES_HEADER -# include -# include -#endif - -#ifdef Z80_STATIC -# define Z80_API -#else -# define Z80_API Z_API_EXPORT -#endif - -#ifdef Z80_WITH_LOCAL_HEADER -# include "Z80.h" -#else -# include -#endif - - -/* MARK: - Types */ - -typedef zuint8 (* Instruction)(Z80 *self); - -#ifdef Z80_WITH_FULL_IM0 - typedef struct { - Z80* z80; - void* context; - Z80Read fetch; - Z80Read read; - Z80Write write; - Z80Read in; - Z80Write out; - Z80Notify ld_i_a; - Z80Notify ld_r_a; - Z80Notify reti; - Z80Notify retn; - zuint16 pc; - } IM0; -#endif - - -/* MARK: - External Macros */ - -#define REGISTER_OFFSET(member) (zusize)Z_MEMBER_OFFSET(Z80, member) -#define ROL(value) Z_UINT8_ROTATE_LEFT (value, 1) -#define ROR(value) Z_UINT8_ROTATE_RIGHT(value, 1) - - -/* MARK: - Instance Variable and Callback Shortcuts */ - -#define MEMPTR self->memptr.uint16_value -#define PC self->pc.uint16_value -#define SP self->sp.uint16_value -#define XY self->xy.uint16_value -#define IX self->ix_iy[0].uint16_value -#define IY self->ix_iy[1].uint16_value -#define AF self->af.uint16_value -#define BC self->bc.uint16_value -#define DE self->de.uint16_value -#define HL self->hl.uint16_value -#define AF_ self->af_.uint16_value -#define BC_ self->bc_.uint16_value -#define DE_ self->de_.uint16_value -#define HL_ self->hl_.uint16_value -#define MEMPTRH self->memptr.uint8_values.at_1 -#define MEMPTRL self->memptr.uint8_values.at_0 -#define PCH self->pc.uint8_values.at_1 -#define A self->af.uint8_values.at_1 -#define F self->af.uint8_values.at_0 -#define B self->bc.uint8_values.at_1 -#define C self->bc.uint8_values.at_0 -#define E self->de.uint8_values.at_0 -#define L self->hl.uint8_values.at_0 -#define I self->i -#define R self->r -#define R7 self->r7 -#define Q self->q -#define IFF1 self->iff1 -#define IFF2 self->iff2 -#define IM self->im -#define HALT_LINE self->halt_line -#define INT_LINE self->int_line -#define DATA self->data.uint8_array -#define REQUEST self->request -#define RESUME self->resume -#define OPTIONS self->options -#define CONTEXT self->context - -#define FETCH_OPCODE(address) self->fetch_opcode(CONTEXT, address) -#define FETCH(address) self->fetch(CONTEXT, address) -#define READ(address) self->read (CONTEXT, address) -#define WRITE(address, value) self->write(CONTEXT, address, value) -#define IN(port) self->in (CONTEXT, port) -#define OUT(port, value) self->out(CONTEXT, port, value) -#define NOTIFY(callback) if (self->callback != Z_NULL) self->callback(CONTEXT) -#define INTA self->inta(CONTEXT, PC) - - -/* MARK: - Callbacks: 16-bit Operations */ - -static Z_INLINE zuint16 fetch_16(Z80 const *self, zuint16 address) - { - zuint8 t = FETCH(address); - return (zuint16)(t | ((zuint16)FETCH(address + 1) << 8)); - } - - -static Z_INLINE zuint16 read_16(Z80 const *self, zuint16 address) - { - zuint8 t = READ(address); - return (zuint16)(t | ((zuint16)READ(address + 1) << 8)); - } - - -static Z_INLINE void write_16f(Z80 const *self, zuint16 address, zuint16 value) - { - WRITE(address, (zuint8)value); - WRITE(address + 1, (zuint8)(value >> 8)); - } - - -static Z_INLINE void write_16b(Z80 const *self, zuint16 address, zuint16 value) - { - WRITE(address + 1, (zuint8)(value >> 8)); - WRITE(address, (zuint8)value); - } - - -#ifndef Z80_WITH_FULL_IM0 - static Z_INLINE zuint16 int_fetch_16(Z80 const *self) - { - zuint8 t = self->int_fetch(CONTEXT, PC); - return (zuint16)(t | ((zuint16)self->int_fetch(CONTEXT, PC) << 8)); - } -#endif - - -#define FETCH_16(address) fetch_16 (self, address) -#define READ_16(address) read_16 (self, address) -#define WRITE_16F(address, value) write_16f(self, address, value) -#define WRITE_16B(address, value) write_16b(self, address, value) - - -/* MARK: - Flags */ - -/*----------------. -| 7 6 5 4 3 2 1 0 | -| S Z Y H X P N C | -'-|-|-|-|-|-|-|-|-' - | | | | | | | '-- carry / borrow - | | | | | | '---- addition / subtraction - | | | | | '------ parity (P) / two's complement signed overflow (V) - | | | | '-------- result's bit 3 (undocumented) - | | | '---------- half carry / half borrow - | | '------------ result's bit 5 (undocumented) - | '-------------- zero - '---------------- sign */ - -#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 SZPCF (SF | ZF | PF | CF) -#define SZPF (SF | ZF | PF ) -#define SZCF (SF | ZF | CF ) -#define SYXF (SF | YF | XF ) -#define ZPF (ZF | PF ) -#define YXCF (YF | XF | CF ) -#define YXF (YF | XF ) -#define HCF (HF | CF ) - -#define F_SZPC (F & SZPCF) -#define F_SZP (F & SZPF) -#define F_SZC (F & SZCF) -#define F_C (F & CF) -#define A_SYX (A & SYXF) -#define A_YX (A & YXF) - -#define ZF_ZERO(value) (!(value) << 6) - -#ifdef Z80_WITH_Q -# define FLAGS Q = F -# define Q_0 Q = 0; -#else -# define FLAGS F -# define Q_0 -#endif - - -/* 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 PF_OVERFLOW(bits, result, lhs, rhs) \ - (((zuint##bits)((lhs ^ rhs) & (lhs ^ result)) >> (bits - 3)) & PF) - - -/* MARK: - 8-Bit Register Resolution */ - -/*---------. .---------------------. -| 76543210 | | J / K | O / P | -|----------| |---------+-----------| -| __jjj___ | | 000 = b | 000 = b | -| _____kkk | | 001 = c | 001 = c | -| __ooo___ | | 010 = d | 010 = d | -| _____ppp | | 011 = e | 011 = e | -'----------' | 100 = h | 100 = XYh | - | 101 = l | 101 = XYl | - | 111 = a | 111 = a | - '--------------------*/ - -static zusize const j_k_table[8] = { - REGISTER_OFFSET(bc.uint8_values.at_1), - REGISTER_OFFSET(bc.uint8_values.at_0), - REGISTER_OFFSET(de.uint8_values.at_1), - REGISTER_OFFSET(de.uint8_values.at_0), - REGISTER_OFFSET(hl.uint8_values.at_1), - REGISTER_OFFSET(hl.uint8_values.at_0), - 0, - REGISTER_OFFSET(af.uint8_values.at_1) -}; - -static zusize const o_p_table[8] = { - REGISTER_OFFSET(bc.uint8_values.at_1), - REGISTER_OFFSET(bc.uint8_values.at_0), - REGISTER_OFFSET(de.uint8_values.at_1), - REGISTER_OFFSET(de.uint8_values.at_0), - REGISTER_OFFSET(xy.uint8_values.at_1), - REGISTER_OFFSET(xy.uint8_values.at_0), - 0, - REGISTER_OFFSET(af.uint8_values.at_1) -}; - -#define REGISTER_8(table, offset, shift) \ - *((zuint8 *)self + table[(DATA[offset] shift) & 7]) - -#define J0 REGISTER_8(j_k_table, 0, >> 3 ) -#define J1 REGISTER_8(j_k_table, 1, >> 3 ) -#define K0 REGISTER_8(j_k_table, 0, Z_EMPTY) -#define K1 REGISTER_8(j_k_table, 1, Z_EMPTY) -#define K3 REGISTER_8(j_k_table, 3, Z_EMPTY) -#define O REGISTER_8(o_p_table, 1, >> 3 ) -#define P REGISTER_8(o_p_table, 1, 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 | -| __ww____ | | 10 = hl | 10 = hl | 10 = XY | -'----------' | 11 = sp | 11 = af | 11 = sp | - '----------------------------*/ - -static zusize const s_table[4] = { - REGISTER_OFFSET(bc.uint16_value), - REGISTER_OFFSET(de.uint16_value), - REGISTER_OFFSET(hl.uint16_value), - REGISTER_OFFSET(sp) -}; - -static zusize const t_table[4] = { - REGISTER_OFFSET(bc.uint16_value), - REGISTER_OFFSET(de.uint16_value), - REGISTER_OFFSET(hl.uint16_value), - REGISTER_OFFSET(af.uint16_value) -}; - -static zusize const w_table[4] = { - REGISTER_OFFSET(bc.uint16_value), - REGISTER_OFFSET(de.uint16_value), - REGISTER_OFFSET(xy.uint16_value), - REGISTER_OFFSET(sp) -}; - -#define REGISTER_16(table, offset) \ - *(zuint16 *)(void *)((zchar *)self + table[(DATA[offset] >> 4) & 3]) - -#define SS0 REGISTER_16(s_table, 0) -#define SS1 REGISTER_16(s_table, 1) -#define TT REGISTER_16(t_table, 0) -#define WW REGISTER_16(w_table, 1) - - -/* MARK: - Condition Evaluation */ - -/*---------. .----------. -| 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 zsint zzz(Z80 const *self, zuint8 mask) - { - zsint z = (DATA[0] >> 3) & mask; - - return !(F & z_table[z]) ^ (z & 1); - } - - -/* MARK: - 8-Bit Arithmetic and Logical Operations */ - -/*---------. .---------------------. -| 76543210 | | U SZYHXPNC | -|----------| |---------------------| -| __uuu___ | | 000 = add szycxv0c | -| _____10v | | 001 = adc szycxv0c | -'----------' | 010 = sub szybxv1b | - | 011 = sbc szybxv1b | - | 100 = and szy1xp00 | - | 101 = xor szy0xp00 | - | 110 = or szy0xp00 | - | 111 = cp sz*b*v1b | - |---------------------| - | V SZYHXPNC | - |---------------------| - | 100 = inc szycxv0. | - | 101 = dec szybxv1. | - '--------------------*/ - -static void uuu(Z80 *self, zuint8 offset, zuint8 value) - { - zuint8 t, f; - - switch ((DATA[offset] >> 3) & 7) - { - case 0: /* add */ - t = A + value; - - f = ((zuint)A + value > 255) | /* CF = carry */ - PF_OVERFLOW(8, t, A, ~value) | /* PF = overflow */ - ((A ^ value ^ t) & HF); /* HF = half-carry */ - A = t; /* NF = 0 */ - break; - - case 1: /* adc */ - t = A + value + (f = F_C); - - f = ((zuint)A + value + f > 255) | /* CF = carry */ - PF_OVERFLOW(8, t, A, ~value) | /* PF = overflow */ - ((A ^ value ^ t) & HF); /* HF = half-carry */ - /* NF = 0 */ - A = t; - break; - - case 2: /* sub */ - t = A - value; - - f = (A < value) | /* CF = borrow */ - NF | /* NF = 1 */ - PF_OVERFLOW(8, t, A, value) | /* PF = overflow */ - ((A ^ value ^ t) & HF); /* HF = half-borrow */ - A = t; - break; - - case 3: /* sbc */ - t = A - value - (f = F_C); - - f = ((zsint)A - value - f < 0) | /* CF = borrow */ - NF | /* NF = 1 */ - PF_OVERFLOW(8, t, A, value) | /* PF = overflow */ - ((A ^ value ^ t) & HF); /* HF = half-borrow */ - - A = 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; - - FLAGS = (zuint8)( - (t & SF) | /* SF = sign */ - ZF_ZERO(t) | /* ZF = zero */ - ((A ^ value ^ t) & HF) | /* HF = half-borrow */ - PF_OVERFLOW(8, t, A, value) | /* PF = overflow */ - (A < value) | /* CF = borrow */ - (value & YXF) | /* YF = rhs.5; XF = rhs.3 */ - NF); /* NF = 1 */ - - return; - } - - FLAGS = (zuint8)( - f | /* HF, PF, NF and CF already computed */ - A_SYX | /* SF = sign; YF = Y; XF = X */ - ZF_ZERO(A)); /* ZF = zero */ - } - - -static zuint8 vvv(Z80 *self, zuint8 offset, zuint8 value) - { - zuint8 t, pnf; - - /* dec */ - if (DATA[offset] & 1) - { - pnf = (zuint8)(((value == 128) << 2) | NF); /* PF = overflow; NF = 1 */ - t = value - 1; - } - - /* inc */ - else { - pnf = (zuint8)((value == 127) << 2); /* PF = overflow; NF = 0 */ - t = value + 1; - } - - FLAGS = (zuint8)( - pnf | /* PF and NF already computed */ - (t & SYXF) | /* SF = sign; YF = Y; XF = X */ - ZF_ZERO(t) | /* ZF = zero */ - ((value ^ t) & HF) | /* HF = half-carry/borrow */ - F_C); /* CF unchanged */ - - return t; - } - - -/* MARK: - Rotation and Shift Operations */ - -/*---------. .-----------. -| 76543210 | | G | -|----------| |-----------| -| __ggg___ | | 000 = rlc | -'----------' | 001 = rrc | - | 010 = rl | - | 011 = rr | - | 100 = sla | - | 101 = sra | - | 110 = sll | - | 111 = srl | - '----------*/ - -static zuint8 ggg(Z80 *self, zuint8 offset, zuint8 value) - { - zuint8 cf; - - switch ((DATA[offset] >> 3) & 7) - { - /* rlc .----------------. - .----. | .---------. | - | CF |<-----| 7 <-- 0 |<--' - '----' '--------*/ - case 0: - cf = (value = ROL(value)) & 1; - break; - - /* rrc .----------------. - | .---------. | .----. - '-->| 7 --> 0 |----->| CF | - '---------' '---*/ - case 1: - cf = value & 1; - value = ROR(value); - break; - - /* rl .-------------------------. - | .----. .---------. | - '--| CF |<--| 7 <-- 0 |<--' - '----' '--------*/ - case 2: - cf = value >> 7; - value = (zuint8)((value << 1) | F_C); - break; - - /* rr .-------------------------. - | .---------. .----. | - '-->| 7 --> 0 |-->| CF |--' - '---------' '---*/ - case 3: - cf = value & 1; - value = (zuint8)((value >> 1) | ((zuint8)F_C << 7)); - break; - - /* sla .----. .---------. - | CF |<--| 7 <-- 0 |<-- 0 - '----' '--------*/ - case 4: - cf = value >> 7; - value <<= 1; - break; - - /* sra .---------. .----. - .-->| 7 --> 0 |-->| CF | - | '---------' '----' - | | - '----*/ - case 5: - cf = value & 1; - value = (zuint8)((value & 128) | (value >> 1)); - break; - - /* sll .----. .---------. - | CF |<--| 7 <-- 0 |<-- 1 - '----' '--------*/ - case 6: - cf = value >> 7; - value = (zuint8)((value << 1) | 1); - break; - - /* srl .---------. .----. - 0 -->| 7 --> 0 |-->| CF | - '---------' '---*/ - case 7: - cf = value & 1; - value >>= 1; - break; - - /* Uncoment to avoid compiler warnings */ - /*default: cf = 0;*/ - } - - FLAGS = (zuint8)( - (value & SYXF) | /* SF = sign; YF = Y; XF = X */ - ZF_ZERO(value) | /* ZF = zero */ - PF_PARITY(value) | /* PF = parity */ - cf); /* CF already computed */ - /* HF, NF = 0 */ - return value; - } - - -/* MARK: - Bit Set and Reset Operations */ - -/*---------. .---------. -| 76543210 | | M | -|----------| |---------| -| _m______ | | 0 = res | -'----------' | 1 = set | - '--------*/ - -static Z_INLINE zuint8 m(Z80 *self, zuint8 offset, zuint8 value) - { - zuint8 t; - - Q_0 - t = DATA[offset]; - - return (zuint8)((t & 64) - ? value | (1U << ((t >> 3) & 7)) - : value & ~(1U << ((t >> 3) & 7))); - } - - -/* MARK: - Function Shortcuts and Reusable Code */ - -#define N(index) ((DATA[index] >> 3) & 7) -#define Z(mask) zzz(self, mask) -#define U0(value) uuu(self, 0, value) -#define U1(value) uuu(self, 1, value) -#define V0(value) vvv(self, 0, value) -#define V1(value) vvv(self, 1, value) -#define G1(value) ggg(self, 1, value) -#define G3(value) ggg(self, 3, value) -#define M1(value) m (self, 1, value) -#define M3(value) m (self, 3, value) -#define PUSH(value) WRITE_16B(SP -= 2, value) -#define R_ALL ((R & 127) | (R7 & 128)) -#define RET MEMPTR = PC = READ_16(SP); SP += 2 -#define FETCH_XY_EA(address) MEMPTR = (zuint16)(XY + (zsint8)FETCH(address)) -#define INSTRUCTION(name) static zuint8 name(Z80 *self) -#define IS_XY_PREFIX(opcode) ((opcode) & 0xDF) == 0xDD -#define EX(a, b) t = a; a = b; b = t - - -#define LD_A_IR(rhs) \ - A = rhs; \ - \ - FLAGS = (zuint8)( /* HF, NF = 0 */ \ - A_SYX | /* SF = sign; YF = Y; XF = X */ \ - ZF_ZERO(A) | /* ZF = zero */ \ - (IFF2 << 2) | /* PF = IFF2 */ \ - F_C); /* CF unchanged */ \ - \ - PC += 2; \ - return 9 - - -#define LDX(operator) \ - zuint8 t = READ(HL operator); \ - \ - WRITE(DE operator, t); \ - t += A; \ - \ - FLAGS = (zuint8)( /* HF, NF = 0 */ \ - F_SZC | /* SF, ZF, CF unchanged */ \ - ((t & 2) << 4) | /* YF = (A + [HLi]).1 */ \ - (t & XF) | /* XF = (A + [HLi]).3 */ \ - (!!(--BC) << 2)); /* PF = !!BCo */ \ - \ - PC += 2; \ - return 16 - - -#define LDXR(operator) \ - zuint8 t = READ(HL operator); \ - \ - WRITE(DE operator, t); \ - t += A; \ - \ - if (--BC) \ - { /* HF, NF = 0 */ \ - FLAGS = F_SZC | /* SF, ZF, CF unchanged */ \ - ((PC >> 8) & YXF) | /* YF = PCi.13; XF = PCi.11 */ \ - PF; /* PF = 1 */ \ - \ - MEMPTR = PC + 1; \ - return 21; \ - } \ - \ - FLAGS = (zuint8)( /* HF, PF, NF = 0 */ \ - F_SZC | /* SF, ZF, CF unchanged */ \ - ((t & 2) << 4) | /* YF = (A + [HLi]).1 */ \ - (t & XF)); /* XF = (A + [HLi]).3 */ \ - \ - PC += 2; \ - return 16 - - -#define CPX(operator) \ - zuint8 n = READ(HL operator); \ - zuint8 t0 = A - n; \ - zuint8 hf = (A ^ n ^ t0) & HF; \ - zuint8 t1 = t0 - (hf >> 4); \ - \ - FLAGS = (zuint8)( \ - (t0 & SF) | /* SF = sign */ \ - ZF_ZERO(t0) | /* ZF = zero */ \ - hf | /* HF = half-borrow */ \ - ((t1 & 2) << 4) | /* YF = (A - [HLi] - HFo).1 */ \ - (t1 & XF) | /* XF = (A - [HLi] - HFo).3 */ \ - (!!(--BC) << 2) | /* PF = !!BCo */ \ - NF | /* NF = 1 */ \ - F_C); /* CF unchanged */ \ - \ - MEMPTR operator; \ - PC += 2; \ - return 16 - - -#define CPXR(operator) \ - zuint8 n = READ(HL operator); \ - zuint8 t0 = A - n; \ - zuint8 hf = (A ^ n ^ t0) & HF; \ - zuint8 t1 = t0 - (hf >> 4); \ - \ - zuint8 f = (zuint8)( \ - (t0 & SF) | /* SF = sign */ \ - ZF_ZERO(t0) | /* ZF = zero */ \ - hf | /* HF = half-borrow */ \ - (!!(--BC) << 2) | /* PF = !!BCo */ \ - NF | /* NF = 1 */ \ - F_C); /* CF unchanged */ \ - \ - if (t0 && BC) \ - { \ - /* YF = PCi.13; XF = PCi.11 */ \ - FLAGS = f | ((PC >> 8) & YXF); \ - MEMPTR = PC + 1; \ - return 21; \ - } \ - \ - FLAGS = (zuint8)( \ - f | \ - ((t1 & 2) << 4) | /* YF = (A - [HLi] - HFo).1 */ \ - (t1 & XF)); /* XF = (A - [HLi] - HFo).3 */ \ - \ - MEMPTR operator; \ - PC += 2; \ - return 16 - - -#define ADD_RR_NN(RR, NN) \ - zuint16 nn = NN; \ - zuint16 t = RR + nn; \ - \ - FLAGS = F_SZP | /* SF, ZF, PF unchanged */ \ - ((t >> 8) & YXF) | /* YF = high-Y; XF = high-X */ \ - (((zuint16)(RR ^ nn ^ t) >> 8) & HF) | /* HF = high-half-carry */ \ - ((zuint32)RR + nn > 65535); /* CF = carry */ \ - /* NF = 0 */ \ - MEMPTR = RR + 1; \ - RR = t - - -#define ADC_SBC_HL_SS(operator, pf_test_rhs, cf_test, set_nf) \ - zuint8 fc = F_C; \ - zuint16 ss = SS1; \ - zuint16 t = HL operator ss operator fc; \ - \ - FLAGS = (zuint8)( \ - ((t >> 8) & SYXF) /* SF = sign; YF = high-Y; XF = high-X */ \ - | ZF_ZERO(t) /* ZF = zero */ \ - /* HF = high-half-carry (adc), high-half-borrow (sbc) */ \ - | (((zuint16)(HL ^ ss ^ t) >> 8) & HF) \ - | PF_OVERFLOW(16, t, HL, pf_test_rhs) /* PF = overflow */ \ - | ((zuint32)cf_test) /* CF = carry (adc), borrow (sbc) */ \ - set_nf); /* NF = 0 (adc), 1 (sbc) */ \ - \ - MEMPTR = HL + 1; \ - HL = t; \ - PC += 2; \ - return 15 - - -#define RXA(a_to_cf, operator, fc_to_a) \ - zuint8 cf = a_to_cf; \ - \ - A = (zuint8)((A operator 1) | fc_to_a); \ - \ - FLAGS = F_SZP | /* SF, ZF, PF unchanged */ \ - A_YX | /* YF = Y; XF = X */ \ - cf; /* CF = Ai.7 (rla), Ai.0 (rra) */ \ - /* HF, NF = 0 */ \ - PC++; \ - return 4 - - -#define RXD(vhl_to_vhl, a_to_vhl, vhl_to_a) \ - zuint8 t = READ(HL); \ - \ - MEMPTR = HL + 1; \ - WRITE(HL, (zuint8)((t vhl_to_vhl) | (A a_to_vhl))); \ - A = (A & 0xF0) | (t vhl_to_a); \ - \ - FLAGS = (zuint8)( /* HF, NF = 0; */ \ - A_SYX | /* SF = sign; YF = Y; XF = X */ \ - ZF_ZERO(A) | /* ZF = zero */ \ - PF_PARITY(A) | /* PF = parity */ \ - F_C); /* CF unchanged */ \ - \ - PC += 2; \ - return 18 - - -#define DJNZ_JR_Z_OFFSET(condition, cycles_if_true, cycles_if_false) \ - zsint8 offset; \ - \ - Q_0 \ - offset = (zsint8)FETCH(PC + 1); /* always */ \ - \ - if (condition) \ - { \ - MEMPTR = (PC += 2 + offset); \ - return cycles_if_true; \ - } \ - \ - PC += 2; \ - return cycles_if_false - - -#define RETX(mnemonic) \ - NOTIFY(mnemonic); \ - Q_0 \ - DATA[2] = IFF1; \ - if ((IFF1 = IFF2) && INT_LINE) REQUEST |= Z80_REQUEST_INT; \ - RET; \ - return 14 - - -#define IN_VC \ - zuint8 t; \ - \ - MEMPTR = BC + 1; \ - t = IN(BC); \ - \ - FLAGS = (zuint8)( /* HF, NF = 0 */ \ - (t & SYXF) | /* SF = sign; YF = Y; XF = X */ \ - ZF_ZERO(t) | /* ZF = zero */ \ - PF_PARITY(t) | /* PF = parity */ \ - F_C) /* CF unchanged */ - - -#define INX_OUTX(io) \ - FLAGS = (zuint8)( \ - (B & SYXF) | /* SF = Bo.7; YF = Bo.5; XF = Bo.3 */ \ - ZF_ZERO(B) | /* ZF = !Bo */ \ - PF_PARITY((t & 7) ^ B) | /* PF = ((T & 7) ^ Bo).parity */ \ - ((t > 255) ? HCF : 0) | /* HF, CF = T > 255 */ \ - ((io >> 6) & NF)); /* NF = IO.7 */ \ - \ - PC += 2; \ - return 16 - - -#define INX(hl_operator, memptr_operator) \ - zuint8 in = IN(BC); \ - zuint t = (zuint)in + (zuint8)(C memptr_operator 1); \ - \ - WRITE(HL hl_operator, in); \ - MEMPTR = BC memptr_operator 1; \ - B--; \ - INX_OUTX(in) \ - - -#define OUTX(hl_operator, memptr_operator) \ - zuint8 out = READ(HL hl_operator); \ - zuint t = (zuint)out + L; \ - \ - B--; \ - MEMPTR = BC memptr_operator 1; \ - OUT(BC, out); \ - INX_OUTX(out) - - -#define INXR_OTXR(io) \ - if (B) { \ - FLAGS = (zuint8)( /* ZF = 0 */ \ - (B & SF) | /* SF = Bo.7 */ \ - (PCH & YXF) | /* YF = PCi.13; XF = PCi.11 */ \ - nf | /* NF = IO.7 */ \ - (hcf ? \ - CF | \ - (nf ? \ - (!(B & 0xF) << 4) | \ - PF_PARITY(p ^ ((B - 1) & 7)) \ - : \ - (((B & 0xF) == 0xF) << 4) | \ - PF_PARITY(p ^ ((B + 1) & 7))) \ - : PF_PARITY(p ^ (B & 7)))); \ - \ - return 21; \ - } \ - \ - FLAGS = ZF | /* ZF = 1; SF, YF, XF = 0 */ \ - hcf | /* HF, CF = T > 255 */ \ - PF_PARITY(p) | /* PF = ((T & 7) ^ Bo).parity */ \ - nf; /* NF = IO.7 */ \ - \ - PC += 2; \ - return 16 - - -#define INXR(hl_operator, memptr_operator) \ - zuint8 in = IN(BC); \ - zuint8 nf = (in >> 6) & NF; \ - zuint t = (zuint)in + (zuint8)(C memptr_operator 1); \ - zuint8 hcf = (t > 255) ? HCF : 0; \ - zuint8 p; \ - \ - WRITE(HL hl_operator, in); \ - MEMPTR = BC memptr_operator 1; \ - p = (t & 7) ^ --B; \ - INXR_OTXR(in) - - -#define OTXR(hl_operator, memptr_operator) \ - zuint8 out = READ(HL hl_operator); \ - zuint8 nf = (out >> 6) & NF; \ - zuint t = (zuint)out + L; \ - zuint8 hcf = (t > 255) ? HCF : 0; \ - zuint8 p = (t & 7) ^ --B; \ - \ - MEMPTR = BC memptr_operator 1; \ - OUT(BC, out); \ - INXR_OTXR(out) - - -#define SET_HALT_LINE(state) \ - HALT_LINE = state; \ - if (self->halt != Z_NULL) self->halt(CONTEXT, state) - - -/* MARK: - Instructions: 8-Bit Load Group */ -/*----------------------------------------------------------------------------. -| 0 1 2 3 Flags T-states | -| Assembly 76543210765432107654321076543210 SZYHXPNC 12345 | -| ------------------- -------------------------------- -------- -------- | -| ld J,K 01jjjkkk ........ 4:4 | -|* ld O,P <--XY-->01oooppp ........ 8:44 | -| ld J,BYTE 00jjj110<-BYTE-> ........ 7:43 | -|* ld O,BYTE <--XY-->00ooo110<-BYTE-> ........ 11:443 | -| ld J,(hl) 01jjj110 ........ 7:43 | -| ld J,(XY+OFFSET) <--XY-->01jjj110 ........ 19:44353 | -| ld (hl),K 01110kkk ........ 7:43 | -| ld (XY+OFFSET),K <--XY-->01110kkk ........ 19:44353 | -| ld (hl),BYTE <--36--><-BYTE-> ........ 10:433 | -| ld (XY+OFFSET),BYTE <--XY--><--36--><-BYTE-> ........ 19:44353 | -| ld a,(bc) <--0A--> ........ 7:43 | -| ld a,(de) <--1A--> ........ 7:43 | -| ld a,(WORD) <--3A--><-----WORD-----> ........ 13:4333 | -| ld (bc),a <--02--> ........ 7:43 | -| ld (de),a <--12--> ........ 7:43 | -| ld (WORD),a <--32--><-----WORD-----> ........ 13:4333 | -| ld a,i <--ED--><--57--> szy0x*0. 9:45 | -| ld a,r <--ED--><--5F--> szy0x*0. 9:45 | -| ld i,a <--ED--><--47--> ........ 9:45 | -| ld r,a <--ED--><--4F--> ........ 9:45 | -|-----------------------------------------------------------------------------| -| (*) Undocumented instruction. | -'============================================================================*/ - -INSTRUCTION(ld_J_K ) {Q_0 J0 = K0; PC++; return 4;} -INSTRUCTION(ld_O_P ) {Q_0 O = P; PC += 2; return 4;} -INSTRUCTION(ld_J_BYTE ) {Q_0 J0 = FETCH((PC += 2) - 1); return 7;} -INSTRUCTION(ld_O_BYTE ) {Q_0 O = FETCH((PC += 3) - 1); return 7;} -INSTRUCTION(ld_J_vhl ) {Q_0 J0 = READ(HL); PC++; return 7;} -INSTRUCTION(ld_J_vXYpOFFSET) {Q_0 J1 = READ(FETCH_XY_EA((PC += 3) - 1)); return 15;} -INSTRUCTION(ld_vhl_K ) {Q_0 WRITE(HL, K0); PC++; return 7;} -INSTRUCTION(ld_vXYpOFFSET_K) {Q_0 WRITE(FETCH_XY_EA((PC += 3) - 1), K1); return 15;} -INSTRUCTION(ld_vhl_BYTE ) {Q_0 WRITE(HL, FETCH((PC += 2) - 1)); return 10;} -INSTRUCTION(ld_a_vbc ) {Q_0 MEMPTR = BC + 1; A = READ(BC); PC++; return 7;} -INSTRUCTION(ld_a_vde ) {Q_0 MEMPTR = DE + 1; A = READ(DE); PC++; return 7;} -INSTRUCTION(ld_a_vWORD ) {Q_0 MEMPTR = FETCH_16((PC += 3) - 2); A = READ(MEMPTR++); return 13;} -INSTRUCTION(ld_vbc_a ) {Q_0 MEMPTRL = C + 1; WRITE(BC, MEMPTRH = A); PC++; return 7;} -INSTRUCTION(ld_vde_a ) {Q_0 MEMPTRL = E + 1; WRITE(DE, MEMPTRH = A); PC++; return 7;} -INSTRUCTION(ld_a_i ) {LD_A_IR(I); } -INSTRUCTION(ld_a_r ) {LD_A_IR(R_ALL); } -INSTRUCTION(ld_i_a ) {NOTIFY(ld_i_a); Q_0 I = A; PC += 2; return 9;} -INSTRUCTION(ld_r_a ) {NOTIFY(ld_r_a); Q_0 R = R7 = A; PC += 2; return 9;} - - -INSTRUCTION(ld_vXYpOFFSET_BYTE) - { - zuint16 ea; - - Q_0 - ea = FETCH_XY_EA((PC += 4) - 2); - WRITE(ea, FETCH(PC - 1)); - return 15; - } - - -INSTRUCTION(ld_vWORD_a) - { - zuint16 ea; - - Q_0 - MEMPTRL = (zuint8)((ea = FETCH_16((PC += 3) - 2)) + 1); - WRITE(ea, MEMPTRH = A); - return 13; - } - - -/* MARK: - Instructions: 16-Bit Load Group */ -/*----------------------------------------------------------------------. -| 0 1 2 3 Flags T-states | -| Assembly 76543210765432107654321076543210 SZYHXPNC 123456 | -| ------------ -------------------------------- -------- --------- | -| ld SS,WORD 00ss0001<-----WORD-----> ........ 10:433 | -| ld XY,WORD <--XY--><--21--><-----WORD-----> ........ 14:4433 | -| ld hl,(WORD) <--2A--><-----WORD-----> ........ 16:43333 | -| ld SS,(WORD) <--ED-->01ss1011<-----WORD-----> ........ 20:443333 | -| ld XY,(WORD) <--XY--><--2A--><-----WORD-----> ........ 20:443333 | -| ld (WORD),hl <--22--><-----WORD-----> ........ 16:43333 | -| ld (WORD),SS <--ED-->01ss0011<-----WORD-----> ........ 20:443333 | -| ld (WORD),XY <--XY--><--22--><-----WORD-----> ........ 20:443333 | -| ld sp,hl <--F9--> ........ 6:6 | -| ld sp,XY <--XY--><--F9--> ........ 10:46 | -| push TT 11tt0101 ........ 11:533 | -| push XY <--XY--><--E5--> ........ 15:4533 | -| pop TT 11tt0001 ........ 10:433 | -| pop XY <--XY--><--E1--> ........ 14:4433 | -'======================================================================*/ - -INSTRUCTION(ld_SS_WORD ) {Q_0 SS0 = FETCH_16((PC += 3) - 2); return 10;} -INSTRUCTION(ld_XY_WORD ) {Q_0 XY = FETCH_16((PC += 4) - 2); return 10;} -INSTRUCTION(ld_hl_vWORD) {Q_0 MEMPTR = FETCH_16((PC += 3) - 2); HL = READ_16(MEMPTR++); return 16;} -INSTRUCTION(ld_SS_vWORD) {Q_0 MEMPTR = FETCH_16((PC += 4) - 2); SS1 = READ_16(MEMPTR++); return 20;} -INSTRUCTION(ld_XY_vWORD) {Q_0 MEMPTR = FETCH_16((PC += 4) - 2); XY = READ_16(MEMPTR++); return 16;} -INSTRUCTION(ld_vWORD_hl) {Q_0 MEMPTR = FETCH_16((PC += 3) - 2); WRITE_16F(MEMPTR++, HL ); return 16;} -INSTRUCTION(ld_vWORD_SS) {Q_0 MEMPTR = FETCH_16((PC += 4) - 2); WRITE_16F(MEMPTR++, SS1); return 20;} -INSTRUCTION(ld_vWORD_XY) {Q_0 MEMPTR = FETCH_16((PC += 4) - 2); WRITE_16F(MEMPTR++, XY ); return 16;} -INSTRUCTION(ld_sp_hl ) {Q_0 SP = HL; PC++; return 6;} -INSTRUCTION(ld_sp_XY ) {Q_0 SP = XY; PC += 2; return 6;} -INSTRUCTION(push_TT ) {Q_0 WRITE_16B(SP -= 2, TT); PC++; return 11;} -INSTRUCTION(push_XY ) {Q_0 WRITE_16B(SP -= 2, XY); PC += 2; return 11;} -INSTRUCTION(pop_TT ) {Q_0 TT = READ_16(SP); SP += 2; PC++; return 10;} -INSTRUCTION(pop_XY ) {Q_0 XY = READ_16(SP); SP += 2; PC += 2; return 10;} - - -/* MARK: - Instructions: Exchange, Block Transfer and Search Groups */ -/*-------------------------------------------------------------. -| 0 1 Flags T-states | -| Assembly 7654321076543210 SZYHXPNC !0 123456 =0 1234 | -| ---------- ---------------- -------- ------------------ | -| ex de,hl <--EB--> ........ 4:4 | -| ex af,af' <--08--> ........ 4:4 | -| exx <--D9--> ........ 4:4 | -| ex (sp),hl <--E3--> ........ 19:43435 | -| ex (sp),XY <--XY--><--E3--> ........ 23:443435 | -| ldi <--ED--><--A0--> ..*0**0. 16:4435 | -| ldir <--ED--><--B0--> ..*0*00. 21:44355 16:4435 | -| ldd <--ED--><--A8--> ..*0**0. 16:4435 | -| lddr <--ED--><--B8--> ..*0*00. 21:44355 16:4435 | -| cpi <--ED--><--A1--> sz*b**1. 16:4435 | -| cpir <--ED--><--B1--> sz*b**1. 21:44355 16:4435 | -| cpd <--ED--><--A9--> sz*b**1. 16:4435 | -| cpdr <--ED--><--B9--> sz*b**1. 21:44355 16:4435 | -'=============================================================*/ - -INSTRUCTION(ex_de_hl ) {zuint16 t; Q_0 EX(DE, HL ); PC++; return 4;} -INSTRUCTION(ex_af_af_) {zuint16 t; Q_0 EX(AF, AF_); PC++; return 4;} -INSTRUCTION(exx ) {zuint16 t; Q_0 EX(BC, BC_); EX(DE, DE_); EX(HL, HL_); PC++; return 4;} -INSTRUCTION(ex_vsp_hl) {Q_0 MEMPTR = READ_16(SP); WRITE_16B(SP, HL); HL = MEMPTR; PC++; return 19;} -INSTRUCTION(ex_vsp_XY) {Q_0 MEMPTR = READ_16(SP); WRITE_16B(SP, XY); XY = MEMPTR; PC += 2; return 19;} -INSTRUCTION(ldi ) {LDX (++); } -INSTRUCTION(ldir ) {LDXR(++); } -INSTRUCTION(ldd ) {LDX (--); } -INSTRUCTION(lddr ) {LDXR(--); } -INSTRUCTION(cpi ) {CPX (++); } -INSTRUCTION(cpir ) {CPXR(++); } -INSTRUCTION(cpd ) {CPX (--); } -INSTRUCTION(cpdr ) {CPXR(--); } - - -/* MARK: - Instructions: 8-Bit Arithmetic and Logical Group */ -/*-------------------------------------------------------------------. -| 0 1 2 Flags T-states | -| Assembly 765432107654321076543210 SZYHXPNC 123456 | -| ----------------- ------------------------ -------- --------- | -| U [a,]K 10uuukkk sz|||||| 4:4 | -|* U [a,]P <--XY-->10uuuppp sz|||||| 8:44 | -| U [a,]BYTE 11uuu110<-BYTE-> sz|||||| 7:43 | -| U [a,](hl) 10uuu110 sz|||||| 7:43 | -| U [a,](XY+OFFSET) <--XY-->10uuu110 sz|||||| 19:44353 | -| V J 00jjj10v szy|xv|. 4:4 | -|* V O <--XY-->00ooo10v szy|xv|. 8:44 | -| V (hl) 0011010v szy|xv|. 11:443 | -| V (XY+OFFSET) <--XY-->0011010v szy|xv|. 23:443543 | -|--------------------------------------------------------------------| -| (*) Undocumented instruction. | -| (|) The flag is explained in a previous table. | -'===================================================================*/ - -INSTRUCTION(U_a_K ) {U0(K0); PC++; return 4;} -INSTRUCTION(U_a_P ) {U1(P); PC += 2; return 4;} -INSTRUCTION(U_a_BYTE ) {U0(FETCH((PC += 2) - 1)); return 7;} -INSTRUCTION(U_a_vhl ) {U0(READ(HL)); PC++; return 7;} -INSTRUCTION(U_a_vXYpOFFSET) {U1(READ(FETCH_XY_EA((PC += 3) - 1))); return 15;} -INSTRUCTION(V_J ) {zuint8 *j = &J0; *j = V0(*j); PC++; return 4;} -INSTRUCTION(V_O ) {zuint8 *o = &O; *o = V1(*o); PC += 2; return 4;} -INSTRUCTION(V_vhl ) {WRITE(HL, V0(READ(HL))); PC++; return 11;} -INSTRUCTION(V_vXYpOFFSET ) {zuint16 ea = FETCH_XY_EA((PC += 3) - 1); WRITE(ea, V1(READ(ea))); return 19;} - - -/* MARK: - Instructions: General-Purpose Arithmetic and CPU Control Groups */ -/*-------------------------------------------------. -| 0 1 Flags T-states | -| Assembly 7654321076543210 SZYHXPNC 12 | -| -------- ---------------- -------- -------- | -| daa <--27--> szy^xp.* 4:4 | -| cpl <--2F--> ..y1x.1. 4:4 | -|+ neg <--ED-->01***100 szybxv1b 8:44 | -| ccf <--3F--> ..***.0~ 4:4 | -| scf <--37--> ..*0*.01 4:4 | -| nop <--00--> ........ 4:4 | -| halt <--76--> ........ 4:4 | -| di <--F3--> ........ 4:4 | -| ei <--FB--> ........ 4:4 | -|+ im 0 <--ED-->01*0*110 ........ 8:44 | -|+ im 1 <--ED-->01*10110 ........ 8:44 | -|+ im 2 <--ED-->01*11110 ........ 8:44 | -|--------------------------------------------------| -| (+) The instruction has undocumented opcodes. | -'=================================================*/ - -INSTRUCTION(nop ) {Q_0 PC++; return 4;} -INSTRUCTION(im_0) {Q_0 IM = 0; PC += 2; return 8;} -INSTRUCTION(im_1) {Q_0 IM = 1; PC += 2; return 8;} -INSTRUCTION(im_2) {Q_0 IM = 2; PC += 2; return 8;} - - -INSTRUCTION(daa) - { - zuint8 cf = A > 0x99, t = ((F & HF) || (A & 0xF) > 9) ? 6 : 0; - - if (F_C || cf) t |= 0x60; - t = (F & NF) ? A - t : A + t; - - FLAGS = (zuint8)( - (F & (NF | CF)) | /* NF unchanged; CF dominant */ - (t & SYXF) | /* SF = sign; YF = Y; XF = X */ - ZF_ZERO(t) | /* ZF = zero */ - ((A ^ t) & HF) | /* HF = Ai.4 != Ao.4 */ - PF_PARITY(t) | /* PF = parity */ - cf); /* CF |= 1 (if BCD carry) */ - - A = t; - PC++; - return 4; - } - - -INSTRUCTION(cpl) - { - FLAGS = F_SZPC | /* SF, ZF, PF, CF unchanged */ - ((A = ~A) & YXF) | /* YF = Y; XF = X */ - HF | NF; /* HF, NF = 1 */ - - PC++; - return 4; - } - - -INSTRUCTION(neg) - { - zuint8 t = (zuint8)-A; - - FLAGS = (zuint8)( - (t & SYXF) | /* SF = sign; YF = Y; XF = X */ - ZF_ZERO(t) | /* ZF = zero */ - ((A ^ t) & HF) | /* HF = half-borrow */ - ((t == 128) << 2) | /* PF = overflow */ - NF | /* NF = 1 */ - !!A); /* CF = borrow (not 0) */ - - A = t; - PC += 2; - return 8; - } - - -/*---------------------------------------------------------------------------. -| `ccf` and `scf` are the only instructions in which Q affects the flags. | -| Patrik Rak cracked the behavior of YF and XF in 2012, confirming that they | -| are taken, respectively, from bits 5 and 3 of the result of "(Q ^ F) | A" | -| [1,2]. This applies to all Zilog Z80 models, both NMOS and CMOS. In 2018, | -| David Banks (AKA hoglet) found that ST CMOS models do not set XF according | -| to this formula, but take this flag from bit 3 of A, while NEC NMOS models | -| take both flags from A [3]. | -| | -| References: | -| 1. https://worldofspectrum.org/forums/discussion/20345 | -| 2. https://worldofspectrum.org/forums/discussion/41704 | -| 3. Banks, David (2018-08-21). "Undocumented Z80 Flags" revision 1.0. | -| * https://github.com/hoglet67/Z80Decoder/wiki/Undocumented-Flags | -| * https://stardot.org.uk/forums/download/file.php?id=39831 | -'===========================================================================*/ - -INSTRUCTION(ccf) - { - FLAGS = (zuint8)( - (F_SZPC ^ CF) | /* SF, ZF, PF unchanged; CF = ~CFi */ - /* Zilog: YF = A.5 | (YFi ^ YQi); XF = A.3 | (XFi ^ XQi) */ - /* ST CMOS: YF = A.5 | (YFi ^ YQi); XF = A.3 */ - /* NEC NMOS: YF = A.5; XF = A.3 */ -# ifdef Z80_WITH_Q - ((((F ^ Q) & OPTIONS) | A) & YXF) | -# else - (A & YXF) | -# endif - (F_C << 4)); /* HF = CFi */ - /* NF = 0 */ - PC++; - return 4; - } - - -INSTRUCTION(scf) - { - FLAGS = F_SZP | /* SF, ZF, PF unchanged */ - /* Zilog: YF = A.5 | (YFi ^ YQi); XF = A.3 | (XFi ^ XQi) */ - /* ST CMOS: YF = A.5 | (YFi ^ YQi); XF = A.3 */ - /* NEC NMOS: YF = A.5; XF = A.3 */ -# ifdef Z80_WITH_Q - ((((F ^ Q) & OPTIONS) | A) & YXF) | -# else - (A & YXF) | -# endif - CF; /* CF = 1 */ - /* HF, NF = 0 */ - PC++; - return 4; - } - - -/*-----------------------------------------------------------------------------. -| The `halt` instruction enables the HALT state after PC is incremented during | -| the opcode fetch. The CPU neither decrements nor avoids incrementing PC "so | -| that the instruction is re-executed" as Sean Young writes in section 5.4 of | -| "The Undocumented Z80 Documented". During the HALT state, the CPU repeatedly | -| executes an internal NOP operation. Each NOP consists of 1 M1 cycle of 4 | -| T-states that fetches and disregards the next opcode after `halt` without | -| incrementing PC. This opcode is read again and again until an exit condition | -| occurs (i.e., INT, NMI or RESET). | -| | -| This was first documented by Tony Brewer in 2014, and was later re-confirmed | -| by the HALT2INT test written by Mark Woodmass (AKA Woody) in 2021. | -| | -| References: | -| * Brewer, Tony (2014-12). "Z80 Special Reset". | -| * http://primrosebank.net/computers/z80/z80_special_reset.htm | -| * https://stardot.org.uk/forums/viewtopic.php?p=357136#p357136 | -'=============================================================================*/ - -#ifdef Z80_WITH_SPECIAL_RESET - static Instruction const instruction_table[256]; -#endif - -INSTRUCTION(halt) - { - if (!HALT_LINE) - { - if (!RESUME) - { - Q_0 - PC++; - if (REQUEST) return 4; - RESUME = Z80_RESUME_HALT; - if ((self->cycles += 4) >= self->cycle_limit) return 0; - } - - SET_HALT_LINE(TRUE); - } - - if (self->nop == Z_NULL || (OPTIONS & Z80_OPTION_HALT_SKIP)) - { - zusize nop_cycles = self->cycle_limit - self->cycles; - - nop_cycles += (4 - (nop_cycles & 3)) & 3; - R += (zuint8)(nop_cycles >> 2); - self->cycles += nop_cycles; - } - -# ifdef Z80_WITH_SPECIAL_RESET - else { - zuint8 opcode; - - do { - R++; /* M1 */ - opcode = self->nop(CONTEXT, PC); - self->cycles += 4; - - if (REQUEST) - { - RESUME = FALSE; - - if (REQUEST & Z80_REQUEST_SPECIAL_RESET) - { - HALT_LINE = FALSE; - - if (self->halt != Z_NULL) - self->halt(CONTEXT, Z80_HALT_EARLY_EXIT); - - if ((DATA[0] = opcode) != 0x76) - { - self->cycles -= 4; - PC--; - return instruction_table[opcode](self); - } - } - - return 0; - } - } - while (self->cycles < self->cycle_limit); - - DATA[2] = opcode; - } - -# else - else do { - R++; /* M1 */ - (void)self->nop(CONTEXT, PC); - self->cycles += 4; - - if (REQUEST) - { - RESUME = FALSE; - return 0; - } - } - while (self->cycles < self->cycle_limit); -# endif - - return 0; - } - - -INSTRUCTION(di) - { - Q_0 - IFF1 = IFF2 = 0; - REQUEST &= ~(zuint8)Z80_REQUEST_INT; - PC++; - return 4; - } - - -INSTRUCTION(ei) - { - Q_0 - IFF1 = IFF2 = 1; - if (INT_LINE) REQUEST |= Z80_REQUEST_INT; - PC++; - return 4; - } - - -/* MARK: - Instructions: 16-Bit Arithmetic Group */ -/*--------------------------------------------------. -| 0 1 Flags T-states | -| Assembly 7654321076543210 SZYHXPNC 1234 | -| --------- ---------------- -------- -------- | -| add hl,SS 00ss1001 ..YCX.0c 11:443 | -| adc hl,SS <--ED-->01ss1010 szYCXv0c 15:4443 | -| sbc hl,SS <--ED-->01ss0010 szYBXv1b 15:4443 | -| add XY,WW <--XY-->00ww1001 ..YCX.0c 15:4443 | -| inc SS 00ss0011 ........ 6:6 | -| inc XY <--XY--><--23--> ........ 10:46 | -| dec SS 00ss1011 ........ 6:6 | -| dec XY <--XY--><--2B--> ........ 10:46 | -'==================================================*/ - -INSTRUCTION(add_hl_SS) {ADD_RR_NN(HL, SS0); PC++; return 11;} -INSTRUCTION(adc_hl_SS) {ADC_SBC_HL_SS(+, ~ss, ss + fc + HL > 65535, Z_EMPTY);} -INSTRUCTION(sbc_hl_SS) {ADC_SBC_HL_SS(-, ss, ss + fc > HL, | NF );} -INSTRUCTION(add_XY_WW) {ADD_RR_NN(XY, WW); PC += 2; return 11;} -INSTRUCTION(inc_SS ) {Q_0 (SS0)++; PC++; return 6;} -INSTRUCTION(inc_XY ) {Q_0 XY++; PC += 2; return 6;} -INSTRUCTION(dec_SS ) {Q_0 (SS0)--; PC++; return 6;} -INSTRUCTION(dec_XY ) {Q_0 XY--; PC += 2; return 6;} - - -/* MARK: - Instructions: Rotate and Shift Group */ -/*-------------------------------------------------------------------------. -| 0 1 2 3 Flags T-states | -| Assembly 76543210765432107654321076543210 SZYHXPNC 123456 | -| --------------- -------------------------------- -------- --------- | -| rlca <--07--> ..y0x.0= 4:4 | -| rla <--17--> ..y0x.0= 4:4 | -| rrca <--0F--> ..y0x.0= 4:4 | -| rra <--1F--> ..y0x.0= 4:4 | -|+ G K <--CB-->00gggkkk szy0xp0= 8:44 | -|+ G (hl) <--CB-->00ggg110 szy0xp0= 15:4443 | -|+ G (XY+OFFSET) <--XY--><--CB-->00ggg110 szy0xp0= 23:443543 | -|* G (XY+OFFSET),K <--XY--><--CB-->00gggkkk szy0xp0= 23:443543 | -| rld <--ED--><--6F--> szy0xp0. 18:44343 | -| rrd <--ED--><--67--> szy0xp0. 18:44343 | -|--------------------------------------------------------------------------| -| (+) Some forms of the instruction are undocumented. | -| (*) Undocumented instruction. | -'=========================================================================*/ - -INSTRUCTION(rlca ) {A = ROL(A); FLAGS = F_SZP | (A & YXCF); PC++; return 4;} -INSTRUCTION(rla ) {RXA(A >> 7, <<, F_C); } -INSTRUCTION(rrca ) {A = ROR(A); FLAGS = F_SZP | A_YX | (A >> 7); PC++; return 4;} -INSTRUCTION(rra ) {RXA(A & 1, >>, (F << 7)); } -INSTRUCTION(G_K ) {zuint8 *k = &K1; *k = G1(*k); return 8;} -INSTRUCTION(G_vhl ) {WRITE(HL, G1(READ(HL))); return 15;} -INSTRUCTION(G_vXYpOFFSET ) {zuint16 ea = MEMPTR; WRITE(ea, G3(READ(ea))); return 19;} -INSTRUCTION(G_vXYpOFFSET_K) {zuint16 ea = MEMPTR; WRITE(ea, K3 = G3(READ(ea))); return 19;} -INSTRUCTION(rld ) {RXD(<< 4, & 0xF, >> 4); } -INSTRUCTION(rrd ) {RXD(>> 4, << 4, & 0xF); } - - -/* MARK: - Instructions: Bit Set, Reset and Test Group */ -/*---------------------------------------------------------------------------. -| 0 1 2 3 Flags T-states | -| Assembly 76543210765432107654321076543210 SZYHXPNC 123456 | -| ----------------- -------------------------------- -------- --------- | -| bit N,K <--CB-->01nnnkkk sz*1*z0. 8:44 | -| bit N,(hl) <--CB-->01nnn110 sz*1*z0. 12:444 [1] -|+ bit N,(XY+OFFSET) <--XY--><--CB-->01nnn*** sz*1*z0. 20:44354 | -| M N,K <--CB-->1mnnnkkk ........ 8:44 | -| M N,(hl) <--CB-->1mnnn110 ........ 15:4443 | -| M N,(XY+OFFSET) <--XY--><--CB-->1mnnn110 ........ 23:443543 | -|* M N,(XY+OFFSET),K <--XY--><--CB-->1mnnnkkk ........ 23:443543 | -|----------------------------------------------------------------------------| -| (+) Some forms of the instruction are undocumented. | -| (*) Undocumented instruction. | -|----------------------------------------------------------------------------| -| 1. All versions of Zilog's "Z80 CPU User Manual" contain a typo in the | -| M-cycles of this instruction: an additional M-cycle of 4 T-states. | -'===========================================================================*/ - -INSTRUCTION(M_N_K ) {zuint8 *k = &K1; *k = M1(*k); return 8;} -INSTRUCTION(M_N_vhl ) {WRITE(HL, M1(READ(HL))); return 15;} -INSTRUCTION(M_N_vXYpOFFSET ) {zuint16 ea = MEMPTR; WRITE(ea, M3(READ(ea))); return 19;} -INSTRUCTION(M_N_vXYpOFFSET_K) {zuint16 ea = MEMPTR; WRITE(ea, K3 = M3(READ(ea))); return 19;} - - -INSTRUCTION(bit_N_K) - { - zuint8 k = K1; - zuint8 t = k & (1U << N(1)); - - /*----------------------------------------------------------. - | In section 4.1 of "The Undocumented Z80 Documented" (all | - | versions), Sean Young says that YF and XF are taken from | - | the value resulting from the bit test operation, but this | - | seems not to be true. They are copies of bits 5 and 3 of | - | the register containing the value to be tested (K). | - '==========================================================*/ - FLAGS = (t ? t & SF : ZPF) | /* SF = sign; ZF, PF = zero */ - (k & YXF) | /* YF = K.5; XF = K.3 */ - HF | /* HF = 1 */ - F_C; /* CF unchanged */ - /* NF = 0 */ - return 8; - } - - -INSTRUCTION(bit_N_vhl) - { - zuint8 t = READ(HL) & (1U << N(1)); - - /*----------------------------------------------------------------. - | This is the only instruction in which MEMPTR affects the flags. | - | YF and XF are taken, respectively, from bits 13 and 11 of this | - | internal register whose behavior was cracked in 2006 by boo_boo | - | and Vladimir Kladov. Official schematics refer to this register | - | as WZ, but this emulator uses the name "MEMPTR" to honour those | - | who cracked it. | - | | - | References: | - | * https://zxpress.ru/zxnet/zxnet.pc/5909 | - | * boo_boo; Kladov, Vladimir (2006-03-29). "MEMPTR, Esoteric | - | Register of the Zilog Z80 CPU". | - | * http://zx.pk.ru/showpost.php?p=43688 | - | * http://zx.pk.ru/attachment.php?attachmentid=2984 | - | * http://zx.pk.ru/showpost.php?p=43800 | - | * http://zx.pk.ru/attachment.php?attachmentid=2989 | - '================================================================*/ - FLAGS = (t ? t & SF : ZPF) | /* SF = sign; ZF, PF = zero */ - (MEMPTRH & YXF) | /* YF = MEMPTRH.5; XF = MEMPTRH.3 */ - HF | /* HF = 1 */ - F_C; /* CF unchanged */ - /* NF = 0 */ - return 12; - } - - -INSTRUCTION(bit_N_vXYpOFFSET) - { - zuint8 t = READ(MEMPTR) & (1U << N(3)); - - FLAGS = (t ? t & SF : ZPF) | /* SF sign; ZF, PF = zero */ - (MEMPTRH & YXF) | /* YF = EA.13; XF = EA.11 */ - HF | /* HF = 1 */ - F_C; /* CF unchanged */ - /* NF = 0 */ - return 16; - } - - -/* MARK: - Instructions: Jump Group */ -/*----------------------------------------------------------------. -| 0 1 2 Flags T-states | -| Assembly 765432107654321076543210 SZYHXPNC Y 123 N 12 | -| ----------- ------------------------ -------- ------------ | -| jp WORD <--C3--><-----WORD-----> ........ 10:433 | -| jp Z,WORD 11zzz010<-----WORD-----> ........ 10:433 | -| jr OFFSET <--18--> ........ 12:435 | -| jr Z,OFFSET 001zz000 ........ 12:435 7:43 | -| jp (hl) <--E9--> ........ 4:4 | -| jp (XY) <--XY--><--E9--> ........ 8:44 | -| djnz OFFSET <--10--> ........ 13:535 8:53 | -'================================================================*/ - -INSTRUCTION(jp_WORD ) {Q_0 MEMPTR = PC = FETCH_16(PC + 1); return 10;} -INSTRUCTION(jp_Z_WORD ) {Q_0 MEMPTR = FETCH_16(PC + 1); PC = Z(7) ? MEMPTR : PC + 3; return 10;} -INSTRUCTION(jr_OFFSET ) {Q_0 MEMPTR = (PC += 2 + (zsint8)FETCH(PC + 1)); return 12;} -INSTRUCTION(jr_Z_OFFSET) {DJNZ_JR_Z_OFFSET(Z(3), 12, 7); } -INSTRUCTION(jp_hl ) {Q_0 PC = HL; return 4;} -INSTRUCTION(jp_XY ) {Q_0 PC = XY; return 4;} -INSTRUCTION(djnz_OFFSET) {DJNZ_JR_Z_OFFSET(--B, 13, 8); } - - -/* MARK: - Instructions: Call and Return Group */ -/*--------------------------------------------------------------------. -| 0 1 2 Flags T-states | -| Assembly 765432107654321076543210 SZYHXPNC Y 123 N 123 | -| ----------- ------------------------ -------- ---------------- | -| call WORD <--CD--><-----WORD-----> ........ 17:43433 | -| call Z,WORD 11zzz100<-----WORD-----> ........ 17:43433 10:433 | -| ret <--C9--> ........ 10:433 | -| ret Z 11zzz000 ........ 11:533 5:5 | -|+ reti/retn <--ED-->01***101 ........ 14:4433 | -| rst N 11nnn111 ........ 11:533 | -|---------------------------------------------------------------------| -| (+) The instruction has undocumented opcodes. The `reti` mnemonic | -| is used to represent the ED4Dh opcode, which is recognized by | -| the Z80 CTC chip. All other opcodes are represented as `retn`. | -'====================================================================*/ - -INSTRUCTION(call_WORD) {Q_0 MEMPTR = FETCH_16(PC + 1); PUSH(PC + 3); PC = MEMPTR; return 17;} -INSTRUCTION(ret ) {Q_0 RET; return 10;} -INSTRUCTION(ret_Z ) {Q_0 if (Z(7)) {RET; return 11;} PC++; return 5;} -INSTRUCTION(reti ) {RETX(reti); } -INSTRUCTION(retn ) {RETX(retn); } -INSTRUCTION(rst_N ) {Q_0 PUSH(PC + 1); MEMPTR = PC = DATA[0] & 56; return 11;} - - -INSTRUCTION(call_Z_WORD) - { - Q_0 - MEMPTR = FETCH_16(PC + 1); /* always */ - - if (Z(7)) - { - PUSH(PC + 3); - PC = MEMPTR; - return 17; - } - - PC += 3; - return 10; - } - - -/* MARK: - Instructions: Input and Output Group */ -/*--------------------------------------------------------------. -| 0 1 Flags T-states | -| Assembly 7654321076543210 SZYHXPNC !0 12345 =0 1234 | -| ------------ ---------------- -------- ----------------- | -| in a,(BYTE) <--DB--><-BYTE-> ........ 11:434 | -| in J,(c) <--ED-->01jjj000 szy0xp0. 12:444 | -|* in (c) <--ED--><--70--> szy0xp0. 12:444 | -| ini <--ED--><--A2--> ******** 16:4543 [1] -| inir <--ED--><--B2--> ******** 21:45435 16:4543 [1] -| ind <--ED--><--AA--> ******** 16:4543 [1] -| indr <--ED--><--BA--> ******** 21:45435 16:4543 [1] -| out (BYTE),a <--D3--><-BYTE-> ........ 11:434 | -| out (c),J <--ED-->01jjj001 ........ 12:444 | -|* out (c),0 <--ED--><--71--> ........ 12:444 | -| outi <--ED--><--A3--> ******** 16:4534 | -| otir <--ED--><--B3--> ******** 21:45345 16:4534 | -| outd <--ED--><--AB--> ******** 16:4534 | -| otdr <--ED--><--BB--> ******** 21:45345 16:4534 | -|---------------------------------------------------------------| -| (*) Undocumented instruction. | -|---------------------------------------------------------------| -| 1. All versions of Zilog's "Z80 CPU User Manual" have a typo | -| in the M-cycles of these instructions: the T-states of the | -| 3rd and 4th M-cycles are swapped. | -'==============================================================*/ - -INSTRUCTION(in_J_vc ) {IN_VC; J1 = t; PC += 2; return 12;} -INSTRUCTION(in_vc ) {IN_VC; PC += 2; return 12;} -INSTRUCTION(ini ) {INX (++, +); } -INSTRUCTION(inir ) {INXR(++, +); } -INSTRUCTION(ind ) {INX (--, -); } -INSTRUCTION(indr ) {INXR(--, -); } -INSTRUCTION(out_vc_J) {Q_0 MEMPTR = BC + 1; OUT(BC, J1); PC += 2; return 12;} -INSTRUCTION(outi ) {OUTX(++, +); } -INSTRUCTION(otir ) {OTXR(++, +); } -INSTRUCTION(outd ) {OUTX(--, -); } -INSTRUCTION(otdr ) {OTXR(--, -); } - - -INSTRUCTION(in_a_vBYTE) - { - zuint16 t; - - Q_0 - - /*--------------------------------------------------------------------. - | In "MEMPTR, Esoteric Register of the Zilog Z80 CPU", boo_boo says | - | that MEMPTR is set to `((A << 8) | BYTE) + 1`, which causes a carry | - | from the LSbyte of the resulting port number if BYTE is 255. This | - | differs from all other instructions where MEMPTRH is set to A, but | - | it has been confirmed to be correct by the IN-MEMPTR test. | - '====================================================================*/ - MEMPTR = (t = (zuint16)(((zuint16)A << 8) | FETCH((PC += 2) - 1))) + 1; - - A = IN(t); - return 11; - } - - -INSTRUCTION(out_vBYTE_a) - { - zuint8 t; - - Q_0 - MEMPTRL = (t = FETCH((PC += 2) - 1)) + 1; - MEMPTRH = A; - OUT((zuint16)(((zuint16)A << 8) | t), A); - return 11; - } - - -/*----------------------------------------------------------------------------. -| The `out (c),0` instruction behaves as `out (c),255` on the Zilog Z80 CMOS. | -| This was first discovered by Simon Cooke, who reported it on Usenet in 1996 | -| [1]. Later, in 2004, Colin Piggot rediscovered it with his SAM Coupé when | -| running a demo for SCPDU 6, coincidentally written by Simon Cooke [2]. In | -| 2008, this was once again rediscovered by the MSX community [3]. | -| | -| References: | -| 1. https://groups.google.com/g/comp.os.cpm/c/HfSTFpaIkuU/m/KotvMWu3bZoJ | -| 2. https://sinclair.wiki.zxnet.co.uk/wiki/Z80 | -| 3. https://msx.org/forum/development/msx-development/bug-z80-emulation-or- | -| tr-hw | -'============================================================================*/ - -INSTRUCTION(out_vc_0) - { - Q_0 - PC += 2; - MEMPTR = BC + 1; - OUT(BC, (OPTIONS & Z80_OPTION_OUT_VC_255) ? 255 : 0); - return 12; - } - - -/* MARK: - Instructions: Optimizations */ - -INSTRUCTION(nop_nop) {Q_0; PC += 2; return 4;} - - -/* MARK: - Instruction Function Tables */ - -INSTRUCTION(cb_prefix ); -INSTRUCTION(ed_prefix ); -INSTRUCTION(dd_prefix ); -INSTRUCTION(fd_prefix ); -INSTRUCTION(xy_cb_prefix); -INSTRUCTION(xy_xy ); -INSTRUCTION(ed_illegal ); -INSTRUCTION(xy_illegal ); -INSTRUCTION(hook ); - -#ifdef Z80_WITH_UNOFFICIAL_RETI -# define reti_retn reti -#else -# define reti_retn retn -#endif - -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_J, V_J, ld_J_BYTE, rlca, ex_af_af_, add_hl_SS, ld_a_vbc, dec_SS, V_J, V_J, ld_J_BYTE, rrca, -/* 1 */ djnz_OFFSET, ld_SS_WORD, ld_vde_a, inc_SS, V_J, V_J, ld_J_BYTE, rla, jr_OFFSET, add_hl_SS, ld_a_vde, dec_SS, V_J, V_J, ld_J_BYTE, rra, -/* 2 */ jr_Z_OFFSET, ld_SS_WORD, ld_vWORD_hl, inc_SS, V_J, V_J, ld_J_BYTE, daa, jr_Z_OFFSET, add_hl_SS, ld_hl_vWORD, dec_SS, V_J, V_J, ld_J_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_J, V_J, ld_J_BYTE, ccf, -/* 4 */ nop, ld_J_K, ld_J_K, ld_J_K, ld_J_K, ld_J_K, ld_J_vhl, ld_J_K, ld_J_K, nop, ld_J_K, ld_J_K, ld_J_K, ld_J_K, ld_J_vhl, ld_J_K, -/* 5 */ ld_J_K, ld_J_K, nop, ld_J_K, ld_J_K, ld_J_K, ld_J_vhl, ld_J_K, ld_J_K, ld_J_K, ld_J_K, nop, ld_J_K, ld_J_K, ld_J_vhl, ld_J_K, -/* 6 */ ld_J_K, ld_J_K, ld_J_K, ld_J_K, hook, ld_J_K, ld_J_vhl, ld_J_K, ld_J_K, ld_J_K, ld_J_K, ld_J_K, ld_J_K, nop, ld_J_vhl, ld_J_K, -/* 7 */ ld_vhl_K, ld_vhl_K, ld_vhl_K, ld_vhl_K, ld_vhl_K, ld_vhl_K, halt, ld_vhl_K, ld_J_K, ld_J_K, ld_J_K, ld_J_K, ld_J_K, ld_J_K, ld_J_vhl, nop, -/* 8 */ U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_vhl, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_vhl, U_a_K, -/* 9 */ U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_vhl, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_vhl, U_a_K, -/* A */ U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_vhl, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_vhl, U_a_K, -/* B */ U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_vhl, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_K, U_a_vhl, U_a_K, -/* 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_prefix, 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_vBYTE, call_Z_WORD, dd_prefix, 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_prefix, 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_prefix, U_a_BYTE, rst_N -}; - -static Instruction const cb_instruction_table[256] = { -/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ -/* 0 */ G_K, G_K, G_K, G_K, G_K, G_K, G_vhl, G_K, G_K, G_K, G_K, G_K, G_K, G_K, G_vhl, G_K, -/* 1 */ G_K, G_K, G_K, G_K, G_K, G_K, G_vhl, G_K, G_K, G_K, G_K, G_K, G_K, G_K, G_vhl, G_K, -/* 2 */ G_K, G_K, G_K, G_K, G_K, G_K, G_vhl, G_K, G_K, G_K, G_K, G_K, G_K, G_K, G_vhl, G_K, -/* 3 */ G_K, G_K, G_K, G_K, G_K, G_K, G_vhl, G_K, G_K, G_K, G_K, G_K, G_K, G_K, G_vhl, G_K, -/* 4 */ bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_vhl, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_vhl, bit_N_K, -/* 5 */ bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_vhl, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_vhl, bit_N_K, -/* 6 */ bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_vhl, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_vhl, bit_N_K, -/* 7 */ bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_vhl, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_K, bit_N_vhl, bit_N_K, -/* 8 */ M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, -/* 9 */ M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, -/* A */ M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, -/* B */ M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, -/* C */ M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, -/* D */ M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, -/* E */ M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, -/* F */ M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_K, M_N_vhl, M_N_K -}; - -static Instruction const ed_instruction_table[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_J_vc, out_vc_J, sbc_hl_SS, ld_vWORD_SS, neg, retn, im_0, ld_i_a, in_J_vc, out_vc_J, adc_hl_SS, ld_SS_vWORD, neg, reti, im_0, ld_r_a, -/* 5 */ in_J_vc, out_vc_J, sbc_hl_SS, ld_vWORD_SS, neg, retn, im_1, ld_a_i, in_J_vc, out_vc_J, adc_hl_SS, ld_SS_vWORD, neg, reti_retn, im_2, ld_a_r, -/* 6 */ in_J_vc, out_vc_J, sbc_hl_SS, ld_vWORD_SS, neg, retn, im_0, rrd, in_J_vc, out_vc_J, adc_hl_SS, ld_SS_vWORD, neg, reti_retn, im_0, rld, -/* 7 */ in_vc, out_vc_0, sbc_hl_SS, ld_vWORD_SS, neg, retn, im_1, ed_illegal, in_J_vc, out_vc_J, adc_hl_SS, ld_SS_vWORD, neg, reti_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 -}; - -static Instruction const xy_instruction_table[256] = { -/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ -/* 0 */ nop_nop, xy_illegal, xy_illegal, xy_illegal, V_O, V_O, ld_O_BYTE, xy_illegal, xy_illegal, add_XY_WW, xy_illegal, xy_illegal, V_O, V_O, ld_O_BYTE, xy_illegal, -/* 1 */ xy_illegal, xy_illegal, xy_illegal, xy_illegal, V_O, V_O, ld_O_BYTE, xy_illegal, xy_illegal, add_XY_WW, xy_illegal, xy_illegal, V_O, V_O, ld_O_BYTE, xy_illegal, -/* 2 */ xy_illegal, ld_XY_WORD, ld_vWORD_XY, inc_XY, V_O, V_O, ld_O_BYTE, xy_illegal, xy_illegal, add_XY_WW, ld_XY_vWORD, dec_XY, V_O, V_O, ld_O_BYTE, xy_illegal, -/* 3 */ xy_illegal, xy_illegal, xy_illegal, xy_illegal, V_vXYpOFFSET, V_vXYpOFFSET, ld_vXYpOFFSET_BYTE, xy_illegal, xy_illegal, add_XY_WW, xy_illegal, xy_illegal, V_O, V_O, ld_O_BYTE, xy_illegal, -/* 4 */ nop_nop, ld_O_P, ld_O_P, ld_O_P, ld_O_P, ld_O_P, ld_J_vXYpOFFSET, ld_O_P, ld_O_P, nop_nop, ld_O_P, ld_O_P, ld_O_P, ld_O_P, ld_J_vXYpOFFSET, ld_O_P, -/* 5 */ ld_O_P, ld_O_P, nop_nop, ld_O_P, ld_O_P, ld_O_P, ld_J_vXYpOFFSET, ld_O_P, ld_O_P, ld_O_P, ld_O_P, nop_nop, ld_O_P, ld_O_P, ld_J_vXYpOFFSET, ld_O_P, -/* 6 */ ld_O_P, ld_O_P, ld_O_P, ld_O_P, nop_nop, ld_O_P, ld_J_vXYpOFFSET, ld_O_P, ld_O_P, ld_O_P, ld_O_P, ld_O_P, ld_O_P, nop_nop, ld_J_vXYpOFFSET, ld_O_P, -/* 7 */ ld_vXYpOFFSET_K, ld_vXYpOFFSET_K, ld_vXYpOFFSET_K, ld_vXYpOFFSET_K, ld_vXYpOFFSET_K, ld_vXYpOFFSET_K, xy_illegal, ld_vXYpOFFSET_K, ld_O_P, ld_O_P, ld_O_P, ld_O_P, ld_O_P, ld_O_P, ld_J_vXYpOFFSET, nop_nop, -/* 8 */ U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_vXYpOFFSET, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_vXYpOFFSET, U_a_P, -/* 9 */ U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_vXYpOFFSET, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_vXYpOFFSET, U_a_P, -/* A */ U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_vXYpOFFSET, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_vXYpOFFSET, U_a_P, -/* B */ U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_vXYpOFFSET, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_P, U_a_vXYpOFFSET, U_a_P, -/* 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_prefix, 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_xy, 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_xy, xy_illegal, xy_illegal -}; - -static Instruction const xy_cb_instruction_table[256] = { -/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ -/* 0 */ G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET, G_vXYpOFFSET_K, -/* 1 */ G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET, G_vXYpOFFSET_K, -/* 2 */ G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET, G_vXYpOFFSET_K, -/* 3 */ G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET_K, G_vXYpOFFSET, G_vXYpOFFSET_K, -/* 4 */ bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, -/* 5 */ bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, -/* 6 */ bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, -/* 7 */ bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, bit_N_vXYpOFFSET, -/* 8 */ M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, -/* 9 */ M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, -/* A */ M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, -/* B */ M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, -/* C */ M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, -/* D */ M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, -/* E */ M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, -/* F */ M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET_K, M_N_vXYpOFFSET, M_N_vXYpOFFSET_K -}; - - -/* MARK: - Instructions: Prefix Handling */ - -INSTRUCTION(cb_prefix) - { - R++; - return cb_instruction_table[DATA[1] = FETCH_OPCODE((PC += 2) - 1)](self); - } - - -INSTRUCTION(ed_prefix) - { - R++; - return ed_instruction_table[DATA[1] = FETCH_OPCODE(PC + 1)](self); - } - - -#define XY_PREFIX(register) \ - zuint8 cycles; \ - \ - if ((self->cycles += 4) >= self->cycle_limit) \ - { \ - RESUME = Z80_RESUME_XY; \ - return 0; \ - } \ - \ - R++; \ - XY = register; \ - cycles = xy_instruction_table[DATA[1] = FETCH_OPCODE(PC + 1)](self); \ - register = XY; \ - return cycles; - - -INSTRUCTION(dd_prefix) {XY_PREFIX(IX)} -INSTRUCTION(fd_prefix) {XY_PREFIX(IY)} - - -/*------------------------------------------------------------------------. -| Instructions with DDCBh or FDCBh prefix increment R by 2, as only the | -| bytes of the prefix are fetched by opcode fetch operations (M1 cycles). | -| The remaining 2 bytes are fetched by normal memory read operations. | -'========================================================================*/ - -INSTRUCTION(xy_cb_prefix) - { - FETCH_XY_EA((PC += 4) - 2); - return xy_cb_instruction_table[DATA[3] = FETCH(PC - 1)](self); - } - - -/*-----------------------------------------------------------------------------. -| In a sequence of DDh and/or FDh prefixes, it is the last one that counts, as | -| each prefix disables and replaces the previous one. No matter how long the | -| sequence is, interrupts can only be responded after all prefixes are fetched | -| and the final instruction is executed. Each prefix consumes 4 T-states. | -'=============================================================================*/ - -INSTRUCTION(xy_xy) - { - zuint8 cycles; - zuint8 first_prefix = DATA[0]; - - do { - PC++; - DATA[0] = DATA[1]; - - if ((self->cycles += 4) >= self->cycle_limit) - { - RESUME = Z80_RESUME_XY; - return 0; - } - - R++; - } - while (IS_XY_PREFIX(DATA[1] = FETCH_OPCODE(PC + 1))); - - if (DATA[0] == first_prefix) return xy_instruction_table[DATA[1]](self); - - if (first_prefix == 0xFD) - { - XY = IX; - cycles = xy_instruction_table[DATA[1]](self); - IX = XY; - XY = IY; - } - - else { - XY = IY; - cycles = xy_instruction_table[DATA[1]](self); - IY = XY; - XY = IX; - } - - return cycles; - } - - -/* MARK: - Instructions: Illegal */ - -/*------------------------------------------------------------------. -| The CPU ignores illegal instructions with EDh prefix; in practice | -| they are all equivalent to two `nop` instructions (8 T-states). | -'==================================================================*/ - -INSTRUCTION(ed_illegal) - { - if (self->illegal != Z_NULL) return self->illegal(CONTEXT, DATA[0]); - Q_0 - PC += 2; - return 8; - } - - -/*------------------------------------------------------------------------. -| Illegal instructions with DDh or FDh prefix cause the CPU to ignore the | -| prefix, i.e., the byte immediately following the prefix is interpreted | -| as the first byte of a new instruction. The prefix consumes 4 T-states. | -'========================================================================*/ - -INSTRUCTION(xy_illegal) - { - PC++; - return instruction_table[DATA[0] = DATA[1]](self); - } - - -/* MARK: - Instructions: Hooking */ - -INSTRUCTION(hook) - { - if (self->hook == Z_NULL) - { - Q_0 - PC++; - return 4; - } - - if ((DATA[0] = self->hook(CONTEXT, PC)) != Z80_HOOK) - return instruction_table[DATA[0]](self); - - R--; - return 0; - } - - -/* MARK: - Interrupt Mode 0: PC Decrements for Unprefixed Instructions */ - -#ifdef Z80_WITH_FULL_IM0 - static zuint8 const im0_pc_decrement_table[256] = { - /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ - /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 1 */ 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, - /* 2 */ 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, - /* 3 */ 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, - /* 4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 5 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 6 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* A */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* B */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* C */ 1, 0, 3, 0, 3, 0, 0, 1, 1, 0, 3, 0, 3, 3, 0, 1, - /* D */ 1, 0, 3, 0, 3, 0, 0, 1, 1, 0, 3, 0, 3, 0, 0, 1, - /* E */ 1, 0, 3, 0, 3, 0, 0, 1, 1, 0, 3, 0, 3, 0, 0, 1, - /* F */ 1, 0, 3, 0, 3, 0, 0, 1, 1, 0, 3, 0, 3, 0, 0, 1 - }; -#endif - - -/* MARK: - Interrupt Mode 0: Callback Trampolines */ - -#ifdef Z80_WITH_FULL_IM0 - static zuint8 im0_fetch(IM0 *self, zuint16 address) - { - Z_UNUSED(address) - return self->z80->int_fetch(CONTEXT, self->pc); - } - - - static zuint8 im0_read(IM0 *self, zuint16 address) - {return READ(address);} - - - static void im0_write(IM0 *self, zuint16 address, zuint8 value) - {WRITE(address, value);} - - - static zuint8 im0_in(IM0 *self, zuint16 port) - {return IN(port);} - - - static void im0_out(IM0 *self, zuint16 port, zuint8 value) - {OUT(port, value);} - - - static void im0_ld_i_a(IM0 *self) {NOTIFY(ld_i_a);} - static void im0_ld_r_a(IM0 *self) {NOTIFY(ld_r_a);} - static void im0_reti (IM0 *self) {NOTIFY(reti );} - static void im0_retn (IM0 *self) {NOTIFY(retn );} -#endif - - -/* MARK: - Public Functions */ - -/*----------------------------------------------------------------------. -| On POWER-ON, the CPU zeroes PC, I, and R, sets SP, IX, IY, AF, BC, | -| DE, HL, AF', BC', DE' and HL' to to FFFFh [1,2], resets the interrupt | -| enable flip-flops (IFF1 and IFF2) and selects interrupt mode 0 [3]. | -| On Zilog NMOS models, F is sometimes set to FDh (NF reset) [1]. | -| | -| There is no information about the initial state of MEMPTR and Q, so | -| they are assumed to be 0. | -| | -| References: | -| 1. https://baltazarstudios.com/webshare/Z80-undocumented-behavior.htm | -| 2. https://worldofspectrum.org/forums/discussion/34574 | -| 3. Young, Sean (2005-09-18). "Undocumented Z80 Documented, The" | -| v0.91, p. 20. | -'======================================================================*/ - -Z80_API void z80_power(Z80 *self, zboolean state) - { - MEMPTR = PC = R = I = IFF1 = IFF2 = IM = Q = - DATA[0] = HALT_LINE = INT_LINE = RESUME = REQUEST = 0; - - SP = IX = IY = AF = BC = DE = HL = AF_ = BC_ = DE_ = HL_ = - state ? Z_UINT16(0xFFFF) : 0; - } - - -/*--------------------------------------------------------------------------. -| The normal RESET zeroes PC, I, and R [1,2,3,4,5,6], resets the interrupt | -| enable flip-flops (IFF1 and IFF2) [1,2,3,4,5] and selects the interrupt | -| mode 0 [1,2,3,4,7]. | -| | -| References: | -| 1. Zilog (2016-09). "Z80 CPU User Manual" revision 11, p. 6. | -| 2. SGS-Thomson (1990-01). "Z80 Microprocessor Family" 1st edition, p. 33. | -| 3. Brewer, Tony (2014-12). "Z80 Special Reset". | -| * http://primrosebank.net/computers/z80/z80_special_reset.htm | -| 4. Flammenkamp, Achim. "Interrupt Behaviour of the Z80 CPU". | -| * http://z80.info/interrup.htm | -| 5. https://baltazarstudios.com/webshare/Z80-undocumented-behavior.htm | -| 6. https://worldofspectrum.org/forums/discussion/34574 | -| 7. Zilog (1978-05). "Z80 Family Program Interrupt Structure, The", p. 8. | -'==========================================================================*/ - -Z80_API void z80_instant_reset(Z80 *self) - { - if (HALT_LINE) {SET_HALT_LINE(FALSE);} - - PC = R = I = IFF1 = IFF2 = IM = - DATA[0] = HALT_LINE = RESUME = REQUEST = 0; - } - - -#ifdef Z80_WITH_SPECIAL_RESET - Z80_API void z80_special_reset(Z80 *self) - {REQUEST |= Z80_REQUEST_SPECIAL_RESET;} -#endif - - -Z80_API void z80_int(Z80 *self, zboolean state) - { - if (!(INT_LINE = state)) REQUEST &= ~(zuint8)Z80_REQUEST_INT; - else if (IFF1) REQUEST |= Z80_REQUEST_INT; - } - - -Z80_API void z80_nmi(Z80 *self) - {REQUEST |= Z80_REQUEST_NMI;} - - -#ifdef Z80_WITH_EXECUTE - Z80_API zusize z80_execute(Z80 *self, zusize cycles) - { - ZInt16 *xy; - - R7 = R; - self->cycles = 0; - self->cycle_limit = cycles; - - if (RESUME && cycles) switch (RESUME) - { - case Z80_RESUME_HALT: - (void)halt(self); - break; - - case Z80_RESUME_XY: - RESUME = FALSE; - R++; /* M1 */ - XY = (xy = &self->ix_iy[(DATA[0] >> 5) & 1])->uint16_value; - self->cycles += xy_instruction_table[DATA[1] = FETCH_OPCODE(PC + 1)](self); - xy->uint16_value = XY; - break; - } - - while (self->cycles < cycles) - { - R++; /* M1 */ - self->cycles += instruction_table[DATA[0] = FETCH_OPCODE(PC)](self); - } - - R = R_ALL; /* restore R7 bit */ - return self->cycles; /* return consumed cycles */ - } -#endif - - -Z80_API zusize z80_run(Z80 *self, zusize cycles) - { - ZInt16 *xy; - zuint8 ird; - - /*---------------------------------------------------------------------. - | The CPU increments R during each M1 cycle without altering the most | - | significant bit, commonly known as R7. This behavior is not emulated | - | in every increment for obvious speed reasons. Instead, a copy of R | - | is used to preserve R7, which is restored before returning from this | - | function. The emulation of `ld {a,r|r,a}` takes this into account. | - '=====================================================================*/ - R7 = R; - - self->cycles = 0; - self->cycle_limit = cycles; - - if (RESUME && cycles) switch (RESUME) - { - /*----------------------------------------------------------------. - | The CPU is halted. In order to avoid affecting the speed of the | - | main execution loop, this state is executed by a dedicated loop | - | within the function that emulates the `halt` instruction. | - '================================================================*/ - case Z80_RESUME_HALT: - if (REQUEST) - { - RESUME = FALSE; - -# ifdef Z80_WITH_SPECIAL_RESET - if ((REQUEST & Z80_REQUEST_SPECIAL_RESET) && HALT_LINE) - { - zuint8 opcode; - - HALT_LINE = FALSE; - - if (self->halt != Z_NULL) - self->halt(CONTEXT, Z80_HALT_EARLY_EXIT); - - if (IS_XY_PREFIX(DATA[0] = opcode = DATA[2])) - self->cycles += instruction_table[FETCH_OPCODE(PC)](self); - - else if (opcode != 0x76) - { - PC--; - self->cycles += instruction_table[opcode](self) - 4; - } - } -# endif - } - - else (void)halt(self); - break; - - /*--------------------------------------------------------------. - | The CPU is in normal operation state; the emulator ran out of | - | clock cycles by fetching a DDh or FDh prefix. | - '==============================================================*/ - case Z80_RESUME_XY: - RESUME = FALSE; - R++; - XY = (xy = &self->ix_iy[(DATA[0] >> 5) & 1])->uint16_value; - self->cycles += xy_instruction_table[DATA[1] = FETCH_OPCODE(PC + 1)](self); - xy->uint16_value = XY; - break; - - /*----------------------------------------------------------------. - | The CPU is responding to an INT in mode 0; the emulator ran out | - | clock cycles by fetching a DDh or FDh prefix. | - '================================================================*/ -# ifdef Z80_WITH_FULL_IM0 - case Z80_RESUME_IM0_XY: - ird = DATA[0]; - goto im0_begin; -# endif - } - - while (self->cycles < cycles) /* main execution loop */ - { - if (REQUEST) - { - /*-------------------------------------------------------------------------. - | After detecting a special RESET signal, the CPU completes the ongoing | - | instruction or interrupt response and then zeroes PC during the falling | - | edge of the next M1T1. The special RESET can be used in conjunction with | - | an interrupt, in which case PC is zeroed during the subsequent interrupt | - | acknowledge M-cycle. Otherwise, if no interrupt has been accepted at TL | - | of the instruction or interrupt response in which the special RESET has | - | been detected, the CPU produces an M1 cycle of 4 T-states to allow for | - | the fetch-execute overlap to take place, during which it fetches the | - | next opcode and zeroes PC. | - | | - | References: | - | * Brewer, Tony (2014-12). "Z80 Special Reset". | - | * http://primrosebank.net/computers/z80/z80_special_reset.htm | - | * US Patent 4486827 | - | * Checked with "Visual Z80 Remix". | - '=========================================================================*/ -# ifdef Z80_WITH_SPECIAL_RESET - zuint8 special_reset = REQUEST & Z80_REQUEST_SPECIAL_RESET; -# endif - - /*-------------------------------------------------------------------------. - | NMI Response: Execute `rst 66h` | T-states: 11:533 | - |--------------------------------------------------------------------------| - | The non-maskable interrupt takes priority over the maskable interrupt | - | and cannot be disabled under software control. Its usual function is to | - | provide immediate response to important signals. The CPU responds to an | - | NMI by storing PC on the stack and jumping to the ISR located at address | - | 0066h. The interrupt enable flip-flop 1 (IFF1) is reset to prevent any | - | INT from being accepted during the execution of this routine, which is | - | usually exited by using a `reti` or `retn` instruction to restore the | - | original state of IFF1 [1]. | - | | - | Some technical documents from Zilog include an erroneous timing diagram | - | showing an NMI acknowledge cycle of 4 T-states. However, documents from | - | other manufacturers and third parties specify that this M-cycle has 5 | - | T-states, as has been confirmed by low-level tests [2] and electronic | - | simulations [3]. | - | | - | The CPU does not accept a second NMI during the NMI response. Therefore, | - | it is not possible to chain two NMI responses in a row without executing | - | at least one instruction between them [3,4,5]. | - | | - | References: | - | 1. Zilog (1978-05). "Z80 Family Program Interrupt Structure, The", | - | pp. 4,5. | - | 2. https://baltazarstudios.com/webshare/Z80-undocumented-behavior.htm | - | 3. Checked with "Visual Z80 Remix". | - | 4. https://spectrumcomputing.co.uk/forums/viewtopic.php?t=7086 | - | 5. https://stardot.org.uk/forums/viewtopic.php?t=24662 | - '=========================================================================*/ - if (REQUEST & Z80_REQUEST_REJECT_NMI) - REQUEST = 0; - - else if (REQUEST & Z80_REQUEST_NMI) - { - REQUEST = Z80_REQUEST_REJECT_NMI; - IFF1 = 0; - if (HALT_LINE) {SET_HALT_LINE(FALSE);} - R++; /* M1 */ - if (self->nmia != Z_NULL) (void)self->nmia(CONTEXT, PC); - DATA[0] = 0; - Q_0 - -# ifdef Z80_WITH_SPECIAL_RESET - PUSH(PC >> special_reset); -# else - PUSH(PC); -# endif - - PC = MEMPTR = 0x66; - self->cycles += 11; - continue; - } - - /*-------------------------------------------------------------------------. - | INT Response | - |--------------------------------------------------------------------------| - | The maskable interrupt can be enabled and disabled by using the `ei` and | - | `di` instructions respectively, which control the state of the interrupt | - | enable flip-flops (IFF1 and IFF2). The CPU does not accept this kind of | - | interrupt directly after an `ei` instruction, but only after the one | - | following `ei` is executed. This is so that ISRs can return without the | - | danger of being interrupted immediately after re-enabling interrupts if | - | the /INT line is still active, which could cause a stack overflow. | - | | - | As in `ei`, all forms of `reti` and `retn` defer the acceptance of the | - | maskable interrupt for one instruction, but this only occurs when IFF1 | - | and IFF2 do not have the same state prior to the execution of either of | - | these instructions, which can only be caused by an earlier NMI response | - | [1,2,3]. | - | | - | References: | - | 1. https://floooh.github.io/2021/12/17/cycle-stepped-z80.html | - | 2. https://spectrumcomputing.co.uk/forums/viewtopic.php?t=7086 | - | 3. https://stardot.org.uk/forums/viewtopic.php?t=24662 | - '=========================================================================*/ - else if ( -# ifdef Z80_WITH_SPECIAL_RESET - (REQUEST & Z80_REQUEST_INT) && -# endif - /* if the previous instruction is not `ei` */ - DATA[0] != 0xFB && - /* if the previous instruction is not `reti/retn` or IFF1 has not changed */ - (self->data.uint32_value & Z_UINT32_BIG_ENDIAN(Z_UINT32(0xFFC7FF00))) - != Z_UINT32_BIG_ENDIAN(Z_UINT32(0xED450000)) - ) - { -# ifdef Z80_WITH_FULL_IM0 - Z80Read hook; - IM0 im0; -# endif - - REQUEST = IFF1 = IFF2 = 0; - if (HALT_LINE) {SET_HALT_LINE(FALSE);} - - /*-------------------------------------------------------------------. - | Due to a bug, the Zilog Z80 NMOS resets PF when an INT is accepted | - | during the execution of the `ld a,{i|r}` instructions. | - '===================================================================*/ -# ifdef Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG - if ( (OPTIONS & Z80_OPTION_LD_A_IR_BUG) && - (self->data.uint16_array[0] & Z_UINT16_BIG_ENDIAN(Z_UINT16(0xFFF7))) - == Z_UINT16_BIG_ENDIAN(Z_UINT16(0xED57)) - ) - FLAGS = F & ~(zuint8)PF; -# endif - - /*---------------------------------------------------------------------. - | The INT acknowledge cycle (INTA) indicates that the interrupting I/O | - | device can write to the data bus. 2 wait T-states are automatically | - | added to this M-cycle, allowing sufficient time to identify which | - | device must insert the interrupt response data (IRD). The first and | - | posibly sole byte of the IRD is read from the data bus during this | - | special M1 cycle. | - | | - | The value FFh is assumed when the `inta` callback is not used. This | - | is the most desirable behavior, since the `rst 38h` instruction will | - | be executed if the interrupt mode is 0. | - '=====================================================================*/ - R++; /* M1 */ - ird = (self->inta != Z_NULL) ? INTA : 0xFF; - -# ifdef Z80_WITH_SPECIAL_RESET - PC >>= special_reset; -# endif - - switch (IM) /* response */ - { - /*-------------------------------------------------------------------------. - | Interrupt Mode 0: Execute Instruction | T-states: 2*n + instruction | - |--------------------------------------------------------------------------| - | An instruction supplied via the data bus is executed. Its first byte is | - | read during the INT acknowledge cycle (INTA). If it is an opcode prefix, | - | additional M-cycles of this kind are produced until the final opcode of | - | the instruction is fetched [1]. Each INT acknowledge cycle consumes as | - | many T-states as its normal M1 counterpart (the opcode fech M-cycle) | - | plus the 2 wait T-states mentioned above [1]. Subsequent bytes of the | - | instruction are fetched by using normal memory read M-cycles [1,2], | - | during which the interrupting I/O device must still supply the data [2]. | - | The PC register, however, remains at its pre-interrupt state, not being | - | incremented as a result of the instruction fetch [1,2]. | - | | - | References: | - | 1. Checked with "Visual Z80 Remix". | - | 2. Zilog (1978-05). "Z80 Family Program Interrupt Structure, The", | - | pp. 6,8. | - '=========================================================================*/ - case 0: - DATA[0] = ird; - -# ifdef Z80_WITH_FULL_IM0 - im0_begin: - hook = self->hook; - im0.z80 = self; - im0.context = self->context; - im0.fetch = self->fetch; - im0.read = self->read; - im0.write = self->write; - im0.in = self->in; - im0.out = self->out; - im0.pc = PC; - self->context = &im0; - self->fetch = (Z80Read )im0_fetch; - self->read = (Z80Read )im0_read; - self->write = (Z80Write)im0_write; - self->in = (Z80Read )im0_in; - self->out = (Z80Write)im0_out; - self->hook = Z_NULL; - - im0_execute: - - if (im0_pc_decrement_table[ird]) - { - PC -= im0_pc_decrement_table[ird]; - self->cycles += 2 + instruction_table[ird](self); - } - - /* halt */ - else if (ird == 0x76) HALT_LINE = TRUE; - - /* instructions with CBh prefix */ - else if (ird == 0xCB) - { - R++; - self->cycles += 4 + cb_instruction_table[DATA[1] = INTA](self); - } - - /* instructions with EDh prefix */ - else if (ird == 0xED) - { - Instruction instruction; - - R++; - - if ((instruction = ed_instruction_table[DATA[1] = ird = INTA]) != ed_illegal) - { - im0.ld_i_a = self->ld_i_a; - im0.ld_r_a = self->ld_r_a; - im0.reti = self->reti; - im0.retn = self->retn; - self->ld_i_a = (Z80Notify)im0_ld_i_a; - self->ld_r_a = (Z80Notify)im0_ld_r_a; - self->reti = (Z80Notify)im0_reti; - self->retn = (Z80Notify)im0_retn; - - self->cycles += 4 + instruction(self); - - self->ld_i_a = im0.ld_i_a; - self->ld_r_a = im0.ld_r_a; - self->reti = im0.reti; - self->retn = im0.retn; - - /* All except: reti / retn */ - if ((ird & 0xC7) != 0x45) PC -= ((ird & 0xC7) == 0x43) - ? 4 /* ld SS,(WORD) / ld (WORD),SS */ - : 2 /* all others */; - } - - else self->cycles += (self->illegal == Z_NULL) - ? 4 + 8 - : 4 + self->illegal(CONTEXT, ird); - } - - /* instructions with DDh, FDh, DDCBh or FDCBh prefix */ - else if (IS_XY_PREFIX(ird)) - { - Instruction instruction; - - if (RESUME) RESUME = FALSE; - - else { - im0_advance_xy: - if ((self->cycles += 6) >= self->cycle_limit) - { - RESUME = Z80_RESUME_IM0_XY; - goto im0_finalize; - } - } - - R++; - - if (IS_XY_PREFIX(ird = INTA)) - { - DATA[0] = ird; - goto im0_advance_xy; - } - - if ((instruction = xy_instruction_table[ird]) == xy_illegal) - { - DATA[0] = ird; - PC++; - goto im0_execute; - } - - XY = (xy = &self->ix_iy[((DATA[1] = ird) >> 5) & 1])->uint16_value; - self->cycles += 2 + instruction(self); - xy->uint16_value = XY; - - /* all except: jp (XY) */ - if (ird != 0xE9) PC = im0.pc; - } - - else { - cycles += 2 + instruction_table[ird](self); - - /* all except: jp WORD / jp (hl)> / ret */ - if (ird != 0xC3 && (ird & 0xDF) != 0xC9) PC = im0.pc; - } - - im0_finalize: - self->context = im0.context; - self->fetch = im0.fetch; - self->read = im0.read; - self->write = im0.write; - self->in = im0.in; - self->out = im0.out; - self->hook = hook; - - if (HALT_LINE) - { - if (self->halt != Z_NULL) self->halt(im0.context, TRUE); - RESUME = Z80_RESUME_HALT; - Q_0 - self->cycles += 6; - (void)halt(self); - } - - continue; - -# else - switch (ird) - { - case 0xC3: /* jp WORD */ - Q_0 - MEMPTR = PC = int_fetch_16(self); - self->cycles += 2 + 10; - continue; - - case 0xCD: /* call WORD */ - Q_0 - MEMPTR = int_fetch_16(self); - PUSH(PC); - PC = MEMPTR; - self->cycles += 2 + 17; - continue; - - default: /* `rst N` is assumed for other instructions */ - Q_0 - PUSH(PC); - MEMPTR = PC = ird & 56; - self->cycles += 2 + 11; - continue; - } -# endif - - /*----------------------------------------------------------. - | Interrupt Mode 1: Execute `rst 38h` | T-states: 13:733 | - |-----------------------------------------------------------| - | An internal `rst 38h` is executed. The interrupt response | - | data read from the data bus is disregarded. | - '==========================================================*/ - case 1: - DATA[0] = 0; - Q_0 - PUSH(PC); - MEMPTR = PC = 0x38; - self->cycles += 13; - continue; - - /*---------------------------------------------------------------------. - | Interrupt Mode 2: Execute `call (i:BYTE)` | T-states: 19:73333 | - |----------------------------------------------------------------------| - | An indirect call is executed. The pointer to the ISR is loaded from | - | the memory address formed by taking the I register as the most | - | significant byte, and the interrupt response vector read from the | - | data bus as the least significant byte. | - | | - | Zilog's official documentation states that the least significant bit | - | of the interrupt response vector "must be a zero", since the address | - | formed "is used to get two adjacent bytes to form a complete 16-bit | - | service routine starting address and the addresses must always start | - | in even locations" [1]. However, Sean Young's experiments confirmed | - | that there is no such limitation [2]; any vector works whether it is | - | odd or even. | - | | - | References: | - | 1. Zilog (2005-03). "Z80 CPU User Manual" revision 5, pp. 25,26. | - | 2. Young, Sean (2005-09-18). "Undocumented Z80 Documented, The" | - | v0.91, p. 20. | - '=====================================================================*/ - case 2: - DATA[0] = 0; - Q_0 - PUSH(PC); - MEMPTR = PC = READ_16((zuint16)(((zuint16)I << 8) | ird)); - self->cycles += 19; - continue; - } - } - -# ifdef Z80_WITH_SPECIAL_RESET - if (special_reset) - { - REQUEST = 0; - - /*-------------------------------------------------------------------. - | The /HALT line quickly goes low and then high in TL when a special | - | RESET is detected during the execution of the `halt` instruction. | - '===================================================================*/ - if (DATA[0] == 0x76 && self->halt != Z_NULL) - self->halt(CONTEXT, Z80_HALT_CANCEL); - - R++; /* M1 */ - if (self->nop != Z_NULL) (void)self->nop(CONTEXT, PC); - DATA[0] = 0; - PC = 0; - self->cycles += 4; - continue; - } -# endif - } - - R++; /* M1 */ - self->cycles += instruction_table[DATA[0] = FETCH_OPCODE(PC)](self); - } - - R = R_ALL; /* restore R7 bit */ - return self->cycles; /* return consumed cycles */ - } - - -#ifdef Z80_WITH_WINDOWS_DLL_MAIN - int Z_MICROSOFT_STD_CALL _DllMainCRTStartup(void *hDllHandle, unsigned long dwReason, void *lpReserved) - {return TRUE;} -#endif - - -/* Z80.c EOF */ diff --git a/software/FusionX/src/driver/Z80.c b/software/FusionX/src/driver/Z80.c new file mode 120000 index 000000000..c4e33b55b --- /dev/null +++ b/software/FusionX/src/driver/Z80.c @@ -0,0 +1 @@ +Z80/sources/Z80.c \ No newline at end of file diff --git a/software/tools/dz80 b/software/tools/dz80 new file mode 100755 index 000000000..64daa866d Binary files /dev/null and b/software/tools/dz80 differ diff --git a/software/tools/dz80_v20 b/software/tools/dz80_v20 new file mode 100755 index 000000000..b47a24a98 Binary files /dev/null and b/software/tools/dz80_v20 differ diff --git a/software/tools/glass-0.5.1.jar b/software/tools/glass-0.5.1.jar new file mode 100755 index 000000000..db0791243 Binary files /dev/null and b/software/tools/glass-0.5.1.jar differ diff --git a/software/tools/glass-0.5.jar b/software/tools/glass-0.5.jar new file mode 100755 index 000000000..7cb301c64 Binary files /dev/null and b/software/tools/glass-0.5.jar differ diff --git a/software/tools/glass.jar b/software/tools/glass.jar new file mode 100755 index 000000000..db0791243 Binary files /dev/null and b/software/tools/glass.jar differ diff --git a/software/tools/nasconv b/software/tools/nasconv new file mode 100755 index 000000000..ac9b7dcb7 Binary files /dev/null and b/software/tools/nasconv differ