diff options
| -rw-r--r-- | arm9/data/splashimg.bin | bin | 26722 -> 23615 bytes | |||
| -rw-r--r-- | arm9/include/kbd81.h | 76 | ||||
| -rw-r--r-- | arm9/include/keyboard.h | 125 | ||||
| -rw-r--r-- | arm9/include/z80.h | 250 | ||||
| -rw-r--r-- | arm9/include/z80_config.h | 59 | ||||
| -rw-r--r-- | arm9/include/z80_private.h | 276 | ||||
| -rw-r--r-- | arm9/include/zx81.h | 59 | ||||
| -rw-r--r-- | arm9/source/keyboard.c | 262 | ||||
| -rw-r--r-- | arm9/source/main.c | 85 | ||||
| -rw-r--r-- | arm9/source/z80.c | 331 | ||||
| -rw-r--r-- | arm9/source/z80_decode.c | 2533 | ||||
| -rw-r--r-- | arm9/source/z80_dis.c | 2494 | ||||
| -rw-r--r-- | arm9/source/zx81.c | 828 | ||||
| -rw-r--r-- | data/splashimg.bin | bin | 26722 -> 23615 bytes | |||
| -rw-r--r-- | include/kbd81.h | 76 | ||||
| -rw-r--r-- | include/keyboard.h | 125 | ||||
| -rw-r--r-- | include/z80.h | 250 | ||||
| -rw-r--r-- | include/z80_config.h | 59 | ||||
| -rw-r--r-- | include/z80_private.h | 276 | ||||
| -rw-r--r-- | include/zx81.h | 59 | ||||
| -rw-r--r-- | source/keyboard.c | 262 | ||||
| -rw-r--r-- | source/main.c | 85 | ||||
| -rw-r--r-- | source/z80.c | 331 | ||||
| -rw-r--r-- | source/z80_decode.c | 2533 | ||||
| -rw-r--r-- | source/z80_dis.c | 2494 | ||||
| -rw-r--r-- | source/zx81.c | 828 | 
26 files changed, 14562 insertions, 194 deletions
| diff --git a/arm9/data/splashimg.bin b/arm9/data/splashimg.binBinary files differ index 910f64b..38161e4 100644 --- a/arm9/data/splashimg.bin +++ b/arm9/data/splashimg.bin diff --git a/arm9/include/kbd81.h b/arm9/include/kbd81.h deleted file mode 100644 index b4e3d62..0000000 --- a/arm9/include/kbd81.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -   ds81 - Nintendo DS ZX81 emulator. - -   Copyright (C) 2006  Ian Cowburn -    -   This program is free software; you can redistribute it and/or -   modify it under the terms of the GNU General Public License -   as published by the Free Software Foundation; either version 2 -   of the License, or (at your option) any later version. -    -   This program is distributed in the hope that it will be useful, -   but WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -   GNU General Public License for more details. -    -   You should have received a copy of the GNU General Public License -   along with this program; if not, write to the Free Software -   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. -   -   $Id$ -*/ -#ifndef DS81_KBD81_H -#define DS81_KBD81_H - -typedef enum -{ -    KBD_1, -    KBD_2, -    KBD_3, -    KBD_4, -    KBD_5, -    KBD_6, -    KBD_7, -    KBD_8, -    KBD_9, -    KBD_0, -    KBD_Q, -    KBD_W, -    KBD_E, -    KBD_R, -    KBD_T, -    KBD_Y, -    KBD_U, -    KBD_I, -    KBD_O, -    KBD_P, -    KBD_A, -    KBD_S, -    KBD_D, -    KBD_F, -    KBD_G, -    KBD_H, -    KBD_J, -    KBD_K, -    KBD_L, -    KBD_NEWLINE, -    KBD_SHIFT, -    KBD_Z, -    KBD_X, -    KBD_C, -    KBD_V, -    KBD_B, -    KBD_N, -    KBD_M, -    KBD_PERIOD, -    KBD_SPACE -} ZX81_Key; - -void		KBD_Reset(void); -void		KBD_Display(const char *text); -void		KBD_Scan(void); -ZX81_Key	KBD_GetKey(void); -void		KBD_MapKey(KEYPAD_BITS pad, ZX81_Key key); -void		KBD_Probe(int scan); - -#endif	/* DS81_KBD81_H */ diff --git a/arm9/include/keyboard.h b/arm9/include/keyboard.h new file mode 100644 index 0000000..eefde86 --- /dev/null +++ b/arm9/include/keyboard.h @@ -0,0 +1,125 @@ +/* +   ds81 - Nintendo ZX81 emulator. + +   Copyright (C) 2006  Ian Cowburn +    +   This program is free software; you can redistribute it and/or +   modify it under the terms of the GNU General Public License +   as published by the Free Software Foundation; either version 2 +   of the License, or (at your option) any later version. +    +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. +    +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. +   +   $Id$ +*/ +#ifndef DS81_KEYBOARD_H +#define DS81_KEYBOARD_H + +/* Note that the first 40 values purposefully are the keyboard matrix keys. +   Note also that they are in display order, not matrix order. +*/ +typedef enum +{ +    SK_1, +    SK_2, +    SK_3, +    SK_4, +    SK_5, + +    SK_6, +    SK_7, +    SK_8, +    SK_9, +    SK_0, + +    SK_Q, +    SK_W, +    SK_E, +    SK_R, +    SK_T, + +    SK_Y, +    SK_U, +    SK_I, +    SK_O, +    SK_P, + +    SK_A, +    SK_S, +    SK_D, +    SK_F, +    SK_G, + +    SK_H, +    SK_J, +    SK_K, +    SK_L, +    SK_NEWLINE, + +    SK_SHIFT, +    SK_Z, +    SK_X, +    SK_C, +    SK_V, + +    SK_B, +    SK_N, +    SK_M, +    SK_PERIOD, +    SK_SPACE, + +    SK_ABOUT, +    SK_CONFIG, +    SK_PAD_UP, +    SK_PAD_DOWN, +    SK_PAD_LEFT, +    SK_PAD_RIGHT, +    SK_PAD_A, +    SK_PAD_B, +    SK_PAD_X, +    SK_PAD_Y, +    SK_PAD_R, +    SK_PAD_L, +    SK_PAD_START, +    SK_PAD_SELECT, + +    NUM_SOFT_KEYS +} SoftKey; + +typedef struct +{ +    SoftKey	key; +    int		pressed; +} SoftKeyEvent; + + +/* Display the soft keyboard +*/ +void	SK_DisplayKeyboard(uint16 *vram); + +/* Returns TRUE while there are still key events for this cycle +*/ +int	SK_GetEvent(SoftKeyEvent *ev); + +/* Sets a key to be 'sticky' (it will be released automatically on the next +   non-sticky press). +*/ +void	SK_SetSticky(SoftKey key, int is_sticky); + +/* Flush all the keys. +*/ +void	SK_ClearKeys(void); + +/* Map the joypad to keys.  Note that when mapped that both the key and the +   joypad code will be generated. +*/ +void	SK_DefineJoypad(void); + +#endif	/* DS81_KEYBOARD_H */ diff --git a/arm9/include/z80.h b/arm9/include/z80.h new file mode 100644 index 0000000..000b950 --- /dev/null +++ b/arm9/include/z80.h @@ -0,0 +1,250 @@ +/* + +    z80 - Z80 emulation + +    Copyright (C) 2006  Ian Cowburn <ianc@noddybox.co.uk> + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    $Id$ + +*/ + +#ifndef Z80_H +#define Z80_H "$Id$" + +/* Configuration +*/ +#include "z80_config.h" + + +/* ---------------------------------------- TYPES +*/ + +/* Large unsigned type +*/ +typedef unsigned long Z80Val; + + +/* 8-bit type.  The emulation will exit with code 2 if this isn't 8 bits. +*/ +typedef unsigned char Z80Byte; + + +/* 8-bit signed type.  The emulation will exit with code 2 if this isn't 8 bits. +*/ +typedef signed char Z80Relative; + + +/* 16-bit type.  The emulation will exit with code 2 if this isn't 16 bits. +*/ +typedef unsigned short Z80Word; + + +/* A Z80 16-bit register.  To access the HI/LO component use the indexes +   Z80_HI_WORD and Z80_LO_WORD which will be initialised once Z80Init has been +   called. +*/ +typedef union +{ +    Z80Word		w; +    Z80Byte		b[2]; +} Z80Reg; + +extern int Z80_HI_WORD; +extern int Z80_LO_WORD; + + +/* The processor +*/ +struct Z80Private; + +typedef struct +{ +    Z80Word		PC; + +    Z80Reg		AF; +    Z80Reg		BC; +    Z80Reg		DE; +    Z80Reg		HL; + +    Z80Word		AF_; +    Z80Word		BC_; +    Z80Word		DE_; +    Z80Word		HL_; + +    Z80Reg		IX; +    Z80Reg		IY; + +    Z80Word		SP; + +    Z80Byte		IFF1; +    Z80Byte		IFF2; +    Z80Byte		IM; +    Z80Byte		I; +    Z80Byte		R; + +    struct Z80Private	*priv; +} Z80; + + +/* Interfaces used to handle memory +*/ +typedef	Z80Byte	(*Z80ReadMemory)(Z80 *cpu, Z80Word address); +typedef	void	(*Z80WriteMemory)(Z80 *cpu, Z80Word address, Z80Byte value); + + +/* Interfaces needed to handle ports (IN/OUT commands) +*/ +typedef	Z80Byte	(*Z80ReadPort)(Z80 *cpu, Z80Word address); +typedef	void	(*Z80WritePort)(Z80 *cpu, Z80Word address, Z80Byte value); + + +/* Callback.  Callback should return TRUE for processing to continue. +*/ +typedef int	(*Z80Callback)(Z80 *cpu, Z80Val data); + + +/* Callback reasons + +   eZ80_Instruction	Called before the initial fetch for an instruction +   			(called just to once no matter how many bytes the +			instruction is made up of). + +   eZ80_EDHook		Called when an undefined ED opcode is executed. + +   eZ80_Halt		Called when the HALT instruction is hit and released. + +   eZ80_RETI		Called when the RETI instruction is executed +*/ +typedef enum +{ +    eZ80_Instruction,	/* data = no cycles since reset                       */ +    eZ80_EDHook,	/* data = byte after ED opcode (only for NOP opcodes) */ +    eZ80_Halt,		/* data = 1 halt raised, 0 halt cleared by int        */ +    eZ80_RETI,		/* data = ignored                                     */ +    eZ80_NO_CALLBACK	/* leave at end                                       */ +} Z80CallbackReason; + + +/* Flags in the F register +*/ +typedef enum +{ +    eZ80_Carry		=0x01, +    eZ80_Neg		=0x02, +    eZ80_PV		=0x04, +    eZ80_Hidden3	=0x08, +    eZ80_HalfCarry	=0x10, +    eZ80_Hidden5	=0x20, +    eZ80_Zero		=0x40, +    eZ80_Sign		=0x80 +} Z80FlagRegister; + + +/* Disassembly label -- only useful if ENABLE_DISASSEMBLER is set. +   Labels are stored as an array, where a NULL in the label field marks +   the end of the list. +*/ +typedef struct +{ +    Z80Word	address; +    const char	*label; +} Z80Label; + + +/* ---------------------------------------- INTERFACES +*/ + + +/* Initialises the processor.   +*/ +#ifdef ENABLE_ARRAY_MEMORY +Z80	*Z80Init(Z80ReadPort read_port, +		 Z80WritePort write_port); +#else +Z80	*Z80Init(Z80ReadMemory read_memory, +		 Z80WriteMemory write_memory, +		 Z80ReadPort read_port, +		 Z80WritePort write_port, +		 Z80ReadMemory read_for_disassem); +#endif + + +/* Resets the processor. +*/ +void	Z80Reset(Z80 *cpu); + + +/* Lodge a callback to be invoked after special events.  Returns FALSE +   if the callback couldn't be lodged (there is a max of 10 callbacks per +   reason). +*/ +int	Z80LodgeCallback(Z80 *cpu, +			 Z80CallbackReason reason, +			 Z80Callback callback); + + +/* Remove a callback.  Does nothing if reason was not lodged with +   Z80LodgeCallback() +*/ +void	Z80RemoveCallback(Z80 *cpu, +			  Z80CallbackReason reason, +			  Z80Callback callback); + + +/* Cause an interrupt before the next opcode. +   devbyte is the byte generated by the device (if any). +*/ +void	Z80Interrupt(Z80 *cpu, Z80Byte devbyte); + + +/* Cause an NMI +*/ +void	Z80NMI(Z80 *cpu); + + +/* Execute a single instruction.  Returns FALSE if any callback returned +   FALSE. +*/ +int	Z80SingleStep(Z80 *cpu); + + +/* Executes until a callback returns FALSE (never returns otherwise) +*/ +void	Z80Exec(Z80 *cpu); + + +/* Manipulate the cylce count of the Z80 +*/ +Z80Val	Z80Cycles(Z80 *cpu); +void	Z80ResetCycles(Z80 *cpu, Z80Val cycles); + + +/* Set address to label mappings for the disassembler +*/ +void	Z80SetLabels(Z80Label labels[]); + + +/* Simple disassembly of memory accessed through read_for_disassem, or  +   Z80_MEMORY as appropriate.  addr is updated on exit. +*/ +const char *Z80Disassemble(Z80 *cpu, Z80Word *addr); + +#endif + +/* END OF FILE */ diff --git a/arm9/include/z80_config.h b/arm9/include/z80_config.h new file mode 100644 index 0000000..8be062b --- /dev/null +++ b/arm9/include/z80_config.h @@ -0,0 +1,59 @@ +/* + +    z80 - Z80 emulation + +    Copyright (C) 2006  Ian Cowburn <ianc@noddybox.co.uk> + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    $Id$ + +*/ + +#ifndef Z80_CONFIG_H +#define Z80_CONFIG_H "$Id$" + + +/* This file defines various compile-time configuration options +   for the Z80 emulation +*/ + + +/* Define this to enable the disassembly interface +#define ENABLE_DISASSEM +*/ + + +/* Define this to enable the array-based memory model.  In this mode +   an externally visible Z80Byte array called Z80_MEMORY must be +   defined.  The macros RAMBOT and RAMTOP define the writable area of +   memory and must be changed accordingly. + +   In this mode the signature of Z80Init changes so that the memory functions +   are not passed.  ALL processor instances share the same memory. +#define ENABLE_ARRAY_MEMORY +*/ + +#ifdef ENABLE_ARRAY_MEMORY +#define RAMBOT 0x0000 +#define RAMTOP 0xffff +#endif + + +#endif + +/* END OF FILE */ diff --git a/arm9/include/z80_private.h b/arm9/include/z80_private.h new file mode 100644 index 0000000..be45e56 --- /dev/null +++ b/arm9/include/z80_private.h @@ -0,0 +1,276 @@ +/* + +    z80 - Z80 emulation + +    Copyright (C) 2006  Ian Cowburn (ianc@noddybox.demon.co.uk) + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    $Id$ + +    Private macros for Z80 + +*/ + +#ifndef Z80_PRIVATE_H +#define Z80_PRIVATE_H "$Id$" + +#include "z80_config.h" + +#ifndef TRUE +#define TRUE	1 +#endif + +#ifndef FALSE +#define FALSE	0 +#endif + +#define MAX_PER_CALLBACK	10 + + +/* ---------------------------------------- TYPES +*/ + +struct Z80Private +{ +    Z80Val		cycle; + +    int			halt; + +    Z80Byte		shift; + +    int			raise; +    Z80Byte		devbyte; +    int			nmi; + +#ifndef ENABLE_ARRAY_MEMORY +    Z80ReadMemory	disread; + +    Z80ReadMemory	mread; +    Z80WriteMemory	mwrite; +#endif + +    Z80ReadPort		pread; +    Z80WritePort	pwrite; + +    Z80Callback		callback[eZ80_NO_CALLBACK][MAX_PER_CALLBACK]; + +    int			last_cb; +}; + +#define PRIV		cpu->priv + + +/* ---------------------------------------- ARRAY MEMORY +*/ + +#ifdef ENABLE_ARRAY_MEMORY +extern Z80Byte	Z80_MEMORY[]; +#endif + + +/* ---------------------------------------- MACROS +*/ + +/* NOTE: A lot of these macros assume you have a variable called 'cpu' +         which is a pointer to Z80 +*/ + + +/* Invoke a callback class +*/ +#define CALLBACK(r,d)	do					\ +			{					\ +			int f;					\ +								\ +			for(f=0;f<MAX_PER_CALLBACK;f++)		\ +			    if (PRIV->callback[r][f])		\ +				PRIV->last_cb &=		\ +				    PRIV->callback[r][f](cpu,d);\ +			} while(0) + +/* Flag register +*/ +#define C_Z80			0x01 +#define N_Z80			0x02 +#define P_Z80			0x04 +#define V_Z80			P_Z80 +#define H_Z80			0x10 +#define Z_Z80			0x40 +#define S_Z80			0x80 + +#define B3_Z80			0x08 +#define B5_Z80			0x20 + + +#define SET(v,b)		(v)|=b +#define CLR(v,b)		(v)&=~(b) + +#define SETFLAG(f)		SET(cpu->AF.b[LO],f) +#define CLRFLAG(f)		CLR(cpu->AF.b[LO],f) + +#ifdef ENABLE_ARRAY_MEMORY + +#define PEEK(addr)		Z80_MEMORY[addr] + +static inline Z80Word PEEKW(Z80Word addr) +{ +    return (PEEK(addr) | (Z80Word)PEEK(addr+1)<<8); +} + +#define POKE(addr,val)		do					\ +				{					\ +				    Z80Word ba=addr;			\ +				    if (ba>=RAMBOT && ba<=RAMTOP)	\ +				    	Z80_MEMORY[ba]=val;		\ +				} while(0) + +#define POKEW(addr,val)		do					\ +				{					\ +				    Z80Word wa=addr;			\ +				    Z80Word wv=val;			\ +				    POKE(wa,wv);			\ +				    POKE(wa+1,wv>>8);			\ +				} while(0) + + +#define FETCH_BYTE		(Z80_MEMORY[cpu->PC++]) +#define FETCH_WORD              (cpu->PC+=2,				\ +				    Z80_MEMORY[cpu->PC-2]|		\ +					((Z80Word)Z80_MEMORY[cpu->PC-1]<<8)) + +#else + +#define PEEK(addr)		(PRIV->mread(cpu,addr)) +#define PEEKW(addr)		FPEEKW(cpu,addr) + +#define POKE(addr,val)		PRIV->mwrite(cpu,addr,val) +#define POKEW(addr,val)		FPOKEW(cpu,addr,val) + +#define FETCH_BYTE		(PRIV->mread(cpu,cpu->PC++)) +#define FETCH_WORD		(cpu->PC+=2,FPEEKW(cpu,cpu->PC-2)) + +#endif + + +#define IS_C			(cpu->AF.b[LO]&C_Z80) +#define IS_N			(cpu->AF.b[LO]&N_Z80) +#define IS_P			(cpu->AF.b[LO]&P_Z80) +#define IS_H			(cpu->AF.b[LO]&H_Z80) +#define IS_Z			(cpu->AF.b[LO]&Z_Z80) +#define IS_S			(cpu->AF.b[LO]&S_Z80) + +#define CARRY			IS_C + +#define IS_IX_IY		(PRIV->shift==0xdd || PRIV->shift==0xfd) +#define OFFSET(off)		off=(IS_IX_IY ? (Z80Relative)FETCH_BYTE:0) + +#define TSTATE(n)		PRIV->cycle+=n + +#define ADD_R(v)		cpu->R=((cpu->R&0x80)|((cpu->R+(v))&0x7f)) +#define INC_R			ADD_R(1) + +#ifdef ENABLE_ARRAY_MEMORY + +#define PUSH(REG)		do					\ +				{					\ +				    Z80Word pv=REG;			\ +				    cpu->SP-=2;				\ +				    POKE(cpu->SP,pv);			\ +				    POKE(cpu->SP+1,pv>>8);		\ +				} while(0) + +#else + +#define PUSH(REG)		do					\ +				{					\ +				    Z80Word pushv=REG;			\ +				    cpu->SP-=2;				\ +				    PRIV->mwrite(cpu,cpu->SP,pushv);	\ +				    PRIV->mwrite(cpu,cpu->SP+1,pushv>>8);\ +				} while(0) +#endif + +#define POP(REG)		do					\ +				{					\ +				    REG=PEEK(cpu->SP) |			\ +				    	(Z80Word)PEEK(cpu->SP+1)<<8;	\ +				    cpu->SP+=2;				\ +				} while(0) + +#define SETHIDDEN(res)		cpu->AF.b[LO]=(cpu->AF.b[LO]&~(B3_Z80|B5_Z80))|\ +					((res)&(B3_Z80|B5_Z80)) + +#define CALL			do				\ +				{				\ +				    PUSH(cpu->PC+2);		\ +				    cpu->PC=PEEKW(cpu->PC);	\ +				} while(0) + +#define NOCALL			cpu->PC+=2 +#define JP			cpu->PC=PEEKW(cpu->PC) +#define NOJP			cpu->PC+=2 +#define JR			cpu->PC+=(Z80Relative)PEEK(cpu->PC)+1 +#define NOJR			cpu->PC++ + +#define OUT(P,V)		do				\ +				{				\ +				    if (PRIV->pwrite)		\ +				    	PRIV->pwrite(cpu,P,V);	\ +				} while(0) + +#define IN(P)			(PRIV->pread?PRIV->pread(cpu,P):0) + + + +/* ---------------------------------------- LABELS +*/ +extern Z80Label			*z80_labels; + + +/* ---------------------------------------- GLOBAL GENERAL OPCODES/ROUTINES +*/ +void Z80_Decode(Z80 *cpu, Z80Byte opcode); +void Z80_InitialiseInternals(void); + + +/* ---------------------------------------- DISASSEMBLY +*/ +#ifdef ENABLE_DISASSEM +typedef void		(*DIS_OP_CALLBACK)(Z80 *z80, Z80Byte op, Z80Word *pc); + +extern DIS_OP_CALLBACK	dis_CB_opcode[]; +extern DIS_OP_CALLBACK	dis_DD_opcode[]; +extern DIS_OP_CALLBACK	dis_DD_CB_opcode[]; +extern DIS_OP_CALLBACK	dis_ED_opcode[]; +extern DIS_OP_CALLBACK	dis_FD_opcode[]; +extern DIS_OP_CALLBACK	dis_FD_CB_opcode[]; +extern DIS_OP_CALLBACK	dis_opcode_z80[]; + +const char	*Z80_Dis_Printf(const char *format, ...); + +Z80Byte		Z80_Dis_FetchByte(Z80 *cpu, Z80Word *pc); +Z80Word		Z80_Dis_FetchWord(Z80 *cpu, Z80Word *pc); + +void		Z80_Dis_Set(const char *op, const char *arg); +const char	*Z80_Dis_GetOp(void); +const char	*Z80_Dis_GetArg(void); +#endif	/* ENABLE_DISASSEM */ + +#endif	/* Z80_PRIVATE_H */ + +/* END OF FILE */ diff --git a/arm9/include/zx81.h b/arm9/include/zx81.h new file mode 100644 index 0000000..5f097bf --- /dev/null +++ b/arm9/include/zx81.h @@ -0,0 +1,59 @@ +/* + +    ezx81 - X11 ZX81 emulator + +    Copyright (C) 2003  Ian Cowburn (ianc@noddybox.demon.co.uk) + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    Provides the emulation for the ZX81 + +*/ + +#ifndef EZX81_ZX81H +#define EZX81_ZX81H "$Id$" + +#include "z80.h" +#include "SDL.h" + + +/* Initialise the ZX81 +*/ +void	ZX81Init(Z80 *z80); + +/* Handle keypresses +*/ +void	ZX81KeyEvent(SDL_Event *e); + +/* Interfaces for the Z80 +*/ +Z80Byte	ZX81ReadMem(Z80 *z80, Z80Word addr); +void	ZX81WriteMem(Z80 *z80, Z80Word addr, Z80Byte val); +Z80Byte	ZX81ReadPort(Z80 *z80, Z80Word port); +void	ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val); +Z80Byte	ZX81ReadForDisassem(Z80 *z80, Z80Word addr); + +/* Interfaces for memory menu +*/ +const char	*ZX81Info(Z80 *z80); +void		ZX81Reset(Z80 *z80); + + +#endif + + +/* END OF FILE */ diff --git a/arm9/source/keyboard.c b/arm9/source/keyboard.c new file mode 100644 index 0000000..d33346d --- /dev/null +++ b/arm9/source/keyboard.c @@ -0,0 +1,262 @@ +/* +   ds81 - Nintendo DS ZX81 emulator. + +   Copyright (C) 2006  Ian Cowburn +    +   This program is free software; you can redistribute it and/or +   modify it under the terms of the GNU General Public License +   as published by the Free Software Foundation; either version 2 +   of the License, or (at your option) any later version. +    +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. +    +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. +   +   $Id$ +*/ + +#include <nds.h> +#include "keyboard.h" +#include "framebuffer.h" +#include "keyb_bin.h" + +/* ---------------------------------------- STATIC DATA +*/ +static uint16 white = FB_RGB(31, 31, 31); +static uint16 black = FB_RGB(0, 0, 0); + +static struct +{ +    int	state; +    int	new_state; +    int	handled; +    int is_sticky; +} key_state[NUM_SOFT_KEYS]; + +static SoftKey	pad_left_key	= SK_5; +static SoftKey	pad_right_key	= SK_8; +static SoftKey	pad_up_key	= SK_7; +static SoftKey	pad_down_key	= SK_6; +static SoftKey	pad_A_key	= SK_0; +static SoftKey	pad_B_key	= SK_NEWLINE; +static SoftKey	pad_X_key	= NUM_SOFT_KEYS; +static SoftKey	pad_Y_key	= NUM_SOFT_KEYS; +static SoftKey	pad_R_key	= NUM_SOFT_KEYS; +static SoftKey	pad_L_key	= NUM_SOFT_KEYS; +static SoftKey	pad_start_key	= NUM_SOFT_KEYS; +static SoftKey	pad_select_key	= NUM_SOFT_KEYS; + +#define CHECK_STATE(KEYS,BIT,CODE,SHORTCUT)			\ +	do							\ +	{							\ +	    key_state[CODE].new_state = (KEYS & BIT);		\ +	    if (SHORTCUT != NUM_SOFT_KEYS &&			\ +		!key_state[SHORTCUT].handled)			\ +	    {							\ +		key_state[SHORTCUT].new_state = (KEYS & BIT);	\ +	    }							\ +	} while(0) + + +/* ---------------------------------------- PRIVATE INTERFACES +*/ +static SoftKey LocatePress(const touchPosition *p) +{ +    int kx=0,ky=0; +    int py=0; +    SoftKey key = NUM_SOFT_KEYS; + +    if (p->py > 36 && p->px > 2) +    { +	kx = (p->px - 3) / 25; +	ky = p->py - 37; + +	py = ky % 30; +	ky /= 30; + +	if (py<17 && kx >= 0 && kx<10 && ky>=0 && ky<=4) +	{ +	    key = kx + ky * 10; +	} +    } + +    return key; +} + + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +void SK_DisplayKeyboard(uint16 *vram) +{ +    sImage img; + +    loadPCX(keyb_bin,&img); +    image8to16(&img); +    dmaCopy(img.data8,vram,SCREEN_WIDTH*SCREEN_HEIGHT*2); +} + + +int SK_GetEvent(SoftKeyEvent *ev) +{ +    static SoftKey last = NUM_SOFT_KEYS; +    static int poll_index = -1; + +    /* Read the keys if this is a new loop +    */ +    if (poll_index == -1) +    { +	int f; +	uint32 keys; + +    	scanKeys(); + +	keys = keysHeld(); + +	/* Clear the non-sticky keys +	*/ +	for(f=SK_1; f<=SK_CONFIG; f++) +	{ +	    key_state[f].handled = FALSE; + +	    if (key_state[f].is_sticky) +	    { +		key_state[f].new_state = key_state[f].state; +	    } +	    else +	    { +		key_state[f].new_state = FALSE; +	    } +	} + +	/* Check the soft keyboard +	*/ +	if (keys & KEY_TOUCH) +	{ +	    touchPosition tp=touchReadXY(); + +	    if (tp.py<21 || tp.py>165) +	    { +	    	key_state[SK_CONFIG].new_state = TRUE; +	    } +	    else +	    { +	    	SoftKey press; + +		press = LocatePress(&tp); + +		if (press != NUM_SOFT_KEYS) +		{ +		    key_state[press].handled = TRUE; + +		    if (key_state[press].is_sticky) +		    { +			if (last != press) +			{ +			    key_state[press].new_state = +			    		!key_state[press].state; +			} +		    } +		    else +		    { +			key_state[press].new_state = TRUE; +		    } + +		    last = press; +		} +	    } +	} +	else +	{ +	    last = NUM_SOFT_KEYS; +	} + +	/* Check non soft-keyboard controls +	*/ +	CHECK_STATE(keys, KEY_A,	SK_PAD_A,	pad_A_key); +	CHECK_STATE(keys, KEY_B,	SK_PAD_B,	pad_B_key); +	CHECK_STATE(keys, KEY_X,	SK_PAD_X,	pad_X_key); +	CHECK_STATE(keys, KEY_Y,	SK_PAD_Y,	pad_Y_key); +	CHECK_STATE(keys, KEY_R,	SK_PAD_R,	pad_R_key); +	CHECK_STATE(keys, KEY_L,	SK_PAD_L,	pad_L_key); +	CHECK_STATE(keys, KEY_START,	SK_PAD_START,	pad_start_key); +	CHECK_STATE(keys, KEY_SELECT,	SK_PAD_SELECT,	pad_select_key); +	CHECK_STATE(keys, KEY_UP,	SK_PAD_UP,	pad_up_key); +	CHECK_STATE(keys, KEY_DOWN,	SK_PAD_DOWN,	pad_down_key); +	CHECK_STATE(keys, KEY_LEFT,	SK_PAD_LEFT,	pad_left_key); +	CHECK_STATE(keys, KEY_RIGHT,	SK_PAD_RIGHT,	pad_right_key); + +	/* Reset key event poll index +	*/ +	poll_index = 0; + +	/* Update any on-screen indicators +	*/ +	for(f=SK_1; f<SK_CONFIG; f++) +	{ +	    if (key_state[f].state != key_state[f].new_state) +	    { +		int x,y; + +		x = 2 + (f % 10) * 25; +		y = 36 + (f / 10) * 30; +	    	 +		FB_Box(x, y, 26, 19, key_state[f].new_state ? white:black); +	    } +	} +    } + +    while(poll_index < NUM_SOFT_KEYS && +    		key_state[poll_index].state == key_state[poll_index].new_state) +    { +    	poll_index++; +    } + +    if (poll_index < NUM_SOFT_KEYS) +    { +	key_state[poll_index].state = key_state[poll_index].new_state; + +	ev->key = poll_index; +	ev->pressed = key_state[poll_index].state; + +	return TRUE; +    } +    else +    { +    	poll_index = -1; +	return FALSE; +    } +} + + +void SK_SetSticky(SoftKey key, int is_sticky) +{ +    key_state[key].is_sticky = is_sticky; + +    if (!is_sticky) +    { +	key_state[key].new_state = FALSE; +    } +} + + +void SK_ClearKeys(void) +{ +    int f; + +    for(f=0; f < NUM_SOFT_KEYS; f++) +    { +    	key_state[f].state = FALSE; +    } +} + + +void SK_DefineJoypad(void) +{ +} + + diff --git a/arm9/source/main.c b/arm9/source/main.c index a5f5035..a2b0565 100644 --- a/arm9/source/main.c +++ b/arm9/source/main.c @@ -28,6 +28,7 @@  #include "gui.h"  #include "splashimg_bin.h" +#include "zx81_bin.h"  /* ---------------------------------------- STATIC DATA  */ @@ -46,10 +47,12 @@ static void Splash(void)      {      	"DS81 \177 2006 Ian C",  	" ", -	"ZX81 ROM \177 1981", +	"ZX81 ROM", +	"\177 1981",  	"Nine Tiles Networks LTD",  	" ", -	"3D MONSTER MAZE \177 1983", +	"3D MONSTER MAZE", +	"\177 1983",  	"Malcom E. Evans",  	" ",  	"PRESS A TO CONTINUE", @@ -62,18 +65,11 @@ static void Splash(void)      sImage img;      int f; -    loadPCX(splashimg_bin,&img); -    image8to16(&img); -    dmaCopy(img.data8,BG_GFX,SCREEN_WIDTH*SCREEN_HEIGHT*2); -      FB_Clear(); -    for(f=0;f<SCREEN_HEIGHT;f++) -    { -	FB_HLine(0,SCREEN_WIDTH-1,f,FB_RGB(f/8,0,0)); -    } - -    FB_Box(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,FB_RGB(31,31,31)); +    loadPCX(splashimg_bin,&img); +    image8to16(&img); +    dmaCopy(img.data8,BG_GFX_SUB,SCREEN_WIDTH*SCREEN_HEIGHT*2);      for(f=0;text[f];f++)      { @@ -91,22 +87,69 @@ static void Splash(void)  */  int main(int argc, char *argv[])  { +    int ch; +    uint8 *ch_data; +      powerON(POWER_ALL_2D); -    videoSetMode(MODE_5_2D | DISPLAY_BG2_ACTIVE); +    /* Set up main text screen and grab the ROM character data +    */ +    videoSetMode(MODE_0_2D | DISPLAY_BG0_ACTIVE);      vramSetBankA(VRAM_A_MAIN_BG_0x6000000); -    BG2_CR = BG_BMP16_256x256; -    BG2_XDX = 0x100; -    BG2_XDY = 0; -    BG2_YDX = 0; -    BG2_YDY = 0x100; -    BG2_CX = 0; -    BG2_CY = 0; +    vramSetBankB(VRAM_B_MAIN_BG_0x6020000); -    videoSetModeSub(MODE_5_2D | DISPLAY_BG2_ACTIVE); +    BG0_CR = BG_COLOR_256|BG_MAP_BASE(31)|BG_TILE_BASE(0); +    BG0_X0 = 0; +    BG0_Y0 = 0; + +    BG_PALETTE[0] = RGB15(31,31,31); +    BG_PALETTE[1] = RGB15(0,0,0); +    ch_data = (uint8*)BG_TILE_RAM(0); +    for(ch=0;ch<64;ch++) +    { +	int r; + +	for(r=0;r<8;r++) +	{ +	    int b; +	    int rd; + +	    rd=zx81_bin[0x1e00+ch*8+r]; + +	    for(b=7;b>=0;b--) +	    { +		if (rd&(1<<b)) +		{ +		    *ch_data = 1; +		    *(ch_data+4096) = 0; +		} +		else +		{ +		    *ch_data = 0; +		    *(ch_data+4096) = 1; +		} + +		ch_data++; +	    } +	} +    } + +    { +    uint16 *tiles; +    tiles = (uint16*)BG_MAP_RAM(31); +    for(ch=0;ch<128;ch++) +    { +    	*(tiles+(ch%32)+(ch/32)*32)=ch; +    } +    } + +    /* Set up the sub-screen for rotation (basically for use as a framebuffer) +    */ +    videoSetModeSub(MODE_5_2D | DISPLAY_BG2_ACTIVE);      vramSetBankC(VRAM_C_SUB_BG_0x6200000); +      SUB_BG2_CR = BG_BMP16_256x256;      SUB_BG2_XDX = 0x100;      SUB_BG2_XDY = 0; diff --git a/arm9/source/z80.c b/arm9/source/z80.c new file mode 100644 index 0000000..36c5793 --- /dev/null +++ b/arm9/source/z80.c @@ -0,0 +1,331 @@ +/* + +    z80 - Z80 Emulator + +    Copyright (C) 2006  Ian Cowburn <ianc@noddybox.co.uk> + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    $Id$ + +    Z80 + +*/ +#include <stdlib.h> +#include <string.h> + +#include "z80.h" +#include "z80_private.h" + +static const char ident[]="$Id$"; +static const char ident_z80_header[]=Z80_H; +static const char ident_z80_private_header[]=Z80_PRIVATE_H; + +Z80Label        *z80_labels=NULL; + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static void InitTables() +{ +    static int init=FALSE; + +    if (init) +    	return; + +    init=TRUE; + +    Z80_InitialiseInternals(); +} + +static void Z80_CheckInterrupt(Z80 *cpu) +{ +    /* Check interrupts +    */ +    if (PRIV->raise) +    { +    	if (PRIV->nmi) +	{ +	    if (PRIV->halt) +	    { +		PRIV->halt=FALSE; +		CALLBACK(eZ80_Halt,0); +		cpu->PC++; +	    } + +	    TSTATE(2); +	    cpu->IFF1=0; +	    PRIV->nmi=FALSE; +	    PUSH(cpu->PC); +	    cpu->PC=0x66; +	} +    	else if (cpu->IFF1) +	{ +	    if (PRIV->halt) +	    { +		PRIV->halt=FALSE; +		CALLBACK(eZ80_Halt,0); +		cpu->PC++; +	    } + +	    TSTATE(2); + +	    cpu->IFF1=0; +	    cpu->IFF2=0; + +	    switch(cpu->IM) +	    { +		default: +		case 0: +		    INC_R; +		    Z80_Decode(cpu,PRIV->devbyte); +		    return; +		    break; + +		case 1: +		    PUSH(cpu->PC); +		    cpu->PC=0x38; +		    break; + +		case 2: +		    PUSH(cpu->PC); +		    cpu->PC=(Z80Word)cpu->I*256+PRIV->devbyte; +		    break; +	    } +	} + +	PRIV->raise=FALSE; +    } +} + + +/* ---------------------------------------- INTERFACES +*/ + +#ifdef ENABLE_ARRAY_MEMORY +Z80     *Z80Init(Z80ReadPort read_port, +                 Z80WritePort write_port) +#else +Z80     *Z80Init(Z80ReadMemory read_memory, +                 Z80WriteMemory write_memory, +                 Z80ReadPort read_port, +                 Z80WritePort write_port, +                 Z80ReadMemory read_for_disassem) +#endif +{ +    Z80 *cpu; +    int f; +    int r; + +    InitTables(); + +#ifndef ENABLE_ARRAY_MEMORY +    if (!read_memory || !write_memory) +    	return NULL; +#endif + +    cpu=malloc(sizeof *cpu); + +    if (cpu) +    { +    	cpu->priv=malloc(sizeof *cpu->priv); + +	if (cpu->priv) +	{ +#ifndef ENABLE_ARRAY_MEMORY +	    PRIV->mread=read_memory; +	    PRIV->mwrite=write_memory; +	    PRIV->disread=read_for_disassem; +#endif +	    PRIV->pread=read_port; +	    PRIV->pwrite=write_port; + +	    for(f=0;f<eZ80_NO_CALLBACK;f++) +		for(r=0;r<MAX_PER_CALLBACK;r++) +		    PRIV->callback[f][r]=NULL; + +	    Z80Reset(cpu); +	} +	else +	{ +	    free(cpu); +	    cpu=NULL; +	} +    } + +    return cpu; +} + + +void Z80Reset(Z80 *cpu) +{ +    PRIV->cycle=0; +    cpu->PC=0; + +    cpu->AF.w=0xffff; +    cpu->BC.w=0xffff; +    cpu->DE.w=0xffff; +    cpu->HL.w=0xffff; +    cpu->AF_=0xffff; +    cpu->BC_=0xffff; +    cpu->DE_=0xffff; +    cpu->HL_=0xffff; + +    cpu->IX.w=0xffff; +    cpu->IY.w=0xffff; + +    cpu->SP=0xffff; +    cpu->IFF1=0; +    cpu->IFF2=0; +    cpu->IM=0; +    cpu->I=0; +    cpu->R=0; +    PRIV->halt=0; + +    PRIV->raise=FALSE; +    PRIV->nmi=FALSE; +} + + +Z80Val Z80Cycles(Z80 *cpu) +{ +    return PRIV->cycle; +} + + +void Z80ResetCycles(Z80 *cpu, Z80Val cycles) +{ +    PRIV->cycle=cycles; +} + + +int Z80LodgeCallback(Z80 *cpu, Z80CallbackReason reason, Z80Callback callback) +{ +    int f; + +    for(f=0;f<MAX_PER_CALLBACK;f++) +    { +    	if (!PRIV->callback[reason][f]) +	{ +	    PRIV->callback[reason][f]=callback; +	    return TRUE; +	} +    } + +    return FALSE; +} + + +void Z80RemoveCallback(Z80 *cpu, Z80CallbackReason reason, Z80Callback callback) +{ +    int f; + +    for(f=0;f<MAX_PER_CALLBACK;f++) +    { +    	if (PRIV->callback[reason][f]==callback) +	{ +	    PRIV->callback[reason][f]=NULL; +	} +    } +} + + +void Z80Interrupt(Z80 *cpu, Z80Byte devbyte) +{ +    PRIV->raise=TRUE; +    PRIV->devbyte=devbyte; +    PRIV->nmi=FALSE; +} + + +void Z80NMI(Z80 *cpu) +{ +    PRIV->raise=TRUE; +    PRIV->nmi=TRUE; +} + + +int Z80SingleStep(Z80 *cpu) +{ +    Z80Byte opcode; + +    PRIV->last_cb=TRUE; +    PRIV->shift=0; + +    Z80_CheckInterrupt(cpu); + +    CALLBACK(eZ80_Instruction,PRIV->cycle); + +    INC_R; + +    opcode=FETCH_BYTE; + +    Z80_Decode(cpu,opcode); + +    return PRIV->last_cb; +} + + +void Z80Exec(Z80 *cpu) +{ +    while (Z80SingleStep(cpu)); +} + + +void Z80SetLabels(Z80Label labels[]) +{ +    z80_labels=labels; +} + + +const char *Z80Disassemble(Z80 *cpu, Z80Word *pc) +{ +#ifdef ENABLE_DISASSEM +    Z80Byte Z80_Dis_FetchByte(Z80 *cpu, Z80Word *pc); +    static char s[80]; +    Z80Word opc,npc; +    Z80Byte op; +    int f; + +    opc=*pc; +    op=Z80_Dis_FetchByte(cpu,pc); +    dis_opcode_z80[op](cpu,op,pc); +    npc=*pc; + +    strcpy(s,Z80_Dis_Printf("%-5s",Z80_Dis_GetOp())); +    strcat(s,Z80_Dis_Printf("%-40s ;",Z80_Dis_GetArg())); + +    for(f=0;f<5 && opc!=npc;f++) +    { +#ifdef ENABLE_ARRAY_MEMORY +	strcat(s,Z80_Dis_Printf(" %.2x",(int)Z80_MEMORY[opc++])); +#else +	strcat(s,Z80_Dis_Printf(" %.2x",(int)PRIV->disread(cpu,opc++))); +#endif +    } + +    if (opc!=npc) +	for(f=1;f<3;f++) +	    s[strlen(s)-f]='.'; + +    return s; +#else +    (*pc)+=4; +    return "NO DISASSEMBLER"; +#endif +} + +/* END OF FILE */ diff --git a/arm9/source/z80_decode.c b/arm9/source/z80_decode.c new file mode 100644 index 0000000..a8f66ca --- /dev/null +++ b/arm9/source/z80_decode.c @@ -0,0 +1,2533 @@ +/* + +    z80 - Z80 Emulator + +    Copyright (C) 2006  Ian Cowburn <ianc@noddybox.co.uk> + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    $Id$ + +*/ +#include <stdlib.h> +#include <limits.h> + +#include "z80.h" +#include "z80_private.h" + +static const char ident[]="$Id$"; + +/* ---------------------------------------- TABLES AND INIT +*/ +static Z80Byte		PSZtable[512]; +static Z80Byte		SZtable[512]; +static Z80Byte		Ptable[512]; +static Z80Byte		Stable[512]; +static Z80Byte		Ztable[512]; + + +int Z80_HI_WORD; +int Z80_LO_WORD; + +#define HI Z80_HI_WORD +#define LO Z80_LO_WORD + +/* ---------------------------------------- MISC FUNCTIONS +*/ +void Z80_InitialiseInternals(void) +{ +    Z80Word f; +    Z80Reg r; + +    /* Check endianness +    */ +    r.w=0x1234; + +    if (r.b[0] == 0x12) +    { +    	HI=0; +	LO=1; +    } +    else if (r.b[1] == 0x12) +    { +    	HI=1; +	LO=0; +    } +    else +    { +    	exit(1); +    } + +    /* Check variable sizes +    */ +    if (CHAR_BIT!=8 || sizeof(Z80Word)!=2) +    { +    	exit(2); +    } + +    /* Initialise flag tables +    */ +    for(f=0;f<256;f++) +    { +	Z80Byte p,z,s; +	int b; + +	p=0; + +	for(b=0;b<8;b++) +	    if (f&(1<<b)) +		p++; + +	if (p&1) +	    p=0; +	else +	    p=P_Z80; + +	if (f) +	    z=0; +	else +	    z=Z_Z80; + +	if (f&0x80) +	    s=S_Z80; +	else +	    s=0; + +	Ptable[f]=p; +	Stable[f]=s; +	Ztable[f]=z; +	SZtable[f]=z|s; +	PSZtable[f]=z|s|p; + +	Ptable[f+256]=Ptable[f]|C_Z80; +	Stable[f+256]=Stable[f]|C_Z80; +	Ztable[f+256]=Ztable[f]|C_Z80; +	SZtable[f+256]=SZtable[f]|C_Z80; +	PSZtable[f+256]=PSZtable[f]|C_Z80; +    } +} + +#ifndef ENABLE_ARRAY_MEMORY +static Z80Word FPEEKW(Z80 *cpu, Z80Word addr) +{ +    return (PEEK(addr) | (Z80Word)PEEK(addr+1)<<8); +} + + +static void FPOKEW(Z80 *cpu, Z80Word addr, Z80Word val) +{ +    PRIV->mwrite(cpu,addr,val); +    PRIV->mwrite(cpu,addr+1,val>>8); +} +#endif + + +/* ---------------------------------------- GENERAL MACROS +*/ +#define SWAP(A,B) \ +do { \ +    unsigned swap_tmp; \ +    swap_tmp=A; \ +    A=B; \ +    B=swap_tmp; \ +} while(0) + + +/* ---------------------------------------- ARITHMETIC OPS +*/ +#define ADD8(ONCE) \ +do { \ +    Z80Byte VAL=ONCE; \ +    unsigned w; \ +    w=cpu->AF.b[HI]+(unsigned)VAL; \ +    cpu->AF.b[LO]=SZtable[w]; \ +    if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ +    if ((VAL^cpu->AF.b[HI]^0x80)&(VAL^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ +    SETHIDDEN(w); \ +    cpu->AF.b[HI]=w; \ +} while(0) + + +#define ADC8(ONCE) \ +do { \ +    Z80Byte VAL=ONCE; \ +    unsigned w; \ +    w=(cpu->AF.b[HI]+(unsigned)VAL+CARRY)&0x1ff; \ +    cpu->AF.b[LO]=SZtable[w]; \ +    if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ +    if ((VAL^cpu->AF.b[HI]^0x80)&(VAL^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ +    SETHIDDEN(w); \ +    cpu->AF.b[HI]=w; \ +} while(0) + + +#define SUB8(ONCE) \ +do { \ +    Z80Byte VAL=ONCE; \ +    unsigned w; \ +    w=(cpu->AF.b[HI]-(unsigned)VAL)&0x1ff; \ +    cpu->AF.b[LO]=SZtable[w]|N_Z80; \ +    if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ +    if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ +    SETHIDDEN(w); \ +    cpu->AF.b[HI]=w; \ +} while(0) + + +#define CMP8(ONCE) \ +do { \ +    Z80Byte VAL=ONCE; \ +    unsigned w; \ +    w=(cpu->AF.b[HI]-(unsigned)VAL)&0x1ff; \ +    cpu->AF.b[LO]=SZtable[w]|N_Z80; \ +    if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ +    if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ +    SETHIDDEN(VAL); \ +} while(0) + + +#define SBC8(ONCE) \ +do { \ +    Z80Byte VAL=ONCE; \ +    unsigned w; \ +    w=(cpu->AF.b[HI]-(unsigned)VAL-CARRY)&0x1ff; \ +    cpu->AF.b[LO]=SZtable[w]|N_Z80; \ +    if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ +    if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ +    SETHIDDEN(w); \ +    cpu->AF.b[HI]=w; \ +} while(0) + + +#define ADD16(REG,ONCE) \ +do { \ +    Z80Word VAL=ONCE; \ +    Z80Val w; \ +    w=(REG)+(Z80Val)VAL; \ +    cpu->AF.b[LO]&=(S_Z80|Z_Z80|V_Z80); \ +    if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \ +    if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \ +    SETHIDDEN(w>>8); \ +    (REG)=w; \ +} while(0)  + + +#define ADC16(REG, ONCE) \ +do { \ +    Z80Word VAL=ONCE; \ +    Z80Val w; \ +    w=(REG)+(Z80Val)VAL+CARRY; \ +    cpu->AF.b[LO]=0; \ +    if ((w&0xffff)==0) cpu->AF.b[LO]=Z_Z80; \ +    if (w&0x8000) cpu->AF.b[LO]|=S_Z80; \ +    if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \ +    if ((VAL^(REG)^0x8000)&((REG)^w)&0x8000) cpu->AF.b[LO]|=P_Z80; \ +    if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \ +    SETHIDDEN(w>>8); \ +    (REG)=w; \ +} while(0)  + + +#define SBC16(REG, ONCE) \ +do { \ +    Z80Word VAL=ONCE; \ +    Z80Val w; \ +    w=(REG)-(Z80Val)VAL-CARRY; \ +    cpu->AF.b[LO]=N_Z80; \ +    if (w&0x8000) cpu->AF.b[LO]|=S_Z80; \ +    if ((w&0xffff)==0) cpu->AF.b[LO]|=Z_Z80; \ +    if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \ +    if ((VAL^(REG))&((REG)^w)&0x8000) cpu->AF.b[LO]|=P_Z80; \ +    if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \ +    SETHIDDEN(w>>8); \ +    (REG)=w; \ +} while(0) + + +#define INC8(REG) \ +do { \ +    (REG)++; \ +    cpu->AF.b[LO]=CARRY|SZtable[(REG)]; \ +    if ((REG)==0x80) cpu->AF.b[LO]|=P_Z80; \ +    if (((REG)&0x0f)==0) cpu->AF.b[LO]|=H_Z80; \ +} while(0)  + + +#define DEC8(REG) \ +do { \ +    (REG)--; \ +    cpu->AF.b[LO]=N_Z80|CARRY; \ +    if ((REG)==0x7f) cpu->AF.b[LO]|=P_Z80; \ +    if (((REG)&0x0f)==0x0f) cpu->AF.b[LO]|=H_Z80; \ +    cpu->AF.b[LO]|=SZtable[(REG)]; \ +} while(0) + + +#define OP_ON_MEM(OP,addr) \ +do { \ +    Z80Byte memop=PEEK(addr); \ +    OP(memop); \ +    POKE(addr,memop); \ +} while(0) + + +#define OP_ON_MEM_WITH_ARG(OP,addr,arg) \ +do { \ +    Z80Byte memop=PEEK(addr); \ +    OP(memop,arg); \ +    POKE(addr,memop); \ +} while(0) + + +#define OP_ON_MEM_WITH_COPY(OP,addr,copy) \ +do { \ +    Z80Byte memop=PEEK(addr); \ +    OP(memop); \ +    copy=memop; \ +    POKE(addr,memop); \ +} while(0) + + +#define OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,arg,copy) \ +do { \ +    Z80Byte memop=PEEK(addr); \ +    OP(memop,arg); \ +    copy=memop; \ +    POKE(addr,memop); \ +} while(0) + + +/* ---------------------------------------- ROTATE AND SHIFT OPS +*/ +#define RRCA \ +do { \ +    cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]&C_Z80); \ +    cpu->AF.b[HI]=(cpu->AF.b[HI]>>1)|(cpu->AF.b[HI]<<7); \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define RRA \ +do { \ +    Z80Byte c; \ +    c=CARRY; \ +    cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]&C_Z80); \ +    cpu->AF.b[HI]=(cpu->AF.b[HI]>>1)|(c<<7); \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define RRC(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)&C_Z80; \ +    (REG)=((REG)>>1)|((REG)<<7); \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0)  + + +#define RR(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)&C_Z80; \ +    (REG)=((REG)>>1)|(CARRY<<7); \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +#define RLCA \ +do { \ +    cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]>>7); \ +    cpu->AF.b[HI]=(cpu->AF.b[HI]<<1)|(cpu->AF.b[HI]>>7); \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define RLA \ +do { \ +    Z80Byte c; \ +    c=CARRY; \ +    cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]>>7); \ +    cpu->AF.b[HI]=(cpu->AF.b[HI]<<1)|c; \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define RLC(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)>>7; \ +    (REG)=((REG)<<1)|c; \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +#define RL(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)>>7; \ +    (REG)=((REG)<<1)|CARRY; \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +#define SRL(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)&C_Z80; \ +    (REG)>>=1; \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +#define SRA(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)&C_Z80; \ +    (REG)=((REG)>>1)|((REG)&0x80); \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +#define SLL(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)>>7; \ +    (REG)=((REG)<<1)|1; \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +#define SLA(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)>>7; \ +    (REG)=(REG)<<1; \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +/* ---------------------------------------- BOOLEAN OPS +*/ +#define AND(VAL) \ +do { \ +    cpu->AF.b[HI]&=VAL; \ +    cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]|H_Z80; \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define OR(VAL) \ +do { \ +    cpu->AF.b[HI]|=VAL; \ +    cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]; \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define XOR(VAL) \ +do { \ +    cpu->AF.b[HI]^=VAL; \ +    cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]; \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define BIT(REG,B) \ +do { \ +    cpu->AF.b[LO]=CARRY|H_Z80; \ +    if ((REG)&(1<<B)) \ +    { \ +	if (B==7 && (REG&S_Z80)) cpu->AF.b[LO]|=S_Z80; \ +	if (B==5 && (REG&B5_Z80)) cpu->AF.b[LO]|=B5_Z80; \ +	if (B==3 && (REG&B3_Z80)) cpu->AF.b[LO]|=B3_Z80; \ +    } \ +    else \ +    { \ +	cpu->AF.b[LO]|=Z_Z80; \ +	cpu->AF.b[LO]|=P_Z80; \ +    } \ +} while(0) + +#define BIT_SET(REG,B) (REG)|=(1<<B) +#define BIT_RES(REG,B) (REG)&=~(1<<B) + + +/* ---------------------------------------- JUMP OPERATIONS +*/ +#define JR_COND(COND) \ +do { \ +    if (COND) \ +    { \ +	TSTATE(12); \ +	JR; \ +    } \ +    else \ +    { \ +	TSTATE(7); \ +	NOJR; \ +    } \ +} while(0) + + +#define JP_COND(COND) \ +do { \ +    TSTATE(10); \ +    if (COND) \ +    { \ +	JP; \ +    } \ +    else \ +    { \ +	NOJP; \ +    } \ +} while(0) + + +#define CALL_COND(COND) \ +do { \ +    if (COND) \ +    { \ +	TSTATE(17); \ +	CALL; \ +    } \ +    else \ +    { \ +	TSTATE(10); \ +	NOCALL; \ +    } \ +} while(0) + + +#define RET_COND(COND) \ +do { \ +    if (COND) \ +    { \ +	TSTATE(11); \ +	POP(cpu->PC); \ +    } \ +    else \ +    { \ +	TSTATE(5); \ +    } \ +} while(0) + + +#define RST(ADDR) \ +    TSTATE(11); \ +    PUSH(cpu->PC); \ +    cpu->PC=ADDR + +/* ---------------------------------------- BLOCK OPERATIONS +*/ +#define LDI \ +do { \ +    Z80Byte b; \ + \ +    b=PEEK(cpu->HL.w); \ +    POKE(cpu->DE.w,b); \ +    cpu->DE.w++; \ +    cpu->HL.w++; \ +    cpu->BC.w--; \ + \ +    CLRFLAG(H_Z80); \ +    CLRFLAG(N_Z80); \ + \ +    if (cpu->BC.w) \ +	SETFLAG(P_Z80); \ +    else \ +	CLRFLAG(P_Z80); \ + \ +    SETHIDDEN(cpu->AF.b[HI]+b); \ +} while(0) + +#define LDD \ +do { \ +    Z80Byte b; \ + \ +    b=PEEK(cpu->HL.w); \ +    POKE(cpu->DE.w,b); \ +    cpu->DE.w--; \ +    cpu->HL.w--; \ +    cpu->BC.w--; \ + \ +    CLRFLAG(H_Z80); \ +    CLRFLAG(N_Z80); \ + \ +    if (cpu->BC.w) \ +	SETFLAG(P_Z80); \ +    else \ +	CLRFLAG(P_Z80); \ + \ +    SETHIDDEN(cpu->AF.b[HI]+b); \ +} while(0) + +#define CPI \ +do { \ +    Z80Byte c,b; \ + \ +    c=CARRY; \ +    b=PEEK(cpu->HL.w); \ + \ +    CMP8(b); \ + \ +    if (c) \ +    	SETFLAG(C_Z80); \ +    else \ +    	CLRFLAG(C_Z80); \ + \ +    cpu->HL.w++; \ +    cpu->BC.w--; \ + \ +    if (cpu->BC.w) \ +	SETFLAG(P_Z80); \ +    else \ +	CLRFLAG(P_Z80); \ +} while(0) + +#define CPD \ +do { \ +    Z80Byte c,b; \ + \ +    c=CARRY; \ +    b=PEEK(cpu->HL.w); \ + \ +    CMP8(b); \ + \ +    if (c) \ +    	SETFLAG(C_Z80); \ +    else \ +    	CLRFLAG(C_Z80); \ + \ +    cpu->HL.w--; \ +    cpu->BC.w--; \ + \ +    if (cpu->BC.w) \ +	SETFLAG(P_Z80); \ +    else \ +	CLRFLAG(P_Z80); \ +} while(0) + +#define INI \ +do { \ +    Z80Word w; \ +    Z80Byte b; \ + \ +    b=IN(cpu->BC.w); \ +    POKE(cpu->HL.w,b); \ + \ +    cpu->BC.b[HI]--; \ +    cpu->HL.w++; \ + \ +    cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \ +    SETHIDDEN(cpu->BC.b[HI]); \ + \ +    w=(((Z80Word)cpu->BC.b[LO])&0xff)+b; \ + \ +    if (b&0x80) \ +    	SETFLAG(N_Z80); \ + \ +    if (w&0x100) \ +    { \ +    	SETFLAG(C_Z80); \ +    	SETFLAG(H_Z80); \ +    } \ +    else \ +    { \ +    	CLRFLAG(C_Z80); \ +    	CLRFLAG(H_Z80); \ +    } \ +} while(0) + +#define IND \ +do { \ +    Z80Word w; \ +    Z80Byte b; \ + \ +    b=IN(cpu->BC.w); \ +    POKE(cpu->HL.w,b); \ + \ +    cpu->BC.b[HI]--; \ +    cpu->HL.w--; \ + \ +    cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \ +    SETHIDDEN(cpu->BC.b[HI]); \ + \ +    w=(((Z80Word)cpu->BC.b[LO])&0xff)+b; \ + \ +    if (b&0x80) \ +    	SETFLAG(N_Z80); \ + \ +    if (w&0x100) \ +    { \ +    	SETFLAG(C_Z80); \ +    	SETFLAG(H_Z80); \ +    } \ +    else \ +    { \ +    	CLRFLAG(C_Z80); \ +    	CLRFLAG(H_Z80); \ +    } \ +} while(0) \ + +#define OUTI \ +do { \ +    OUT(cpu->BC.w,PEEK(cpu->HL.w)); \ + \ +    cpu->HL.w++; \ +    cpu->BC.b[HI]--; \ + \ +    cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \ +    SETHIDDEN(cpu->BC.b[HI]); \ +} while(0) + +#define OUTD \ +do { \ +    OUT(cpu->BC.w,PEEK(cpu->HL.w)); \ + \ +    cpu->HL.w--; \ +    cpu->BC.b[HI]--; \ + \ +    cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \ +    SETFLAG(N_Z80); \ +    SETHIDDEN(cpu->BC.b[HI]); \ +} while(0) + + +/* ---------------------------------------- BASE OPCODE SHORT-HAND BLOCKS +*/ + +#define LD_BLOCK(BASE,DEST,DEST2) \ +    case BASE:		/* LD DEST,B */ \ +	TSTATE(4); \ +	DEST=cpu->BC.b[HI]; \ +	break; \ + \ +    case BASE+1:	/* LD DEST,C */ \ +	TSTATE(4); \ +	DEST=cpu->BC.b[LO]; \ +	break; \ + \ +    case BASE+2:	/* LD DEST,D */ \ +	TSTATE(4); \ +	DEST=cpu->DE.b[HI]; \ +	break; \ + \ +    case BASE+3:	/* LD DEST,E */ \ +	TSTATE(4); \ +	DEST=cpu->DE.b[LO]; \ +	break; \ + \ +    case BASE+4:	/* LD DEST,H */ \ +	TSTATE(4); \ +	DEST=*H; \ +	break; \ + \ +    case BASE+5:	/* LD DEST,L */ \ +	TSTATE(4); \ +	DEST=*L; \ +	break; \ + \ +    case BASE+6:	/* LD DEST,(HL) */ \ +	TSTATE(7); \ +	OFFSET(off); \ +	DEST2=PEEK(*HL+off); \ +	break; \ + \ +    case BASE+7:	/* LD DEST,A */ \ +	TSTATE(4); \ +	DEST=cpu->AF.b[HI]; \ +	break; + +#define ALU_BLOCK(BASE,OP) \ +    case BASE:		/* OP A,B */ \ +	TSTATE(4); \ +	OP(cpu->BC.b[HI]); \ +	break; \ + \ +    case BASE+1:	/* OP A,C */ \ +	TSTATE(4); \ +	OP(cpu->BC.b[LO]); \ +	break; \ + \ +    case BASE+2:	/* OP A,D */ \ +	TSTATE(4); \ +	OP(cpu->DE.b[HI]); \ +	break; \ + \ +    case BASE+3:	/* OP A,E */ \ +	TSTATE(4); \ +	OP(cpu->DE.b[LO]); \ +	break; \ + \ +    case BASE+4:	/* OP A,H */ \ +	TSTATE(4); \ +	OP(*H); \ +	break; \ + \ +    case BASE+5:	/* OP A,L */ \ +	TSTATE(4); \ +	OP(*L); \ +	break; \ + \ +    case BASE+6:	/* OP A,(HL) */ \ +	TSTATE(7); \ +	OFFSET(off); \ +	OP_ON_MEM(OP,*HL+off); \ +	break; \ + \ +    case BASE+7:	/* OP A,A */ \ +	TSTATE(4); \ +	OP(cpu->AF.b[HI]); \ +	break; + + +/* ---------------------------------------- CB OPCODE SHORT-HAND BLOCKS +*/ + +#define CB_ALU_BLOCK(BASE,OP) \ +    case BASE:		/* OP B */ \ +	TSTATE(8); \ +	OP(cpu->BC.b[HI]); \ +	break; \ + \ +    case BASE+1:	/* OP C */ \ +	TSTATE(8); \ +	OP(cpu->BC.b[LO]); \ +	break; \ + \ +    case BASE+2:	/* OP D */ \ +	TSTATE(8); \ +	OP(cpu->DE.b[HI]); \ +	break; \ + \ +    case BASE+3:	/* OP E */ \ +	TSTATE(8); \ +	OP(cpu->DE.b[LO]); \ +	break; \ + \ +    case BASE+4:	/* OP H */ \ +	TSTATE(8); \ +	OP(cpu->HL.b[HI]); \ +	break; \ + \ +    case BASE+5:	/* OP L */ \ +	TSTATE(8); \ +	OP(cpu->HL.b[LO]); \ +	break; \ + \ +    case BASE+6:	/* OP (HL) */ \ +	TSTATE(15); \ +	OP_ON_MEM(OP,cpu->HL.w); \ +	break; \ + \ +    case BASE+7:	/* OP A */ \ +	TSTATE(8); \ +	OP(cpu->AF.b[HI]); \ +	break; + +#define CB_BITMANIP_BLOCK(BASE,OP,BIT_NO) \ +    case BASE:		/* OP B */ \ +	TSTATE(8); \ +	OP(cpu->BC.b[HI],BIT_NO); \ +	break; \ + \ +    case BASE+1:	/* OP C */ \ +	TSTATE(8); \ +	OP(cpu->BC.b[LO],BIT_NO); \ +	break; \ + \ +    case BASE+2:	/* OP D */ \ +	TSTATE(8); \ +	OP(cpu->DE.b[HI],BIT_NO); \ +	break; \ + \ +    case BASE+3:	/* OP E */ \ +	TSTATE(8); \ +	OP(cpu->DE.b[LO],BIT_NO); \ +	break; \ + \ +    case BASE+4:	/* OP H */ \ +	TSTATE(8); \ +	OP(cpu->HL.b[HI],BIT_NO); \ +	break; \ + \ +    case BASE+5:	/* OP L */ \ +	TSTATE(8); \ +	OP(cpu->HL.b[LO],BIT_NO); \ +	break; \ + \ +    case BASE+6:	/* OP (HL) */ \ +	TSTATE(12); \ +	OP_ON_MEM_WITH_ARG(OP,cpu->HL.w,BIT_NO); \ +	break; \ + \ +    case BASE+7:	/* OP A */ \ +	TSTATE(8); \ +	OP(cpu->AF.b[HI],BIT_NO); \ +	break; + +/* ---------------------------------------- SHIFTED CB OPCODE SHORT-HAND BLOCKS +*/ + +#define SHIFTED_CB_ALU_BLOCK(BASE,OP) \ +    case BASE:		/* OP B */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->BC.b[HI]); \ +	break; \ + \ +    case BASE+1:	/* OP C */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->BC.b[LO]); \ +	break; \ + \ +    case BASE+2:	/* OP D */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->DE.b[HI]); \ +	break; \ + \ +    case BASE+3:	/* OP E */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->DE.b[LO]); \ +	break; \ + \ +    case BASE+4:	/* OP H */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->HL.b[HI]); \ +	break; \ + \ +    case BASE+5:	/* OP L */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->HL.b[LO]); \ +	break; \ + \ +    case BASE+6:	/* OP (HL) */ \ +	TSTATE(15); \ +	OP_ON_MEM(OP,addr); \ +	break; \ + \ +    case BASE+7:	/* OP A */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->AF.b[HI]); \ +	break; + +#define SHIFTED_CB_BITMANIP_BLOCK(BASE,OP,BIT_NO) \ +    case BASE:		/* OP B */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->BC.b[HI]); \ +	break; \ + \ +    case BASE+1:	/* OP C */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->BC.b[LO]); \ +	break; \ + \ +    case BASE+2:	/* OP D */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->DE.b[HI]); \ +	break; \ + \ +    case BASE+3:	/* OP E */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->DE.b[LO]); \ +	break; \ + \ +    case BASE+4:	/* OP H */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->HL.b[HI]); \ +	break; \ + \ +    case BASE+5:	/* OP L */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->HL.b[LO]); \ +	break; \ + \ +    case BASE+6:	/* OP (HL) */ \ +	TSTATE(12); \ +	OP_ON_MEM_WITH_ARG(OP,addr,BIT_NO); \ +	break; \ + \ +    case BASE+7:	/* OP A */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->AF.b[HI]); \ +	break; + +/* ---------------------------------------- DAA +*/ + +/* This alogrithm is based on info from +   http://www.worldofspectrum.org/faq/reference/z80reference.htm +*/ +static void DAA (Z80 *cpu) +{ +    Z80Byte add=0; +    Z80Byte carry=0; +    Z80Byte nf=cpu->AF.b[LO]&N_Z80; +    Z80Byte acc=cpu->AF.b[HI]; + +    if (acc>0x99 || IS_C) +    { +	add|=0x60; +	carry=C_Z80; +    } + +    if ((acc&0xf)>0x9 || IS_H) +    { +    	add|=0x06; +    } + +    if (nf) +    { +    	cpu->AF.b[HI]-=add; +    } +    else +    { +    	cpu->AF.b[HI]+=add; +    } + +    cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]] +		    | carry +		    | nf +		    | ((acc^cpu->AF.b[HI])&H_Z80) +		    | (cpu->AF.b[HI]&(B3_Z80|B5_Z80)); +} + +/* ---------------------------------------- HANDLERS FOR ED OPCODES +*/ +static void DecodeED(Z80 *cpu, Z80Byte opcode) +{ +    switch(opcode) +    { +	case 0x40:	/* IN B,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->BC.b[HI]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->BC.b[HI]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->BC.b[HI]]; +	    SETHIDDEN(cpu->BC.b[HI]); +	    break; + +	case 0x41:	/* OUT (C),B */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->BC.b[HI]); +	    break; + +	case 0x42:	/* SBC HL,BC */ +	    TSTATE(15); +	    SBC16(cpu->HL.w,cpu->BC.w); +	    break; + +	case 0x43:	/* LD (nnnn),BC */ +	    TSTATE(20); +	    POKEW(FETCH_WORD,cpu->BC.w); +	    break; + +	case 0x44:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x45:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x46:	/* IM 0 */ +	    TSTATE(8); +	    cpu->IM=0; +	    break; + +	case 0x47:	/* LD I,A */ +	    TSTATE(9); +	    cpu->I=cpu->AF.b[HI]; +	    break; + +	case 0x48:	/* IN C,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->BC.b[LO]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->BC.b[LO]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->BC.b[LO]]; +	    SETHIDDEN(cpu->BC.b[LO]); +	    break; + +	case 0x49:	/* OUT (C),C */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->BC.b[LO]); +	    break; + +	case 0x4a:	/* ADC HL,BC */ +	    TSTATE(15); +	    ADC16(cpu->HL.w,cpu->BC.w); +	    break; + +	case 0x4b:	/* LD BC,(nnnn) */ +	    TSTATE(20); +	    cpu->BC.w=PEEKW(FETCH_WORD); +	    break; + +	case 0x4c:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x4d:	/* RETI */ +	    TSTATE(14); +	    CALLBACK(eZ80_RETI,0); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x4e:	/* IM 0/1 */ +	    TSTATE(8); +	    cpu->IM=0; +	    break; + +	case 0x4f:	/* LD R,A */ +	    TSTATE(9); +	    cpu->R=cpu->AF.b[HI]; +	    break; + +	case 0x50:	/* IN D,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->DE.b[HI]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->DE.b[HI]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->DE.b[HI]]; +	    SETHIDDEN(cpu->BC.b[HI]); +	    break; + +	case 0x51:	/* OUT (C),D */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->DE.b[HI]); +	    break; + +	case 0x52:	/* SBC HL,DE */ +	    TSTATE(15); +	    SBC16(cpu->HL.w,cpu->DE.w); +	    break; + +	case 0x53:	/* LD (nnnn),DE */ +	    TSTATE(20); +	    POKEW(FETCH_WORD,cpu->DE.w); +	    break; + +	case 0x54:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x55:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x56:	/* IM 1 */ +	    TSTATE(8); +	    cpu->IM=1; +	    break; + +	case 0x57:	/* LD A,I */ +	    TSTATE(9); +	    cpu->AF.b[HI]=cpu->I; +	    break; + +	case 0x58:	/* IN E,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->DE.b[LO]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->BC.b[LO]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->DE.b[LO]]; +	    SETHIDDEN(cpu->DE.b[LO]); +	    break; + +	case 0x59:	/* OUT (C),E */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->DE.b[LO]); +	    break; + +	case 0x5a:	/* ADC HL,DE */ +	    TSTATE(15); +	    ADC16(cpu->HL.w,cpu->DE.w); +	    break; + +	case 0x5b:	/* LD DE,(nnnn) */ +	    TSTATE(20); +	    cpu->DE.w=PEEKW(FETCH_WORD); +	    break; + +	case 0x5c:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x5d:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x5e:	/* IM 2 */ +	    TSTATE(8); +	    cpu->IM=2; +	    break; + +	case 0x5f:	/* LD A,R */ +	    TSTATE(9); +	    cpu->AF.b[HI]=cpu->R; +	    break; + +	case 0x60:	/* IN H,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->HL.b[HI]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->HL.b[HI]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->HL.b[HI]]; +	    SETHIDDEN(cpu->HL.b[HI]); +	    break; + +	case 0x61:	/* OUT (C),H */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->HL.b[HI]); +	    break; + +	case 0x62:	/* SBC HL,HL */ +	    TSTATE(15); +	    SBC16(cpu->HL.w,cpu->HL.w); +	    break; + +	case 0x63:	/* LD (nnnn),HL */ +	    TSTATE(20); +	    POKEW(FETCH_WORD,cpu->HL.w); +	    break; + +	case 0x64:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x65:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x66:	/* IM 0 */ +	    TSTATE(8); +	    cpu->IM=0; +	    break; + +	case 0x67:	/* RRD */ +	    { +	    Z80Byte b; + +	    TSTATE(18); + +	    b=PEEK(cpu->HL.w); + +	    POKE(cpu->HL.w,(b>>4)|(cpu->AF.b[HI]<<4)); +	    cpu->AF.b[HI]=(cpu->AF.b[HI]&0xf0)|(b&0x0f); + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]]; +	    SETHIDDEN(cpu->AF.b[HI]); +	    break; +	    } + +	case 0x68:	/* IN L,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->HL.b[LO]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->HL.b[LO]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->HL.b[LO]]; +	    SETHIDDEN(cpu->HL.b[LO]); +	    break; + +	case 0x69:	/* OUT (C),L */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->HL.b[LO]); +	    break; + +	case 0x6a:	/* ADC HL,HL */ +	    TSTATE(15); +	    ADC16(cpu->HL.w,cpu->HL.w); +	    break; + +	case 0x6b:	/* LD HL,(nnnn) */ +	    TSTATE(20); +	    cpu->HL.w=PEEKW(FETCH_WORD); +	    break; + +	case 0x6c:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x6d:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x6e:	/* IM 0/1 */ +	    TSTATE(8); +	    cpu->IM=0; +	    break; + +	case 0x6f:	/* RLD */ +	    { +	    Z80Byte b; + +	    TSTATE(18); + +	    b=PEEK(cpu->HL.w); + +	    POKE(cpu->HL.w,(b<<4)|(cpu->AF.b[HI]&0x0f)); +	    cpu->AF.b[HI]=(cpu->AF.b[HI]&0xf0)|(b>>4); + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]]; +	    SETHIDDEN(cpu->AF.b[HI]); +	    break; +	    } + +	case 0x70:	/* IN (C) */ +	    { +	    Z80Byte b; + +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		b=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	b=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[b]; +	    SETHIDDEN(b); +	    break; +	    } + +	case 0x71:	/* OUT (C) */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,0); +	    break; + +	case 0x72:	/* SBC HL,SP */ +	    TSTATE(15); +	    SBC16(cpu->HL.w,cpu->SP); +	    break; + +	case 0x73:	/* LD (nnnn),SP */ +	    TSTATE(20); +	    POKEW(FETCH_WORD,cpu->SP); +	    break; + +	case 0x74:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x75:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x76:	/* IM 1 */ +	    TSTATE(8); +	    cpu->IM=1; +	    break; + +	case 0x77:	/* NOP */ +	    TSTATE(8); +	    CALLBACK(eZ80_EDHook,opcode); +	    break; + +	case 0x78:	/* IN A,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->AF.b[HI]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->AF.b[HI]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]]; +	    SETHIDDEN(cpu->AF.b[HI]); +	    break; + +	case 0x79:	/* OUT (C),A */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->AF.b[HI]); +	    break; + +	case 0x7a:	/* ADC HL,SP */ +	    TSTATE(15); +	    ADC16(cpu->HL.w,cpu->SP); +	    break; + +	case 0x7b:	/* LD SP,(nnnn) */ +	    TSTATE(20); +	    cpu->SP=PEEKW(FETCH_WORD); +	    break; + +	case 0x7c:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x7d:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x7e:	/* IM 2 */ +	    TSTATE(8); +	    cpu->IM=2; +	    break; + +	case 0x7f:	/* NOP */ +	    TSTATE(8); +	    CALLBACK(eZ80_EDHook,opcode); +	    break; + +	case 0xa0:	/* LDI */ +	    TSTATE(16); +	    LDI; +	    break; + +	case 0xa1:	/* CPI */ +	    TSTATE(16); +	    CPI; +	    break; + +	case 0xa2:	/* INI */ +	    TSTATE(16); +	    INI; +	    break; + +	case 0xa3:	/* OUTI */ +	    TSTATE(16); +	    OUTI; +	    break; + +	case 0xa8:	/* LDD */ +	    TSTATE(16); +	    LDD; +	    break; + +	case 0xa9:	/* CPD */ +	    TSTATE(16); +	    CPD; +	    break; + +	case 0xaa:	/* IND */ +	    TSTATE(16); +	    IND; +	    break; + +	case 0xab:	/* OUTD */ +	    TSTATE(16); +	    OUTD; +	    break; + +	case 0xb0:	/* LDIR */ +	    TSTATE(16); +	    LDI; +	    if (cpu->BC.w) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xb1:	/* CPIR */ +	    TSTATE(16); +	    CPI; +	    if (cpu->BC.w && !IS_Z) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xb2:	/* INIR */ +	    TSTATE(16); +	    INI; +	    if (cpu->BC.w) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xb3:	/* OTIR */ +	    TSTATE(16); +	    OUTI; +	    if (cpu->BC.w) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xb8:	/* LDDR */ +	    TSTATE(16); +	    LDD; +	    if (cpu->BC.w) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xb9:	/* CPDR */ +	    TSTATE(16); +	    CPD; +	    if (cpu->BC.w && !IS_Z) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xba:	/* INDR */ +	    TSTATE(16); +	    IND; +	    if (cpu->BC.w) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xbb:	/* OTDR */ +	    TSTATE(16); +	    OUTD; +	    if (cpu->BC.w) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	/* All the rest are NOP/invalid +	*/ +    	default: +	    TSTATE(8); +	    CALLBACK(eZ80_EDHook,opcode); +	    break; +    } +} + + +/* ---------------------------------------- HANDLERS FOR CB OPCODES +*/ +static void DecodeCB(Z80 *cpu, Z80Byte opcode) +{ +    switch(opcode) +    { +    	CB_ALU_BLOCK(0x00,RLC) +    	CB_ALU_BLOCK(0x08,RRC) +    	CB_ALU_BLOCK(0x10,RL) +    	CB_ALU_BLOCK(0x18,RR) +    	CB_ALU_BLOCK(0x20,SLA) +    	CB_ALU_BLOCK(0x28,SRA) +    	CB_ALU_BLOCK(0x30,SLL) +    	CB_ALU_BLOCK(0x38,SRL) + +    	CB_BITMANIP_BLOCK(0x40,BIT,0) +    	CB_BITMANIP_BLOCK(0x48,BIT,1) +    	CB_BITMANIP_BLOCK(0x50,BIT,2) +    	CB_BITMANIP_BLOCK(0x58,BIT,3) +    	CB_BITMANIP_BLOCK(0x60,BIT,4) +    	CB_BITMANIP_BLOCK(0x68,BIT,5) +    	CB_BITMANIP_BLOCK(0x70,BIT,6) +    	CB_BITMANIP_BLOCK(0x78,BIT,7) + +    	CB_BITMANIP_BLOCK(0x80,BIT_RES,0) +    	CB_BITMANIP_BLOCK(0x88,BIT_RES,1) +    	CB_BITMANIP_BLOCK(0x90,BIT_RES,2) +    	CB_BITMANIP_BLOCK(0x98,BIT_RES,3) +    	CB_BITMANIP_BLOCK(0xa0,BIT_RES,4) +    	CB_BITMANIP_BLOCK(0xa8,BIT_RES,5) +    	CB_BITMANIP_BLOCK(0xb0,BIT_RES,6) +    	CB_BITMANIP_BLOCK(0xb8,BIT_RES,7) + +    	CB_BITMANIP_BLOCK(0xc0,BIT_SET,0) +    	CB_BITMANIP_BLOCK(0xc8,BIT_SET,1) +    	CB_BITMANIP_BLOCK(0xd0,BIT_SET,2) +    	CB_BITMANIP_BLOCK(0xd8,BIT_SET,3) +    	CB_BITMANIP_BLOCK(0xe0,BIT_SET,4) +    	CB_BITMANIP_BLOCK(0xe8,BIT_SET,5) +    	CB_BITMANIP_BLOCK(0xf0,BIT_SET,6) +    	CB_BITMANIP_BLOCK(0xf8,BIT_SET,7) +    } +} + + +static void ShiftedDecodeCB(Z80 *cpu, Z80Byte opcode, Z80Relative offset) +{ +    Z80Word addr; + +    /* See if we've come here from a IX/IY shift. +    */ +    switch (PRIV->shift) +    { +    	case 0xdd: +	    addr=cpu->IX.w+offset; +	    break; +    	case 0xfd: +	    addr=cpu->IY.w+offset; +	    break; +	default: +	    addr=cpu->HL.w;	/* Play safe... */ +	    break; +    } + +    switch(opcode) +    { +    	SHIFTED_CB_ALU_BLOCK(0x00,RLC) +    	SHIFTED_CB_ALU_BLOCK(0x08,RRC) +    	SHIFTED_CB_ALU_BLOCK(0x10,RL) +    	SHIFTED_CB_ALU_BLOCK(0x18,RR) +    	SHIFTED_CB_ALU_BLOCK(0x20,SLA) +    	SHIFTED_CB_ALU_BLOCK(0x28,SRA) +    	SHIFTED_CB_ALU_BLOCK(0x30,SLL) +    	SHIFTED_CB_ALU_BLOCK(0x38,SRL) + +    	SHIFTED_CB_BITMANIP_BLOCK(0x40,BIT,0) +    	SHIFTED_CB_BITMANIP_BLOCK(0x48,BIT,1) +    	SHIFTED_CB_BITMANIP_BLOCK(0x50,BIT,2) +    	SHIFTED_CB_BITMANIP_BLOCK(0x58,BIT,3) +    	SHIFTED_CB_BITMANIP_BLOCK(0x60,BIT,4) +    	SHIFTED_CB_BITMANIP_BLOCK(0x68,BIT,5) +    	SHIFTED_CB_BITMANIP_BLOCK(0x70,BIT,6) +    	SHIFTED_CB_BITMANIP_BLOCK(0x78,BIT,7) + +    	SHIFTED_CB_BITMANIP_BLOCK(0x80,BIT_RES,0) +    	SHIFTED_CB_BITMANIP_BLOCK(0x88,BIT_RES,1) +    	SHIFTED_CB_BITMANIP_BLOCK(0x90,BIT_RES,2) +    	SHIFTED_CB_BITMANIP_BLOCK(0x98,BIT_RES,3) +    	SHIFTED_CB_BITMANIP_BLOCK(0xa0,BIT_RES,4) +    	SHIFTED_CB_BITMANIP_BLOCK(0xa8,BIT_RES,5) +    	SHIFTED_CB_BITMANIP_BLOCK(0xb0,BIT_RES,6) +    	SHIFTED_CB_BITMANIP_BLOCK(0xb8,BIT_RES,7) + +    	SHIFTED_CB_BITMANIP_BLOCK(0xc0,BIT_SET,0) +    	SHIFTED_CB_BITMANIP_BLOCK(0xc8,BIT_SET,1) +    	SHIFTED_CB_BITMANIP_BLOCK(0xd0,BIT_SET,2) +    	SHIFTED_CB_BITMANIP_BLOCK(0xd8,BIT_SET,3) +    	SHIFTED_CB_BITMANIP_BLOCK(0xe0,BIT_SET,4) +    	SHIFTED_CB_BITMANIP_BLOCK(0xe8,BIT_SET,5) +    	SHIFTED_CB_BITMANIP_BLOCK(0xf0,BIT_SET,6) +    	SHIFTED_CB_BITMANIP_BLOCK(0xf8,BIT_SET,7) +    } +} + + +/* ---------------------------------------- NORMAL OPCODE DECODER +*/ +void Z80_Decode(Z80 *cpu, Z80Byte opcode) +{ +    Z80Word *HL; +    Z80Byte *H; +    Z80Byte *L; +    Z80Relative off; + +    /* See if we've come here from a IX/IY shift +    */ +    switch (PRIV->shift) +    { +    	case 0xdd: +	    HL=&(cpu->IX.w); +	    L=cpu->IX.b+LO; +	    H=cpu->IX.b+HI; +	    break; +    	case 0xfd: +	    HL=&(cpu->IY.w); +	    L=cpu->IY.b+LO; +	    H=cpu->IY.b+HI; +	    break; +	default: +	    HL=&(cpu->HL.w); +	    L=cpu->HL.b+LO; +	    H=cpu->HL.b+HI; +	    break; +    } + +    switch(opcode) +    { +	case 0x00:	/* NOP */ +	    TSTATE(4); +	    break; + +	case 0x01:	/* LD BC,nnnn */ +	    TSTATE(10); +	    cpu->BC.w=FETCH_WORD; +	    break; + +	case 0x02:	/* LD (BC),A */ +	    TSTATE(7); +	    POKE(cpu->BC.w,cpu->AF.b[HI]); +	    break; + +	case 0x03:	/* INC BC */ +	    TSTATE(6); +	    cpu->BC.w++; +	    break; + +	case 0x04:	/* INC B */ +	    TSTATE(4); +	    INC8(cpu->BC.b[HI]); +	    break; + +	case 0x05:	/* DEC B */ +	    TSTATE(4); +	    DEC8(cpu->BC.b[HI]); +	    break; + +	case 0x06:	/* LD B,n */ +	    TSTATE(7); +	    cpu->BC.b[HI]=FETCH_BYTE; +	    break; + +	case 0x07:	/* RLCA */ +	    TSTATE(4); +	    RLCA; +	    break; + +	case 0x08:	/* EX AF,AF' */ +	    TSTATE(4); +	    SWAP(cpu->AF.w,cpu->AF_); +	    break; + +	case 0x09:	/* ADD HL,BC */ +	    TSTATE(11); +	    ADD16(*HL,cpu->BC.w); +	    break; + +	case 0x0a:	/* LD A,(BC) */ +	    TSTATE(7); +	    cpu->AF.b[HI]=PEEK(cpu->BC.w); +	    break; + +	case 0x0b:	/* DEC BC */ +	    TSTATE(6); +	    cpu->BC.w--; +	    break; + +	case 0x0c:	/* INC C */ +	    TSTATE(4); +	    INC8(cpu->BC.b[LO]); +	    break; + +	case 0x0d:	/* DEC C */ +	    TSTATE(4); +	    DEC8(cpu->BC.b[LO]); +	    break; + +	case 0x0e:	/* LD C,n */ +	    TSTATE(7); +	    cpu->BC.b[LO]=FETCH_BYTE; +	    break; + +	case 0x0f:	/* RRCA */ +	    TSTATE(4); +	    RRCA; +	    break; + +	case 0x10:	/* DJNZ */ +	    if (--(cpu->BC.b[HI])) +	    { +		TSTATE(13); +		JR; +	    } +	    else +	    { +		TSTATE(8); +		NOJR; +	    } +	    break; + +	case 0x11:	/* LD DE,nnnn */ +	    TSTATE(10); +	    cpu->DE.w=FETCH_WORD; +	    break; + +	case 0x12:	/* LD (DE),A */ +	    TSTATE(7); +	    POKE(cpu->DE.w,cpu->AF.b[HI]); +	    break; + +	case 0x13:	/* INC DE */ +	    TSTATE(6); +	    cpu->DE.w++; +	    break; + +	case 0x14:	/* INC D */ +	    TSTATE(4); +	    INC8(cpu->DE.b[HI]); +	    break; + +	case 0x15:	/* DEC D */ +	    TSTATE(4); +	    DEC8(cpu->DE.b[HI]); +	    break; + +	case 0x16:	/* LD D,n */ +	    TSTATE(7); +	    cpu->DE.b[HI]=FETCH_BYTE; +	    break; + +	case 0x17:	/* RLA */ +	    TSTATE(4); +	    RLA; +	    break; + +	case 0x18:	/* JR d */ +	    TSTATE(12); +	    JR; +	    break; + +	case 0x19:	/* ADD HL,DE */ +	    TSTATE(11); +	    ADD16(*HL,cpu->DE.w); +	    break; + +	case 0x1a:	/* LD A,(DE) */ +	    TSTATE(7); +	    cpu->AF.b[HI]=PEEK(cpu->DE.w); +	    break; + +	case 0x1b:	/* DEC DE */ +	    TSTATE(6); +	    cpu->DE.w--; +	    break; + +	case 0x1c:	/* INC E */ +	    TSTATE(4); +	    INC8(cpu->DE.b[LO]); +	    break; + +	case 0x1d:	/* DEC E */ +	    TSTATE(4); +	    DEC8(cpu->DE.b[LO]); +	    break; + +	case 0x1e:	/* LD E,n */ +	    TSTATE(7); +	    cpu->DE.b[LO]=FETCH_BYTE; +	    break; + +	case 0x1f:	/* RRA */ +	    TSTATE(4); +	    RRA; +	    break; + +	case 0x20:	/* JR NZ,e */ +	    JR_COND(!IS_Z); +	    break; + +	case 0x21:	/* LD HL,nnnn */ +	    TSTATE(10); +	    *HL=FETCH_WORD; +	    break; + +	case 0x22:	/* LD (nnnn),HL */ +	    TSTATE(16); +	    POKEW(FETCH_WORD,*HL); +	    break; + +	case 0x23:	/* INC HL */ +	    TSTATE(6); +	    (*HL)++; +	    break; + +	case 0x24:	/* INC H */ +	    TSTATE(4); +	    INC8(*H); +	    break; + +	case 0x25:	/* DEC H */ +	    TSTATE(4); +	    DEC8(*H); +	    break; + +	case 0x26:	/* LD H,n */ +	    TSTATE(7); +	    *H=FETCH_BYTE; +	    break; + +	case 0x27:	/* DAA */ +	    TSTATE(4); +	    DAA(cpu); +	    break; + +	case 0x28:	/* JR Z,d */ +	    JR_COND(IS_Z); +	    break; + +	case 0x29:	/* ADD HL,HL */ +	    TSTATE(11); +	    ADD16(*HL,*HL); +	    break; + +	case 0x2a:	/* LD HL,(nnnn) */ +	    TSTATE(7); +	    *HL=PEEKW(FETCH_WORD); +	    break; + +	case 0x2b:	/* DEC HL */ +	    TSTATE(6); +	    (*HL)--; +	    break; + +	case 0x2c:	/* INC L */ +	    TSTATE(4); +	    INC8(*L); +	    break; + +	case 0x2d:	/* DEC L */ +	    TSTATE(4); +	    DEC8(*L); +	    break; + +	case 0x2e:	/* LD L,n */ +	    TSTATE(7); +	    *L=FETCH_BYTE; +	    break; + +	case 0x2f:	/* CPL */ +	    TSTATE(4); +	    cpu->AF.b[HI]^=0xff; +	    SETFLAG(H_Z80); +	    SETFLAG(N_Z80); +	    SETHIDDEN(cpu->AF.b[HI]); +	    break; + +	case 0x30:	/* JR NC,d */ +	    JR_COND(!IS_C); +	    break; + +	case 0x31:	/* LD SP,nnnn */ +	    TSTATE(10); +	    cpu->SP=FETCH_WORD; +	    break; + +	case 0x32:	/* LD (nnnn),A */ +	    TSTATE(13); +	    POKE(FETCH_WORD,cpu->AF.b[HI]); +	    break; + +	case 0x33:	/* INC SP */ +	    TSTATE(6); +	    cpu->SP++; +	    break; + +	case 0x34:	/* INC (HL) */ +	    TSTATE(11); +	    OFFSET(off); +	    OP_ON_MEM(INC8,*HL+off); +	    break; + +	case 0x35:	/* DEC (HL) */ +	    TSTATE(11); +	    OFFSET(off); +	    OP_ON_MEM(DEC8,*HL+off); +	    break; + +	case 0x36:	/* LD (HL),n */ +	    TSTATE(10); +	    OFFSET(off); +	    POKE(*HL+off,FETCH_BYTE); +	    break; + +	case 0x37:	/* SCF */ +	    TSTATE(4); +	    cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80)) +			  | C_Z80 +			  | (cpu->AF.b[HI]&(B3_Z80|B5_Z80)); +	    break; + +	case 0x38:	/* JR C,d */ +	    JR_COND(IS_C); +	    break; + +	case 0x39:	/* ADD HL,SP */ +	    TSTATE(11); +	    ADD16(*HL,cpu->SP); +	    break; + +	case 0x3a:	/* LD A,(nnnn) */ +	    TSTATE(13); +	    cpu->AF.b[HI]=PEEK(FETCH_WORD); +	    break; + +	case 0x3b:	/* DEC SP */ +	    TSTATE(6); +	    cpu->SP--; +	    break; + +	case 0x3c:	/* INC A */ +	    TSTATE(4); +	    INC8(cpu->AF.b[HI]); +	    break; + +	case 0x3d:	/* DEC A */ +	    TSTATE(4); +	    DEC8(cpu->AF.b[HI]); +	    break; + +	case 0x3e:	/* LD A,n */ +	    TSTATE(7); +	    cpu->AF.b[HI]=FETCH_BYTE; +	    break; + +	case 0x3f:	/* CCF */ +	    TSTATE(4); + +	    if (CARRY) +	    	SETFLAG(H_Z80); +	    else +	    	CLRFLAG(H_Z80); + +	    cpu->AF.b[LO]^=C_Z80; +	    SETHIDDEN(cpu->AF.b[HI]); +	    break; + +	LD_BLOCK(0x40,cpu->BC.b[HI],cpu->BC.b[HI]) +	LD_BLOCK(0x48,cpu->BC.b[LO],cpu->BC.b[LO]) +	LD_BLOCK(0x50,cpu->DE.b[HI],cpu->DE.b[HI]) +	LD_BLOCK(0x58,cpu->DE.b[LO],cpu->DE.b[LO]) +	LD_BLOCK(0x60,*H,cpu->HL.b[HI]) +	LD_BLOCK(0x68,*L,cpu->HL.b[LO]) + +	case 0x70:	/* LD (HL),B */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->BC.b[HI]); +	    break; + +	case 0x71:	/* LD (HL),C */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->BC.b[LO]); +	    break; + +	case 0x72:	/* LD (HL),D */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->DE.b[HI]); +	    break; + +	case 0x73:	/* LD (HL),E */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->DE.b[LO]); +	    break; + +	case 0x74:	/* LD (HL),H */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->HL.b[HI]); +	    break; + +	case 0x75:	/* LD (HL),L */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->HL.b[LO]); +	    break; + +	case 0x76:	/* HALT */ +	    TSTATE(4); +	    cpu->PC--; + +	    if (!PRIV->halt) +		CALLBACK(eZ80_Halt,1); + +	    PRIV->halt=TRUE; +	    break; + +	case 0x77:	/* LD (HL),A */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->AF.b[HI]); +	    break; + +	LD_BLOCK(0x78,cpu->AF.b[HI],cpu->AF.b[HI]) + +	ALU_BLOCK(0x80,ADD8) +	ALU_BLOCK(0x88,ADC8) +	ALU_BLOCK(0x90,SUB8) +	ALU_BLOCK(0x98,SBC8) +	ALU_BLOCK(0xa0,AND) +	ALU_BLOCK(0xa8,XOR) +	ALU_BLOCK(0xb0,OR) +	ALU_BLOCK(0xb8,CMP8) + +	case 0xc0:	/* RET NZ */ +	    RET_COND(!IS_Z); +	    break; + +	case 0xc1:	/* POP BC */ +	    TSTATE(10); +	    POP(cpu->BC.w); +	    break; + +	case 0xc2:	/* JP NZ,nnnn */ +	    JP_COND(!IS_Z); +	    break; + +	case 0xc3:	/* JP nnnn */ +	    JP_COND(1); +	    break; + +	case 0xc4:	/* CALL NZ,nnnn */ +	    CALL_COND(!IS_Z); +	    break; + +	case 0xc5:	/* PUSH BC */ +	    TSTATE(10); +	    PUSH(cpu->BC.w); +	    break; + +	case 0xc6:	/* ADD A,n */ +	    TSTATE(7); +	    ADD8(FETCH_BYTE); +	    break; + +	case 0xc7:	/* RST 0 */ +	    RST(0); +	    break; + +	case 0xc8:	/* RET Z */ +	    RET_COND(IS_Z); +	    break; + +	case 0xc9:	/* RET */ +	    TSTATE(10); +	    POP(cpu->PC); +	    break; + +	case 0xca:	/* JP Z,nnnn */ +	    JP_COND(IS_Z); +	    break; + +	case 0xcb:	/* CB PREFIX */ +	    INC_R; + +	    /* Check for previous IX/IY shift. +	    */ +	    if (PRIV->shift!=0) +	    { +		Z80Relative cb_offset; + +		TSTATE(4);	/* Wild stab in the dark! */ +		cb_offset=FETCH_BYTE; +		ShiftedDecodeCB(cpu,FETCH_BYTE,cb_offset); +	    } +	    else +	    { +		DecodeCB(cpu,FETCH_BYTE); +	    } +	    break; + +	case 0xcc:	/* CALL Z,nnnn */ +	    CALL_COND(IS_Z); +	    break; + +	case 0xcd:	/* CALL nnnn */ +	    CALL_COND(1); +	    break; + +	case 0xce:	/* ADC A,n */ +	    ADC8(FETCH_BYTE); +	    break; + +	case 0xcf:	/* RST 8 */ +	    RST(8); +	    break; + +	case 0xd0:	/* RET NC */ +	    RET_COND(!IS_C); +	    break; + +	case 0xd1:	/* POP DE */ +	    TSTATE(10); +	    POP(cpu->DE.w); +	    break; + +	case 0xd2:	/* JP NC,nnnn */ +	    JP_COND(!IS_C); +	    break; + +	case 0xd3:	/* OUT (n),A */ +	    TSTATE(11); +	    if (PRIV->pwrite) +	    { +		Z80Word port; + +		port=FETCH_BYTE; +		port|=(Z80Word)cpu->AF.b[HI]<<8; +	    	PRIV->pwrite(cpu,port,cpu->AF.b[HI]); +	    } +	    else +	    	cpu->PC++; +	    break; + +	case 0xd4:	/* CALL NC,nnnn */ +	    CALL_COND(!IS_C); +	    break; + +	case 0xd5:	/* PUSH DE */ +	    TSTATE(11); +	    PUSH(cpu->DE.w); +	    break; + +	case 0xd6:	/* SUB A,n */ +	    TSTATE(7); +	    SUB8(FETCH_BYTE); +	    break; + +	case 0xd7:	/* RST 10 */ +	    RST(0x10); +	    break; + +	case 0xd8:	/* RET C */ +	    RET_COND(IS_C); +	    break; + +	case 0xd9:	/* EXX */ +	    TSTATE(4); +	    SWAP(cpu->BC.w,cpu->BC_); +	    SWAP(cpu->DE.w,cpu->DE_); +	    SWAP(cpu->HL.w,cpu->HL_); +	    break; + +	case 0xda:	/* JP C,nnnn */ +	    JP_COND(IS_C); +	    break; + +	case 0xdb:	/* IN A,(n) */ +	    TSTATE(11); +	    if (PRIV->pread) +	    { +		Z80Word port; + +		port=FETCH_BYTE; +		port|=(Z80Word)cpu->AF.b[HI]<<8; +		cpu->AF.b[HI]=PRIV->pread(cpu,port); +	    } +	    else +	    	cpu->PC++; +	    break; + +	case 0xdc:	/* CALL C,nnnn */ +	    CALL_COND(IS_C); +	    break; + +	case 0xdd:	/* DD PREFIX */ +	    TSTATE(4); +	    INC_R; + +	    PRIV->shift=opcode; +	    Z80_Decode(cpu,FETCH_BYTE); +	    break; + +	case 0xde:	/* SBC A,n */ +	    TSTATE(7); +	    SBC8(FETCH_BYTE); +	    break; + +	case 0xdf:	/* RST 18 */ +	    RST(0x18); +	    break; + +	case 0xe0:	/* RET PO */ +	    RET_COND(!IS_P); +	    break; + +	case 0xe1:	/* POP HL */ +	    TSTATE(10); +	    POP(*HL); +	    break; + +	case 0xe2:	/* JP PO,nnnn */ +	    JP_COND(!IS_P); +	    break; + +	case 0xe3:	/* EX (SP),HL */ +	    { +	    Z80Word tmp; +	    TSTATE(19); +	    POP(tmp); +	    PUSH(*HL); +	    *HL=tmp; +	    } +	    break; + +	case 0xe4:	/* CALL PO,nnnn */ +	    CALL_COND(!IS_P); +	    break; + +	case 0xe5:	/* PUSH HL */ +	    TSTATE(10); +	    PUSH(*HL); +	    break; + +	case 0xe6:	/* AND A,n */ +	    TSTATE(7); +	    AND(FETCH_BYTE); +	    break; + +	case 0xe7:	/* RST 20 */ +	    RST(0x20); +	    break; + +	case 0xe8:	/* RET PE */ +	    RET_COND(IS_P); +	    break; + +	case 0xe9:	/* JP (HL) */ +	    TSTATE(4); +	    cpu->PC=*HL; +	    break; + +	case 0xea:	/* JP PE,nnnn */ +	    JP_COND(IS_P); +	    break; + +	case 0xeb:	/* EX DE,HL */ +	    TSTATE(4); +	    SWAP(cpu->DE.w,*HL); +	    break; + +	case 0xec:	/* CALL PE,nnnn */ +	    CALL_COND(IS_P); +	    break; + +	case 0xed:	/* ED PREFIX */ +	    INC_R; +	    DecodeED(cpu,FETCH_BYTE); +	    break; + +	case 0xee:	/* XOR A,n */ +	    TSTATE(7); +	    XOR(FETCH_BYTE); +	    break; + +	case 0xef:	/* RST 28 */ +	    RST(0x28); +	    break; + +	case 0xf0:	/* RET P */ +	    RET_COND(!IS_S); +	    break; + +	case 0xf1:	/* POP AF */ +	    TSTATE(10); +	    POP(cpu->AF.w); +	    break; + +	case 0xf2:	/* JP P,nnnn */ +	    JP_COND(!IS_S); +	    break; + +	case 0xf3:	/* DI */ +	    TSTATE(4); +	    cpu->IFF1=0; +	    cpu->IFF2=0; +	    break; + +	case 0xf4:	/* CALL P,nnnn */ +	    CALL_COND(!IS_S); +	    break; + +	case 0xf5:	/* PUSH AF */ +	    TSTATE(10); +	    PUSH(cpu->AF.w); +	    break; + +	case 0xf6:	/* OR A,n */ +	    TSTATE(7); +	    OR(FETCH_BYTE); +	    break; + +	case 0xf7:	/* RST 30 */ +	    RST(0x30); +	    break; + +	case 0xf8:	/* RET M */ +	    RET_COND(IS_S); +	    break; + +	case 0xf9:	/* LD SP,HL */ +	    TSTATE(6); +	    cpu->SP=*HL; +	    break; + +	case 0xfa:	/* JP M,nnnn */ +	    JP_COND(IS_S); +	    break; + +	case 0xfb:	/* EI */ +	    TSTATE(4); +	    cpu->IFF1=1; +	    cpu->IFF2=1; +	    break; + +	case 0xfc:	/* CALL M,nnnn */ +	    CALL_COND(IS_S); +	    break; + +	case 0xfd:	/* FD PREFIX */ +	    TSTATE(4); +	    INC_R; + +	    PRIV->shift=opcode; +	    Z80_Decode(cpu,FETCH_BYTE); +	    break; + +	case 0xfe:	/* CP A,n */ +	    TSTATE(7); +	    CMP8(FETCH_BYTE); +	    break; + +	case 0xff:	/* RST 38 */ +	    RST(0x38); +	    break; + +    } +} + + +/* END OF FILE */ diff --git a/arm9/source/z80_dis.c b/arm9/source/z80_dis.c new file mode 100644 index 0000000..8a8ade8 --- /dev/null +++ b/arm9/source/z80_dis.c @@ -0,0 +1,2494 @@ +/* + +    z80 - Z80 Emulator + +    Copyright (C) 2006  Ian Cowburn <ianc@noddybox.co.uk> + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    $Id$ + +*/ +static const char ident[]="$Id$"; + +#include "z80_config.h" + +#ifdef ENABLE_DISASSEM + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +#include "z80.h" +#include "z80_private.h" + +static Z80Relative	cb_off; + +/* ---------------------------------------- SHARED ROUTINES +*/ +static const char *z80_dis_reg8[]={"b","c","d","e","h","l","(hl)","a"}; +static const char *z80_dis_reg16[]={"bc","de","hl","sp"}; +static const char *z80_dis_condition[]={"nz","z","nc","c","po","pe","p","m"}; + +static const char *dis_op; +static const char *dis_arg; + +const char *Z80_Dis_Printf(const char *format, ...) +{ +    static int p=0; +    static char s[16][80]; +    va_list arg; + +    va_start(arg,format); +    p=(p+1)%16; +    vsprintf(s[p],format,arg); +    va_end(arg); + +    return s[p]; +} + + +Z80Byte Z80_Dis_FetchByte(Z80 *cpu, Z80Word *pc) +{ +#ifdef ENABLE_ARRAY_MEMORY +    return Z80_MEMORY[(*pc)++]; +#else +    return cpu->priv->disread(cpu,(*pc)++); +#endif +} + + +Z80Word Z80_Dis_FetchWord(Z80 *cpu, Z80Word *pc) +{ +    Z80Byte l,h; + +    l=Z80_Dis_FetchByte(cpu,pc); +    h=Z80_Dis_FetchByte(cpu,pc); + +    return ((Z80Word)h<<8)|l; +} + + +void Z80_Dis_Set(const char *op, const char *arg) +{ +    dis_op=op; +    dis_arg=arg; +} + + +const char *Z80_Dis_GetOp(void) +{ +    return dis_op ? dis_op : ""; +} + + +const char *Z80_Dis_GetArg(void) +{ +    return dis_arg ? dis_arg : ""; +} + + +static const char *GetLabel(Z80Word w) +{ +    if (z80_labels) +    { +    	int f; + +	for(f=0;z80_labels[f].label;f++) +	{ +	    if (z80_labels[f].address==w) +	    { +	    	return z80_labels[f].label; +	    } +	} +    } + +    return NULL; +} + + + +/* ---------------------------------------- CB xx BYTE OPCODES +*/ +static void DIS_RLC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("rlc",reg); +} + +static void DIS_RRC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("rrc",reg); +} + +static void DIS_RL_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("rl",reg); +} + +static void DIS_RR_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("rr",reg); +} + +static void DIS_SLA_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("sla",reg); +} + +static void DIS_SRA_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("sra",reg); +} + +static void DIS_SLL_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("sll",reg); +} + +static void DIS_SRL_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("srl",reg); +} + +static void DIS_BIT_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; +    int bit; + +    reg=z80_dis_reg8[op%8]; +    bit=(op-0x40)/8; +    Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s",bit,reg)); +} + +static void DIS_RES_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; +    int bit; + +    reg=z80_dis_reg8[op%8]; +    bit=(op-0x80)/8; +    Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s",bit,reg)); +} + +static void DIS_SET_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; +    int bit; + +    reg=z80_dis_reg8[op%8]; +    bit=(op-0xc0)/8; +    Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s",bit,reg)); +} + +/* ---------------------------------------- DD OPCODES +*/ + +static const char *IX_RelStr(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    static char s[80]; +    Z80Relative r; + +    r=(Z80Relative)Z80_Dis_FetchByte(z80,pc); + +    if (r<0) +	sprintf(s,"(ix-$%.2x)",-r); +    else +	sprintf(s,"(ix+$%.2x)",r); + +    return(s); +} + + +static const char *IX_RelStrCB(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    static char s[80]; +    Z80Relative r; + +    r=(Z80Relative)cb_off; + +    if (r<0) +	sprintf(s,"(ix-$%.2x)",-r); +    else +	sprintf(s,"(ix+$%.2x)",r); + +    return(s); +} + + +static const char *XR8(Z80 *z80, int reg, Z80Word *pc) +{ +    switch(reg) +    	{ +	case 0: +	    return("b"); +	    break; +	case 1: +	    return("c"); +	    break; +	case 2: +	    return("d"); +	    break; +	case 3: +	    return("e"); +	    break; +	case 4: +	    return("ixh"); +	    break; +	case 5: +	    return("ixl"); +	    break; +	case 6: +	    return(IX_RelStr(z80,0,pc)); +	    break; +	case 7: +	    return("a"); +	    break; +	default: +	    return(Z80_Dis_Printf("BUG %d",reg)); +	    break; +	} +} + +static void DIS_DD_NOP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    dis_opcode_z80[op](z80,op,pc); +} + +static void DIS_ADD_IX_BC(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","ix,bc"); +} +  +static void DIS_ADD_IX_DE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","ix,de"); +} + +static void DIS_LD_IX_WORD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld",Z80_Dis_Printf("ix,$%.4x",Z80_Dis_FetchWord(z80,pc))); +} + +static void DIS_LD_ADDR_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),ix",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),ix",w)); +} + +static void DIS_INC_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc","ix"); +} + +static void DIS_INC_IXH(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc","ixh"); +} + +static void DIS_DEC_IXH(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec","ixh"); +} + +static void DIS_LD_IXH_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld",Z80_Dis_Printf("ixh,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_ADD_IX_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","ix,ix"); +} + +static void DIS_LD_IX_ADDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("ix,(%s)",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("ix,($%.4x)",w)); +} + +static void DIS_DEC_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec","ix"); +} + +static void DIS_INC_IXL(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc","ixl"); +} + +static void DIS_DEC_IXL(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec","ixl"); +} + +static void DIS_LD_IXL_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld",Z80_Dis_Printf("ixl,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} +  +static void DIS_INC_IIX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc",Z80_Dis_Printf("%s",IX_RelStr(z80,op,pc))); +} + +static void DIS_DEC_IIX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec",Z80_Dis_Printf("%s",IX_RelStr(z80,op,pc))); +} + +static void DIS_LD_IIX_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *rel; +    int b; + +    rel=IX_RelStr(z80,op,pc); +    b=Z80_Dis_FetchByte(z80,pc); +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.2x",rel,b)); +} + + +static void DIS_ADD_IX_SP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","ix,sp"); +} +  +static void DIS_XLD_R8_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int src_r,dest_r; +    const char *src,*dest; + +    dest_r=(op-0x40)/8; +    src_r=op%8; + +    /* IX can't be used as source and destination when reading z80ory +    */ +    if (dest_r==6) +    	{ +	dest=XR8(z80,dest_r,pc); +	src=z80_dis_reg8[src_r]; +	} +    else if (((dest_r==4)||(dest_r==5))&&(src_r==6)) +    	{ +	dest=z80_dis_reg8[dest_r]; +	src=XR8(z80,src_r,pc); +	} +    else +	{ +	dest=XR8(z80,dest_r,pc); +	src=XR8(z80,src_r,pc); +	} + +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,%s",dest,src)); +} + +static void DIS_XADD_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XADC_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("adc",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XSUB_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sub",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XSBC_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sbc",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XAND_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("and",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XXOR_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("xor",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc))); +} + +static void DIS_X_OR_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("or",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XCP_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cp",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc))); +} + +static void DIS_POP_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("pop","ix"); +} + +static void DIS_EX_ISP_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ex","(sp),ix"); +} + +static void DIS_PUSH_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("push","ix"); +} + +static void DIS_JP_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("jp","(ix)"); +} +  +static void DIS_LD_SP_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","sp,ix"); +} + +static void DIS_DD_CB_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    cb_off=(Z80Relative)Z80_Dis_FetchByte(z80,pc); +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_DD_CB_opcode[nop](z80,nop,pc); +} + +static void DIS_DD_DD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_DD_opcode[nop](z80,nop,pc); +} + +static void DIS_DD_ED_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_ED_opcode[nop](z80,nop,pc); +} + +static void DIS_DD_FD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_FD_opcode[nop](z80,nop,pc); +} + + +/* ---------------------------------------- DD CB OPCODES +*/ + +static void DIS_RLC_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rlc",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +	{ +        Z80_Dis_Set("rlc",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +	} +} + +static void DIS_RRC_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rrc",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rrc",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RL_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rl",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rl",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RR_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rr",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rr",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SLA_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("sla",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("sla",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SRA_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("sra",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("sra",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SRL_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("srl",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("srl",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SLL_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("sll",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("sll",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_BIT_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; +    int bit; + +    reg=(op%8); +    bit=(op-0x40)/8; + +    if (reg==6) +        Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s",bit,IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s[%s]",bit,IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RES_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; +    int bit; + +    reg=(op%8); +    bit=(op-0x80)/8; + +    if (reg==6) +        Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s",bit,IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s[%s]",bit,IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SET_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; +    int bit; + +    reg=(op%8); +    bit=(op-0xc0)/8; + +    if (reg==6) +        Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s",bit,IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s[%s]",bit,IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + + +/* ---------------------------------------- ED OPCODES +*/ + +static const char *ER8(int reg) +{ +    switch(reg) +    	{ +	case 0: +	    return("b"); +	    break; +	case 1: +	    return("c"); +	    break; +	case 2: +	    return("d"); +	    break; +	case 3: +	    return("e"); +	    break; +	case 4: +	    return("h"); +	    break; +	case 5: +	    return("l"); +	    break; +	case 6: +	    return("0"); +	    break; +	case 7: +	    return("a"); +	    break; +	} + +    return "?"; +} + +/* Assumes illegal ED ops are being used for break points +*/ +static void DIS_ED_NOP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("brk",Z80_Dis_Printf("$%.2x",op)); +} + +static void DIS_IN_R8_C(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("in",Z80_Dis_Printf("%s,(c)",ER8((op-0x40)/8))); +} + +static void DIS_OUT_C_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("out",Z80_Dis_Printf("(c),%s",ER8((op-0x40)/8))); +} + +static void DIS_SBC_HL_R16(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sbc",Z80_Dis_Printf("hl,%s",z80_dis_reg16[(op-0x40)/16])); +} + +static void DIS_ED_LD_ADDR_R16(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),%s",p,z80_dis_reg16[(op-0x40)/16])); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),%s",w,z80_dis_reg16[(op-0x40)/16])); +} + +static void DIS_NEG(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("neg",NULL); +} + +static void DIS_RETN(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("retn",NULL); +} + +static void DIS_IM_0(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("im","0"); +} + +static void DIS_LD_I_A(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","i,a"); +} + +static void DIS_ADC_HL_R16(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("adc",Z80_Dis_Printf("hl,%s",z80_dis_reg16[(op-0x40)/16])); +} + +static void DIS_ED_LD_R16_ADDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("%s,(%s)",z80_dis_reg16[(op-0x40)/16],p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("%s,($%.4x)",z80_dis_reg16[(op-0x40)/16],w)); +} + +static void DIS_RETI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("reti",NULL); +} + +static void DIS_LD_R_A(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","r,a"); +} + +static void DIS_IM_1(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("im","1"); +} + +static void DIS_LD_A_I(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","a,i"); +} + +static void DIS_IM_2(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("im","2"); +} + +static void DIS_LD_A_R(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","a,r"); +} + +static void DIS_RRD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("rrd",NULL); +} + +static void DIS_RLD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("rld",NULL); +} + +static void DIS_LDI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ldi",NULL); +} + +static void DIS_CPI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cpi",NULL); +} + +static void DIS_INI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ini",NULL); +} + +static void DIS_OUTI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("outi",NULL); +} + +static void DIS_LDD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ldd",NULL); +} + +static void DIS_CPD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cpd",NULL); +} + +static void DIS_IND(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ind",NULL); +} + +static void DIS_OUTD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("outd",NULL); +} + +static void DIS_LDIR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ldir",NULL); +} + +static void DIS_CPIR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cpir",NULL); +} + +static void DIS_INIR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inir",NULL); +} + +static void DIS_OTIR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("otir",NULL); +} + +static void DIS_LDDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("lddr",NULL); +} + +static void DIS_CPDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cpdr",NULL); +} + +static void DIS_INDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("indr",NULL); +} + +static void DIS_OTDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("otdr",NULL); +} + + +/* ---------------------------------------- FD OPCODES +*/ + +static const char *IY_RelStr(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    static char s[80]; +    Z80Relative r; + +    r=(Z80Relative)Z80_Dis_FetchByte(z80,pc); + +    if (r<0) +	sprintf(s,"(iy-$%.2x)",-r); +    else +	sprintf(s,"(iy+$%.2x)",r); + +    return(s); +} + + +static const char *IY_RelStrCB(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    static char s[80]; +    Z80Relative r; + +    r=(Z80Relative)cb_off; + +    if (r<0) +	sprintf(s,"(iy-$%.2x)",-r); +    else +	sprintf(s,"(iy+$%.2x)",r); + +    return(s); +} + + +static const char *YR8(Z80 *z80, int reg, Z80Word *pc) +{ +    switch(reg) +    	{ +	case 0: +	    return("b"); +	    break; +	case 1: +	    return("c"); +	    break; +	case 2: +	    return("d"); +	    break; +	case 3: +	    return("e"); +	    break; +	case 4: +	    return("iyh"); +	    break; +	case 5: +	    return("iyl"); +	    break; +	case 6: +	    return(IY_RelStr(z80,0,pc)); +	    break; +	case 7: +	    return("a"); +	    break; +	default: +	    return(Z80_Dis_Printf("BUG %d",reg)); +	    break; +	} +} + +static void DIS_FD_NOP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    dis_opcode_z80[op](z80,op,pc); +} + +static void DIS_ADD_IY_BC(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","iy,bc"); +} +  +static void DIS_ADD_IY_DE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","iy,de"); +} + +static void DIS_LD_IY_WORD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld",Z80_Dis_Printf("iy,$%.4x",Z80_Dis_FetchWord(z80,pc))); +} + +static void DIS_LD_ADDR_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),iy",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),iy",w)); +} + +static void DIS_INC_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc","iy"); +} + +static void DIS_INC_IYH(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc","iyh"); +} + +static void DIS_DEC_IYH(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec","iyh"); +} + +static void DIS_LD_IYH_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld",Z80_Dis_Printf("iyh,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_ADD_IY_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","iy,iy"); +} + +static void DIS_LD_IY_ADDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("iy,(%s)",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("iy,($%.4x)",w)); +} + +static void DIS_DEC_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec","iy"); +} + +static void DIS_INC_IYL(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc","iyl"); +} + +static void DIS_DEC_IYL(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec","iyl"); +} + +static void DIS_LD_IYL_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld",Z80_Dis_Printf("iyl,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} +  +static void DIS_INC_IIY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc",Z80_Dis_Printf("%s",IY_RelStr(z80,op,pc))); +} + +static void DIS_DEC_IIY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec",Z80_Dis_Printf("%s",IY_RelStr(z80,op,pc))); +} + +static void DIS_LD_IIY_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *rel; +    int b; + +    rel=IY_RelStr(z80,op,pc); +    b=Z80_Dis_FetchByte(z80,pc); +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.2x",rel,b)); +} + + +static void DIS_ADD_IY_SP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","iy,sp"); +} +  +static void DIS_YLD_R8_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int src_r,dest_r; +    const char *src,*dest; + +    dest_r=(op-0x40)/8; +    src_r=op%8; + +    /* IY can't be used as source and destination when reading z80ory +    */ +    if (dest_r==6) +	{ +	dest=YR8(z80,dest_r,pc); +	src=z80_dis_reg8[src_r]; +	} +    else if (((dest_r==4)||(dest_r==5))&&(src_r==6)) +	{ +	dest=z80_dis_reg8[dest_r]; +	src=YR8(z80,src_r,pc); +	} +    else +	{ +	dest=YR8(z80,dest_r,pc); +	src=YR8(z80,src_r,pc); +	} + +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,%s",dest,src)); +} + +static void DIS_YADD_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YADC_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("adc",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YSUB_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sub",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YSBC_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sbc",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YAND_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("and",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YYOR_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("xor",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc))); +} + +static void DIS_Y_OR_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("or",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YCP_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cp",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc))); +} + +static void DIS_POP_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("pop","iy"); +} + +static void DIS_EY_ISP_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ex","(sp),iy"); +} + +static void DIS_PUSH_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("push","iy"); +} + +static void DIS_JP_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("jp","(iy)"); +} +  +static void DIS_LD_SP_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","sp,iy"); +} + +static void DIS_FD_CB_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    cb_off=(Z80Relative)Z80_Dis_FetchByte(z80,pc); +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_FD_CB_opcode[nop](z80,nop,pc); +} + +static void DIS_FD_DD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_DD_opcode[nop](z80,nop,pc); +} + +static void DIS_FD_ED_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_ED_opcode[nop](z80,nop,pc); +} + +static void DIS_FD_FD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_FD_opcode[nop](z80,nop,pc); +} + + +/* ---------------------------------------- FD CB OPCODES +*/ + +static void DIS_RLC_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rlc",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rlc",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RRC_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rrc",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rrc",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RL_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rl",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rl",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RR_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rr",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rr",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SLA_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("sla",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("sla",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SRA_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("sra",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("sra",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SRL_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("srl",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("srl",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SLL_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("sll",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("sll",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_BIT_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; +    int bit; + +    reg=(op%8); +    bit=(op-0x40)/8; + +    if (reg==6) +        Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s",bit,IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s[%s]",bit,IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RES_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; +    int bit; + +    reg=(op%8); +    bit=(op-0x80)/8; + +    if (reg==6) +        Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s",bit,IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s[%s]",bit,IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SET_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; +    int bit; + +    reg=(op%8); +    bit=(op-0xc0)/8; + +    if (reg==6) +        Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s",bit,IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s[%s]",bit,IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + + +/* ---------------------------------------- SINGLE BYTE OPCODES +*/ +static void DIS_NOP (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("nop",NULL); +} + +static void DIS_LD_R16_WORD (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op&0x30)/0x10]; +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.4x",reg,Z80_Dis_FetchWord(z80,pc))); +} + +static void DIS_LD_R16_A (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op&0x30)/0x10]; +    Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),a",reg)); +} + +static void DIS_INC_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op&0x30)/0x10]; +    Z80_Dis_Set("inc",reg); +} + +static void DIS_INC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[(op&0x38)/0x8]; +    Z80_Dis_Set("inc",reg); +} + +static void DIS_DEC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[(op&0x38)/0x8]; +    Z80_Dis_Set("dec",reg); +} + +static void DIS_LD_R8_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[(op&0x38)/0x8]; +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.2x",reg,Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_RLCA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("rlca",NULL); +} + +static void DIS_EX_AF_AF (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ex","af,af'"); +} + +static void DIS_ADD_HL_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op&0x30)/0x10]; +    Z80_Dis_Set("add",Z80_Dis_Printf("hl,%s",reg)); +} + +static void DIS_LD_A_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op&0x30)/0x10]; +    Z80_Dis_Set("ld",Z80_Dis_Printf("a,(%s)",reg)); +} + +static void DIS_DEC_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op&0x30)/0x10]; +    Z80_Dis_Set("dec",reg); +} + +static void DIS_RRCA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("rrca",NULL); +} + +static void DIS_DJNZ (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word new; + +#ifdef ENABLE_ARRAY_MEMORY +    new=*pc+(Z80Relative)Z80_MEMORY[*pc]+1; +#else +    new=*pc+(Z80Relative)z80->priv->disread(z80,*pc)+1; +#endif +    (*pc)++; +    Z80_Dis_Set("djnz",Z80_Dis_Printf("$%.4x",new)); +} + +static void DIS_RLA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("rla",NULL); +} + +static void DIS_JR (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word new; +    const char *p; + +#ifdef ENABLE_ARRAY_MEMORY +    new=*pc+(Z80Relative)Z80_MEMORY[*pc]+1; +#else +    new=*pc+(Z80Relative)z80->priv->disread(z80,*pc)+1; +#endif +    (*pc)++; + +    if ((p=GetLabel(new))) +	Z80_Dis_Set("jr",Z80_Dis_Printf("%s",p)); +    else +	Z80_Dis_Set("jr",Z80_Dis_Printf("$%.4x",new)); +} + +static void DIS_RRA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("rra",NULL); +} + +static void DIS_JR_CO (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *con; +    Z80Word new; +    const char *p; + +    con=z80_dis_condition[(op-0x20)/8]; +#ifdef ENABLE_ARRAY_MEMORY +    new=*pc+(Z80Relative)Z80_MEMORY[*pc]+1; +#else +    new=*pc+(Z80Relative)z80->priv->disread(z80,*pc)+1; +#endif +    (*pc)++; + +    if ((p=GetLabel(new))) +	Z80_Dis_Set("jr",Z80_Dis_Printf("%s,%s",con,p)); +    else +	Z80_Dis_Set("jr",Z80_Dis_Printf("%s,$%.4x",con,new)); +} + +static void DIS_LD_ADDR_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),hl",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),hl",w)); +} + +static void DIS_DAA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("daa",NULL); +} + +static void DIS_LD_HL_ADDR (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("hl,(%s)",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("hl,($%.4x)",w)); +} + +static void DIS_CPL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cpl",NULL); +} + +static void DIS_LD_ADDR_A (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),a",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),a",w)); +} + +static void DIS_SCF (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("scf",NULL); +} + +static void DIS_LD_A_ADDR (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("a,(%s)",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("a,($%.4x)",w)); +} + +static void DIS_CCF (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ccf",NULL); +} + +static void DIS_LD_R8_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *src,*dest; + +    dest=z80_dis_reg8[(op-0x40)/8]; +    src=z80_dis_reg8[op%8]; +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,%s",dest,src)); +} + +static void DIS_HALT (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("halt",NULL); +} + +static void DIS_ADD_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("add",Z80_Dis_Printf("a,%s",reg)); +} + +static void DIS_ADC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("adc",Z80_Dis_Printf("a,%s",reg)); +} + +static void DIS_SUB_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("sub",Z80_Dis_Printf("a,%s",reg)); +} + +static void DIS_SBC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("sbc",Z80_Dis_Printf("a,%s",reg)); +} + +static void DIS_AND_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("and",Z80_Dis_Printf("%s",reg)); +} + +static void DIS_XOR_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("xor",Z80_Dis_Printf("%s",reg)); +} + +static void DIS_OR_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("or",Z80_Dis_Printf("%s",reg)); +} + +static void DIS_CP_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("cp",Z80_Dis_Printf("%s",reg)); +} + + +static void DIS_RET_CO (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *con; + +    con=z80_dis_condition[(op-0xc0)/8]; +    Z80_Dis_Set("ret",con); +} + +static void DIS_POP_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op-0xc0)/16]; + +    if (!strcmp(reg,"sp")) +    	reg="af"; + +    Z80_Dis_Set("pop",reg); +} + +static void DIS_JP (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("jp",Z80_Dis_Printf("%s",p)); +    else +	Z80_Dis_Set("jp",Z80_Dis_Printf("$%.4x",w)); +} + +static void DIS_PUSH_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op-0xc0)/16]; + +    if (!strcmp(reg,"sp")) +    	reg="af"; + +    Z80_Dis_Set("push",reg); +} + +static void DIS_ADD_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_RST (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int add; + +    add=(op&0x3f)-7; +    Z80_Dis_Set("rst",Z80_Dis_Printf("%.2xh",add)); +} + +static void DIS_RET (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ret",NULL); +} + +static void DIS_JP_CO (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *con; +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); +    con=z80_dis_condition[(op-0xc0)/8]; + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("jp",Z80_Dis_Printf("%s,%s",con,p)); +    else +	Z80_Dis_Set("jp",Z80_Dis_Printf("%s,$%.4x",con,w)); +} + +static void DIS_CB_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_CB_opcode[nop](z80,nop,pc); +} + +static void DIS_CALL_CO (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *con; +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); +    con=z80_dis_condition[(op-0xc0)/8]; + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("call",Z80_Dis_Printf("%s,%s",con,p)); +    else +	Z80_Dis_Set("call",Z80_Dis_Printf("%s,$%.4x",con,w)); +} + +static void DIS_CALL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("call",Z80_Dis_Printf("%s",p)); +    else +	Z80_Dis_Set("call",Z80_Dis_Printf("$%.4x",w)); +} + +static void DIS_ADC_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("adc",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_OUT_BYTE_A (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("out",Z80_Dis_Printf("($%.2x),a",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_SUB_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sub",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_EXX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("exx",NULL); +} + +static void DIS_IN_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("in",Z80_Dis_Printf("a,($%.2x)",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_DD_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_DD_opcode[nop](z80,nop,pc); +} + +static void DIS_SBC_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sbc",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + + +static void DIS_EX_ISP_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ex","(sp),hl"); +} + +static void DIS_AND_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("and",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_JP_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("jp","(hl)"); +} + +static void DIS_EX_DE_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ex","de,hl"); +} + +static void DIS_ED_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_ED_opcode[nop](z80,nop,pc); +} + +static void DIS_XOR_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("xor",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_DI (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("di",NULL); +} + +static void DIS_OR_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("or",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_LD_SP_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","sp,hl"); +} + +static void DIS_EI (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ei",NULL); +} + +static void DIS_FD_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_FD_opcode[nop](z80,nop,pc); +} + +static void DIS_CP_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cp",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + + +/* ---------------------------------------- TABLES +*/ + +/* CB opcodes +*/ +DIS_OP_CALLBACK	dis_CB_opcode[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_RLC_R8,  DIS_RLC_R8,    DIS_RLC_R8,    DIS_RLC_R8, +/* 0x04 - 0x07 */    DIS_RLC_R8,  DIS_RLC_R8,    DIS_RLC_R8,    DIS_RLC_R8, +/* 0x08 - 0x0b */    DIS_RRC_R8,  DIS_RRC_R8,    DIS_RRC_R8,    DIS_RRC_R8, +/* 0x0c - 0x0f */    DIS_RRC_R8,  DIS_RRC_R8,    DIS_RRC_R8,    DIS_RRC_R8, + +/* 0x10 - 0x13 */    DIS_RL_R8,  DIS_RL_R8,    DIS_RL_R8,    DIS_RL_R8,   +/* 0x14 - 0x17 */    DIS_RL_R8,  DIS_RL_R8,    DIS_RL_R8,    DIS_RL_R8, +/* 0x18 - 0x1b */    DIS_RR_R8,  DIS_RR_R8,    DIS_RR_R8,    DIS_RR_R8,   +/* 0x1c - 0x1f */    DIS_RR_R8,  DIS_RR_R8,    DIS_RR_R8,    DIS_RR_R8, + +/* 0x20 - 0x23 */    DIS_SLA_R8,  DIS_SLA_R8,    DIS_SLA_R8,    DIS_SLA_R8, +/* 0x24 - 0x27 */    DIS_SLA_R8,  DIS_SLA_R8,    DIS_SLA_R8,    DIS_SLA_R8, +/* 0x28 - 0x2b */    DIS_SRA_R8,  DIS_SRA_R8,    DIS_SRA_R8,    DIS_SRA_R8, +/* 0x2c - 0x2f */    DIS_SRA_R8,  DIS_SRA_R8,    DIS_SRA_R8,    DIS_SRA_R8, + +/* 0x30 - 0x33 */    DIS_SLL_R8,  DIS_SLL_R8,    DIS_SLL_R8,    DIS_SLL_R8, +/* 0x34 - 0x37 */    DIS_SLL_R8,  DIS_SLL_R8,    DIS_SLL_R8,    DIS_SLL_R8, +/* 0x38 - 0x3b */    DIS_SRL_R8,  DIS_SRL_R8,    DIS_SRL_R8,    DIS_SRL_R8, +/* 0x3c - 0x3f */    DIS_SRL_R8,  DIS_SRL_R8,    DIS_SRL_R8,    DIS_SRL_R8, + +/* 0x40 - 0x43 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x44 - 0x47 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x48 - 0x4b */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x4c - 0x4f */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, + +/* 0x50 - 0x53 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x54 - 0x57 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x58 - 0x5b */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x5c - 0x5f */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, + +/* 0x60 - 0x63 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x64 - 0x67 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x68 - 0x6b */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x6c - 0x6f */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, + +/* 0x70 - 0x73 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x74 - 0x77 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x78 - 0x7b */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x7c - 0x7f */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, + +/* 0x80 - 0x83 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0x84 - 0x87 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0x88 - 0x8b */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0x8c - 0x8f */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, + +/* 0x90 - 0x93 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0x94 - 0x97 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0x98 - 0x9b */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0x9c - 0x9f */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, + +/* 0xa0 - 0xa3 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0xa4 - 0xa7 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0xa8 - 0xab */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0xac - 0xaf */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, + +/* 0xb0 - 0xb3 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0xb4 - 0xb7 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0xb8 - 0xbb */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0xbc - 0xbf */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, + +/* 0xc0 - 0xc3 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xc4 - 0xc7 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xc8 - 0xcb */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xcc - 0xcf */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, + +/* 0xd0 - 0xd3 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xd4 - 0xd7 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xd8 - 0xdb */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xdc - 0xdf */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, + +/* 0xe0 - 0xe3 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xe4 - 0xe7 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xe8 - 0xeb */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xec - 0xef */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, + +/* 0xf0 - 0xf3 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xf4 - 0xf7 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xf8 - 0xfb */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xfc - 0xff */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +        }; + +/* DIS_DD opcodes +*/ +DIS_OP_CALLBACK	dis_DD_opcode[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x04 - 0x07 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x08 - 0x0b */    DIS_DD_NOP,	DIS_ADD_IX_BC,	DIS_DD_NOP,		DIS_DD_NOP,	 +/* 0x0c - 0x0f */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP,		 + +/* 0x10 - 0x13 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x14 - 0x17 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x18 - 0x1b */    DIS_DD_NOP,	DIS_ADD_IX_DE,	DIS_DD_NOP,		DIS_DD_NOP,	 +/* 0x1c - 0x1f */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP,		 + +/* 0x20 - 0x23 */    DIS_DD_NOP,	DIS_LD_IX_WORD,	DIS_LD_ADDR_IX,	DIS_INC_IX, +/* 0x24 - 0x27 */    DIS_INC_IXH,	DIS_DEC_IXH,	DIS_LD_IXH_BYTE,	DIS_DD_NOP, +/* 0x28 - 0x2b */    DIS_DD_NOP,	DIS_ADD_IX_IX,	DIS_LD_IX_ADDR,	DIS_DEC_IX, +/* 0x2c - 0x2f */    DIS_INC_IXL,	DIS_DEC_IXL,	DIS_LD_IXL_BYTE,	DIS_DD_NOP, + +/* 0x30 - 0x33 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x34 - 0x37 */    DIS_INC_IIX,	DIS_DEC_IIX,	DIS_LD_IIX_BYTE,	DIS_DD_NOP, +/* 0x38 - 0x3b */    DIS_DD_NOP,	DIS_ADD_IX_SP,	DIS_DD_NOP,		DIS_DD_NOP, +/* 0x3c - 0x3f */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, + +/* 0x40 - 0x43 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x44 - 0x47 */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_DD_NOP, +/* 0x48 - 0x4b */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x4c - 0x4f */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_DD_NOP, + +/* 0x50 - 0x53 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x54 - 0x57 */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_DD_NOP, +/* 0x58 - 0x5b */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x5c - 0x5f */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_DD_NOP, + +/* 0x60 - 0x63 */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8, +/* 0x64 - 0x67 */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8, +/* 0x68 - 0x6b */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8, +/* 0x6c - 0x6f */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8, + +/* 0x70 - 0x73 */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8, +/* 0x74 - 0x77 */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_DD_NOP,		DIS_XLD_R8_R8, +/* 0x78 - 0x7b */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x7c - 0x7f */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_DD_NOP, + +/* 0x80 - 0x83 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x84 - 0x87 */    DIS_XADD_R8,	DIS_XADD_R8,	DIS_XADD_R8,	DIS_DD_NOP, +/* 0x88 - 0x8b */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x8c - 0x8f */    DIS_XADC_R8,	DIS_XADC_R8,	DIS_XADC_R8,	DIS_DD_NOP, + +/* 0x90 - 0x93 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x94 - 0x97 */    DIS_XSUB_R8,	DIS_XSUB_R8,	DIS_XSUB_R8,	DIS_DD_NOP, +/* 0x98 - 0x9b */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x9c - 0x9f */    DIS_XSBC_R8,	DIS_XSBC_R8,	DIS_XSBC_R8,	DIS_DD_NOP, + +/* 0xa0 - 0xa3 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xa4 - 0xa7 */    DIS_XAND_R8,	DIS_XAND_R8,	DIS_XAND_R8,	DIS_DD_NOP, +/* 0xa8 - 0xab */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xac - 0xaf */    DIS_XXOR_R8,	DIS_XXOR_R8,	DIS_XXOR_R8,	DIS_DD_NOP, + +/* 0xb0 - 0xb3 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xb4 - 0xb7 */    DIS_X_OR_R8,	DIS_X_OR_R8,	DIS_X_OR_R8,	DIS_DD_NOP, +/* 0xb8 - 0xbb */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xbc - 0xbf */    DIS_XCP_R8,	DIS_XCP_R8,		DIS_XCP_R8,		DIS_DD_NOP, + +/* 0xc0 - 0xc3 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xc4 - 0xc7 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xc8 - 0xcb */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_CB_DECODE, +/* 0xcc - 0xcf */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, + +/* 0xd0 - 0xd3 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xd4 - 0xd7 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xd8 - 0xdb */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xdc - 0xdf */    DIS_DD_NOP,	DIS_DD_DD_DECODE,	DIS_DD_NOP,		DIS_DD_NOP, + +/* 0xe0 - 0xe3 */    DIS_DD_NOP,	DIS_POP_IX,		DIS_DD_NOP,		DIS_EX_ISP_IX, +/* 0xe4 - 0xe7 */    DIS_DD_NOP,	DIS_PUSH_IX,	DIS_DD_NOP,		DIS_DD_NOP, +/* 0xe8 - 0xeb */    DIS_DD_NOP,	DIS_JP_IX,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xec - 0xef */    DIS_DD_NOP,	DIS_DD_ED_DECODE,	DIS_DD_NOP,		DIS_DD_NOP, + +/* 0xf0 - 0xf3 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xf4 - 0xf7 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xf8 - 0xfb */    DIS_DD_NOP,	DIS_LD_SP_IX,	DIS_DD_NOP,		DIS_DD_NOP, +/* 0xfc - 0xff */    DIS_DD_NOP,	DIS_DD_FD_DECODE,	DIS_DD_NOP,		DIS_DD_NOP, +		    }; + + +/* DIS_DD DIS_CB opcodes +*/ +DIS_OP_CALLBACK	dis_DD_CB_opcode[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_RLC_IX,	DIS_RLC_IX,		DIS_RLC_IX,		DIS_RLC_IX, +/* 0x04 - 0x07 */    DIS_RLC_IX,	DIS_RLC_IX,		DIS_RLC_IX,		DIS_RLC_IX, +/* 0x08 - 0x0b */    DIS_RRC_IX,	DIS_RRC_IX,		DIS_RRC_IX,		DIS_RRC_IX, +/* 0x0c - 0x0f */    DIS_RRC_IX,	DIS_RRC_IX,		DIS_RRC_IX,		DIS_RRC_IX, + +/* 0x10 - 0x13 */    DIS_RL_IX,	DIS_RL_IX,		DIS_RL_IX,		DIS_RL_IX,	 +/* 0x14 - 0x17 */    DIS_RL_IX,	DIS_RL_IX,		DIS_RL_IX,		DIS_RL_IX, +/* 0x18 - 0x1b */    DIS_RR_IX,	DIS_RR_IX,		DIS_RR_IX,		DIS_RR_IX,	 +/* 0x1c - 0x1f */    DIS_RR_IX,	DIS_RR_IX,		DIS_RR_IX,		DIS_RR_IX, + +/* 0x20 - 0x23 */    DIS_SLA_IX,	DIS_SLA_IX,		DIS_SLA_IX,		DIS_SLA_IX, +/* 0x24 - 0x27 */    DIS_SLA_IX,	DIS_SLA_IX,		DIS_SLA_IX,		DIS_SLA_IX, +/* 0x28 - 0x2b */    DIS_SRA_IX,	DIS_SRA_IX,		DIS_SRA_IX,		DIS_SRA_IX, +/* 0x2c - 0x2f */    DIS_SRA_IX,	DIS_SRA_IX,		DIS_SRA_IX,		DIS_SRA_IX, + +/* 0x30 - 0x33 */    DIS_SLL_IX,	DIS_SLL_IX,		DIS_SLL_IX,		DIS_SLL_IX, +/* 0x34 - 0x37 */    DIS_SLL_IX,	DIS_SLL_IX,		DIS_SLL_IX,		DIS_SLL_IX, +/* 0x38 - 0x3b */    DIS_SRL_IX,	DIS_SRL_IX,		DIS_SRL_IX,		DIS_SRL_IX, +/* 0x3c - 0x3f */    DIS_SRL_IX,	DIS_SRL_IX,		DIS_SRL_IX,		DIS_SRL_IX, + +/* 0x40 - 0x43 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x44 - 0x47 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x48 - 0x4b */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x4c - 0x4f */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, + +/* 0x50 - 0x53 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x54 - 0x57 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x58 - 0x5b */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x5c - 0x5f */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, + +/* 0x60 - 0x63 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x64 - 0x67 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x68 - 0x6b */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x6c - 0x6f */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, + +/* 0x70 - 0x73 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x74 - 0x77 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x78 - 0x7b */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x7c - 0x7f */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, + +/* 0x80 - 0x83 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0x84 - 0x87 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0x88 - 0x8b */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0x8c - 0x8f */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, + +/* 0x90 - 0x93 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0x94 - 0x97 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0x98 - 0x9b */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0x9c - 0x9f */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, + +/* 0xa0 - 0xa3 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0xa4 - 0xa7 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0xa8 - 0xab */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0xac - 0xaf */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, + +/* 0xb0 - 0xb3 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0xb4 - 0xb7 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0xb8 - 0xbb */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0xbc - 0xbf */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, + +/* 0xc0 - 0xc3 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xc4 - 0xc7 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xc8 - 0xcb */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xcc - 0xcf */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, + +/* 0xd0 - 0xd3 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xd4 - 0xd7 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xd8 - 0xdb */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xdc - 0xdf */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, + +/* 0xe0 - 0xe3 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xe4 - 0xe7 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xe8 - 0xeb */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xec - 0xef */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, + +/* 0xf0 - 0xf3 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xf4 - 0xf7 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xf8 - 0xfb */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xfc - 0xff */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +		    }; + +/* DIS_ED opcodes +*/ +DIS_OP_CALLBACK	dis_ED_opcode[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x04 - 0x07 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x08 - 0x0b */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0x0c - 0x0f */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0x10 - 0x13 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x14 - 0x17 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x18 - 0x1b */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0x1c - 0x1f */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0x20 - 0x23 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x24 - 0x27 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x28 - 0x2b */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0x2c - 0x2f */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0x30 - 0x33 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x34 - 0x37 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x38 - 0x3b */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0x3c - 0x3f */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0x40 - 0x43 */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_SBC_HL_R16,	DIS_ED_LD_ADDR_R16, +/* 0x44 - 0x47 */    DIS_NEG,	DIS_RETN,		DIS_IM_0,		DIS_LD_I_A, +/* 0x48 - 0x4b */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_ADC_HL_R16,	DIS_ED_LD_R16_ADDR, +/* 0x4c - 0x4f */    DIS_NEG,	DIS_RETI,		DIS_IM_0,		DIS_LD_R_A, + +/* 0x50 - 0x53 */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_SBC_HL_R16,	DIS_ED_LD_ADDR_R16, +/* 0x54 - 0x57 */    DIS_NEG,	DIS_RETN,		DIS_IM_1,		DIS_LD_A_I, +/* 0x58 - 0x5b */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_ADC_HL_R16,	DIS_ED_LD_R16_ADDR, +/* 0x5c - 0x5f */    DIS_NEG,	DIS_RETI,		DIS_IM_2,		DIS_LD_A_R, + +/* 0x60 - 0x63 */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_SBC_HL_R16,	DIS_ED_LD_ADDR_R16, +/* 0x64 - 0x67 */    DIS_NEG,	DIS_RETN,		DIS_IM_0,		DIS_RRD, +/* 0x68 - 0x6b */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_ADC_HL_R16,	DIS_ED_LD_R16_ADDR, +/* 0x6c - 0x6f */    DIS_NEG,	DIS_RETI,		DIS_IM_0,		DIS_RLD, + +/* 0x70 - 0x73 */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_SBC_HL_R16,	DIS_ED_LD_ADDR_R16, +/* 0x74 - 0x77 */    DIS_NEG,	DIS_RETN,		DIS_IM_1,		DIS_ED_NOP, +/* 0x78 - 0x7b */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_ADC_HL_R16,	DIS_ED_LD_R16_ADDR, +/* 0x7c - 0x7f */    DIS_NEG,	DIS_RETI,		DIS_IM_2,		DIS_ED_NOP, + +/* 0x80 - 0x83 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x84 - 0x87 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x88 - 0x8b */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0x8c - 0x8f */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0x90 - 0x93 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x94 - 0x97 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x98 - 0x9b */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0x9c - 0x9f */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0xa0 - 0xa3 */    DIS_LDI,	DIS_CPI,		DIS_INI,		DIS_OUTI, +/* 0xa4 - 0xa7 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xa8 - 0xab */    DIS_LDD,	DIS_CPD,		DIS_IND,		DIS_OUTD,	 +/* 0xac - 0xaf */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0xb0 - 0xb3 */    DIS_LDIR,	DIS_CPIR,		DIS_INIR,		DIS_OTIR, +/* 0xb4 - 0xb7 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xb8 - 0xbb */    DIS_LDDR,	DIS_CPDR,		DIS_INDR,		DIS_OTDR,	 +/* 0xbc - 0xbf */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0xc0 - 0xc3 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xc4 - 0xc7 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xc8 - 0xcb */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0xcc - 0xcf */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0xd0 - 0xd3 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xd4 - 0xd7 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xd8 - 0xdb */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0xdc - 0xdf */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0xe0 - 0xe3 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xe4 - 0xe7 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xe8 - 0xeb */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0xec - 0xef */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0xf0 - 0xf3 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xf4 - 0xf7 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xf8 - 0xfb */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0xfc - 0xff */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 +		    }; + +/* DIS_FD opcodes +*/ +DIS_OP_CALLBACK	dis_FD_opcode[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x04 - 0x07 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x08 - 0x0b */    DIS_FD_NOP,	DIS_ADD_IY_BC,	DIS_FD_NOP,		DIS_FD_NOP,	 +/* 0x0c - 0x0f */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP,		 + +/* 0x10 - 0x13 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x14 - 0x17 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x18 - 0x1b */    DIS_FD_NOP,	DIS_ADD_IY_DE,	DIS_FD_NOP,		DIS_FD_NOP,	 +/* 0x1c - 0x1f */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP,		 + +/* 0x20 - 0x23 */    DIS_FD_NOP,	DIS_LD_IY_WORD,	DIS_LD_ADDR_IY,	DIS_INC_IY, +/* 0x24 - 0x27 */    DIS_INC_IYH,	DIS_DEC_IYH,	DIS_LD_IYH_BYTE,	DIS_FD_NOP, +/* 0x28 - 0x2b */    DIS_FD_NOP,	DIS_ADD_IY_IY,	DIS_LD_IY_ADDR,	DIS_DEC_IY, +/* 0x2c - 0x2f */    DIS_INC_IYL,	DIS_DEC_IYL,	DIS_LD_IYL_BYTE,	DIS_FD_NOP, + +/* 0x30 - 0x33 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x34 - 0x37 */    DIS_INC_IIY,	DIS_DEC_IIY,	DIS_LD_IIY_BYTE,	DIS_FD_NOP, +/* 0x38 - 0x3b */    DIS_FD_NOP,	DIS_ADD_IY_SP,	DIS_FD_NOP,		DIS_FD_NOP, +/* 0x3c - 0x3f */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, + +/* 0x40 - 0x43 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x44 - 0x47 */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_FD_NOP, +/* 0x48 - 0x4b */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x4c - 0x4f */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_FD_NOP, + +/* 0x50 - 0x53 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x54 - 0x57 */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_FD_NOP, +/* 0x58 - 0x5b */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x5c - 0x5f */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_FD_NOP, + +/* 0x60 - 0x63 */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8, +/* 0x64 - 0x67 */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8, +/* 0x68 - 0x6b */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8, +/* 0x6c - 0x6f */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8, + +/* 0x70 - 0x73 */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8, +/* 0x74 - 0x77 */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_FD_NOP,		DIS_YLD_R8_R8, +/* 0x78 - 0x7b */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x7c - 0x7f */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_FD_NOP, + +/* 0x80 - 0x83 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x84 - 0x87 */    DIS_YADD_R8,	DIS_YADD_R8,	DIS_YADD_R8,	DIS_FD_NOP, +/* 0x88 - 0x8b */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x8c - 0x8f */    DIS_YADC_R8,	DIS_YADC_R8,	DIS_YADC_R8,	DIS_FD_NOP, + +/* 0x90 - 0x93 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x94 - 0x97 */    DIS_YSUB_R8,	DIS_YSUB_R8,	DIS_YSUB_R8,	DIS_FD_NOP, +/* 0x98 - 0x9b */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x9c - 0x9f */    DIS_YSBC_R8,	DIS_YSBC_R8,	DIS_YSBC_R8,	DIS_FD_NOP, + +/* 0xa0 - 0xa3 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xa4 - 0xa7 */    DIS_YAND_R8,	DIS_YAND_R8,	DIS_YAND_R8,	DIS_FD_NOP, +/* 0xa8 - 0xab */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xac - 0xaf */    DIS_YYOR_R8,	DIS_YYOR_R8,	DIS_YYOR_R8,	DIS_FD_NOP, + +/* 0xb0 - 0xb3 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xb4 - 0xb7 */    DIS_Y_OR_R8,	DIS_Y_OR_R8,	DIS_Y_OR_R8,	DIS_FD_NOP, +/* 0xb8 - 0xbb */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xbc - 0xbf */    DIS_YCP_R8,	DIS_YCP_R8,		DIS_YCP_R8,		DIS_FD_NOP, + +/* 0xc0 - 0xc3 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xc4 - 0xc7 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xc8 - 0xcb */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_CB_DECODE, +/* 0xcc - 0xcf */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, + +/* 0xd0 - 0xd3 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xd4 - 0xd7 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xd8 - 0xdb */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xdc - 0xdf */    DIS_FD_NOP,	DIS_FD_DD_DECODE,	DIS_FD_NOP,		DIS_FD_NOP, + +/* 0xe0 - 0xe3 */    DIS_FD_NOP,	DIS_POP_IY,		DIS_FD_NOP,		DIS_EY_ISP_IY, +/* 0xe4 - 0xe7 */    DIS_FD_NOP,	DIS_PUSH_IY,	DIS_FD_NOP,		DIS_FD_NOP, +/* 0xe8 - 0xeb */    DIS_FD_NOP,	DIS_JP_IY,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xec - 0xef */    DIS_FD_NOP,	DIS_FD_ED_DECODE,	DIS_FD_NOP,		DIS_FD_NOP, + +/* 0xf0 - 0xf3 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xf4 - 0xf7 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xf8 - 0xfb */    DIS_FD_NOP,	DIS_LD_SP_IY,	DIS_FD_NOP,		DIS_FD_NOP, +/* 0xfc - 0xff */    DIS_FD_NOP,	DIS_FD_FD_DECODE,	DIS_FD_NOP,		DIS_FD_NOP, +		    }; + + +/* DIS_FD DIS_CB opcodes +*/ +DIS_OP_CALLBACK	dis_FD_CB_opcode[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_RLC_IY,	DIS_RLC_IY,		DIS_RLC_IY,		DIS_RLC_IY, +/* 0x04 - 0x07 */    DIS_RLC_IY,	DIS_RLC_IY,		DIS_RLC_IY,		DIS_RLC_IY, +/* 0x08 - 0x0b */    DIS_RRC_IY,	DIS_RRC_IY,		DIS_RRC_IY,		DIS_RRC_IY, +/* 0x0c - 0x0f */    DIS_RRC_IY,	DIS_RRC_IY,		DIS_RRC_IY,		DIS_RRC_IY, + +/* 0x10 - 0x13 */    DIS_RL_IY,	DIS_RL_IY,		DIS_RL_IY,		DIS_RL_IY,	 +/* 0x14 - 0x17 */    DIS_RL_IY,	DIS_RL_IY,		DIS_RL_IY,		DIS_RL_IY, +/* 0x18 - 0x1b */    DIS_RR_IY,	DIS_RR_IY,		DIS_RR_IY,		DIS_RR_IY,	 +/* 0x1c - 0x1f */    DIS_RR_IY,	DIS_RR_IY,		DIS_RR_IY,		DIS_RR_IY, + +/* 0x20 - 0x23 */    DIS_SLA_IY,	DIS_SLA_IY,		DIS_SLA_IY,		DIS_SLA_IY, +/* 0x24 - 0x27 */    DIS_SLA_IY,	DIS_SLA_IY,		DIS_SLA_IY,		DIS_SLA_IY, +/* 0x28 - 0x2b */    DIS_SRA_IY,	DIS_SRA_IY,		DIS_SRA_IY,		DIS_SRA_IY, +/* 0x2c - 0x2f */    DIS_SRA_IY,	DIS_SRA_IY,		DIS_SRA_IY,		DIS_SRA_IY, + +/* 0x30 - 0x33 */    DIS_SLL_IY,	DIS_SLL_IY,		DIS_SLL_IY,		DIS_SLL_IY, +/* 0x34 - 0x37 */    DIS_SLL_IY,	DIS_SLL_IY,		DIS_SLL_IY,		DIS_SLL_IY, +/* 0x38 - 0x3b */    DIS_SRL_IY,	DIS_SRL_IY,		DIS_SRL_IY,		DIS_SRL_IY, +/* 0x3c - 0x3f */    DIS_SRL_IY,	DIS_SRL_IY,		DIS_SRL_IY,		DIS_SRL_IY, + +/* 0x40 - 0x43 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x44 - 0x47 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x48 - 0x4b */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x4c - 0x4f */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, + +/* 0x50 - 0x53 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x54 - 0x57 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x58 - 0x5b */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x5c - 0x5f */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, + +/* 0x60 - 0x63 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x64 - 0x67 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x68 - 0x6b */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x6c - 0x6f */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, + +/* 0x70 - 0x73 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x74 - 0x77 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x78 - 0x7b */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x7c - 0x7f */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, + +/* 0x80 - 0x83 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0x84 - 0x87 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0x88 - 0x8b */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0x8c - 0x8f */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, + +/* 0x90 - 0x93 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0x94 - 0x97 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0x98 - 0x9b */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0x9c - 0x9f */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, + +/* 0xa0 - 0xa3 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0xa4 - 0xa7 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0xa8 - 0xab */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0xac - 0xaf */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, + +/* 0xb0 - 0xb3 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0xb4 - 0xb7 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0xb8 - 0xbb */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0xbc - 0xbf */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, + +/* 0xc0 - 0xc3 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xc4 - 0xc7 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xc8 - 0xcb */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xcc - 0xcf */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, + +/* 0xd0 - 0xd3 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xd4 - 0xd7 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xd8 - 0xdb */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xdc - 0xdf */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, + +/* 0xe0 - 0xe3 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xe4 - 0xe7 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xe8 - 0xeb */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xec - 0xef */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, + +/* 0xf0 - 0xf3 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xf4 - 0xf7 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xf8 - 0xfb */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xfc - 0xff */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +		    }; + +/* DIS_First/single byte opcodes +*/ +DIS_OP_CALLBACK	dis_opcode_z80[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_NOP,	DIS_LD_R16_WORD,	DIS_LD_R16_A,	DIS_INC_R16, +/* 0x04 - 0x07 */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_RLCA, +/* 0x08 - 0x0b */    DIS_EX_AF_AF,	DIS_ADD_HL_R16,	DIS_LD_A_R16,	DIS_DEC_R16,	 +/* 0x0c - 0x0f */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_RRCA,		 + +/* 0x10 - 0x13 */    DIS_DJNZ,	DIS_LD_R16_WORD,	DIS_LD_R16_A,	DIS_INC_R16, +/* 0x14 - 0x17 */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_RLA, +/* 0x18 - 0x1b */    DIS_JR,	DIS_ADD_HL_R16,	DIS_LD_A_R16,	DIS_DEC_R16,	 +/* 0x1c - 0x1f */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_RRA,		 + +/* 0x20 - 0x23 */    DIS_JR_CO,	DIS_LD_R16_WORD,	DIS_LD_ADDR_HL,	DIS_INC_R16, +/* 0x24 - 0x27 */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_DAA, +/* 0x28 - 0x2b */    DIS_JR_CO,	DIS_ADD_HL_R16,	DIS_LD_HL_ADDR,	DIS_DEC_R16,	 +/* 0x2c - 0x2f */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_CPL,		 + +/* 0x30 - 0x33 */    DIS_JR_CO,	DIS_LD_R16_WORD,	DIS_LD_ADDR_A,	DIS_INC_R16, +/* 0x34 - 0x37 */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_SCF, +/* 0x38 - 0x3b */    DIS_JR_CO,	DIS_ADD_HL_R16,	DIS_LD_A_ADDR,	DIS_DEC_R16,	 +/* 0x3c - 0x3f */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_CCF,		 + +/* 0x40 - 0x43 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x44 - 0x47 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x48 - 0x4b */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x4c - 0x4f */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, + +/* 0x50 - 0x53 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x54 - 0x57 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x58 - 0x5b */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x5c - 0x5f */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, + +/* 0x60 - 0x63 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x64 - 0x67 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x68 - 0x6b */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x6c - 0x6f */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, + +/* 0x70 - 0x73 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x74 - 0x77 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_HALT,		DIS_LD_R8_R8, +/* 0x78 - 0x7b */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x7c - 0x7f */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, + +/* 0x80 - 0x83 */    DIS_ADD_R8,	DIS_ADD_R8,		DIS_ADD_R8,		DIS_ADD_R8, +/* 0x84 - 0x87 */    DIS_ADD_R8,	DIS_ADD_R8,		DIS_ADD_R8,		DIS_ADD_R8, +/* 0x88 - 0x8b */    DIS_ADC_R8,	DIS_ADC_R8,		DIS_ADC_R8,		DIS_ADC_R8, +/* 0x8c - 0x8f */    DIS_ADC_R8,	DIS_ADC_R8,		DIS_ADC_R8,		DIS_ADC_R8, + +/* 0x90 - 0x93 */    DIS_SUB_R8,	DIS_SUB_R8,		DIS_SUB_R8,		DIS_SUB_R8, +/* 0x94 - 0x97 */    DIS_SUB_R8,	DIS_SUB_R8,		DIS_SUB_R8,		DIS_SUB_R8, +/* 0x98 - 0x9b */    DIS_SBC_R8,	DIS_SBC_R8,		DIS_SBC_R8,		DIS_SBC_R8, +/* 0x9c - 0x9f */    DIS_SBC_R8,	DIS_SBC_R8,		DIS_SBC_R8,		DIS_SBC_R8, + +/* 0xa0 - 0xa3 */    DIS_AND_R8,	DIS_AND_R8,		DIS_AND_R8,		DIS_AND_R8, +/* 0xa4 - 0xa7 */    DIS_AND_R8,	DIS_AND_R8,		DIS_AND_R8,		DIS_AND_R8, +/* 0xa8 - 0xab */    DIS_XOR_R8,	DIS_XOR_R8,		DIS_XOR_R8,		DIS_XOR_R8, +/* 0xac - 0xaf */    DIS_XOR_R8,	DIS_XOR_R8,		DIS_XOR_R8,		DIS_XOR_R8, + +/* 0xb0 - 0xb3 */    DIS_OR_R8,	DIS_OR_R8,		DIS_OR_R8,		DIS_OR_R8, +/* 0xb4 - 0xb7 */    DIS_OR_R8,	DIS_OR_R8,		DIS_OR_R8,		DIS_OR_R8, +/* 0xb8 - 0xbb */    DIS_CP_R8,	DIS_CP_R8,		DIS_CP_R8,		DIS_CP_R8, +/* 0xbc - 0xbf */    DIS_CP_R8,	DIS_CP_R8,		DIS_CP_R8,		DIS_CP_R8, + +/* 0xc0 - 0xc3 */    DIS_RET_CO,	DIS_POP_R16,	DIS_JP_CO,		DIS_JP, +/* 0xc4 - 0xc7 */    DIS_CALL_CO,	DIS_PUSH_R16,	DIS_ADD_A_BYTE,	DIS_RST, +/* 0xc8 - 0xcb */    DIS_RET_CO,	DIS_RET,		DIS_JP_CO,		DIS_CB_DECODE, +/* 0xcc - 0xcf */    DIS_CALL_CO,	DIS_CALL,		DIS_ADC_A_BYTE,	DIS_RST, + +/* 0xd0 - 0xd3 */    DIS_RET_CO,	DIS_POP_R16,	DIS_JP_CO,		DIS_OUT_BYTE_A, +/* 0xd4 - 0xd7 */    DIS_CALL_CO,	DIS_PUSH_R16,	DIS_SUB_A_BYTE,	DIS_RST, +/* 0xd8 - 0xdb */    DIS_RET_CO,	DIS_EXX,		DIS_JP_CO,		DIS_IN_A_BYTE, +/* 0xdc - 0xdf */    DIS_CALL_CO,	DIS_DD_DECODE,	DIS_SBC_A_BYTE,	DIS_RST, + +/* 0xe0 - 0xe3 */    DIS_RET_CO,	DIS_POP_R16,	DIS_JP_CO,		DIS_EX_ISP_HL, +/* 0xe4 - 0xe7 */    DIS_CALL_CO,	DIS_PUSH_R16,	DIS_AND_A_BYTE,	DIS_RST, +/* 0xe8 - 0xeb */    DIS_RET_CO,	DIS_JP_HL,		DIS_JP_CO,		DIS_EX_DE_HL, +/* 0xec - 0xef */    DIS_CALL_CO,	DIS_ED_DECODE,	DIS_XOR_A_BYTE,	DIS_RST, + +/* 0xf0 - 0xf3 */    DIS_RET_CO,	DIS_POP_R16,	DIS_JP_CO,		DIS_DI, +/* 0xf4 - 0xf7 */    DIS_CALL_CO,	DIS_PUSH_R16,	DIS_OR_A_BYTE,	DIS_RST, +/* 0xf8 - 0xfb */    DIS_RET_CO,	DIS_LD_SP_HL,	DIS_JP_CO,		DIS_EI, +/* 0xfc - 0xff */    DIS_CALL_CO,	DIS_FD_DECODE,	DIS_CP_A_BYTE,	DIS_RST, +		    }; + + +#endif + +/* END OF FILE */ diff --git a/arm9/source/zx81.c b/arm9/source/zx81.c new file mode 100644 index 0000000..df30dd7 --- /dev/null +++ b/arm9/source/zx81.c @@ -0,0 +1,828 @@ +/* +    ezx81 - X11 ZX81 emulator + +    Copyright (C) 2003  Ian Cowburn (ianc@noddybox.demon.co.uk) + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    Provides the emulation for the ZX81 + +*/ +static const char ident[]="$Id$"; + +#if 0 +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "zx81.h" +#include "gfx.h" +#include "gui.h" +#include "config.h" +#include "util.h" +#include "exit.h" + +static const char ident_h[]=EZX81_ZX81H; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + +/* ---------------------------------------- STATICS +*/ +#define ROMLEN		0x2000 +#define ROM_SAVE	0x2fc +#define ROM_LOAD	0x347 + +#define ED_SAVE		0xf0 +#define ED_LOAD		0xf1 +#define ED_WAITKEY	0xf2 +#define ED_ENDWAITKEY	0xf3 +#define ED_PAUSE	0xf4 + +#define SLOW_TSTATES	16000 +#define FAST_TSTATES	64000 + +#define LASTK1		16421 +#define LASTK2		16422 +#define MARGIN		16424 +#define FRAMES		16436 +#define CDFLAG		16443 + +static Z80Val		FRAME_TSTATES=FAST_TSTATES; + +/* The ZX81 screen and memory +*/ +static int		waitkey=FALSE; +static int		started=FALSE; + +#define	SCR_W		256 +#define	SCR_H		192 +#define	TXT_W		32 +#define	TXT_H		24 + +#define OFF_X		(GFX_WIDTH-SCR_W)/2 +#define OFF_Y		(GFX_HEIGHT-SCR_H)/2 + +static Z80Byte		mem[0x10000]; + +static Z80Word		RAMBOT=0; +static Z80Word		RAMTOP=0; +static Z80Word		RAMLEN=0; + +#define DFILE		0x400c + +#define WORD(a)		(mem[a] | (Z80Word)mem[a+1]<<8) + +/* GFX vars +*/ +static Uint32		white; +static Uint32		black; + + +/* The keyboard +*/ +static Z80Byte		matrix[8]; + +typedef struct +{ +    SDLKey	key; +    int		m1,b1,m2,b2; +} MatrixMap; + +#define KY1(m,b)		m,1<<b,-1,-1 +#define KY2(m1,b1,m2,b2)	m1,1<<b1,m2,1<<b2 + +static const MatrixMap keymap[]= +{ +    {SDLK_1,		KY1(3,0)}, +    {SDLK_2,		KY1(3,1)}, +    {SDLK_3,		KY1(3,2)}, +    {SDLK_4,		KY1(3,3)}, +    {SDLK_5,		KY1(3,4)}, +    {SDLK_6,		KY1(4,4)}, +    {SDLK_7,		KY1(4,3)}, +    {SDLK_8,		KY1(4,2)}, +    {SDLK_9,		KY1(4,1)}, +    {SDLK_0,		KY1(4,0)}, + +    {SDLK_a,		KY1(1,0)}, +    {SDLK_b,		KY1(7,4)}, +    {SDLK_c,		KY1(0,3)}, +    {SDLK_d,		KY1(1,2)}, +    {SDLK_e,		KY1(2,2)}, +    {SDLK_f,		KY1(1,3)}, +    {SDLK_g,		KY1(1,4)}, +    {SDLK_h,		KY1(6,4)}, +    {SDLK_i,		KY1(5,2)}, +    {SDLK_j,		KY1(6,3)}, +    {SDLK_k,		KY1(6,2)}, +    {SDLK_l,		KY1(6,1)}, +    {SDLK_m,		KY1(7,2)}, +    {SDLK_n,		KY1(7,3)}, +    {SDLK_o,		KY1(5,1)}, +    {SDLK_p,		KY1(5,0)}, +    {SDLK_q,		KY1(2,0)}, +    {SDLK_r,		KY1(2,3)}, +    {SDLK_s,		KY1(1,1)}, +    {SDLK_t,		KY1(2,4)}, +    {SDLK_u,		KY1(5,3)}, +    {SDLK_v,		KY1(0,4)}, +    {SDLK_w,		KY1(2,1)}, +    {SDLK_x,		KY1(0,2)}, +    {SDLK_y,		KY1(5,4)}, +    {SDLK_z,		KY1(0,1)}, + +    {SDLK_RETURN,	KY1(6,0)}, +    {SDLK_SPACE,	KY1(7,0)}, + +    {SDLK_COMMA,	KY1(7,1)},	/* In the right place... */ +    {SDLK_PERIOD,	KY1(7,1)},	/* ...or the right key... */ + +    {SDLK_BACKSPACE,	KY2(0,0,4,0)}, +    {SDLK_DELETE,	KY2(0,0,4,0)}, +    {SDLK_UP,		KY2(0,0,4,3)}, +    {SDLK_DOWN,		KY2(0,0,4,4)}, +    {SDLK_LEFT,		KY2(0,0,3,4)}, +    {SDLK_RIGHT,	KY2(0,0,4,2)}, + +    {SDLK_RSHIFT,	KY1(0,0)}, +    {SDLK_LSHIFT,	KY1(0,0)}, + +    {SDLK_UNKNOWN,	0,0,0,0}, +}; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +#define PEEKW(addr)		(mem[addr] | (Z80Word)mem[addr+1]<<8) + +#define POKEW(addr,val)         do					\ +                                {					\ +                                    Z80Word wa=addr;			\ +                                    Z80Word wv=val;			\ +                                    mem[wa]=wv;				\ +                                    mem[wa+1]=wv>>8;			\ +                                } while(0) + +static void RomPatch(void) +{ +    static const Z80Byte save[]= +    { +    	0xed, ED_SAVE,		/* (SAVE)		*/ +	0xc3, 0x07, 0x02,	/* JP $0207		*/ +	0xff			/* End of patch		*/ +    }; + +    static const Z80Byte load[]= +    { +    	0xed, ED_LOAD,		/* (LOAD)		*/ +	0xc3, 0x07, 0x02,	/* JP $0207		*/ +	0xff			/* End of patch		*/ +    }; + +    static const Z80Byte fast_hack[]= +    { +	0xed, ED_WAITKEY,	/* (START KEY WAIT)	*/ +	0xcb,0x46,		/* L: bit 0,(hl)	*/ +	0x28,0xfc,		/* jr z,L		*/ +	0xed, ED_ENDWAITKEY,	/* (END KEY WAIT)	*/ +    	0x00,			/* nop			*/ +	0xff			/* End of patch		*/ +    }; + +    static const Z80Byte kbd_hack[]= +    { +	0x2a,0x25,0x40,		/* ld hl,(LASTK)	*/ +	0xc9,			/* ret			*/ +	0xff			/* End of patch		*/ +    }; + +    static const Z80Byte pause_hack[]= +    { +	0xed, ED_PAUSE,		/* (PAUSE)		*/ +    	0x00,			/* nop			*/ +	0xff			/* End of patch		*/ +    }; + +    int f; + +    for(f=0;save[f]!=0xff;f++) +    { +	mem[ROM_SAVE+f]=save[f]; +    } + +    for(f=0;load[f]!=0xff;f++) +    { +	mem[ROM_LOAD+f]=load[f]; +    } + +    for(f=0;fast_hack[f]!=0xff;f++) +    { +	mem[0x4ca+f]=fast_hack[f]; +    } + +    for(f=0;kbd_hack[f]!=0xff;f++) +    { +	mem[0x2bb+f]=kbd_hack[f]; +    } + +    for(f=0;pause_hack[f]!=0xff;f++) +    { +	mem[0xf3a+f]=pause_hack[f]; +    } + +    /* Trust me, we have a ZX81... Honestly. +    */ +    mem[0x21c]=0x00; +    mem[0x21d]=0x00; + +    /* Remove HALTs as we don't do interrupts +    */ +    mem[0x0079]=0; +    mem[0x02ec]=0; +} + +static char ToASCII(Z80Byte b) +{ +    if (b==0)			/* SPACE */ +    	return ' '; +     +    if (b==22)			/* Dash (-) */ +    	return '-'; + +    if (b==27)			/* Period (.) */ +    	return '.'; + +    if (b>=28 && b<=37)		/* 0-9 */ +    	return '0'+b-28; + +    if (b>=38 && b<=63)		/* A-Z */ +    	return 'a'+b-38; + +    return 0; +} + + +static const char *ConvertFilename(Z80Word addr) +{ +    static char buff[FILENAME_MAX]; +    char *p; + +    p=buff; +    *p=0; + +    if (addr>0x8000) +    { +    	return buff; +    } + +    do +    { +    	char c=ToASCII(mem[addr]&0x7f); + +	if (c) +	    *p++=c; + +    } while(mem[addr++]<0x80); + +    *p=0; + +    return buff; +} + + +static void LoadTape(Z80 *z80) +{ +    const char *p=ConvertFilename(z80->DE.w); +    char path[FILENAME_MAX]; +    FILE *fp; + +    if (strlen(p)==0) +    { +    	GUIMessage(eMessageBox,"ERROR","Can't load empty filename"); +	return; +    } + +    strcpy(path,SConfig(CONF_TAPEDIR)); +    strcat(path,"/"); +    strcat(path,p); +    strcat(path,".p"); + +    if (!(fp=fopen(path,"rb"))) +    { +    	GUIMessage(eMessageBox,"ERROR","Can't load file:\n%s",path); +	return; +    } + +    fread(mem+0x4009,1,0x4000,fp); +    fclose(fp); +} + + +static void SaveTape(Z80 *z80) +{ +    const char *p=ConvertFilename(z80->DE.w); +    char path[FILENAME_MAX]; +    FILE *fp; +    Z80Word start; +    Z80Word end; + +    if (strlen(p)==0) +    { +    	GUIMessage(eMessageBox,"ERROR","Can't save empty filename"); +	return; +    } + +    strcpy(path,SConfig(CONF_TAPEDIR)); +    strcat(path,"/"); +    strcat(path,p); +    strcat(path,".p"); + +    if (!(fp=fopen(path,"wb"))) +    { +    	GUIMessage(eMessageBox,"ERROR","Can't write file:\n%s",path); +	return; +    } + +    start=0x4009; +    end=(Z80Word)mem[0x4014]|(Z80Word)mem[0x4015]<<8; + +    while(start<=end) +    	putc(mem[start++],fp); + +    fclose(fp); +} + + +static void PrintZX81Char(int x,int y,int code,int base) +{ +    int cx,cy; +    Uint32 fg,bg; + +    x*=8; +    y*=8; + +    if (code&0x80) +    { +	fg=white; +	bg=black; +	code-=0x80; +    } +    else +    { +	fg=black; +	bg=white; +    } + +    base=base<<8; +    base+=code*8; + +    for(cy=0;cy<8;cy++) +    { +	for(cx=0;cx<8;cx++) +	{ +	    if (mem[base]&(1<<(7-cx))) +		GFXFastPlot(OFF_X+x+cx,OFF_Y+y+cy,fg); +	    else +		GFXFastPlot(OFF_X+x+cx,OFF_Y+y+cy,bg); +	} + +	base++; +    } +} + + +static void DrawScreen(Z80 *z80) +{ +    Z80Byte *scr=mem+WORD(DFILE); +    int x,y; + +    x=0; +    y=0; + +    while(y<TXT_H) +    { +	scr++; +	x=0; + +	while((*scr!=118)&&(x<TXT_W)) +	{ +	    PrintZX81Char(x,y,*scr++,z80->I); +	    x++; +	} + +	y++; +    } +} + + +static void DrawSnow(Z80 *z80) +{ +    int x,y; + +    x=0; +    y=0; + +    for(x=0;x<SCR_W;x++) +    { +	for(y=0;y<SCR_H;y++) +	{ +	    GFXFastPlot(OFF_X+x,OFF_Y+y,rand()&1 ? white:black); +	} +    } +} + + +/* Perform ZX81 housekeeping functions like updating FRAMES and updating LASTK +*/ +static void ZX81HouseKeeping(Z80 *z80) +{ +    static unsigned prev_lk1,prev_lk2; +    unsigned row; +    unsigned lastk1; +    unsigned lastk2; + +    /* British ZX81 +    */ +    mem[MARGIN]=55; + +    /* Update FRAMES +    */ +    if (FRAME_TSTATES==SLOW_TSTATES) +    { +    	Z80Word frame=PEEKW(FRAMES)&0x7fff; + +	if (frame) +	{ +	    frame--; +	} + +	POKEW(FRAMES,frame|0x8000); +    } + +    if (!started) +    { +    	prev_lk1=0; +    	prev_lk2=0; +	return; +    } + +    /* Update LASTK +    */ +    lastk1=0; +    lastk2=0; + +    for(row=0;row<8;row++) +    { +    	unsigned b; + +	b=(~matrix[row]&0x1f)<<1; + +	if (row==0) +	{ +	    unsigned shift; + +	    shift=b&2; +	    b&=~2; +	    b|=(shift>>1); +	} + +	if (b) +	{ +	    if (b>1) +	    { +		lastk1|=(1<<row); +	    } + +	    lastk2|=b; +	} +    } + +    /* if ((lastk1 || lastk2) && (lastk1!=prev_lk1 || lastk2!=prev_lk2)) */ +    if (lastk1 && (lastk1!=prev_lk1 || lastk2!=prev_lk2)) +    { +    	mem[CDFLAG]|=1; +    } + +    prev_lk1=lastk1; +    prev_lk2=lastk2; + +    mem[LASTK1]=lastk1^0xff; +    mem[LASTK2]=lastk2^0xff; +} + + +static int CheckTimers(Z80 *z80, Z80Val val) +{ +    if (val>=FRAME_TSTATES) +    { +	Z80ResetCycles(z80,val-FRAME_TSTATES); + +	GFXLock(); + +	if (started && ((mem[CDFLAG] & 0x80) || waitkey)) +	{ +	    DrawScreen(z80); +	    FRAME_TSTATES=SLOW_TSTATES; +	} +	else +	{ +	    DrawSnow(z80); +	    FRAME_TSTATES=FAST_TSTATES; +	} + +	/* Update FRAMES (if in SLOW) and scan the keyboard.  This only happens +	   once we've got to a decent point in the boot cycle (detected with +	   a valid stack pointer). +	*/ +	if (z80->SP<0x8000) +	{ +	    ZX81HouseKeeping(z80); +	} + +	GFXUnlock(); +	GFXEndFrame(TRUE); +	GFXStartFrame(); +    } + +    return TRUE; +} + + +static int EDCallback(Z80 *z80, Z80Val data) +{ +    Z80Word pause; + +    switch((Z80Byte)data) +    { +    	case ED_SAVE: +	    SaveTape(z80); +	    break; + +    	case ED_LOAD: +	    LoadTape(z80); +	    mem[CDFLAG]=0xc0; +	    break; + +	case ED_WAITKEY: +	    waitkey=TRUE; +	    started=TRUE; +	    break; + +	case ED_ENDWAITKEY: +	    waitkey=FALSE; +	    break; + +	case ED_PAUSE: +	    waitkey=TRUE; + +	    pause=z80->BC.w; + +	    while(pause-- && !(mem[CDFLAG]&1)) +	    { +		SDL_Event *e; + +		e=GFXGetKey(); + +		if (e) +		{ +		    ZX81KeyEvent(e); +		} + +	    	CheckTimers(z80,FRAME_TSTATES); +	    } + +	    waitkey=FALSE; +	    break; + +	default: +	    break; +    } + +    return TRUE; +} + + +/* ---------------------------------------- EXPORTED INTERFACES +*/ +void ZX81Init(Z80 *z80) +{ +    FILE *fp; +    Z80Word f; + +    if (!(fp=fopen(SConfig(CONF_ROMFILE),"rb"))) +    { +	GUIMessage(eMessageBox, +		   "ERROR","Failed to open ZX81 ROM\n%s",SConfig(CONF_ROMFILE)); +	Exit(""); +    } + +    if (fread(mem,1,ROMLEN,fp)!=ROMLEN) +    { +    	fclose(fp); +	GUIMessage(eMessageBox, +		   "ERROR","ROM file must be %d bytes long\n",ROMLEN); +	Exit(""); +    } + +    /* Patch the ROM +    */ +    RomPatch(); +    Z80LodgeCallback(z80,eZ80_EDHook,EDCallback); +    Z80LodgeCallback(z80,eZ80_Instruction,CheckTimers); + +    /* Mirror the ROM +    */ +    memcpy(mem+ROMLEN,mem,ROMLEN); + +    RAMBOT=0x4000; + +    /* Memory size (1 or 16K) +    */ +    if (IConfig(CONF_MEMSIZE)==16) +	RAMLEN=0x4000; +    else +	RAMLEN=0x400; + +    RAMTOP=RAMBOT+RAMLEN; + +    for(f=RAMBOT;f<=RAMTOP;f++) +    	mem[f]=0; + +    for(f=0;f<8;f++) +    	matrix[f]=0x1f; + +    white=GFXRGB(230,230,230); +    black=GFXRGB(0,0,0); + +    GFXStartFrame(); +} + + +void ZX81KeyEvent(SDL_Event *e) +{ +    const MatrixMap *m; + +    m=keymap; + +    while(m->key!=SDLK_UNKNOWN) +    { +	if (e->key.keysym.sym==m->key) +	{ +	    if (e->key.state==SDL_PRESSED) +	    { +		matrix[m->m1]&=~m->b1; + +		if (m->m2!=-1) +		    matrix[m->m2]&=~m->b2; +	    } +	    else +	    { +		matrix[m->m1]|=m->b1; + +		if (m->m2!=-1) +		    matrix[m->m2]|=m->b2; +	    } +	} + +	m++; +    } +} + + +Z80Byte ZX81ReadMem(Z80 *z80, Z80Word addr) +{ +    /* Hopefully by simply returning RET for ULA reads we save a lot of +       ROM patching shenanigans. +    */ +    if (addr>0x7fff) +    { +    	return 0xc9; +    } +    else +    { +	return mem[addr]; +    } +} + + +void ZX81WriteMem(Z80 *z80, Z80Word addr, Z80Byte val) +{ +    if (addr>=RAMBOT && addr<=RAMTOP) +    { +	mem[addr]=val; +    } +} + + +Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port) +{ +    Z80Byte b=0; + +    switch(port&0xff) +    { +    	case 0xfe:	/* ULA */ +	    /* Key matrix +	    */ +	    switch(port&0xff00) +	    { +	    	case 0xfe00: +		    b=matrix[0]; +		    break; +	    	case 0xfd00: +		    b=matrix[1]; +		    break; +	    	case 0xfb00: +		    b=matrix[2]; +		    break; +	    	case 0xf700: +		    b=matrix[3]; +		    break; +	    	case 0xef00: +		    b=matrix[4]; +		    break; +	    	case 0xdf00: +		    b=matrix[5]; +		    break; +	    	case 0xbf00: +		    b=matrix[6]; +		    break; +	    	case 0x7f00: +		    b=matrix[7]; +		    break; +	    } +	    break; + +	default: +	    break; +    } + +    return b; +} + + +void ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val) +{ +    switch(port&0xff) +    { +    	case 0xfd: +	    break; + +	case 0xfe: +	    break; +    } +} + + +Z80Byte ZX81ReadForDisassem(Z80 *z80, Z80Word addr) +{ +    return mem[addr&0x7fff]; +} + + +const char *ZX81Info(Z80 *z80) +{ +    static char buff[80]; + +    sprintf(buff,"T-State/frame: %lu",FRAME_TSTATES); +    return buff; +} + + +void ZX81Reset(Z80 *z80) +{ +    int f; + +    for(f=0;f<8;f++) +    	matrix[f]=0x1f; + +    Z80ResetCycles(z80,0); + +    started=FALSE; + +    GFXStartFrame(); +} + +#endif + + +/* END OF FILE */ diff --git a/data/splashimg.bin b/data/splashimg.binBinary files differ index 910f64b..38161e4 100644 --- a/data/splashimg.bin +++ b/data/splashimg.bin diff --git a/include/kbd81.h b/include/kbd81.h deleted file mode 100644 index b4e3d62..0000000 --- a/include/kbd81.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -   ds81 - Nintendo DS ZX81 emulator. - -   Copyright (C) 2006  Ian Cowburn -    -   This program is free software; you can redistribute it and/or -   modify it under the terms of the GNU General Public License -   as published by the Free Software Foundation; either version 2 -   of the License, or (at your option) any later version. -    -   This program is distributed in the hope that it will be useful, -   but WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -   GNU General Public License for more details. -    -   You should have received a copy of the GNU General Public License -   along with this program; if not, write to the Free Software -   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. -   -   $Id$ -*/ -#ifndef DS81_KBD81_H -#define DS81_KBD81_H - -typedef enum -{ -    KBD_1, -    KBD_2, -    KBD_3, -    KBD_4, -    KBD_5, -    KBD_6, -    KBD_7, -    KBD_8, -    KBD_9, -    KBD_0, -    KBD_Q, -    KBD_W, -    KBD_E, -    KBD_R, -    KBD_T, -    KBD_Y, -    KBD_U, -    KBD_I, -    KBD_O, -    KBD_P, -    KBD_A, -    KBD_S, -    KBD_D, -    KBD_F, -    KBD_G, -    KBD_H, -    KBD_J, -    KBD_K, -    KBD_L, -    KBD_NEWLINE, -    KBD_SHIFT, -    KBD_Z, -    KBD_X, -    KBD_C, -    KBD_V, -    KBD_B, -    KBD_N, -    KBD_M, -    KBD_PERIOD, -    KBD_SPACE -} ZX81_Key; - -void		KBD_Reset(void); -void		KBD_Display(const char *text); -void		KBD_Scan(void); -ZX81_Key	KBD_GetKey(void); -void		KBD_MapKey(KEYPAD_BITS pad, ZX81_Key key); -void		KBD_Probe(int scan); - -#endif	/* DS81_KBD81_H */ diff --git a/include/keyboard.h b/include/keyboard.h new file mode 100644 index 0000000..eefde86 --- /dev/null +++ b/include/keyboard.h @@ -0,0 +1,125 @@ +/* +   ds81 - Nintendo ZX81 emulator. + +   Copyright (C) 2006  Ian Cowburn +    +   This program is free software; you can redistribute it and/or +   modify it under the terms of the GNU General Public License +   as published by the Free Software Foundation; either version 2 +   of the License, or (at your option) any later version. +    +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. +    +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. +   +   $Id$ +*/ +#ifndef DS81_KEYBOARD_H +#define DS81_KEYBOARD_H + +/* Note that the first 40 values purposefully are the keyboard matrix keys. +   Note also that they are in display order, not matrix order. +*/ +typedef enum +{ +    SK_1, +    SK_2, +    SK_3, +    SK_4, +    SK_5, + +    SK_6, +    SK_7, +    SK_8, +    SK_9, +    SK_0, + +    SK_Q, +    SK_W, +    SK_E, +    SK_R, +    SK_T, + +    SK_Y, +    SK_U, +    SK_I, +    SK_O, +    SK_P, + +    SK_A, +    SK_S, +    SK_D, +    SK_F, +    SK_G, + +    SK_H, +    SK_J, +    SK_K, +    SK_L, +    SK_NEWLINE, + +    SK_SHIFT, +    SK_Z, +    SK_X, +    SK_C, +    SK_V, + +    SK_B, +    SK_N, +    SK_M, +    SK_PERIOD, +    SK_SPACE, + +    SK_ABOUT, +    SK_CONFIG, +    SK_PAD_UP, +    SK_PAD_DOWN, +    SK_PAD_LEFT, +    SK_PAD_RIGHT, +    SK_PAD_A, +    SK_PAD_B, +    SK_PAD_X, +    SK_PAD_Y, +    SK_PAD_R, +    SK_PAD_L, +    SK_PAD_START, +    SK_PAD_SELECT, + +    NUM_SOFT_KEYS +} SoftKey; + +typedef struct +{ +    SoftKey	key; +    int		pressed; +} SoftKeyEvent; + + +/* Display the soft keyboard +*/ +void	SK_DisplayKeyboard(uint16 *vram); + +/* Returns TRUE while there are still key events for this cycle +*/ +int	SK_GetEvent(SoftKeyEvent *ev); + +/* Sets a key to be 'sticky' (it will be released automatically on the next +   non-sticky press). +*/ +void	SK_SetSticky(SoftKey key, int is_sticky); + +/* Flush all the keys. +*/ +void	SK_ClearKeys(void); + +/* Map the joypad to keys.  Note that when mapped that both the key and the +   joypad code will be generated. +*/ +void	SK_DefineJoypad(void); + +#endif	/* DS81_KEYBOARD_H */ diff --git a/include/z80.h b/include/z80.h new file mode 100644 index 0000000..000b950 --- /dev/null +++ b/include/z80.h @@ -0,0 +1,250 @@ +/* + +    z80 - Z80 emulation + +    Copyright (C) 2006  Ian Cowburn <ianc@noddybox.co.uk> + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    $Id$ + +*/ + +#ifndef Z80_H +#define Z80_H "$Id$" + +/* Configuration +*/ +#include "z80_config.h" + + +/* ---------------------------------------- TYPES +*/ + +/* Large unsigned type +*/ +typedef unsigned long Z80Val; + + +/* 8-bit type.  The emulation will exit with code 2 if this isn't 8 bits. +*/ +typedef unsigned char Z80Byte; + + +/* 8-bit signed type.  The emulation will exit with code 2 if this isn't 8 bits. +*/ +typedef signed char Z80Relative; + + +/* 16-bit type.  The emulation will exit with code 2 if this isn't 16 bits. +*/ +typedef unsigned short Z80Word; + + +/* A Z80 16-bit register.  To access the HI/LO component use the indexes +   Z80_HI_WORD and Z80_LO_WORD which will be initialised once Z80Init has been +   called. +*/ +typedef union +{ +    Z80Word		w; +    Z80Byte		b[2]; +} Z80Reg; + +extern int Z80_HI_WORD; +extern int Z80_LO_WORD; + + +/* The processor +*/ +struct Z80Private; + +typedef struct +{ +    Z80Word		PC; + +    Z80Reg		AF; +    Z80Reg		BC; +    Z80Reg		DE; +    Z80Reg		HL; + +    Z80Word		AF_; +    Z80Word		BC_; +    Z80Word		DE_; +    Z80Word		HL_; + +    Z80Reg		IX; +    Z80Reg		IY; + +    Z80Word		SP; + +    Z80Byte		IFF1; +    Z80Byte		IFF2; +    Z80Byte		IM; +    Z80Byte		I; +    Z80Byte		R; + +    struct Z80Private	*priv; +} Z80; + + +/* Interfaces used to handle memory +*/ +typedef	Z80Byte	(*Z80ReadMemory)(Z80 *cpu, Z80Word address); +typedef	void	(*Z80WriteMemory)(Z80 *cpu, Z80Word address, Z80Byte value); + + +/* Interfaces needed to handle ports (IN/OUT commands) +*/ +typedef	Z80Byte	(*Z80ReadPort)(Z80 *cpu, Z80Word address); +typedef	void	(*Z80WritePort)(Z80 *cpu, Z80Word address, Z80Byte value); + + +/* Callback.  Callback should return TRUE for processing to continue. +*/ +typedef int	(*Z80Callback)(Z80 *cpu, Z80Val data); + + +/* Callback reasons + +   eZ80_Instruction	Called before the initial fetch for an instruction +   			(called just to once no matter how many bytes the +			instruction is made up of). + +   eZ80_EDHook		Called when an undefined ED opcode is executed. + +   eZ80_Halt		Called when the HALT instruction is hit and released. + +   eZ80_RETI		Called when the RETI instruction is executed +*/ +typedef enum +{ +    eZ80_Instruction,	/* data = no cycles since reset                       */ +    eZ80_EDHook,	/* data = byte after ED opcode (only for NOP opcodes) */ +    eZ80_Halt,		/* data = 1 halt raised, 0 halt cleared by int        */ +    eZ80_RETI,		/* data = ignored                                     */ +    eZ80_NO_CALLBACK	/* leave at end                                       */ +} Z80CallbackReason; + + +/* Flags in the F register +*/ +typedef enum +{ +    eZ80_Carry		=0x01, +    eZ80_Neg		=0x02, +    eZ80_PV		=0x04, +    eZ80_Hidden3	=0x08, +    eZ80_HalfCarry	=0x10, +    eZ80_Hidden5	=0x20, +    eZ80_Zero		=0x40, +    eZ80_Sign		=0x80 +} Z80FlagRegister; + + +/* Disassembly label -- only useful if ENABLE_DISASSEMBLER is set. +   Labels are stored as an array, where a NULL in the label field marks +   the end of the list. +*/ +typedef struct +{ +    Z80Word	address; +    const char	*label; +} Z80Label; + + +/* ---------------------------------------- INTERFACES +*/ + + +/* Initialises the processor.   +*/ +#ifdef ENABLE_ARRAY_MEMORY +Z80	*Z80Init(Z80ReadPort read_port, +		 Z80WritePort write_port); +#else +Z80	*Z80Init(Z80ReadMemory read_memory, +		 Z80WriteMemory write_memory, +		 Z80ReadPort read_port, +		 Z80WritePort write_port, +		 Z80ReadMemory read_for_disassem); +#endif + + +/* Resets the processor. +*/ +void	Z80Reset(Z80 *cpu); + + +/* Lodge a callback to be invoked after special events.  Returns FALSE +   if the callback couldn't be lodged (there is a max of 10 callbacks per +   reason). +*/ +int	Z80LodgeCallback(Z80 *cpu, +			 Z80CallbackReason reason, +			 Z80Callback callback); + + +/* Remove a callback.  Does nothing if reason was not lodged with +   Z80LodgeCallback() +*/ +void	Z80RemoveCallback(Z80 *cpu, +			  Z80CallbackReason reason, +			  Z80Callback callback); + + +/* Cause an interrupt before the next opcode. +   devbyte is the byte generated by the device (if any). +*/ +void	Z80Interrupt(Z80 *cpu, Z80Byte devbyte); + + +/* Cause an NMI +*/ +void	Z80NMI(Z80 *cpu); + + +/* Execute a single instruction.  Returns FALSE if any callback returned +   FALSE. +*/ +int	Z80SingleStep(Z80 *cpu); + + +/* Executes until a callback returns FALSE (never returns otherwise) +*/ +void	Z80Exec(Z80 *cpu); + + +/* Manipulate the cylce count of the Z80 +*/ +Z80Val	Z80Cycles(Z80 *cpu); +void	Z80ResetCycles(Z80 *cpu, Z80Val cycles); + + +/* Set address to label mappings for the disassembler +*/ +void	Z80SetLabels(Z80Label labels[]); + + +/* Simple disassembly of memory accessed through read_for_disassem, or  +   Z80_MEMORY as appropriate.  addr is updated on exit. +*/ +const char *Z80Disassemble(Z80 *cpu, Z80Word *addr); + +#endif + +/* END OF FILE */ diff --git a/include/z80_config.h b/include/z80_config.h new file mode 100644 index 0000000..8be062b --- /dev/null +++ b/include/z80_config.h @@ -0,0 +1,59 @@ +/* + +    z80 - Z80 emulation + +    Copyright (C) 2006  Ian Cowburn <ianc@noddybox.co.uk> + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    $Id$ + +*/ + +#ifndef Z80_CONFIG_H +#define Z80_CONFIG_H "$Id$" + + +/* This file defines various compile-time configuration options +   for the Z80 emulation +*/ + + +/* Define this to enable the disassembly interface +#define ENABLE_DISASSEM +*/ + + +/* Define this to enable the array-based memory model.  In this mode +   an externally visible Z80Byte array called Z80_MEMORY must be +   defined.  The macros RAMBOT and RAMTOP define the writable area of +   memory and must be changed accordingly. + +   In this mode the signature of Z80Init changes so that the memory functions +   are not passed.  ALL processor instances share the same memory. +#define ENABLE_ARRAY_MEMORY +*/ + +#ifdef ENABLE_ARRAY_MEMORY +#define RAMBOT 0x0000 +#define RAMTOP 0xffff +#endif + + +#endif + +/* END OF FILE */ diff --git a/include/z80_private.h b/include/z80_private.h new file mode 100644 index 0000000..be45e56 --- /dev/null +++ b/include/z80_private.h @@ -0,0 +1,276 @@ +/* + +    z80 - Z80 emulation + +    Copyright (C) 2006  Ian Cowburn (ianc@noddybox.demon.co.uk) + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    $Id$ + +    Private macros for Z80 + +*/ + +#ifndef Z80_PRIVATE_H +#define Z80_PRIVATE_H "$Id$" + +#include "z80_config.h" + +#ifndef TRUE +#define TRUE	1 +#endif + +#ifndef FALSE +#define FALSE	0 +#endif + +#define MAX_PER_CALLBACK	10 + + +/* ---------------------------------------- TYPES +*/ + +struct Z80Private +{ +    Z80Val		cycle; + +    int			halt; + +    Z80Byte		shift; + +    int			raise; +    Z80Byte		devbyte; +    int			nmi; + +#ifndef ENABLE_ARRAY_MEMORY +    Z80ReadMemory	disread; + +    Z80ReadMemory	mread; +    Z80WriteMemory	mwrite; +#endif + +    Z80ReadPort		pread; +    Z80WritePort	pwrite; + +    Z80Callback		callback[eZ80_NO_CALLBACK][MAX_PER_CALLBACK]; + +    int			last_cb; +}; + +#define PRIV		cpu->priv + + +/* ---------------------------------------- ARRAY MEMORY +*/ + +#ifdef ENABLE_ARRAY_MEMORY +extern Z80Byte	Z80_MEMORY[]; +#endif + + +/* ---------------------------------------- MACROS +*/ + +/* NOTE: A lot of these macros assume you have a variable called 'cpu' +         which is a pointer to Z80 +*/ + + +/* Invoke a callback class +*/ +#define CALLBACK(r,d)	do					\ +			{					\ +			int f;					\ +								\ +			for(f=0;f<MAX_PER_CALLBACK;f++)		\ +			    if (PRIV->callback[r][f])		\ +				PRIV->last_cb &=		\ +				    PRIV->callback[r][f](cpu,d);\ +			} while(0) + +/* Flag register +*/ +#define C_Z80			0x01 +#define N_Z80			0x02 +#define P_Z80			0x04 +#define V_Z80			P_Z80 +#define H_Z80			0x10 +#define Z_Z80			0x40 +#define S_Z80			0x80 + +#define B3_Z80			0x08 +#define B5_Z80			0x20 + + +#define SET(v,b)		(v)|=b +#define CLR(v,b)		(v)&=~(b) + +#define SETFLAG(f)		SET(cpu->AF.b[LO],f) +#define CLRFLAG(f)		CLR(cpu->AF.b[LO],f) + +#ifdef ENABLE_ARRAY_MEMORY + +#define PEEK(addr)		Z80_MEMORY[addr] + +static inline Z80Word PEEKW(Z80Word addr) +{ +    return (PEEK(addr) | (Z80Word)PEEK(addr+1)<<8); +} + +#define POKE(addr,val)		do					\ +				{					\ +				    Z80Word ba=addr;			\ +				    if (ba>=RAMBOT && ba<=RAMTOP)	\ +				    	Z80_MEMORY[ba]=val;		\ +				} while(0) + +#define POKEW(addr,val)		do					\ +				{					\ +				    Z80Word wa=addr;			\ +				    Z80Word wv=val;			\ +				    POKE(wa,wv);			\ +				    POKE(wa+1,wv>>8);			\ +				} while(0) + + +#define FETCH_BYTE		(Z80_MEMORY[cpu->PC++]) +#define FETCH_WORD              (cpu->PC+=2,				\ +				    Z80_MEMORY[cpu->PC-2]|		\ +					((Z80Word)Z80_MEMORY[cpu->PC-1]<<8)) + +#else + +#define PEEK(addr)		(PRIV->mread(cpu,addr)) +#define PEEKW(addr)		FPEEKW(cpu,addr) + +#define POKE(addr,val)		PRIV->mwrite(cpu,addr,val) +#define POKEW(addr,val)		FPOKEW(cpu,addr,val) + +#define FETCH_BYTE		(PRIV->mread(cpu,cpu->PC++)) +#define FETCH_WORD		(cpu->PC+=2,FPEEKW(cpu,cpu->PC-2)) + +#endif + + +#define IS_C			(cpu->AF.b[LO]&C_Z80) +#define IS_N			(cpu->AF.b[LO]&N_Z80) +#define IS_P			(cpu->AF.b[LO]&P_Z80) +#define IS_H			(cpu->AF.b[LO]&H_Z80) +#define IS_Z			(cpu->AF.b[LO]&Z_Z80) +#define IS_S			(cpu->AF.b[LO]&S_Z80) + +#define CARRY			IS_C + +#define IS_IX_IY		(PRIV->shift==0xdd || PRIV->shift==0xfd) +#define OFFSET(off)		off=(IS_IX_IY ? (Z80Relative)FETCH_BYTE:0) + +#define TSTATE(n)		PRIV->cycle+=n + +#define ADD_R(v)		cpu->R=((cpu->R&0x80)|((cpu->R+(v))&0x7f)) +#define INC_R			ADD_R(1) + +#ifdef ENABLE_ARRAY_MEMORY + +#define PUSH(REG)		do					\ +				{					\ +				    Z80Word pv=REG;			\ +				    cpu->SP-=2;				\ +				    POKE(cpu->SP,pv);			\ +				    POKE(cpu->SP+1,pv>>8);		\ +				} while(0) + +#else + +#define PUSH(REG)		do					\ +				{					\ +				    Z80Word pushv=REG;			\ +				    cpu->SP-=2;				\ +				    PRIV->mwrite(cpu,cpu->SP,pushv);	\ +				    PRIV->mwrite(cpu,cpu->SP+1,pushv>>8);\ +				} while(0) +#endif + +#define POP(REG)		do					\ +				{					\ +				    REG=PEEK(cpu->SP) |			\ +				    	(Z80Word)PEEK(cpu->SP+1)<<8;	\ +				    cpu->SP+=2;				\ +				} while(0) + +#define SETHIDDEN(res)		cpu->AF.b[LO]=(cpu->AF.b[LO]&~(B3_Z80|B5_Z80))|\ +					((res)&(B3_Z80|B5_Z80)) + +#define CALL			do				\ +				{				\ +				    PUSH(cpu->PC+2);		\ +				    cpu->PC=PEEKW(cpu->PC);	\ +				} while(0) + +#define NOCALL			cpu->PC+=2 +#define JP			cpu->PC=PEEKW(cpu->PC) +#define NOJP			cpu->PC+=2 +#define JR			cpu->PC+=(Z80Relative)PEEK(cpu->PC)+1 +#define NOJR			cpu->PC++ + +#define OUT(P,V)		do				\ +				{				\ +				    if (PRIV->pwrite)		\ +				    	PRIV->pwrite(cpu,P,V);	\ +				} while(0) + +#define IN(P)			(PRIV->pread?PRIV->pread(cpu,P):0) + + + +/* ---------------------------------------- LABELS +*/ +extern Z80Label			*z80_labels; + + +/* ---------------------------------------- GLOBAL GENERAL OPCODES/ROUTINES +*/ +void Z80_Decode(Z80 *cpu, Z80Byte opcode); +void Z80_InitialiseInternals(void); + + +/* ---------------------------------------- DISASSEMBLY +*/ +#ifdef ENABLE_DISASSEM +typedef void		(*DIS_OP_CALLBACK)(Z80 *z80, Z80Byte op, Z80Word *pc); + +extern DIS_OP_CALLBACK	dis_CB_opcode[]; +extern DIS_OP_CALLBACK	dis_DD_opcode[]; +extern DIS_OP_CALLBACK	dis_DD_CB_opcode[]; +extern DIS_OP_CALLBACK	dis_ED_opcode[]; +extern DIS_OP_CALLBACK	dis_FD_opcode[]; +extern DIS_OP_CALLBACK	dis_FD_CB_opcode[]; +extern DIS_OP_CALLBACK	dis_opcode_z80[]; + +const char	*Z80_Dis_Printf(const char *format, ...); + +Z80Byte		Z80_Dis_FetchByte(Z80 *cpu, Z80Word *pc); +Z80Word		Z80_Dis_FetchWord(Z80 *cpu, Z80Word *pc); + +void		Z80_Dis_Set(const char *op, const char *arg); +const char	*Z80_Dis_GetOp(void); +const char	*Z80_Dis_GetArg(void); +#endif	/* ENABLE_DISASSEM */ + +#endif	/* Z80_PRIVATE_H */ + +/* END OF FILE */ diff --git a/include/zx81.h b/include/zx81.h new file mode 100644 index 0000000..5f097bf --- /dev/null +++ b/include/zx81.h @@ -0,0 +1,59 @@ +/* + +    ezx81 - X11 ZX81 emulator + +    Copyright (C) 2003  Ian Cowburn (ianc@noddybox.demon.co.uk) + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    Provides the emulation for the ZX81 + +*/ + +#ifndef EZX81_ZX81H +#define EZX81_ZX81H "$Id$" + +#include "z80.h" +#include "SDL.h" + + +/* Initialise the ZX81 +*/ +void	ZX81Init(Z80 *z80); + +/* Handle keypresses +*/ +void	ZX81KeyEvent(SDL_Event *e); + +/* Interfaces for the Z80 +*/ +Z80Byte	ZX81ReadMem(Z80 *z80, Z80Word addr); +void	ZX81WriteMem(Z80 *z80, Z80Word addr, Z80Byte val); +Z80Byte	ZX81ReadPort(Z80 *z80, Z80Word port); +void	ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val); +Z80Byte	ZX81ReadForDisassem(Z80 *z80, Z80Word addr); + +/* Interfaces for memory menu +*/ +const char	*ZX81Info(Z80 *z80); +void		ZX81Reset(Z80 *z80); + + +#endif + + +/* END OF FILE */ diff --git a/source/keyboard.c b/source/keyboard.c new file mode 100644 index 0000000..d33346d --- /dev/null +++ b/source/keyboard.c @@ -0,0 +1,262 @@ +/* +   ds81 - Nintendo DS ZX81 emulator. + +   Copyright (C) 2006  Ian Cowburn +    +   This program is free software; you can redistribute it and/or +   modify it under the terms of the GNU General Public License +   as published by the Free Software Foundation; either version 2 +   of the License, or (at your option) any later version. +    +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. +    +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. +   +   $Id$ +*/ + +#include <nds.h> +#include "keyboard.h" +#include "framebuffer.h" +#include "keyb_bin.h" + +/* ---------------------------------------- STATIC DATA +*/ +static uint16 white = FB_RGB(31, 31, 31); +static uint16 black = FB_RGB(0, 0, 0); + +static struct +{ +    int	state; +    int	new_state; +    int	handled; +    int is_sticky; +} key_state[NUM_SOFT_KEYS]; + +static SoftKey	pad_left_key	= SK_5; +static SoftKey	pad_right_key	= SK_8; +static SoftKey	pad_up_key	= SK_7; +static SoftKey	pad_down_key	= SK_6; +static SoftKey	pad_A_key	= SK_0; +static SoftKey	pad_B_key	= SK_NEWLINE; +static SoftKey	pad_X_key	= NUM_SOFT_KEYS; +static SoftKey	pad_Y_key	= NUM_SOFT_KEYS; +static SoftKey	pad_R_key	= NUM_SOFT_KEYS; +static SoftKey	pad_L_key	= NUM_SOFT_KEYS; +static SoftKey	pad_start_key	= NUM_SOFT_KEYS; +static SoftKey	pad_select_key	= NUM_SOFT_KEYS; + +#define CHECK_STATE(KEYS,BIT,CODE,SHORTCUT)			\ +	do							\ +	{							\ +	    key_state[CODE].new_state = (KEYS & BIT);		\ +	    if (SHORTCUT != NUM_SOFT_KEYS &&			\ +		!key_state[SHORTCUT].handled)			\ +	    {							\ +		key_state[SHORTCUT].new_state = (KEYS & BIT);	\ +	    }							\ +	} while(0) + + +/* ---------------------------------------- PRIVATE INTERFACES +*/ +static SoftKey LocatePress(const touchPosition *p) +{ +    int kx=0,ky=0; +    int py=0; +    SoftKey key = NUM_SOFT_KEYS; + +    if (p->py > 36 && p->px > 2) +    { +	kx = (p->px - 3) / 25; +	ky = p->py - 37; + +	py = ky % 30; +	ky /= 30; + +	if (py<17 && kx >= 0 && kx<10 && ky>=0 && ky<=4) +	{ +	    key = kx + ky * 10; +	} +    } + +    return key; +} + + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +void SK_DisplayKeyboard(uint16 *vram) +{ +    sImage img; + +    loadPCX(keyb_bin,&img); +    image8to16(&img); +    dmaCopy(img.data8,vram,SCREEN_WIDTH*SCREEN_HEIGHT*2); +} + + +int SK_GetEvent(SoftKeyEvent *ev) +{ +    static SoftKey last = NUM_SOFT_KEYS; +    static int poll_index = -1; + +    /* Read the keys if this is a new loop +    */ +    if (poll_index == -1) +    { +	int f; +	uint32 keys; + +    	scanKeys(); + +	keys = keysHeld(); + +	/* Clear the non-sticky keys +	*/ +	for(f=SK_1; f<=SK_CONFIG; f++) +	{ +	    key_state[f].handled = FALSE; + +	    if (key_state[f].is_sticky) +	    { +		key_state[f].new_state = key_state[f].state; +	    } +	    else +	    { +		key_state[f].new_state = FALSE; +	    } +	} + +	/* Check the soft keyboard +	*/ +	if (keys & KEY_TOUCH) +	{ +	    touchPosition tp=touchReadXY(); + +	    if (tp.py<21 || tp.py>165) +	    { +	    	key_state[SK_CONFIG].new_state = TRUE; +	    } +	    else +	    { +	    	SoftKey press; + +		press = LocatePress(&tp); + +		if (press != NUM_SOFT_KEYS) +		{ +		    key_state[press].handled = TRUE; + +		    if (key_state[press].is_sticky) +		    { +			if (last != press) +			{ +			    key_state[press].new_state = +			    		!key_state[press].state; +			} +		    } +		    else +		    { +			key_state[press].new_state = TRUE; +		    } + +		    last = press; +		} +	    } +	} +	else +	{ +	    last = NUM_SOFT_KEYS; +	} + +	/* Check non soft-keyboard controls +	*/ +	CHECK_STATE(keys, KEY_A,	SK_PAD_A,	pad_A_key); +	CHECK_STATE(keys, KEY_B,	SK_PAD_B,	pad_B_key); +	CHECK_STATE(keys, KEY_X,	SK_PAD_X,	pad_X_key); +	CHECK_STATE(keys, KEY_Y,	SK_PAD_Y,	pad_Y_key); +	CHECK_STATE(keys, KEY_R,	SK_PAD_R,	pad_R_key); +	CHECK_STATE(keys, KEY_L,	SK_PAD_L,	pad_L_key); +	CHECK_STATE(keys, KEY_START,	SK_PAD_START,	pad_start_key); +	CHECK_STATE(keys, KEY_SELECT,	SK_PAD_SELECT,	pad_select_key); +	CHECK_STATE(keys, KEY_UP,	SK_PAD_UP,	pad_up_key); +	CHECK_STATE(keys, KEY_DOWN,	SK_PAD_DOWN,	pad_down_key); +	CHECK_STATE(keys, KEY_LEFT,	SK_PAD_LEFT,	pad_left_key); +	CHECK_STATE(keys, KEY_RIGHT,	SK_PAD_RIGHT,	pad_right_key); + +	/* Reset key event poll index +	*/ +	poll_index = 0; + +	/* Update any on-screen indicators +	*/ +	for(f=SK_1; f<SK_CONFIG; f++) +	{ +	    if (key_state[f].state != key_state[f].new_state) +	    { +		int x,y; + +		x = 2 + (f % 10) * 25; +		y = 36 + (f / 10) * 30; +	    	 +		FB_Box(x, y, 26, 19, key_state[f].new_state ? white:black); +	    } +	} +    } + +    while(poll_index < NUM_SOFT_KEYS && +    		key_state[poll_index].state == key_state[poll_index].new_state) +    { +    	poll_index++; +    } + +    if (poll_index < NUM_SOFT_KEYS) +    { +	key_state[poll_index].state = key_state[poll_index].new_state; + +	ev->key = poll_index; +	ev->pressed = key_state[poll_index].state; + +	return TRUE; +    } +    else +    { +    	poll_index = -1; +	return FALSE; +    } +} + + +void SK_SetSticky(SoftKey key, int is_sticky) +{ +    key_state[key].is_sticky = is_sticky; + +    if (!is_sticky) +    { +	key_state[key].new_state = FALSE; +    } +} + + +void SK_ClearKeys(void) +{ +    int f; + +    for(f=0; f < NUM_SOFT_KEYS; f++) +    { +    	key_state[f].state = FALSE; +    } +} + + +void SK_DefineJoypad(void) +{ +} + + diff --git a/source/main.c b/source/main.c index a5f5035..a2b0565 100644 --- a/source/main.c +++ b/source/main.c @@ -28,6 +28,7 @@  #include "gui.h"  #include "splashimg_bin.h" +#include "zx81_bin.h"  /* ---------------------------------------- STATIC DATA  */ @@ -46,10 +47,12 @@ static void Splash(void)      {      	"DS81 \177 2006 Ian C",  	" ", -	"ZX81 ROM \177 1981", +	"ZX81 ROM", +	"\177 1981",  	"Nine Tiles Networks LTD",  	" ", -	"3D MONSTER MAZE \177 1983", +	"3D MONSTER MAZE", +	"\177 1983",  	"Malcom E. Evans",  	" ",  	"PRESS A TO CONTINUE", @@ -62,18 +65,11 @@ static void Splash(void)      sImage img;      int f; -    loadPCX(splashimg_bin,&img); -    image8to16(&img); -    dmaCopy(img.data8,BG_GFX,SCREEN_WIDTH*SCREEN_HEIGHT*2); -      FB_Clear(); -    for(f=0;f<SCREEN_HEIGHT;f++) -    { -	FB_HLine(0,SCREEN_WIDTH-1,f,FB_RGB(f/8,0,0)); -    } - -    FB_Box(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,FB_RGB(31,31,31)); +    loadPCX(splashimg_bin,&img); +    image8to16(&img); +    dmaCopy(img.data8,BG_GFX_SUB,SCREEN_WIDTH*SCREEN_HEIGHT*2);      for(f=0;text[f];f++)      { @@ -91,22 +87,69 @@ static void Splash(void)  */  int main(int argc, char *argv[])  { +    int ch; +    uint8 *ch_data; +      powerON(POWER_ALL_2D); -    videoSetMode(MODE_5_2D | DISPLAY_BG2_ACTIVE); +    /* Set up main text screen and grab the ROM character data +    */ +    videoSetMode(MODE_0_2D | DISPLAY_BG0_ACTIVE);      vramSetBankA(VRAM_A_MAIN_BG_0x6000000); -    BG2_CR = BG_BMP16_256x256; -    BG2_XDX = 0x100; -    BG2_XDY = 0; -    BG2_YDX = 0; -    BG2_YDY = 0x100; -    BG2_CX = 0; -    BG2_CY = 0; +    vramSetBankB(VRAM_B_MAIN_BG_0x6020000); -    videoSetModeSub(MODE_5_2D | DISPLAY_BG2_ACTIVE); +    BG0_CR = BG_COLOR_256|BG_MAP_BASE(31)|BG_TILE_BASE(0); +    BG0_X0 = 0; +    BG0_Y0 = 0; + +    BG_PALETTE[0] = RGB15(31,31,31); +    BG_PALETTE[1] = RGB15(0,0,0); +    ch_data = (uint8*)BG_TILE_RAM(0); +    for(ch=0;ch<64;ch++) +    { +	int r; + +	for(r=0;r<8;r++) +	{ +	    int b; +	    int rd; + +	    rd=zx81_bin[0x1e00+ch*8+r]; + +	    for(b=7;b>=0;b--) +	    { +		if (rd&(1<<b)) +		{ +		    *ch_data = 1; +		    *(ch_data+4096) = 0; +		} +		else +		{ +		    *ch_data = 0; +		    *(ch_data+4096) = 1; +		} + +		ch_data++; +	    } +	} +    } + +    { +    uint16 *tiles; +    tiles = (uint16*)BG_MAP_RAM(31); +    for(ch=0;ch<128;ch++) +    { +    	*(tiles+(ch%32)+(ch/32)*32)=ch; +    } +    } + +    /* Set up the sub-screen for rotation (basically for use as a framebuffer) +    */ +    videoSetModeSub(MODE_5_2D | DISPLAY_BG2_ACTIVE);      vramSetBankC(VRAM_C_SUB_BG_0x6200000); +      SUB_BG2_CR = BG_BMP16_256x256;      SUB_BG2_XDX = 0x100;      SUB_BG2_XDY = 0; diff --git a/source/z80.c b/source/z80.c new file mode 100644 index 0000000..36c5793 --- /dev/null +++ b/source/z80.c @@ -0,0 +1,331 @@ +/* + +    z80 - Z80 Emulator + +    Copyright (C) 2006  Ian Cowburn <ianc@noddybox.co.uk> + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    $Id$ + +    Z80 + +*/ +#include <stdlib.h> +#include <string.h> + +#include "z80.h" +#include "z80_private.h" + +static const char ident[]="$Id$"; +static const char ident_z80_header[]=Z80_H; +static const char ident_z80_private_header[]=Z80_PRIVATE_H; + +Z80Label        *z80_labels=NULL; + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static void InitTables() +{ +    static int init=FALSE; + +    if (init) +    	return; + +    init=TRUE; + +    Z80_InitialiseInternals(); +} + +static void Z80_CheckInterrupt(Z80 *cpu) +{ +    /* Check interrupts +    */ +    if (PRIV->raise) +    { +    	if (PRIV->nmi) +	{ +	    if (PRIV->halt) +	    { +		PRIV->halt=FALSE; +		CALLBACK(eZ80_Halt,0); +		cpu->PC++; +	    } + +	    TSTATE(2); +	    cpu->IFF1=0; +	    PRIV->nmi=FALSE; +	    PUSH(cpu->PC); +	    cpu->PC=0x66; +	} +    	else if (cpu->IFF1) +	{ +	    if (PRIV->halt) +	    { +		PRIV->halt=FALSE; +		CALLBACK(eZ80_Halt,0); +		cpu->PC++; +	    } + +	    TSTATE(2); + +	    cpu->IFF1=0; +	    cpu->IFF2=0; + +	    switch(cpu->IM) +	    { +		default: +		case 0: +		    INC_R; +		    Z80_Decode(cpu,PRIV->devbyte); +		    return; +		    break; + +		case 1: +		    PUSH(cpu->PC); +		    cpu->PC=0x38; +		    break; + +		case 2: +		    PUSH(cpu->PC); +		    cpu->PC=(Z80Word)cpu->I*256+PRIV->devbyte; +		    break; +	    } +	} + +	PRIV->raise=FALSE; +    } +} + + +/* ---------------------------------------- INTERFACES +*/ + +#ifdef ENABLE_ARRAY_MEMORY +Z80     *Z80Init(Z80ReadPort read_port, +                 Z80WritePort write_port) +#else +Z80     *Z80Init(Z80ReadMemory read_memory, +                 Z80WriteMemory write_memory, +                 Z80ReadPort read_port, +                 Z80WritePort write_port, +                 Z80ReadMemory read_for_disassem) +#endif +{ +    Z80 *cpu; +    int f; +    int r; + +    InitTables(); + +#ifndef ENABLE_ARRAY_MEMORY +    if (!read_memory || !write_memory) +    	return NULL; +#endif + +    cpu=malloc(sizeof *cpu); + +    if (cpu) +    { +    	cpu->priv=malloc(sizeof *cpu->priv); + +	if (cpu->priv) +	{ +#ifndef ENABLE_ARRAY_MEMORY +	    PRIV->mread=read_memory; +	    PRIV->mwrite=write_memory; +	    PRIV->disread=read_for_disassem; +#endif +	    PRIV->pread=read_port; +	    PRIV->pwrite=write_port; + +	    for(f=0;f<eZ80_NO_CALLBACK;f++) +		for(r=0;r<MAX_PER_CALLBACK;r++) +		    PRIV->callback[f][r]=NULL; + +	    Z80Reset(cpu); +	} +	else +	{ +	    free(cpu); +	    cpu=NULL; +	} +    } + +    return cpu; +} + + +void Z80Reset(Z80 *cpu) +{ +    PRIV->cycle=0; +    cpu->PC=0; + +    cpu->AF.w=0xffff; +    cpu->BC.w=0xffff; +    cpu->DE.w=0xffff; +    cpu->HL.w=0xffff; +    cpu->AF_=0xffff; +    cpu->BC_=0xffff; +    cpu->DE_=0xffff; +    cpu->HL_=0xffff; + +    cpu->IX.w=0xffff; +    cpu->IY.w=0xffff; + +    cpu->SP=0xffff; +    cpu->IFF1=0; +    cpu->IFF2=0; +    cpu->IM=0; +    cpu->I=0; +    cpu->R=0; +    PRIV->halt=0; + +    PRIV->raise=FALSE; +    PRIV->nmi=FALSE; +} + + +Z80Val Z80Cycles(Z80 *cpu) +{ +    return PRIV->cycle; +} + + +void Z80ResetCycles(Z80 *cpu, Z80Val cycles) +{ +    PRIV->cycle=cycles; +} + + +int Z80LodgeCallback(Z80 *cpu, Z80CallbackReason reason, Z80Callback callback) +{ +    int f; + +    for(f=0;f<MAX_PER_CALLBACK;f++) +    { +    	if (!PRIV->callback[reason][f]) +	{ +	    PRIV->callback[reason][f]=callback; +	    return TRUE; +	} +    } + +    return FALSE; +} + + +void Z80RemoveCallback(Z80 *cpu, Z80CallbackReason reason, Z80Callback callback) +{ +    int f; + +    for(f=0;f<MAX_PER_CALLBACK;f++) +    { +    	if (PRIV->callback[reason][f]==callback) +	{ +	    PRIV->callback[reason][f]=NULL; +	} +    } +} + + +void Z80Interrupt(Z80 *cpu, Z80Byte devbyte) +{ +    PRIV->raise=TRUE; +    PRIV->devbyte=devbyte; +    PRIV->nmi=FALSE; +} + + +void Z80NMI(Z80 *cpu) +{ +    PRIV->raise=TRUE; +    PRIV->nmi=TRUE; +} + + +int Z80SingleStep(Z80 *cpu) +{ +    Z80Byte opcode; + +    PRIV->last_cb=TRUE; +    PRIV->shift=0; + +    Z80_CheckInterrupt(cpu); + +    CALLBACK(eZ80_Instruction,PRIV->cycle); + +    INC_R; + +    opcode=FETCH_BYTE; + +    Z80_Decode(cpu,opcode); + +    return PRIV->last_cb; +} + + +void Z80Exec(Z80 *cpu) +{ +    while (Z80SingleStep(cpu)); +} + + +void Z80SetLabels(Z80Label labels[]) +{ +    z80_labels=labels; +} + + +const char *Z80Disassemble(Z80 *cpu, Z80Word *pc) +{ +#ifdef ENABLE_DISASSEM +    Z80Byte Z80_Dis_FetchByte(Z80 *cpu, Z80Word *pc); +    static char s[80]; +    Z80Word opc,npc; +    Z80Byte op; +    int f; + +    opc=*pc; +    op=Z80_Dis_FetchByte(cpu,pc); +    dis_opcode_z80[op](cpu,op,pc); +    npc=*pc; + +    strcpy(s,Z80_Dis_Printf("%-5s",Z80_Dis_GetOp())); +    strcat(s,Z80_Dis_Printf("%-40s ;",Z80_Dis_GetArg())); + +    for(f=0;f<5 && opc!=npc;f++) +    { +#ifdef ENABLE_ARRAY_MEMORY +	strcat(s,Z80_Dis_Printf(" %.2x",(int)Z80_MEMORY[opc++])); +#else +	strcat(s,Z80_Dis_Printf(" %.2x",(int)PRIV->disread(cpu,opc++))); +#endif +    } + +    if (opc!=npc) +	for(f=1;f<3;f++) +	    s[strlen(s)-f]='.'; + +    return s; +#else +    (*pc)+=4; +    return "NO DISASSEMBLER"; +#endif +} + +/* END OF FILE */ diff --git a/source/z80_decode.c b/source/z80_decode.c new file mode 100644 index 0000000..a8f66ca --- /dev/null +++ b/source/z80_decode.c @@ -0,0 +1,2533 @@ +/* + +    z80 - Z80 Emulator + +    Copyright (C) 2006  Ian Cowburn <ianc@noddybox.co.uk> + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    $Id$ + +*/ +#include <stdlib.h> +#include <limits.h> + +#include "z80.h" +#include "z80_private.h" + +static const char ident[]="$Id$"; + +/* ---------------------------------------- TABLES AND INIT +*/ +static Z80Byte		PSZtable[512]; +static Z80Byte		SZtable[512]; +static Z80Byte		Ptable[512]; +static Z80Byte		Stable[512]; +static Z80Byte		Ztable[512]; + + +int Z80_HI_WORD; +int Z80_LO_WORD; + +#define HI Z80_HI_WORD +#define LO Z80_LO_WORD + +/* ---------------------------------------- MISC FUNCTIONS +*/ +void Z80_InitialiseInternals(void) +{ +    Z80Word f; +    Z80Reg r; + +    /* Check endianness +    */ +    r.w=0x1234; + +    if (r.b[0] == 0x12) +    { +    	HI=0; +	LO=1; +    } +    else if (r.b[1] == 0x12) +    { +    	HI=1; +	LO=0; +    } +    else +    { +    	exit(1); +    } + +    /* Check variable sizes +    */ +    if (CHAR_BIT!=8 || sizeof(Z80Word)!=2) +    { +    	exit(2); +    } + +    /* Initialise flag tables +    */ +    for(f=0;f<256;f++) +    { +	Z80Byte p,z,s; +	int b; + +	p=0; + +	for(b=0;b<8;b++) +	    if (f&(1<<b)) +		p++; + +	if (p&1) +	    p=0; +	else +	    p=P_Z80; + +	if (f) +	    z=0; +	else +	    z=Z_Z80; + +	if (f&0x80) +	    s=S_Z80; +	else +	    s=0; + +	Ptable[f]=p; +	Stable[f]=s; +	Ztable[f]=z; +	SZtable[f]=z|s; +	PSZtable[f]=z|s|p; + +	Ptable[f+256]=Ptable[f]|C_Z80; +	Stable[f+256]=Stable[f]|C_Z80; +	Ztable[f+256]=Ztable[f]|C_Z80; +	SZtable[f+256]=SZtable[f]|C_Z80; +	PSZtable[f+256]=PSZtable[f]|C_Z80; +    } +} + +#ifndef ENABLE_ARRAY_MEMORY +static Z80Word FPEEKW(Z80 *cpu, Z80Word addr) +{ +    return (PEEK(addr) | (Z80Word)PEEK(addr+1)<<8); +} + + +static void FPOKEW(Z80 *cpu, Z80Word addr, Z80Word val) +{ +    PRIV->mwrite(cpu,addr,val); +    PRIV->mwrite(cpu,addr+1,val>>8); +} +#endif + + +/* ---------------------------------------- GENERAL MACROS +*/ +#define SWAP(A,B) \ +do { \ +    unsigned swap_tmp; \ +    swap_tmp=A; \ +    A=B; \ +    B=swap_tmp; \ +} while(0) + + +/* ---------------------------------------- ARITHMETIC OPS +*/ +#define ADD8(ONCE) \ +do { \ +    Z80Byte VAL=ONCE; \ +    unsigned w; \ +    w=cpu->AF.b[HI]+(unsigned)VAL; \ +    cpu->AF.b[LO]=SZtable[w]; \ +    if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ +    if ((VAL^cpu->AF.b[HI]^0x80)&(VAL^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ +    SETHIDDEN(w); \ +    cpu->AF.b[HI]=w; \ +} while(0) + + +#define ADC8(ONCE) \ +do { \ +    Z80Byte VAL=ONCE; \ +    unsigned w; \ +    w=(cpu->AF.b[HI]+(unsigned)VAL+CARRY)&0x1ff; \ +    cpu->AF.b[LO]=SZtable[w]; \ +    if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ +    if ((VAL^cpu->AF.b[HI]^0x80)&(VAL^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ +    SETHIDDEN(w); \ +    cpu->AF.b[HI]=w; \ +} while(0) + + +#define SUB8(ONCE) \ +do { \ +    Z80Byte VAL=ONCE; \ +    unsigned w; \ +    w=(cpu->AF.b[HI]-(unsigned)VAL)&0x1ff; \ +    cpu->AF.b[LO]=SZtable[w]|N_Z80; \ +    if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ +    if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ +    SETHIDDEN(w); \ +    cpu->AF.b[HI]=w; \ +} while(0) + + +#define CMP8(ONCE) \ +do { \ +    Z80Byte VAL=ONCE; \ +    unsigned w; \ +    w=(cpu->AF.b[HI]-(unsigned)VAL)&0x1ff; \ +    cpu->AF.b[LO]=SZtable[w]|N_Z80; \ +    if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ +    if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ +    SETHIDDEN(VAL); \ +} while(0) + + +#define SBC8(ONCE) \ +do { \ +    Z80Byte VAL=ONCE; \ +    unsigned w; \ +    w=(cpu->AF.b[HI]-(unsigned)VAL-CARRY)&0x1ff; \ +    cpu->AF.b[LO]=SZtable[w]|N_Z80; \ +    if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ +    if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ +    SETHIDDEN(w); \ +    cpu->AF.b[HI]=w; \ +} while(0) + + +#define ADD16(REG,ONCE) \ +do { \ +    Z80Word VAL=ONCE; \ +    Z80Val w; \ +    w=(REG)+(Z80Val)VAL; \ +    cpu->AF.b[LO]&=(S_Z80|Z_Z80|V_Z80); \ +    if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \ +    if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \ +    SETHIDDEN(w>>8); \ +    (REG)=w; \ +} while(0)  + + +#define ADC16(REG, ONCE) \ +do { \ +    Z80Word VAL=ONCE; \ +    Z80Val w; \ +    w=(REG)+(Z80Val)VAL+CARRY; \ +    cpu->AF.b[LO]=0; \ +    if ((w&0xffff)==0) cpu->AF.b[LO]=Z_Z80; \ +    if (w&0x8000) cpu->AF.b[LO]|=S_Z80; \ +    if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \ +    if ((VAL^(REG)^0x8000)&((REG)^w)&0x8000) cpu->AF.b[LO]|=P_Z80; \ +    if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \ +    SETHIDDEN(w>>8); \ +    (REG)=w; \ +} while(0)  + + +#define SBC16(REG, ONCE) \ +do { \ +    Z80Word VAL=ONCE; \ +    Z80Val w; \ +    w=(REG)-(Z80Val)VAL-CARRY; \ +    cpu->AF.b[LO]=N_Z80; \ +    if (w&0x8000) cpu->AF.b[LO]|=S_Z80; \ +    if ((w&0xffff)==0) cpu->AF.b[LO]|=Z_Z80; \ +    if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \ +    if ((VAL^(REG))&((REG)^w)&0x8000) cpu->AF.b[LO]|=P_Z80; \ +    if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \ +    SETHIDDEN(w>>8); \ +    (REG)=w; \ +} while(0) + + +#define INC8(REG) \ +do { \ +    (REG)++; \ +    cpu->AF.b[LO]=CARRY|SZtable[(REG)]; \ +    if ((REG)==0x80) cpu->AF.b[LO]|=P_Z80; \ +    if (((REG)&0x0f)==0) cpu->AF.b[LO]|=H_Z80; \ +} while(0)  + + +#define DEC8(REG) \ +do { \ +    (REG)--; \ +    cpu->AF.b[LO]=N_Z80|CARRY; \ +    if ((REG)==0x7f) cpu->AF.b[LO]|=P_Z80; \ +    if (((REG)&0x0f)==0x0f) cpu->AF.b[LO]|=H_Z80; \ +    cpu->AF.b[LO]|=SZtable[(REG)]; \ +} while(0) + + +#define OP_ON_MEM(OP,addr) \ +do { \ +    Z80Byte memop=PEEK(addr); \ +    OP(memop); \ +    POKE(addr,memop); \ +} while(0) + + +#define OP_ON_MEM_WITH_ARG(OP,addr,arg) \ +do { \ +    Z80Byte memop=PEEK(addr); \ +    OP(memop,arg); \ +    POKE(addr,memop); \ +} while(0) + + +#define OP_ON_MEM_WITH_COPY(OP,addr,copy) \ +do { \ +    Z80Byte memop=PEEK(addr); \ +    OP(memop); \ +    copy=memop; \ +    POKE(addr,memop); \ +} while(0) + + +#define OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,arg,copy) \ +do { \ +    Z80Byte memop=PEEK(addr); \ +    OP(memop,arg); \ +    copy=memop; \ +    POKE(addr,memop); \ +} while(0) + + +/* ---------------------------------------- ROTATE AND SHIFT OPS +*/ +#define RRCA \ +do { \ +    cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]&C_Z80); \ +    cpu->AF.b[HI]=(cpu->AF.b[HI]>>1)|(cpu->AF.b[HI]<<7); \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define RRA \ +do { \ +    Z80Byte c; \ +    c=CARRY; \ +    cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]&C_Z80); \ +    cpu->AF.b[HI]=(cpu->AF.b[HI]>>1)|(c<<7); \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define RRC(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)&C_Z80; \ +    (REG)=((REG)>>1)|((REG)<<7); \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0)  + + +#define RR(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)&C_Z80; \ +    (REG)=((REG)>>1)|(CARRY<<7); \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +#define RLCA \ +do { \ +    cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]>>7); \ +    cpu->AF.b[HI]=(cpu->AF.b[HI]<<1)|(cpu->AF.b[HI]>>7); \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define RLA \ +do { \ +    Z80Byte c; \ +    c=CARRY; \ +    cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]>>7); \ +    cpu->AF.b[HI]=(cpu->AF.b[HI]<<1)|c; \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define RLC(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)>>7; \ +    (REG)=((REG)<<1)|c; \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +#define RL(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)>>7; \ +    (REG)=((REG)<<1)|CARRY; \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +#define SRL(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)&C_Z80; \ +    (REG)>>=1; \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +#define SRA(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)&C_Z80; \ +    (REG)=((REG)>>1)|((REG)&0x80); \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +#define SLL(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)>>7; \ +    (REG)=((REG)<<1)|1; \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +#define SLA(REG) \ +do { \ +    Z80Byte c; \ +    c=(REG)>>7; \ +    (REG)=(REG)<<1; \ +    cpu->AF.b[LO]=PSZtable[(REG)]|c; \ +    SETHIDDEN(REG); \ +} while(0) + + +/* ---------------------------------------- BOOLEAN OPS +*/ +#define AND(VAL) \ +do { \ +    cpu->AF.b[HI]&=VAL; \ +    cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]|H_Z80; \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define OR(VAL) \ +do { \ +    cpu->AF.b[HI]|=VAL; \ +    cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]; \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define XOR(VAL) \ +do { \ +    cpu->AF.b[HI]^=VAL; \ +    cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]; \ +    SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define BIT(REG,B) \ +do { \ +    cpu->AF.b[LO]=CARRY|H_Z80; \ +    if ((REG)&(1<<B)) \ +    { \ +	if (B==7 && (REG&S_Z80)) cpu->AF.b[LO]|=S_Z80; \ +	if (B==5 && (REG&B5_Z80)) cpu->AF.b[LO]|=B5_Z80; \ +	if (B==3 && (REG&B3_Z80)) cpu->AF.b[LO]|=B3_Z80; \ +    } \ +    else \ +    { \ +	cpu->AF.b[LO]|=Z_Z80; \ +	cpu->AF.b[LO]|=P_Z80; \ +    } \ +} while(0) + +#define BIT_SET(REG,B) (REG)|=(1<<B) +#define BIT_RES(REG,B) (REG)&=~(1<<B) + + +/* ---------------------------------------- JUMP OPERATIONS +*/ +#define JR_COND(COND) \ +do { \ +    if (COND) \ +    { \ +	TSTATE(12); \ +	JR; \ +    } \ +    else \ +    { \ +	TSTATE(7); \ +	NOJR; \ +    } \ +} while(0) + + +#define JP_COND(COND) \ +do { \ +    TSTATE(10); \ +    if (COND) \ +    { \ +	JP; \ +    } \ +    else \ +    { \ +	NOJP; \ +    } \ +} while(0) + + +#define CALL_COND(COND) \ +do { \ +    if (COND) \ +    { \ +	TSTATE(17); \ +	CALL; \ +    } \ +    else \ +    { \ +	TSTATE(10); \ +	NOCALL; \ +    } \ +} while(0) + + +#define RET_COND(COND) \ +do { \ +    if (COND) \ +    { \ +	TSTATE(11); \ +	POP(cpu->PC); \ +    } \ +    else \ +    { \ +	TSTATE(5); \ +    } \ +} while(0) + + +#define RST(ADDR) \ +    TSTATE(11); \ +    PUSH(cpu->PC); \ +    cpu->PC=ADDR + +/* ---------------------------------------- BLOCK OPERATIONS +*/ +#define LDI \ +do { \ +    Z80Byte b; \ + \ +    b=PEEK(cpu->HL.w); \ +    POKE(cpu->DE.w,b); \ +    cpu->DE.w++; \ +    cpu->HL.w++; \ +    cpu->BC.w--; \ + \ +    CLRFLAG(H_Z80); \ +    CLRFLAG(N_Z80); \ + \ +    if (cpu->BC.w) \ +	SETFLAG(P_Z80); \ +    else \ +	CLRFLAG(P_Z80); \ + \ +    SETHIDDEN(cpu->AF.b[HI]+b); \ +} while(0) + +#define LDD \ +do { \ +    Z80Byte b; \ + \ +    b=PEEK(cpu->HL.w); \ +    POKE(cpu->DE.w,b); \ +    cpu->DE.w--; \ +    cpu->HL.w--; \ +    cpu->BC.w--; \ + \ +    CLRFLAG(H_Z80); \ +    CLRFLAG(N_Z80); \ + \ +    if (cpu->BC.w) \ +	SETFLAG(P_Z80); \ +    else \ +	CLRFLAG(P_Z80); \ + \ +    SETHIDDEN(cpu->AF.b[HI]+b); \ +} while(0) + +#define CPI \ +do { \ +    Z80Byte c,b; \ + \ +    c=CARRY; \ +    b=PEEK(cpu->HL.w); \ + \ +    CMP8(b); \ + \ +    if (c) \ +    	SETFLAG(C_Z80); \ +    else \ +    	CLRFLAG(C_Z80); \ + \ +    cpu->HL.w++; \ +    cpu->BC.w--; \ + \ +    if (cpu->BC.w) \ +	SETFLAG(P_Z80); \ +    else \ +	CLRFLAG(P_Z80); \ +} while(0) + +#define CPD \ +do { \ +    Z80Byte c,b; \ + \ +    c=CARRY; \ +    b=PEEK(cpu->HL.w); \ + \ +    CMP8(b); \ + \ +    if (c) \ +    	SETFLAG(C_Z80); \ +    else \ +    	CLRFLAG(C_Z80); \ + \ +    cpu->HL.w--; \ +    cpu->BC.w--; \ + \ +    if (cpu->BC.w) \ +	SETFLAG(P_Z80); \ +    else \ +	CLRFLAG(P_Z80); \ +} while(0) + +#define INI \ +do { \ +    Z80Word w; \ +    Z80Byte b; \ + \ +    b=IN(cpu->BC.w); \ +    POKE(cpu->HL.w,b); \ + \ +    cpu->BC.b[HI]--; \ +    cpu->HL.w++; \ + \ +    cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \ +    SETHIDDEN(cpu->BC.b[HI]); \ + \ +    w=(((Z80Word)cpu->BC.b[LO])&0xff)+b; \ + \ +    if (b&0x80) \ +    	SETFLAG(N_Z80); \ + \ +    if (w&0x100) \ +    { \ +    	SETFLAG(C_Z80); \ +    	SETFLAG(H_Z80); \ +    } \ +    else \ +    { \ +    	CLRFLAG(C_Z80); \ +    	CLRFLAG(H_Z80); \ +    } \ +} while(0) + +#define IND \ +do { \ +    Z80Word w; \ +    Z80Byte b; \ + \ +    b=IN(cpu->BC.w); \ +    POKE(cpu->HL.w,b); \ + \ +    cpu->BC.b[HI]--; \ +    cpu->HL.w--; \ + \ +    cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \ +    SETHIDDEN(cpu->BC.b[HI]); \ + \ +    w=(((Z80Word)cpu->BC.b[LO])&0xff)+b; \ + \ +    if (b&0x80) \ +    	SETFLAG(N_Z80); \ + \ +    if (w&0x100) \ +    { \ +    	SETFLAG(C_Z80); \ +    	SETFLAG(H_Z80); \ +    } \ +    else \ +    { \ +    	CLRFLAG(C_Z80); \ +    	CLRFLAG(H_Z80); \ +    } \ +} while(0) \ + +#define OUTI \ +do { \ +    OUT(cpu->BC.w,PEEK(cpu->HL.w)); \ + \ +    cpu->HL.w++; \ +    cpu->BC.b[HI]--; \ + \ +    cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \ +    SETHIDDEN(cpu->BC.b[HI]); \ +} while(0) + +#define OUTD \ +do { \ +    OUT(cpu->BC.w,PEEK(cpu->HL.w)); \ + \ +    cpu->HL.w--; \ +    cpu->BC.b[HI]--; \ + \ +    cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \ +    SETFLAG(N_Z80); \ +    SETHIDDEN(cpu->BC.b[HI]); \ +} while(0) + + +/* ---------------------------------------- BASE OPCODE SHORT-HAND BLOCKS +*/ + +#define LD_BLOCK(BASE,DEST,DEST2) \ +    case BASE:		/* LD DEST,B */ \ +	TSTATE(4); \ +	DEST=cpu->BC.b[HI]; \ +	break; \ + \ +    case BASE+1:	/* LD DEST,C */ \ +	TSTATE(4); \ +	DEST=cpu->BC.b[LO]; \ +	break; \ + \ +    case BASE+2:	/* LD DEST,D */ \ +	TSTATE(4); \ +	DEST=cpu->DE.b[HI]; \ +	break; \ + \ +    case BASE+3:	/* LD DEST,E */ \ +	TSTATE(4); \ +	DEST=cpu->DE.b[LO]; \ +	break; \ + \ +    case BASE+4:	/* LD DEST,H */ \ +	TSTATE(4); \ +	DEST=*H; \ +	break; \ + \ +    case BASE+5:	/* LD DEST,L */ \ +	TSTATE(4); \ +	DEST=*L; \ +	break; \ + \ +    case BASE+6:	/* LD DEST,(HL) */ \ +	TSTATE(7); \ +	OFFSET(off); \ +	DEST2=PEEK(*HL+off); \ +	break; \ + \ +    case BASE+7:	/* LD DEST,A */ \ +	TSTATE(4); \ +	DEST=cpu->AF.b[HI]; \ +	break; + +#define ALU_BLOCK(BASE,OP) \ +    case BASE:		/* OP A,B */ \ +	TSTATE(4); \ +	OP(cpu->BC.b[HI]); \ +	break; \ + \ +    case BASE+1:	/* OP A,C */ \ +	TSTATE(4); \ +	OP(cpu->BC.b[LO]); \ +	break; \ + \ +    case BASE+2:	/* OP A,D */ \ +	TSTATE(4); \ +	OP(cpu->DE.b[HI]); \ +	break; \ + \ +    case BASE+3:	/* OP A,E */ \ +	TSTATE(4); \ +	OP(cpu->DE.b[LO]); \ +	break; \ + \ +    case BASE+4:	/* OP A,H */ \ +	TSTATE(4); \ +	OP(*H); \ +	break; \ + \ +    case BASE+5:	/* OP A,L */ \ +	TSTATE(4); \ +	OP(*L); \ +	break; \ + \ +    case BASE+6:	/* OP A,(HL) */ \ +	TSTATE(7); \ +	OFFSET(off); \ +	OP_ON_MEM(OP,*HL+off); \ +	break; \ + \ +    case BASE+7:	/* OP A,A */ \ +	TSTATE(4); \ +	OP(cpu->AF.b[HI]); \ +	break; + + +/* ---------------------------------------- CB OPCODE SHORT-HAND BLOCKS +*/ + +#define CB_ALU_BLOCK(BASE,OP) \ +    case BASE:		/* OP B */ \ +	TSTATE(8); \ +	OP(cpu->BC.b[HI]); \ +	break; \ + \ +    case BASE+1:	/* OP C */ \ +	TSTATE(8); \ +	OP(cpu->BC.b[LO]); \ +	break; \ + \ +    case BASE+2:	/* OP D */ \ +	TSTATE(8); \ +	OP(cpu->DE.b[HI]); \ +	break; \ + \ +    case BASE+3:	/* OP E */ \ +	TSTATE(8); \ +	OP(cpu->DE.b[LO]); \ +	break; \ + \ +    case BASE+4:	/* OP H */ \ +	TSTATE(8); \ +	OP(cpu->HL.b[HI]); \ +	break; \ + \ +    case BASE+5:	/* OP L */ \ +	TSTATE(8); \ +	OP(cpu->HL.b[LO]); \ +	break; \ + \ +    case BASE+6:	/* OP (HL) */ \ +	TSTATE(15); \ +	OP_ON_MEM(OP,cpu->HL.w); \ +	break; \ + \ +    case BASE+7:	/* OP A */ \ +	TSTATE(8); \ +	OP(cpu->AF.b[HI]); \ +	break; + +#define CB_BITMANIP_BLOCK(BASE,OP,BIT_NO) \ +    case BASE:		/* OP B */ \ +	TSTATE(8); \ +	OP(cpu->BC.b[HI],BIT_NO); \ +	break; \ + \ +    case BASE+1:	/* OP C */ \ +	TSTATE(8); \ +	OP(cpu->BC.b[LO],BIT_NO); \ +	break; \ + \ +    case BASE+2:	/* OP D */ \ +	TSTATE(8); \ +	OP(cpu->DE.b[HI],BIT_NO); \ +	break; \ + \ +    case BASE+3:	/* OP E */ \ +	TSTATE(8); \ +	OP(cpu->DE.b[LO],BIT_NO); \ +	break; \ + \ +    case BASE+4:	/* OP H */ \ +	TSTATE(8); \ +	OP(cpu->HL.b[HI],BIT_NO); \ +	break; \ + \ +    case BASE+5:	/* OP L */ \ +	TSTATE(8); \ +	OP(cpu->HL.b[LO],BIT_NO); \ +	break; \ + \ +    case BASE+6:	/* OP (HL) */ \ +	TSTATE(12); \ +	OP_ON_MEM_WITH_ARG(OP,cpu->HL.w,BIT_NO); \ +	break; \ + \ +    case BASE+7:	/* OP A */ \ +	TSTATE(8); \ +	OP(cpu->AF.b[HI],BIT_NO); \ +	break; + +/* ---------------------------------------- SHIFTED CB OPCODE SHORT-HAND BLOCKS +*/ + +#define SHIFTED_CB_ALU_BLOCK(BASE,OP) \ +    case BASE:		/* OP B */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->BC.b[HI]); \ +	break; \ + \ +    case BASE+1:	/* OP C */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->BC.b[LO]); \ +	break; \ + \ +    case BASE+2:	/* OP D */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->DE.b[HI]); \ +	break; \ + \ +    case BASE+3:	/* OP E */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->DE.b[LO]); \ +	break; \ + \ +    case BASE+4:	/* OP H */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->HL.b[HI]); \ +	break; \ + \ +    case BASE+5:	/* OP L */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->HL.b[LO]); \ +	break; \ + \ +    case BASE+6:	/* OP (HL) */ \ +	TSTATE(15); \ +	OP_ON_MEM(OP,addr); \ +	break; \ + \ +    case BASE+7:	/* OP A */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_COPY(OP,addr,cpu->AF.b[HI]); \ +	break; + +#define SHIFTED_CB_BITMANIP_BLOCK(BASE,OP,BIT_NO) \ +    case BASE:		/* OP B */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->BC.b[HI]); \ +	break; \ + \ +    case BASE+1:	/* OP C */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->BC.b[LO]); \ +	break; \ + \ +    case BASE+2:	/* OP D */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->DE.b[HI]); \ +	break; \ + \ +    case BASE+3:	/* OP E */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->DE.b[LO]); \ +	break; \ + \ +    case BASE+4:	/* OP H */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->HL.b[HI]); \ +	break; \ + \ +    case BASE+5:	/* OP L */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->HL.b[LO]); \ +	break; \ + \ +    case BASE+6:	/* OP (HL) */ \ +	TSTATE(12); \ +	OP_ON_MEM_WITH_ARG(OP,addr,BIT_NO); \ +	break; \ + \ +    case BASE+7:	/* OP A */ \ +	TSTATE(8); \ +	OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->AF.b[HI]); \ +	break; + +/* ---------------------------------------- DAA +*/ + +/* This alogrithm is based on info from +   http://www.worldofspectrum.org/faq/reference/z80reference.htm +*/ +static void DAA (Z80 *cpu) +{ +    Z80Byte add=0; +    Z80Byte carry=0; +    Z80Byte nf=cpu->AF.b[LO]&N_Z80; +    Z80Byte acc=cpu->AF.b[HI]; + +    if (acc>0x99 || IS_C) +    { +	add|=0x60; +	carry=C_Z80; +    } + +    if ((acc&0xf)>0x9 || IS_H) +    { +    	add|=0x06; +    } + +    if (nf) +    { +    	cpu->AF.b[HI]-=add; +    } +    else +    { +    	cpu->AF.b[HI]+=add; +    } + +    cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]] +		    | carry +		    | nf +		    | ((acc^cpu->AF.b[HI])&H_Z80) +		    | (cpu->AF.b[HI]&(B3_Z80|B5_Z80)); +} + +/* ---------------------------------------- HANDLERS FOR ED OPCODES +*/ +static void DecodeED(Z80 *cpu, Z80Byte opcode) +{ +    switch(opcode) +    { +	case 0x40:	/* IN B,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->BC.b[HI]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->BC.b[HI]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->BC.b[HI]]; +	    SETHIDDEN(cpu->BC.b[HI]); +	    break; + +	case 0x41:	/* OUT (C),B */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->BC.b[HI]); +	    break; + +	case 0x42:	/* SBC HL,BC */ +	    TSTATE(15); +	    SBC16(cpu->HL.w,cpu->BC.w); +	    break; + +	case 0x43:	/* LD (nnnn),BC */ +	    TSTATE(20); +	    POKEW(FETCH_WORD,cpu->BC.w); +	    break; + +	case 0x44:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x45:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x46:	/* IM 0 */ +	    TSTATE(8); +	    cpu->IM=0; +	    break; + +	case 0x47:	/* LD I,A */ +	    TSTATE(9); +	    cpu->I=cpu->AF.b[HI]; +	    break; + +	case 0x48:	/* IN C,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->BC.b[LO]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->BC.b[LO]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->BC.b[LO]]; +	    SETHIDDEN(cpu->BC.b[LO]); +	    break; + +	case 0x49:	/* OUT (C),C */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->BC.b[LO]); +	    break; + +	case 0x4a:	/* ADC HL,BC */ +	    TSTATE(15); +	    ADC16(cpu->HL.w,cpu->BC.w); +	    break; + +	case 0x4b:	/* LD BC,(nnnn) */ +	    TSTATE(20); +	    cpu->BC.w=PEEKW(FETCH_WORD); +	    break; + +	case 0x4c:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x4d:	/* RETI */ +	    TSTATE(14); +	    CALLBACK(eZ80_RETI,0); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x4e:	/* IM 0/1 */ +	    TSTATE(8); +	    cpu->IM=0; +	    break; + +	case 0x4f:	/* LD R,A */ +	    TSTATE(9); +	    cpu->R=cpu->AF.b[HI]; +	    break; + +	case 0x50:	/* IN D,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->DE.b[HI]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->DE.b[HI]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->DE.b[HI]]; +	    SETHIDDEN(cpu->BC.b[HI]); +	    break; + +	case 0x51:	/* OUT (C),D */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->DE.b[HI]); +	    break; + +	case 0x52:	/* SBC HL,DE */ +	    TSTATE(15); +	    SBC16(cpu->HL.w,cpu->DE.w); +	    break; + +	case 0x53:	/* LD (nnnn),DE */ +	    TSTATE(20); +	    POKEW(FETCH_WORD,cpu->DE.w); +	    break; + +	case 0x54:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x55:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x56:	/* IM 1 */ +	    TSTATE(8); +	    cpu->IM=1; +	    break; + +	case 0x57:	/* LD A,I */ +	    TSTATE(9); +	    cpu->AF.b[HI]=cpu->I; +	    break; + +	case 0x58:	/* IN E,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->DE.b[LO]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->BC.b[LO]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->DE.b[LO]]; +	    SETHIDDEN(cpu->DE.b[LO]); +	    break; + +	case 0x59:	/* OUT (C),E */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->DE.b[LO]); +	    break; + +	case 0x5a:	/* ADC HL,DE */ +	    TSTATE(15); +	    ADC16(cpu->HL.w,cpu->DE.w); +	    break; + +	case 0x5b:	/* LD DE,(nnnn) */ +	    TSTATE(20); +	    cpu->DE.w=PEEKW(FETCH_WORD); +	    break; + +	case 0x5c:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x5d:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x5e:	/* IM 2 */ +	    TSTATE(8); +	    cpu->IM=2; +	    break; + +	case 0x5f:	/* LD A,R */ +	    TSTATE(9); +	    cpu->AF.b[HI]=cpu->R; +	    break; + +	case 0x60:	/* IN H,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->HL.b[HI]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->HL.b[HI]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->HL.b[HI]]; +	    SETHIDDEN(cpu->HL.b[HI]); +	    break; + +	case 0x61:	/* OUT (C),H */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->HL.b[HI]); +	    break; + +	case 0x62:	/* SBC HL,HL */ +	    TSTATE(15); +	    SBC16(cpu->HL.w,cpu->HL.w); +	    break; + +	case 0x63:	/* LD (nnnn),HL */ +	    TSTATE(20); +	    POKEW(FETCH_WORD,cpu->HL.w); +	    break; + +	case 0x64:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x65:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x66:	/* IM 0 */ +	    TSTATE(8); +	    cpu->IM=0; +	    break; + +	case 0x67:	/* RRD */ +	    { +	    Z80Byte b; + +	    TSTATE(18); + +	    b=PEEK(cpu->HL.w); + +	    POKE(cpu->HL.w,(b>>4)|(cpu->AF.b[HI]<<4)); +	    cpu->AF.b[HI]=(cpu->AF.b[HI]&0xf0)|(b&0x0f); + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]]; +	    SETHIDDEN(cpu->AF.b[HI]); +	    break; +	    } + +	case 0x68:	/* IN L,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->HL.b[LO]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->HL.b[LO]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->HL.b[LO]]; +	    SETHIDDEN(cpu->HL.b[LO]); +	    break; + +	case 0x69:	/* OUT (C),L */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->HL.b[LO]); +	    break; + +	case 0x6a:	/* ADC HL,HL */ +	    TSTATE(15); +	    ADC16(cpu->HL.w,cpu->HL.w); +	    break; + +	case 0x6b:	/* LD HL,(nnnn) */ +	    TSTATE(20); +	    cpu->HL.w=PEEKW(FETCH_WORD); +	    break; + +	case 0x6c:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x6d:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x6e:	/* IM 0/1 */ +	    TSTATE(8); +	    cpu->IM=0; +	    break; + +	case 0x6f:	/* RLD */ +	    { +	    Z80Byte b; + +	    TSTATE(18); + +	    b=PEEK(cpu->HL.w); + +	    POKE(cpu->HL.w,(b<<4)|(cpu->AF.b[HI]&0x0f)); +	    cpu->AF.b[HI]=(cpu->AF.b[HI]&0xf0)|(b>>4); + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]]; +	    SETHIDDEN(cpu->AF.b[HI]); +	    break; +	    } + +	case 0x70:	/* IN (C) */ +	    { +	    Z80Byte b; + +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		b=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	b=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[b]; +	    SETHIDDEN(b); +	    break; +	    } + +	case 0x71:	/* OUT (C) */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,0); +	    break; + +	case 0x72:	/* SBC HL,SP */ +	    TSTATE(15); +	    SBC16(cpu->HL.w,cpu->SP); +	    break; + +	case 0x73:	/* LD (nnnn),SP */ +	    TSTATE(20); +	    POKEW(FETCH_WORD,cpu->SP); +	    break; + +	case 0x74:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x75:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x76:	/* IM 1 */ +	    TSTATE(8); +	    cpu->IM=1; +	    break; + +	case 0x77:	/* NOP */ +	    TSTATE(8); +	    CALLBACK(eZ80_EDHook,opcode); +	    break; + +	case 0x78:	/* IN A,(C) */ +	    TSTATE(12); + +	    if (PRIV->pread) +	    { +		cpu->AF.b[HI]=PRIV->pread(cpu,cpu->BC.w); +	    } +	    else +	    { +	    	cpu->AF.b[HI]=0; +	    } + +	    cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]]; +	    SETHIDDEN(cpu->AF.b[HI]); +	    break; + +	case 0x79:	/* OUT (C),A */ +	    TSTATE(12); +	    if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->AF.b[HI]); +	    break; + +	case 0x7a:	/* ADC HL,SP */ +	    TSTATE(15); +	    ADC16(cpu->HL.w,cpu->SP); +	    break; + +	case 0x7b:	/* LD SP,(nnnn) */ +	    TSTATE(20); +	    cpu->SP=PEEKW(FETCH_WORD); +	    break; + +	case 0x7c:	/* NEG */ +	    { +	    Z80Byte b; + +	    TSTATE(8); + +	    b=cpu->AF.b[HI]; +	    cpu->AF.b[HI]=0; +	    SUB8(b); +	    break; +	    } + +	case 0x7d:	/* RETN */ +	    TSTATE(14); +	    cpu->IFF1=cpu->IFF2; +	    POP(cpu->PC); +	    break; + +	case 0x7e:	/* IM 2 */ +	    TSTATE(8); +	    cpu->IM=2; +	    break; + +	case 0x7f:	/* NOP */ +	    TSTATE(8); +	    CALLBACK(eZ80_EDHook,opcode); +	    break; + +	case 0xa0:	/* LDI */ +	    TSTATE(16); +	    LDI; +	    break; + +	case 0xa1:	/* CPI */ +	    TSTATE(16); +	    CPI; +	    break; + +	case 0xa2:	/* INI */ +	    TSTATE(16); +	    INI; +	    break; + +	case 0xa3:	/* OUTI */ +	    TSTATE(16); +	    OUTI; +	    break; + +	case 0xa8:	/* LDD */ +	    TSTATE(16); +	    LDD; +	    break; + +	case 0xa9:	/* CPD */ +	    TSTATE(16); +	    CPD; +	    break; + +	case 0xaa:	/* IND */ +	    TSTATE(16); +	    IND; +	    break; + +	case 0xab:	/* OUTD */ +	    TSTATE(16); +	    OUTD; +	    break; + +	case 0xb0:	/* LDIR */ +	    TSTATE(16); +	    LDI; +	    if (cpu->BC.w) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xb1:	/* CPIR */ +	    TSTATE(16); +	    CPI; +	    if (cpu->BC.w && !IS_Z) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xb2:	/* INIR */ +	    TSTATE(16); +	    INI; +	    if (cpu->BC.w) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xb3:	/* OTIR */ +	    TSTATE(16); +	    OUTI; +	    if (cpu->BC.w) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xb8:	/* LDDR */ +	    TSTATE(16); +	    LDD; +	    if (cpu->BC.w) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xb9:	/* CPDR */ +	    TSTATE(16); +	    CPD; +	    if (cpu->BC.w && !IS_Z) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xba:	/* INDR */ +	    TSTATE(16); +	    IND; +	    if (cpu->BC.w) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	case 0xbb:	/* OTDR */ +	    TSTATE(16); +	    OUTD; +	    if (cpu->BC.w) +	    { +	    	TSTATE(5); +		cpu->PC-=2; +	    } +	    break; + +	/* All the rest are NOP/invalid +	*/ +    	default: +	    TSTATE(8); +	    CALLBACK(eZ80_EDHook,opcode); +	    break; +    } +} + + +/* ---------------------------------------- HANDLERS FOR CB OPCODES +*/ +static void DecodeCB(Z80 *cpu, Z80Byte opcode) +{ +    switch(opcode) +    { +    	CB_ALU_BLOCK(0x00,RLC) +    	CB_ALU_BLOCK(0x08,RRC) +    	CB_ALU_BLOCK(0x10,RL) +    	CB_ALU_BLOCK(0x18,RR) +    	CB_ALU_BLOCK(0x20,SLA) +    	CB_ALU_BLOCK(0x28,SRA) +    	CB_ALU_BLOCK(0x30,SLL) +    	CB_ALU_BLOCK(0x38,SRL) + +    	CB_BITMANIP_BLOCK(0x40,BIT,0) +    	CB_BITMANIP_BLOCK(0x48,BIT,1) +    	CB_BITMANIP_BLOCK(0x50,BIT,2) +    	CB_BITMANIP_BLOCK(0x58,BIT,3) +    	CB_BITMANIP_BLOCK(0x60,BIT,4) +    	CB_BITMANIP_BLOCK(0x68,BIT,5) +    	CB_BITMANIP_BLOCK(0x70,BIT,6) +    	CB_BITMANIP_BLOCK(0x78,BIT,7) + +    	CB_BITMANIP_BLOCK(0x80,BIT_RES,0) +    	CB_BITMANIP_BLOCK(0x88,BIT_RES,1) +    	CB_BITMANIP_BLOCK(0x90,BIT_RES,2) +    	CB_BITMANIP_BLOCK(0x98,BIT_RES,3) +    	CB_BITMANIP_BLOCK(0xa0,BIT_RES,4) +    	CB_BITMANIP_BLOCK(0xa8,BIT_RES,5) +    	CB_BITMANIP_BLOCK(0xb0,BIT_RES,6) +    	CB_BITMANIP_BLOCK(0xb8,BIT_RES,7) + +    	CB_BITMANIP_BLOCK(0xc0,BIT_SET,0) +    	CB_BITMANIP_BLOCK(0xc8,BIT_SET,1) +    	CB_BITMANIP_BLOCK(0xd0,BIT_SET,2) +    	CB_BITMANIP_BLOCK(0xd8,BIT_SET,3) +    	CB_BITMANIP_BLOCK(0xe0,BIT_SET,4) +    	CB_BITMANIP_BLOCK(0xe8,BIT_SET,5) +    	CB_BITMANIP_BLOCK(0xf0,BIT_SET,6) +    	CB_BITMANIP_BLOCK(0xf8,BIT_SET,7) +    } +} + + +static void ShiftedDecodeCB(Z80 *cpu, Z80Byte opcode, Z80Relative offset) +{ +    Z80Word addr; + +    /* See if we've come here from a IX/IY shift. +    */ +    switch (PRIV->shift) +    { +    	case 0xdd: +	    addr=cpu->IX.w+offset; +	    break; +    	case 0xfd: +	    addr=cpu->IY.w+offset; +	    break; +	default: +	    addr=cpu->HL.w;	/* Play safe... */ +	    break; +    } + +    switch(opcode) +    { +    	SHIFTED_CB_ALU_BLOCK(0x00,RLC) +    	SHIFTED_CB_ALU_BLOCK(0x08,RRC) +    	SHIFTED_CB_ALU_BLOCK(0x10,RL) +    	SHIFTED_CB_ALU_BLOCK(0x18,RR) +    	SHIFTED_CB_ALU_BLOCK(0x20,SLA) +    	SHIFTED_CB_ALU_BLOCK(0x28,SRA) +    	SHIFTED_CB_ALU_BLOCK(0x30,SLL) +    	SHIFTED_CB_ALU_BLOCK(0x38,SRL) + +    	SHIFTED_CB_BITMANIP_BLOCK(0x40,BIT,0) +    	SHIFTED_CB_BITMANIP_BLOCK(0x48,BIT,1) +    	SHIFTED_CB_BITMANIP_BLOCK(0x50,BIT,2) +    	SHIFTED_CB_BITMANIP_BLOCK(0x58,BIT,3) +    	SHIFTED_CB_BITMANIP_BLOCK(0x60,BIT,4) +    	SHIFTED_CB_BITMANIP_BLOCK(0x68,BIT,5) +    	SHIFTED_CB_BITMANIP_BLOCK(0x70,BIT,6) +    	SHIFTED_CB_BITMANIP_BLOCK(0x78,BIT,7) + +    	SHIFTED_CB_BITMANIP_BLOCK(0x80,BIT_RES,0) +    	SHIFTED_CB_BITMANIP_BLOCK(0x88,BIT_RES,1) +    	SHIFTED_CB_BITMANIP_BLOCK(0x90,BIT_RES,2) +    	SHIFTED_CB_BITMANIP_BLOCK(0x98,BIT_RES,3) +    	SHIFTED_CB_BITMANIP_BLOCK(0xa0,BIT_RES,4) +    	SHIFTED_CB_BITMANIP_BLOCK(0xa8,BIT_RES,5) +    	SHIFTED_CB_BITMANIP_BLOCK(0xb0,BIT_RES,6) +    	SHIFTED_CB_BITMANIP_BLOCK(0xb8,BIT_RES,7) + +    	SHIFTED_CB_BITMANIP_BLOCK(0xc0,BIT_SET,0) +    	SHIFTED_CB_BITMANIP_BLOCK(0xc8,BIT_SET,1) +    	SHIFTED_CB_BITMANIP_BLOCK(0xd0,BIT_SET,2) +    	SHIFTED_CB_BITMANIP_BLOCK(0xd8,BIT_SET,3) +    	SHIFTED_CB_BITMANIP_BLOCK(0xe0,BIT_SET,4) +    	SHIFTED_CB_BITMANIP_BLOCK(0xe8,BIT_SET,5) +    	SHIFTED_CB_BITMANIP_BLOCK(0xf0,BIT_SET,6) +    	SHIFTED_CB_BITMANIP_BLOCK(0xf8,BIT_SET,7) +    } +} + + +/* ---------------------------------------- NORMAL OPCODE DECODER +*/ +void Z80_Decode(Z80 *cpu, Z80Byte opcode) +{ +    Z80Word *HL; +    Z80Byte *H; +    Z80Byte *L; +    Z80Relative off; + +    /* See if we've come here from a IX/IY shift +    */ +    switch (PRIV->shift) +    { +    	case 0xdd: +	    HL=&(cpu->IX.w); +	    L=cpu->IX.b+LO; +	    H=cpu->IX.b+HI; +	    break; +    	case 0xfd: +	    HL=&(cpu->IY.w); +	    L=cpu->IY.b+LO; +	    H=cpu->IY.b+HI; +	    break; +	default: +	    HL=&(cpu->HL.w); +	    L=cpu->HL.b+LO; +	    H=cpu->HL.b+HI; +	    break; +    } + +    switch(opcode) +    { +	case 0x00:	/* NOP */ +	    TSTATE(4); +	    break; + +	case 0x01:	/* LD BC,nnnn */ +	    TSTATE(10); +	    cpu->BC.w=FETCH_WORD; +	    break; + +	case 0x02:	/* LD (BC),A */ +	    TSTATE(7); +	    POKE(cpu->BC.w,cpu->AF.b[HI]); +	    break; + +	case 0x03:	/* INC BC */ +	    TSTATE(6); +	    cpu->BC.w++; +	    break; + +	case 0x04:	/* INC B */ +	    TSTATE(4); +	    INC8(cpu->BC.b[HI]); +	    break; + +	case 0x05:	/* DEC B */ +	    TSTATE(4); +	    DEC8(cpu->BC.b[HI]); +	    break; + +	case 0x06:	/* LD B,n */ +	    TSTATE(7); +	    cpu->BC.b[HI]=FETCH_BYTE; +	    break; + +	case 0x07:	/* RLCA */ +	    TSTATE(4); +	    RLCA; +	    break; + +	case 0x08:	/* EX AF,AF' */ +	    TSTATE(4); +	    SWAP(cpu->AF.w,cpu->AF_); +	    break; + +	case 0x09:	/* ADD HL,BC */ +	    TSTATE(11); +	    ADD16(*HL,cpu->BC.w); +	    break; + +	case 0x0a:	/* LD A,(BC) */ +	    TSTATE(7); +	    cpu->AF.b[HI]=PEEK(cpu->BC.w); +	    break; + +	case 0x0b:	/* DEC BC */ +	    TSTATE(6); +	    cpu->BC.w--; +	    break; + +	case 0x0c:	/* INC C */ +	    TSTATE(4); +	    INC8(cpu->BC.b[LO]); +	    break; + +	case 0x0d:	/* DEC C */ +	    TSTATE(4); +	    DEC8(cpu->BC.b[LO]); +	    break; + +	case 0x0e:	/* LD C,n */ +	    TSTATE(7); +	    cpu->BC.b[LO]=FETCH_BYTE; +	    break; + +	case 0x0f:	/* RRCA */ +	    TSTATE(4); +	    RRCA; +	    break; + +	case 0x10:	/* DJNZ */ +	    if (--(cpu->BC.b[HI])) +	    { +		TSTATE(13); +		JR; +	    } +	    else +	    { +		TSTATE(8); +		NOJR; +	    } +	    break; + +	case 0x11:	/* LD DE,nnnn */ +	    TSTATE(10); +	    cpu->DE.w=FETCH_WORD; +	    break; + +	case 0x12:	/* LD (DE),A */ +	    TSTATE(7); +	    POKE(cpu->DE.w,cpu->AF.b[HI]); +	    break; + +	case 0x13:	/* INC DE */ +	    TSTATE(6); +	    cpu->DE.w++; +	    break; + +	case 0x14:	/* INC D */ +	    TSTATE(4); +	    INC8(cpu->DE.b[HI]); +	    break; + +	case 0x15:	/* DEC D */ +	    TSTATE(4); +	    DEC8(cpu->DE.b[HI]); +	    break; + +	case 0x16:	/* LD D,n */ +	    TSTATE(7); +	    cpu->DE.b[HI]=FETCH_BYTE; +	    break; + +	case 0x17:	/* RLA */ +	    TSTATE(4); +	    RLA; +	    break; + +	case 0x18:	/* JR d */ +	    TSTATE(12); +	    JR; +	    break; + +	case 0x19:	/* ADD HL,DE */ +	    TSTATE(11); +	    ADD16(*HL,cpu->DE.w); +	    break; + +	case 0x1a:	/* LD A,(DE) */ +	    TSTATE(7); +	    cpu->AF.b[HI]=PEEK(cpu->DE.w); +	    break; + +	case 0x1b:	/* DEC DE */ +	    TSTATE(6); +	    cpu->DE.w--; +	    break; + +	case 0x1c:	/* INC E */ +	    TSTATE(4); +	    INC8(cpu->DE.b[LO]); +	    break; + +	case 0x1d:	/* DEC E */ +	    TSTATE(4); +	    DEC8(cpu->DE.b[LO]); +	    break; + +	case 0x1e:	/* LD E,n */ +	    TSTATE(7); +	    cpu->DE.b[LO]=FETCH_BYTE; +	    break; + +	case 0x1f:	/* RRA */ +	    TSTATE(4); +	    RRA; +	    break; + +	case 0x20:	/* JR NZ,e */ +	    JR_COND(!IS_Z); +	    break; + +	case 0x21:	/* LD HL,nnnn */ +	    TSTATE(10); +	    *HL=FETCH_WORD; +	    break; + +	case 0x22:	/* LD (nnnn),HL */ +	    TSTATE(16); +	    POKEW(FETCH_WORD,*HL); +	    break; + +	case 0x23:	/* INC HL */ +	    TSTATE(6); +	    (*HL)++; +	    break; + +	case 0x24:	/* INC H */ +	    TSTATE(4); +	    INC8(*H); +	    break; + +	case 0x25:	/* DEC H */ +	    TSTATE(4); +	    DEC8(*H); +	    break; + +	case 0x26:	/* LD H,n */ +	    TSTATE(7); +	    *H=FETCH_BYTE; +	    break; + +	case 0x27:	/* DAA */ +	    TSTATE(4); +	    DAA(cpu); +	    break; + +	case 0x28:	/* JR Z,d */ +	    JR_COND(IS_Z); +	    break; + +	case 0x29:	/* ADD HL,HL */ +	    TSTATE(11); +	    ADD16(*HL,*HL); +	    break; + +	case 0x2a:	/* LD HL,(nnnn) */ +	    TSTATE(7); +	    *HL=PEEKW(FETCH_WORD); +	    break; + +	case 0x2b:	/* DEC HL */ +	    TSTATE(6); +	    (*HL)--; +	    break; + +	case 0x2c:	/* INC L */ +	    TSTATE(4); +	    INC8(*L); +	    break; + +	case 0x2d:	/* DEC L */ +	    TSTATE(4); +	    DEC8(*L); +	    break; + +	case 0x2e:	/* LD L,n */ +	    TSTATE(7); +	    *L=FETCH_BYTE; +	    break; + +	case 0x2f:	/* CPL */ +	    TSTATE(4); +	    cpu->AF.b[HI]^=0xff; +	    SETFLAG(H_Z80); +	    SETFLAG(N_Z80); +	    SETHIDDEN(cpu->AF.b[HI]); +	    break; + +	case 0x30:	/* JR NC,d */ +	    JR_COND(!IS_C); +	    break; + +	case 0x31:	/* LD SP,nnnn */ +	    TSTATE(10); +	    cpu->SP=FETCH_WORD; +	    break; + +	case 0x32:	/* LD (nnnn),A */ +	    TSTATE(13); +	    POKE(FETCH_WORD,cpu->AF.b[HI]); +	    break; + +	case 0x33:	/* INC SP */ +	    TSTATE(6); +	    cpu->SP++; +	    break; + +	case 0x34:	/* INC (HL) */ +	    TSTATE(11); +	    OFFSET(off); +	    OP_ON_MEM(INC8,*HL+off); +	    break; + +	case 0x35:	/* DEC (HL) */ +	    TSTATE(11); +	    OFFSET(off); +	    OP_ON_MEM(DEC8,*HL+off); +	    break; + +	case 0x36:	/* LD (HL),n */ +	    TSTATE(10); +	    OFFSET(off); +	    POKE(*HL+off,FETCH_BYTE); +	    break; + +	case 0x37:	/* SCF */ +	    TSTATE(4); +	    cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80)) +			  | C_Z80 +			  | (cpu->AF.b[HI]&(B3_Z80|B5_Z80)); +	    break; + +	case 0x38:	/* JR C,d */ +	    JR_COND(IS_C); +	    break; + +	case 0x39:	/* ADD HL,SP */ +	    TSTATE(11); +	    ADD16(*HL,cpu->SP); +	    break; + +	case 0x3a:	/* LD A,(nnnn) */ +	    TSTATE(13); +	    cpu->AF.b[HI]=PEEK(FETCH_WORD); +	    break; + +	case 0x3b:	/* DEC SP */ +	    TSTATE(6); +	    cpu->SP--; +	    break; + +	case 0x3c:	/* INC A */ +	    TSTATE(4); +	    INC8(cpu->AF.b[HI]); +	    break; + +	case 0x3d:	/* DEC A */ +	    TSTATE(4); +	    DEC8(cpu->AF.b[HI]); +	    break; + +	case 0x3e:	/* LD A,n */ +	    TSTATE(7); +	    cpu->AF.b[HI]=FETCH_BYTE; +	    break; + +	case 0x3f:	/* CCF */ +	    TSTATE(4); + +	    if (CARRY) +	    	SETFLAG(H_Z80); +	    else +	    	CLRFLAG(H_Z80); + +	    cpu->AF.b[LO]^=C_Z80; +	    SETHIDDEN(cpu->AF.b[HI]); +	    break; + +	LD_BLOCK(0x40,cpu->BC.b[HI],cpu->BC.b[HI]) +	LD_BLOCK(0x48,cpu->BC.b[LO],cpu->BC.b[LO]) +	LD_BLOCK(0x50,cpu->DE.b[HI],cpu->DE.b[HI]) +	LD_BLOCK(0x58,cpu->DE.b[LO],cpu->DE.b[LO]) +	LD_BLOCK(0x60,*H,cpu->HL.b[HI]) +	LD_BLOCK(0x68,*L,cpu->HL.b[LO]) + +	case 0x70:	/* LD (HL),B */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->BC.b[HI]); +	    break; + +	case 0x71:	/* LD (HL),C */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->BC.b[LO]); +	    break; + +	case 0x72:	/* LD (HL),D */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->DE.b[HI]); +	    break; + +	case 0x73:	/* LD (HL),E */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->DE.b[LO]); +	    break; + +	case 0x74:	/* LD (HL),H */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->HL.b[HI]); +	    break; + +	case 0x75:	/* LD (HL),L */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->HL.b[LO]); +	    break; + +	case 0x76:	/* HALT */ +	    TSTATE(4); +	    cpu->PC--; + +	    if (!PRIV->halt) +		CALLBACK(eZ80_Halt,1); + +	    PRIV->halt=TRUE; +	    break; + +	case 0x77:	/* LD (HL),A */ +	    TSTATE(7); +	    OFFSET(off); +	    POKE(*HL+off,cpu->AF.b[HI]); +	    break; + +	LD_BLOCK(0x78,cpu->AF.b[HI],cpu->AF.b[HI]) + +	ALU_BLOCK(0x80,ADD8) +	ALU_BLOCK(0x88,ADC8) +	ALU_BLOCK(0x90,SUB8) +	ALU_BLOCK(0x98,SBC8) +	ALU_BLOCK(0xa0,AND) +	ALU_BLOCK(0xa8,XOR) +	ALU_BLOCK(0xb0,OR) +	ALU_BLOCK(0xb8,CMP8) + +	case 0xc0:	/* RET NZ */ +	    RET_COND(!IS_Z); +	    break; + +	case 0xc1:	/* POP BC */ +	    TSTATE(10); +	    POP(cpu->BC.w); +	    break; + +	case 0xc2:	/* JP NZ,nnnn */ +	    JP_COND(!IS_Z); +	    break; + +	case 0xc3:	/* JP nnnn */ +	    JP_COND(1); +	    break; + +	case 0xc4:	/* CALL NZ,nnnn */ +	    CALL_COND(!IS_Z); +	    break; + +	case 0xc5:	/* PUSH BC */ +	    TSTATE(10); +	    PUSH(cpu->BC.w); +	    break; + +	case 0xc6:	/* ADD A,n */ +	    TSTATE(7); +	    ADD8(FETCH_BYTE); +	    break; + +	case 0xc7:	/* RST 0 */ +	    RST(0); +	    break; + +	case 0xc8:	/* RET Z */ +	    RET_COND(IS_Z); +	    break; + +	case 0xc9:	/* RET */ +	    TSTATE(10); +	    POP(cpu->PC); +	    break; + +	case 0xca:	/* JP Z,nnnn */ +	    JP_COND(IS_Z); +	    break; + +	case 0xcb:	/* CB PREFIX */ +	    INC_R; + +	    /* Check for previous IX/IY shift. +	    */ +	    if (PRIV->shift!=0) +	    { +		Z80Relative cb_offset; + +		TSTATE(4);	/* Wild stab in the dark! */ +		cb_offset=FETCH_BYTE; +		ShiftedDecodeCB(cpu,FETCH_BYTE,cb_offset); +	    } +	    else +	    { +		DecodeCB(cpu,FETCH_BYTE); +	    } +	    break; + +	case 0xcc:	/* CALL Z,nnnn */ +	    CALL_COND(IS_Z); +	    break; + +	case 0xcd:	/* CALL nnnn */ +	    CALL_COND(1); +	    break; + +	case 0xce:	/* ADC A,n */ +	    ADC8(FETCH_BYTE); +	    break; + +	case 0xcf:	/* RST 8 */ +	    RST(8); +	    break; + +	case 0xd0:	/* RET NC */ +	    RET_COND(!IS_C); +	    break; + +	case 0xd1:	/* POP DE */ +	    TSTATE(10); +	    POP(cpu->DE.w); +	    break; + +	case 0xd2:	/* JP NC,nnnn */ +	    JP_COND(!IS_C); +	    break; + +	case 0xd3:	/* OUT (n),A */ +	    TSTATE(11); +	    if (PRIV->pwrite) +	    { +		Z80Word port; + +		port=FETCH_BYTE; +		port|=(Z80Word)cpu->AF.b[HI]<<8; +	    	PRIV->pwrite(cpu,port,cpu->AF.b[HI]); +	    } +	    else +	    	cpu->PC++; +	    break; + +	case 0xd4:	/* CALL NC,nnnn */ +	    CALL_COND(!IS_C); +	    break; + +	case 0xd5:	/* PUSH DE */ +	    TSTATE(11); +	    PUSH(cpu->DE.w); +	    break; + +	case 0xd6:	/* SUB A,n */ +	    TSTATE(7); +	    SUB8(FETCH_BYTE); +	    break; + +	case 0xd7:	/* RST 10 */ +	    RST(0x10); +	    break; + +	case 0xd8:	/* RET C */ +	    RET_COND(IS_C); +	    break; + +	case 0xd9:	/* EXX */ +	    TSTATE(4); +	    SWAP(cpu->BC.w,cpu->BC_); +	    SWAP(cpu->DE.w,cpu->DE_); +	    SWAP(cpu->HL.w,cpu->HL_); +	    break; + +	case 0xda:	/* JP C,nnnn */ +	    JP_COND(IS_C); +	    break; + +	case 0xdb:	/* IN A,(n) */ +	    TSTATE(11); +	    if (PRIV->pread) +	    { +		Z80Word port; + +		port=FETCH_BYTE; +		port|=(Z80Word)cpu->AF.b[HI]<<8; +		cpu->AF.b[HI]=PRIV->pread(cpu,port); +	    } +	    else +	    	cpu->PC++; +	    break; + +	case 0xdc:	/* CALL C,nnnn */ +	    CALL_COND(IS_C); +	    break; + +	case 0xdd:	/* DD PREFIX */ +	    TSTATE(4); +	    INC_R; + +	    PRIV->shift=opcode; +	    Z80_Decode(cpu,FETCH_BYTE); +	    break; + +	case 0xde:	/* SBC A,n */ +	    TSTATE(7); +	    SBC8(FETCH_BYTE); +	    break; + +	case 0xdf:	/* RST 18 */ +	    RST(0x18); +	    break; + +	case 0xe0:	/* RET PO */ +	    RET_COND(!IS_P); +	    break; + +	case 0xe1:	/* POP HL */ +	    TSTATE(10); +	    POP(*HL); +	    break; + +	case 0xe2:	/* JP PO,nnnn */ +	    JP_COND(!IS_P); +	    break; + +	case 0xe3:	/* EX (SP),HL */ +	    { +	    Z80Word tmp; +	    TSTATE(19); +	    POP(tmp); +	    PUSH(*HL); +	    *HL=tmp; +	    } +	    break; + +	case 0xe4:	/* CALL PO,nnnn */ +	    CALL_COND(!IS_P); +	    break; + +	case 0xe5:	/* PUSH HL */ +	    TSTATE(10); +	    PUSH(*HL); +	    break; + +	case 0xe6:	/* AND A,n */ +	    TSTATE(7); +	    AND(FETCH_BYTE); +	    break; + +	case 0xe7:	/* RST 20 */ +	    RST(0x20); +	    break; + +	case 0xe8:	/* RET PE */ +	    RET_COND(IS_P); +	    break; + +	case 0xe9:	/* JP (HL) */ +	    TSTATE(4); +	    cpu->PC=*HL; +	    break; + +	case 0xea:	/* JP PE,nnnn */ +	    JP_COND(IS_P); +	    break; + +	case 0xeb:	/* EX DE,HL */ +	    TSTATE(4); +	    SWAP(cpu->DE.w,*HL); +	    break; + +	case 0xec:	/* CALL PE,nnnn */ +	    CALL_COND(IS_P); +	    break; + +	case 0xed:	/* ED PREFIX */ +	    INC_R; +	    DecodeED(cpu,FETCH_BYTE); +	    break; + +	case 0xee:	/* XOR A,n */ +	    TSTATE(7); +	    XOR(FETCH_BYTE); +	    break; + +	case 0xef:	/* RST 28 */ +	    RST(0x28); +	    break; + +	case 0xf0:	/* RET P */ +	    RET_COND(!IS_S); +	    break; + +	case 0xf1:	/* POP AF */ +	    TSTATE(10); +	    POP(cpu->AF.w); +	    break; + +	case 0xf2:	/* JP P,nnnn */ +	    JP_COND(!IS_S); +	    break; + +	case 0xf3:	/* DI */ +	    TSTATE(4); +	    cpu->IFF1=0; +	    cpu->IFF2=0; +	    break; + +	case 0xf4:	/* CALL P,nnnn */ +	    CALL_COND(!IS_S); +	    break; + +	case 0xf5:	/* PUSH AF */ +	    TSTATE(10); +	    PUSH(cpu->AF.w); +	    break; + +	case 0xf6:	/* OR A,n */ +	    TSTATE(7); +	    OR(FETCH_BYTE); +	    break; + +	case 0xf7:	/* RST 30 */ +	    RST(0x30); +	    break; + +	case 0xf8:	/* RET M */ +	    RET_COND(IS_S); +	    break; + +	case 0xf9:	/* LD SP,HL */ +	    TSTATE(6); +	    cpu->SP=*HL; +	    break; + +	case 0xfa:	/* JP M,nnnn */ +	    JP_COND(IS_S); +	    break; + +	case 0xfb:	/* EI */ +	    TSTATE(4); +	    cpu->IFF1=1; +	    cpu->IFF2=1; +	    break; + +	case 0xfc:	/* CALL M,nnnn */ +	    CALL_COND(IS_S); +	    break; + +	case 0xfd:	/* FD PREFIX */ +	    TSTATE(4); +	    INC_R; + +	    PRIV->shift=opcode; +	    Z80_Decode(cpu,FETCH_BYTE); +	    break; + +	case 0xfe:	/* CP A,n */ +	    TSTATE(7); +	    CMP8(FETCH_BYTE); +	    break; + +	case 0xff:	/* RST 38 */ +	    RST(0x38); +	    break; + +    } +} + + +/* END OF FILE */ diff --git a/source/z80_dis.c b/source/z80_dis.c new file mode 100644 index 0000000..8a8ade8 --- /dev/null +++ b/source/z80_dis.c @@ -0,0 +1,2494 @@ +/* + +    z80 - Z80 Emulator + +    Copyright (C) 2006  Ian Cowburn <ianc@noddybox.co.uk> + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    $Id$ + +*/ +static const char ident[]="$Id$"; + +#include "z80_config.h" + +#ifdef ENABLE_DISASSEM + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +#include "z80.h" +#include "z80_private.h" + +static Z80Relative	cb_off; + +/* ---------------------------------------- SHARED ROUTINES +*/ +static const char *z80_dis_reg8[]={"b","c","d","e","h","l","(hl)","a"}; +static const char *z80_dis_reg16[]={"bc","de","hl","sp"}; +static const char *z80_dis_condition[]={"nz","z","nc","c","po","pe","p","m"}; + +static const char *dis_op; +static const char *dis_arg; + +const char *Z80_Dis_Printf(const char *format, ...) +{ +    static int p=0; +    static char s[16][80]; +    va_list arg; + +    va_start(arg,format); +    p=(p+1)%16; +    vsprintf(s[p],format,arg); +    va_end(arg); + +    return s[p]; +} + + +Z80Byte Z80_Dis_FetchByte(Z80 *cpu, Z80Word *pc) +{ +#ifdef ENABLE_ARRAY_MEMORY +    return Z80_MEMORY[(*pc)++]; +#else +    return cpu->priv->disread(cpu,(*pc)++); +#endif +} + + +Z80Word Z80_Dis_FetchWord(Z80 *cpu, Z80Word *pc) +{ +    Z80Byte l,h; + +    l=Z80_Dis_FetchByte(cpu,pc); +    h=Z80_Dis_FetchByte(cpu,pc); + +    return ((Z80Word)h<<8)|l; +} + + +void Z80_Dis_Set(const char *op, const char *arg) +{ +    dis_op=op; +    dis_arg=arg; +} + + +const char *Z80_Dis_GetOp(void) +{ +    return dis_op ? dis_op : ""; +} + + +const char *Z80_Dis_GetArg(void) +{ +    return dis_arg ? dis_arg : ""; +} + + +static const char *GetLabel(Z80Word w) +{ +    if (z80_labels) +    { +    	int f; + +	for(f=0;z80_labels[f].label;f++) +	{ +	    if (z80_labels[f].address==w) +	    { +	    	return z80_labels[f].label; +	    } +	} +    } + +    return NULL; +} + + + +/* ---------------------------------------- CB xx BYTE OPCODES +*/ +static void DIS_RLC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("rlc",reg); +} + +static void DIS_RRC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("rrc",reg); +} + +static void DIS_RL_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("rl",reg); +} + +static void DIS_RR_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("rr",reg); +} + +static void DIS_SLA_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("sla",reg); +} + +static void DIS_SRA_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("sra",reg); +} + +static void DIS_SLL_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("sll",reg); +} + +static void DIS_SRL_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("srl",reg); +} + +static void DIS_BIT_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; +    int bit; + +    reg=z80_dis_reg8[op%8]; +    bit=(op-0x40)/8; +    Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s",bit,reg)); +} + +static void DIS_RES_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; +    int bit; + +    reg=z80_dis_reg8[op%8]; +    bit=(op-0x80)/8; +    Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s",bit,reg)); +} + +static void DIS_SET_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; +    int bit; + +    reg=z80_dis_reg8[op%8]; +    bit=(op-0xc0)/8; +    Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s",bit,reg)); +} + +/* ---------------------------------------- DD OPCODES +*/ + +static const char *IX_RelStr(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    static char s[80]; +    Z80Relative r; + +    r=(Z80Relative)Z80_Dis_FetchByte(z80,pc); + +    if (r<0) +	sprintf(s,"(ix-$%.2x)",-r); +    else +	sprintf(s,"(ix+$%.2x)",r); + +    return(s); +} + + +static const char *IX_RelStrCB(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    static char s[80]; +    Z80Relative r; + +    r=(Z80Relative)cb_off; + +    if (r<0) +	sprintf(s,"(ix-$%.2x)",-r); +    else +	sprintf(s,"(ix+$%.2x)",r); + +    return(s); +} + + +static const char *XR8(Z80 *z80, int reg, Z80Word *pc) +{ +    switch(reg) +    	{ +	case 0: +	    return("b"); +	    break; +	case 1: +	    return("c"); +	    break; +	case 2: +	    return("d"); +	    break; +	case 3: +	    return("e"); +	    break; +	case 4: +	    return("ixh"); +	    break; +	case 5: +	    return("ixl"); +	    break; +	case 6: +	    return(IX_RelStr(z80,0,pc)); +	    break; +	case 7: +	    return("a"); +	    break; +	default: +	    return(Z80_Dis_Printf("BUG %d",reg)); +	    break; +	} +} + +static void DIS_DD_NOP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    dis_opcode_z80[op](z80,op,pc); +} + +static void DIS_ADD_IX_BC(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","ix,bc"); +} +  +static void DIS_ADD_IX_DE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","ix,de"); +} + +static void DIS_LD_IX_WORD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld",Z80_Dis_Printf("ix,$%.4x",Z80_Dis_FetchWord(z80,pc))); +} + +static void DIS_LD_ADDR_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),ix",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),ix",w)); +} + +static void DIS_INC_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc","ix"); +} + +static void DIS_INC_IXH(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc","ixh"); +} + +static void DIS_DEC_IXH(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec","ixh"); +} + +static void DIS_LD_IXH_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld",Z80_Dis_Printf("ixh,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_ADD_IX_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","ix,ix"); +} + +static void DIS_LD_IX_ADDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("ix,(%s)",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("ix,($%.4x)",w)); +} + +static void DIS_DEC_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec","ix"); +} + +static void DIS_INC_IXL(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc","ixl"); +} + +static void DIS_DEC_IXL(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec","ixl"); +} + +static void DIS_LD_IXL_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld",Z80_Dis_Printf("ixl,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} +  +static void DIS_INC_IIX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc",Z80_Dis_Printf("%s",IX_RelStr(z80,op,pc))); +} + +static void DIS_DEC_IIX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec",Z80_Dis_Printf("%s",IX_RelStr(z80,op,pc))); +} + +static void DIS_LD_IIX_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *rel; +    int b; + +    rel=IX_RelStr(z80,op,pc); +    b=Z80_Dis_FetchByte(z80,pc); +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.2x",rel,b)); +} + + +static void DIS_ADD_IX_SP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","ix,sp"); +} +  +static void DIS_XLD_R8_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int src_r,dest_r; +    const char *src,*dest; + +    dest_r=(op-0x40)/8; +    src_r=op%8; + +    /* IX can't be used as source and destination when reading z80ory +    */ +    if (dest_r==6) +    	{ +	dest=XR8(z80,dest_r,pc); +	src=z80_dis_reg8[src_r]; +	} +    else if (((dest_r==4)||(dest_r==5))&&(src_r==6)) +    	{ +	dest=z80_dis_reg8[dest_r]; +	src=XR8(z80,src_r,pc); +	} +    else +	{ +	dest=XR8(z80,dest_r,pc); +	src=XR8(z80,src_r,pc); +	} + +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,%s",dest,src)); +} + +static void DIS_XADD_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XADC_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("adc",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XSUB_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sub",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XSBC_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sbc",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XAND_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("and",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XXOR_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("xor",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc))); +} + +static void DIS_X_OR_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("or",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XCP_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cp",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc))); +} + +static void DIS_POP_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("pop","ix"); +} + +static void DIS_EX_ISP_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ex","(sp),ix"); +} + +static void DIS_PUSH_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("push","ix"); +} + +static void DIS_JP_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("jp","(ix)"); +} +  +static void DIS_LD_SP_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","sp,ix"); +} + +static void DIS_DD_CB_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    cb_off=(Z80Relative)Z80_Dis_FetchByte(z80,pc); +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_DD_CB_opcode[nop](z80,nop,pc); +} + +static void DIS_DD_DD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_DD_opcode[nop](z80,nop,pc); +} + +static void DIS_DD_ED_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_ED_opcode[nop](z80,nop,pc); +} + +static void DIS_DD_FD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_FD_opcode[nop](z80,nop,pc); +} + + +/* ---------------------------------------- DD CB OPCODES +*/ + +static void DIS_RLC_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rlc",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +	{ +        Z80_Dis_Set("rlc",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +	} +} + +static void DIS_RRC_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rrc",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rrc",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RL_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rl",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rl",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RR_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rr",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rr",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SLA_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("sla",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("sla",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SRA_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("sra",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("sra",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SRL_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("srl",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("srl",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SLL_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("sll",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("sll",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_BIT_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; +    int bit; + +    reg=(op%8); +    bit=(op-0x40)/8; + +    if (reg==6) +        Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s",bit,IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s[%s]",bit,IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RES_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; +    int bit; + +    reg=(op%8); +    bit=(op-0x80)/8; + +    if (reg==6) +        Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s",bit,IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s[%s]",bit,IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SET_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; +    int bit; + +    reg=(op%8); +    bit=(op-0xc0)/8; + +    if (reg==6) +        Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s",bit,IX_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s[%s]",bit,IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + + +/* ---------------------------------------- ED OPCODES +*/ + +static const char *ER8(int reg) +{ +    switch(reg) +    	{ +	case 0: +	    return("b"); +	    break; +	case 1: +	    return("c"); +	    break; +	case 2: +	    return("d"); +	    break; +	case 3: +	    return("e"); +	    break; +	case 4: +	    return("h"); +	    break; +	case 5: +	    return("l"); +	    break; +	case 6: +	    return("0"); +	    break; +	case 7: +	    return("a"); +	    break; +	} + +    return "?"; +} + +/* Assumes illegal ED ops are being used for break points +*/ +static void DIS_ED_NOP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("brk",Z80_Dis_Printf("$%.2x",op)); +} + +static void DIS_IN_R8_C(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("in",Z80_Dis_Printf("%s,(c)",ER8((op-0x40)/8))); +} + +static void DIS_OUT_C_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("out",Z80_Dis_Printf("(c),%s",ER8((op-0x40)/8))); +} + +static void DIS_SBC_HL_R16(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sbc",Z80_Dis_Printf("hl,%s",z80_dis_reg16[(op-0x40)/16])); +} + +static void DIS_ED_LD_ADDR_R16(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),%s",p,z80_dis_reg16[(op-0x40)/16])); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),%s",w,z80_dis_reg16[(op-0x40)/16])); +} + +static void DIS_NEG(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("neg",NULL); +} + +static void DIS_RETN(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("retn",NULL); +} + +static void DIS_IM_0(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("im","0"); +} + +static void DIS_LD_I_A(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","i,a"); +} + +static void DIS_ADC_HL_R16(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("adc",Z80_Dis_Printf("hl,%s",z80_dis_reg16[(op-0x40)/16])); +} + +static void DIS_ED_LD_R16_ADDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("%s,(%s)",z80_dis_reg16[(op-0x40)/16],p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("%s,($%.4x)",z80_dis_reg16[(op-0x40)/16],w)); +} + +static void DIS_RETI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("reti",NULL); +} + +static void DIS_LD_R_A(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","r,a"); +} + +static void DIS_IM_1(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("im","1"); +} + +static void DIS_LD_A_I(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","a,i"); +} + +static void DIS_IM_2(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("im","2"); +} + +static void DIS_LD_A_R(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","a,r"); +} + +static void DIS_RRD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("rrd",NULL); +} + +static void DIS_RLD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("rld",NULL); +} + +static void DIS_LDI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ldi",NULL); +} + +static void DIS_CPI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cpi",NULL); +} + +static void DIS_INI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ini",NULL); +} + +static void DIS_OUTI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("outi",NULL); +} + +static void DIS_LDD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ldd",NULL); +} + +static void DIS_CPD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cpd",NULL); +} + +static void DIS_IND(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ind",NULL); +} + +static void DIS_OUTD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("outd",NULL); +} + +static void DIS_LDIR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ldir",NULL); +} + +static void DIS_CPIR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cpir",NULL); +} + +static void DIS_INIR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inir",NULL); +} + +static void DIS_OTIR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("otir",NULL); +} + +static void DIS_LDDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("lddr",NULL); +} + +static void DIS_CPDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cpdr",NULL); +} + +static void DIS_INDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("indr",NULL); +} + +static void DIS_OTDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("otdr",NULL); +} + + +/* ---------------------------------------- FD OPCODES +*/ + +static const char *IY_RelStr(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    static char s[80]; +    Z80Relative r; + +    r=(Z80Relative)Z80_Dis_FetchByte(z80,pc); + +    if (r<0) +	sprintf(s,"(iy-$%.2x)",-r); +    else +	sprintf(s,"(iy+$%.2x)",r); + +    return(s); +} + + +static const char *IY_RelStrCB(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    static char s[80]; +    Z80Relative r; + +    r=(Z80Relative)cb_off; + +    if (r<0) +	sprintf(s,"(iy-$%.2x)",-r); +    else +	sprintf(s,"(iy+$%.2x)",r); + +    return(s); +} + + +static const char *YR8(Z80 *z80, int reg, Z80Word *pc) +{ +    switch(reg) +    	{ +	case 0: +	    return("b"); +	    break; +	case 1: +	    return("c"); +	    break; +	case 2: +	    return("d"); +	    break; +	case 3: +	    return("e"); +	    break; +	case 4: +	    return("iyh"); +	    break; +	case 5: +	    return("iyl"); +	    break; +	case 6: +	    return(IY_RelStr(z80,0,pc)); +	    break; +	case 7: +	    return("a"); +	    break; +	default: +	    return(Z80_Dis_Printf("BUG %d",reg)); +	    break; +	} +} + +static void DIS_FD_NOP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    dis_opcode_z80[op](z80,op,pc); +} + +static void DIS_ADD_IY_BC(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","iy,bc"); +} +  +static void DIS_ADD_IY_DE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","iy,de"); +} + +static void DIS_LD_IY_WORD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld",Z80_Dis_Printf("iy,$%.4x",Z80_Dis_FetchWord(z80,pc))); +} + +static void DIS_LD_ADDR_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),iy",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),iy",w)); +} + +static void DIS_INC_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc","iy"); +} + +static void DIS_INC_IYH(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc","iyh"); +} + +static void DIS_DEC_IYH(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec","iyh"); +} + +static void DIS_LD_IYH_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld",Z80_Dis_Printf("iyh,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_ADD_IY_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","iy,iy"); +} + +static void DIS_LD_IY_ADDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("iy,(%s)",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("iy,($%.4x)",w)); +} + +static void DIS_DEC_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec","iy"); +} + +static void DIS_INC_IYL(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc","iyl"); +} + +static void DIS_DEC_IYL(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec","iyl"); +} + +static void DIS_LD_IYL_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld",Z80_Dis_Printf("iyl,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} +  +static void DIS_INC_IIY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("inc",Z80_Dis_Printf("%s",IY_RelStr(z80,op,pc))); +} + +static void DIS_DEC_IIY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("dec",Z80_Dis_Printf("%s",IY_RelStr(z80,op,pc))); +} + +static void DIS_LD_IIY_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *rel; +    int b; + +    rel=IY_RelStr(z80,op,pc); +    b=Z80_Dis_FetchByte(z80,pc); +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.2x",rel,b)); +} + + +static void DIS_ADD_IY_SP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add","iy,sp"); +} +  +static void DIS_YLD_R8_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int src_r,dest_r; +    const char *src,*dest; + +    dest_r=(op-0x40)/8; +    src_r=op%8; + +    /* IY can't be used as source and destination when reading z80ory +    */ +    if (dest_r==6) +	{ +	dest=YR8(z80,dest_r,pc); +	src=z80_dis_reg8[src_r]; +	} +    else if (((dest_r==4)||(dest_r==5))&&(src_r==6)) +	{ +	dest=z80_dis_reg8[dest_r]; +	src=YR8(z80,src_r,pc); +	} +    else +	{ +	dest=YR8(z80,dest_r,pc); +	src=YR8(z80,src_r,pc); +	} + +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,%s",dest,src)); +} + +static void DIS_YADD_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YADC_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("adc",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YSUB_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sub",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YSBC_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sbc",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YAND_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("and",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YYOR_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("xor",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc))); +} + +static void DIS_Y_OR_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("or",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YCP_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cp",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc))); +} + +static void DIS_POP_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("pop","iy"); +} + +static void DIS_EY_ISP_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ex","(sp),iy"); +} + +static void DIS_PUSH_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("push","iy"); +} + +static void DIS_JP_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("jp","(iy)"); +} +  +static void DIS_LD_SP_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","sp,iy"); +} + +static void DIS_FD_CB_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    cb_off=(Z80Relative)Z80_Dis_FetchByte(z80,pc); +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_FD_CB_opcode[nop](z80,nop,pc); +} + +static void DIS_FD_DD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_DD_opcode[nop](z80,nop,pc); +} + +static void DIS_FD_ED_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_ED_opcode[nop](z80,nop,pc); +} + +static void DIS_FD_FD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_FD_opcode[nop](z80,nop,pc); +} + + +/* ---------------------------------------- FD CB OPCODES +*/ + +static void DIS_RLC_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rlc",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rlc",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RRC_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rrc",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rrc",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RL_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rl",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rl",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RR_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("rr",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("rr",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SLA_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("sla",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("sla",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SRA_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("sra",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("sra",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SRL_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("srl",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("srl",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SLL_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; + +    reg=(op%8); + +    if (reg==6) +        Z80_Dis_Set("sll",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("sll",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_BIT_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; +    int bit; + +    reg=(op%8); +    bit=(op-0x40)/8; + +    if (reg==6) +        Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s",bit,IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s[%s]",bit,IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RES_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; +    int bit; + +    reg=(op%8); +    bit=(op-0x80)/8; + +    if (reg==6) +        Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s",bit,IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s[%s]",bit,IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SET_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int reg; +    int bit; + +    reg=(op%8); +    bit=(op-0xc0)/8; + +    if (reg==6) +        Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s",bit,IY_RelStrCB(z80,op,pc))); +    else +        Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s[%s]",bit,IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + + +/* ---------------------------------------- SINGLE BYTE OPCODES +*/ +static void DIS_NOP (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("nop",NULL); +} + +static void DIS_LD_R16_WORD (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op&0x30)/0x10]; +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.4x",reg,Z80_Dis_FetchWord(z80,pc))); +} + +static void DIS_LD_R16_A (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op&0x30)/0x10]; +    Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),a",reg)); +} + +static void DIS_INC_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op&0x30)/0x10]; +    Z80_Dis_Set("inc",reg); +} + +static void DIS_INC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[(op&0x38)/0x8]; +    Z80_Dis_Set("inc",reg); +} + +static void DIS_DEC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[(op&0x38)/0x8]; +    Z80_Dis_Set("dec",reg); +} + +static void DIS_LD_R8_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[(op&0x38)/0x8]; +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.2x",reg,Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_RLCA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("rlca",NULL); +} + +static void DIS_EX_AF_AF (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ex","af,af'"); +} + +static void DIS_ADD_HL_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op&0x30)/0x10]; +    Z80_Dis_Set("add",Z80_Dis_Printf("hl,%s",reg)); +} + +static void DIS_LD_A_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op&0x30)/0x10]; +    Z80_Dis_Set("ld",Z80_Dis_Printf("a,(%s)",reg)); +} + +static void DIS_DEC_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op&0x30)/0x10]; +    Z80_Dis_Set("dec",reg); +} + +static void DIS_RRCA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("rrca",NULL); +} + +static void DIS_DJNZ (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word new; + +#ifdef ENABLE_ARRAY_MEMORY +    new=*pc+(Z80Relative)Z80_MEMORY[*pc]+1; +#else +    new=*pc+(Z80Relative)z80->priv->disread(z80,*pc)+1; +#endif +    (*pc)++; +    Z80_Dis_Set("djnz",Z80_Dis_Printf("$%.4x",new)); +} + +static void DIS_RLA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("rla",NULL); +} + +static void DIS_JR (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word new; +    const char *p; + +#ifdef ENABLE_ARRAY_MEMORY +    new=*pc+(Z80Relative)Z80_MEMORY[*pc]+1; +#else +    new=*pc+(Z80Relative)z80->priv->disread(z80,*pc)+1; +#endif +    (*pc)++; + +    if ((p=GetLabel(new))) +	Z80_Dis_Set("jr",Z80_Dis_Printf("%s",p)); +    else +	Z80_Dis_Set("jr",Z80_Dis_Printf("$%.4x",new)); +} + +static void DIS_RRA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("rra",NULL); +} + +static void DIS_JR_CO (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *con; +    Z80Word new; +    const char *p; + +    con=z80_dis_condition[(op-0x20)/8]; +#ifdef ENABLE_ARRAY_MEMORY +    new=*pc+(Z80Relative)Z80_MEMORY[*pc]+1; +#else +    new=*pc+(Z80Relative)z80->priv->disread(z80,*pc)+1; +#endif +    (*pc)++; + +    if ((p=GetLabel(new))) +	Z80_Dis_Set("jr",Z80_Dis_Printf("%s,%s",con,p)); +    else +	Z80_Dis_Set("jr",Z80_Dis_Printf("%s,$%.4x",con,new)); +} + +static void DIS_LD_ADDR_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),hl",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),hl",w)); +} + +static void DIS_DAA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("daa",NULL); +} + +static void DIS_LD_HL_ADDR (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("hl,(%s)",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("hl,($%.4x)",w)); +} + +static void DIS_CPL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cpl",NULL); +} + +static void DIS_LD_ADDR_A (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),a",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),a",w)); +} + +static void DIS_SCF (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("scf",NULL); +} + +static void DIS_LD_A_ADDR (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("ld",Z80_Dis_Printf("a,(%s)",p)); +    else +	Z80_Dis_Set("ld",Z80_Dis_Printf("a,($%.4x)",w)); +} + +static void DIS_CCF (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ccf",NULL); +} + +static void DIS_LD_R8_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *src,*dest; + +    dest=z80_dis_reg8[(op-0x40)/8]; +    src=z80_dis_reg8[op%8]; +    Z80_Dis_Set("ld",Z80_Dis_Printf("%s,%s",dest,src)); +} + +static void DIS_HALT (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("halt",NULL); +} + +static void DIS_ADD_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("add",Z80_Dis_Printf("a,%s",reg)); +} + +static void DIS_ADC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("adc",Z80_Dis_Printf("a,%s",reg)); +} + +static void DIS_SUB_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("sub",Z80_Dis_Printf("a,%s",reg)); +} + +static void DIS_SBC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("sbc",Z80_Dis_Printf("a,%s",reg)); +} + +static void DIS_AND_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("and",Z80_Dis_Printf("%s",reg)); +} + +static void DIS_XOR_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("xor",Z80_Dis_Printf("%s",reg)); +} + +static void DIS_OR_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("or",Z80_Dis_Printf("%s",reg)); +} + +static void DIS_CP_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg8[op%8]; +    Z80_Dis_Set("cp",Z80_Dis_Printf("%s",reg)); +} + + +static void DIS_RET_CO (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *con; + +    con=z80_dis_condition[(op-0xc0)/8]; +    Z80_Dis_Set("ret",con); +} + +static void DIS_POP_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op-0xc0)/16]; + +    if (!strcmp(reg,"sp")) +    	reg="af"; + +    Z80_Dis_Set("pop",reg); +} + +static void DIS_JP (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("jp",Z80_Dis_Printf("%s",p)); +    else +	Z80_Dis_Set("jp",Z80_Dis_Printf("$%.4x",w)); +} + +static void DIS_PUSH_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *reg; + +    reg=z80_dis_reg16[(op-0xc0)/16]; + +    if (!strcmp(reg,"sp")) +    	reg="af"; + +    Z80_Dis_Set("push",reg); +} + +static void DIS_ADD_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("add",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_RST (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int add; + +    add=(op&0x3f)-7; +    Z80_Dis_Set("rst",Z80_Dis_Printf("%.2xh",add)); +} + +static void DIS_RET (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ret",NULL); +} + +static void DIS_JP_CO (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *con; +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); +    con=z80_dis_condition[(op-0xc0)/8]; + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("jp",Z80_Dis_Printf("%s,%s",con,p)); +    else +	Z80_Dis_Set("jp",Z80_Dis_Printf("%s,$%.4x",con,w)); +} + +static void DIS_CB_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_CB_opcode[nop](z80,nop,pc); +} + +static void DIS_CALL_CO (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    const char *con; +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); +    con=z80_dis_condition[(op-0xc0)/8]; + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("call",Z80_Dis_Printf("%s,%s",con,p)); +    else +	Z80_Dis_Set("call",Z80_Dis_Printf("%s,$%.4x",con,w)); +} + +static void DIS_CALL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80Word w; +    const char *p; + +    w=Z80_Dis_FetchWord(z80,pc); + +    if ((p=GetLabel(w))) +	Z80_Dis_Set("call",Z80_Dis_Printf("%s",p)); +    else +	Z80_Dis_Set("call",Z80_Dis_Printf("$%.4x",w)); +} + +static void DIS_ADC_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("adc",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_OUT_BYTE_A (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("out",Z80_Dis_Printf("($%.2x),a",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_SUB_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sub",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_EXX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("exx",NULL); +} + +static void DIS_IN_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("in",Z80_Dis_Printf("a,($%.2x)",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_DD_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_DD_opcode[nop](z80,nop,pc); +} + +static void DIS_SBC_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("sbc",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + + +static void DIS_EX_ISP_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ex","(sp),hl"); +} + +static void DIS_AND_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("and",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_JP_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("jp","(hl)"); +} + +static void DIS_EX_DE_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ex","de,hl"); +} + +static void DIS_ED_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_ED_opcode[nop](z80,nop,pc); +} + +static void DIS_XOR_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("xor",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_DI (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("di",NULL); +} + +static void DIS_OR_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("or",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_LD_SP_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ld","sp,hl"); +} + +static void DIS_EI (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("ei",NULL); +} + +static void DIS_FD_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    int nop; + +    nop=Z80_Dis_FetchByte(z80,pc); +    dis_FD_opcode[nop](z80,nop,pc); +} + +static void DIS_CP_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ +    Z80_Dis_Set("cp",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + + +/* ---------------------------------------- TABLES +*/ + +/* CB opcodes +*/ +DIS_OP_CALLBACK	dis_CB_opcode[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_RLC_R8,  DIS_RLC_R8,    DIS_RLC_R8,    DIS_RLC_R8, +/* 0x04 - 0x07 */    DIS_RLC_R8,  DIS_RLC_R8,    DIS_RLC_R8,    DIS_RLC_R8, +/* 0x08 - 0x0b */    DIS_RRC_R8,  DIS_RRC_R8,    DIS_RRC_R8,    DIS_RRC_R8, +/* 0x0c - 0x0f */    DIS_RRC_R8,  DIS_RRC_R8,    DIS_RRC_R8,    DIS_RRC_R8, + +/* 0x10 - 0x13 */    DIS_RL_R8,  DIS_RL_R8,    DIS_RL_R8,    DIS_RL_R8,   +/* 0x14 - 0x17 */    DIS_RL_R8,  DIS_RL_R8,    DIS_RL_R8,    DIS_RL_R8, +/* 0x18 - 0x1b */    DIS_RR_R8,  DIS_RR_R8,    DIS_RR_R8,    DIS_RR_R8,   +/* 0x1c - 0x1f */    DIS_RR_R8,  DIS_RR_R8,    DIS_RR_R8,    DIS_RR_R8, + +/* 0x20 - 0x23 */    DIS_SLA_R8,  DIS_SLA_R8,    DIS_SLA_R8,    DIS_SLA_R8, +/* 0x24 - 0x27 */    DIS_SLA_R8,  DIS_SLA_R8,    DIS_SLA_R8,    DIS_SLA_R8, +/* 0x28 - 0x2b */    DIS_SRA_R8,  DIS_SRA_R8,    DIS_SRA_R8,    DIS_SRA_R8, +/* 0x2c - 0x2f */    DIS_SRA_R8,  DIS_SRA_R8,    DIS_SRA_R8,    DIS_SRA_R8, + +/* 0x30 - 0x33 */    DIS_SLL_R8,  DIS_SLL_R8,    DIS_SLL_R8,    DIS_SLL_R8, +/* 0x34 - 0x37 */    DIS_SLL_R8,  DIS_SLL_R8,    DIS_SLL_R8,    DIS_SLL_R8, +/* 0x38 - 0x3b */    DIS_SRL_R8,  DIS_SRL_R8,    DIS_SRL_R8,    DIS_SRL_R8, +/* 0x3c - 0x3f */    DIS_SRL_R8,  DIS_SRL_R8,    DIS_SRL_R8,    DIS_SRL_R8, + +/* 0x40 - 0x43 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x44 - 0x47 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x48 - 0x4b */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x4c - 0x4f */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, + +/* 0x50 - 0x53 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x54 - 0x57 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x58 - 0x5b */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x5c - 0x5f */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, + +/* 0x60 - 0x63 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x64 - 0x67 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x68 - 0x6b */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x6c - 0x6f */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, + +/* 0x70 - 0x73 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x74 - 0x77 */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x78 - 0x7b */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, +/* 0x7c - 0x7f */    DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8,  DIS_BIT_R8, + +/* 0x80 - 0x83 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0x84 - 0x87 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0x88 - 0x8b */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0x8c - 0x8f */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, + +/* 0x90 - 0x93 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0x94 - 0x97 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0x98 - 0x9b */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0x9c - 0x9f */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, + +/* 0xa0 - 0xa3 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0xa4 - 0xa7 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0xa8 - 0xab */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0xac - 0xaf */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, + +/* 0xb0 - 0xb3 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0xb4 - 0xb7 */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0xb8 - 0xbb */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, +/* 0xbc - 0xbf */    DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8,  DIS_RES_R8, + +/* 0xc0 - 0xc3 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xc4 - 0xc7 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xc8 - 0xcb */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xcc - 0xcf */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, + +/* 0xd0 - 0xd3 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xd4 - 0xd7 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xd8 - 0xdb */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xdc - 0xdf */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, + +/* 0xe0 - 0xe3 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xe4 - 0xe7 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xe8 - 0xeb */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xec - 0xef */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, + +/* 0xf0 - 0xf3 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xf4 - 0xf7 */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xf8 - 0xfb */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +/* 0xfc - 0xff */    DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8,  DIS_SET_R8, +        }; + +/* DIS_DD opcodes +*/ +DIS_OP_CALLBACK	dis_DD_opcode[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x04 - 0x07 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x08 - 0x0b */    DIS_DD_NOP,	DIS_ADD_IX_BC,	DIS_DD_NOP,		DIS_DD_NOP,	 +/* 0x0c - 0x0f */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP,		 + +/* 0x10 - 0x13 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x14 - 0x17 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x18 - 0x1b */    DIS_DD_NOP,	DIS_ADD_IX_DE,	DIS_DD_NOP,		DIS_DD_NOP,	 +/* 0x1c - 0x1f */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP,		 + +/* 0x20 - 0x23 */    DIS_DD_NOP,	DIS_LD_IX_WORD,	DIS_LD_ADDR_IX,	DIS_INC_IX, +/* 0x24 - 0x27 */    DIS_INC_IXH,	DIS_DEC_IXH,	DIS_LD_IXH_BYTE,	DIS_DD_NOP, +/* 0x28 - 0x2b */    DIS_DD_NOP,	DIS_ADD_IX_IX,	DIS_LD_IX_ADDR,	DIS_DEC_IX, +/* 0x2c - 0x2f */    DIS_INC_IXL,	DIS_DEC_IXL,	DIS_LD_IXL_BYTE,	DIS_DD_NOP, + +/* 0x30 - 0x33 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x34 - 0x37 */    DIS_INC_IIX,	DIS_DEC_IIX,	DIS_LD_IIX_BYTE,	DIS_DD_NOP, +/* 0x38 - 0x3b */    DIS_DD_NOP,	DIS_ADD_IX_SP,	DIS_DD_NOP,		DIS_DD_NOP, +/* 0x3c - 0x3f */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, + +/* 0x40 - 0x43 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x44 - 0x47 */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_DD_NOP, +/* 0x48 - 0x4b */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x4c - 0x4f */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_DD_NOP, + +/* 0x50 - 0x53 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x54 - 0x57 */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_DD_NOP, +/* 0x58 - 0x5b */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x5c - 0x5f */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_DD_NOP, + +/* 0x60 - 0x63 */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8, +/* 0x64 - 0x67 */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8, +/* 0x68 - 0x6b */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8, +/* 0x6c - 0x6f */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8, + +/* 0x70 - 0x73 */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8, +/* 0x74 - 0x77 */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_DD_NOP,		DIS_XLD_R8_R8, +/* 0x78 - 0x7b */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x7c - 0x7f */    DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_XLD_R8_R8,	DIS_DD_NOP, + +/* 0x80 - 0x83 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x84 - 0x87 */    DIS_XADD_R8,	DIS_XADD_R8,	DIS_XADD_R8,	DIS_DD_NOP, +/* 0x88 - 0x8b */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x8c - 0x8f */    DIS_XADC_R8,	DIS_XADC_R8,	DIS_XADC_R8,	DIS_DD_NOP, + +/* 0x90 - 0x93 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x94 - 0x97 */    DIS_XSUB_R8,	DIS_XSUB_R8,	DIS_XSUB_R8,	DIS_DD_NOP, +/* 0x98 - 0x9b */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0x9c - 0x9f */    DIS_XSBC_R8,	DIS_XSBC_R8,	DIS_XSBC_R8,	DIS_DD_NOP, + +/* 0xa0 - 0xa3 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xa4 - 0xa7 */    DIS_XAND_R8,	DIS_XAND_R8,	DIS_XAND_R8,	DIS_DD_NOP, +/* 0xa8 - 0xab */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xac - 0xaf */    DIS_XXOR_R8,	DIS_XXOR_R8,	DIS_XXOR_R8,	DIS_DD_NOP, + +/* 0xb0 - 0xb3 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xb4 - 0xb7 */    DIS_X_OR_R8,	DIS_X_OR_R8,	DIS_X_OR_R8,	DIS_DD_NOP, +/* 0xb8 - 0xbb */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xbc - 0xbf */    DIS_XCP_R8,	DIS_XCP_R8,		DIS_XCP_R8,		DIS_DD_NOP, + +/* 0xc0 - 0xc3 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xc4 - 0xc7 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xc8 - 0xcb */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_CB_DECODE, +/* 0xcc - 0xcf */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, + +/* 0xd0 - 0xd3 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xd4 - 0xd7 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xd8 - 0xdb */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xdc - 0xdf */    DIS_DD_NOP,	DIS_DD_DD_DECODE,	DIS_DD_NOP,		DIS_DD_NOP, + +/* 0xe0 - 0xe3 */    DIS_DD_NOP,	DIS_POP_IX,		DIS_DD_NOP,		DIS_EX_ISP_IX, +/* 0xe4 - 0xe7 */    DIS_DD_NOP,	DIS_PUSH_IX,	DIS_DD_NOP,		DIS_DD_NOP, +/* 0xe8 - 0xeb */    DIS_DD_NOP,	DIS_JP_IX,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xec - 0xef */    DIS_DD_NOP,	DIS_DD_ED_DECODE,	DIS_DD_NOP,		DIS_DD_NOP, + +/* 0xf0 - 0xf3 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xf4 - 0xf7 */    DIS_DD_NOP,	DIS_DD_NOP,		DIS_DD_NOP,		DIS_DD_NOP, +/* 0xf8 - 0xfb */    DIS_DD_NOP,	DIS_LD_SP_IX,	DIS_DD_NOP,		DIS_DD_NOP, +/* 0xfc - 0xff */    DIS_DD_NOP,	DIS_DD_FD_DECODE,	DIS_DD_NOP,		DIS_DD_NOP, +		    }; + + +/* DIS_DD DIS_CB opcodes +*/ +DIS_OP_CALLBACK	dis_DD_CB_opcode[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_RLC_IX,	DIS_RLC_IX,		DIS_RLC_IX,		DIS_RLC_IX, +/* 0x04 - 0x07 */    DIS_RLC_IX,	DIS_RLC_IX,		DIS_RLC_IX,		DIS_RLC_IX, +/* 0x08 - 0x0b */    DIS_RRC_IX,	DIS_RRC_IX,		DIS_RRC_IX,		DIS_RRC_IX, +/* 0x0c - 0x0f */    DIS_RRC_IX,	DIS_RRC_IX,		DIS_RRC_IX,		DIS_RRC_IX, + +/* 0x10 - 0x13 */    DIS_RL_IX,	DIS_RL_IX,		DIS_RL_IX,		DIS_RL_IX,	 +/* 0x14 - 0x17 */    DIS_RL_IX,	DIS_RL_IX,		DIS_RL_IX,		DIS_RL_IX, +/* 0x18 - 0x1b */    DIS_RR_IX,	DIS_RR_IX,		DIS_RR_IX,		DIS_RR_IX,	 +/* 0x1c - 0x1f */    DIS_RR_IX,	DIS_RR_IX,		DIS_RR_IX,		DIS_RR_IX, + +/* 0x20 - 0x23 */    DIS_SLA_IX,	DIS_SLA_IX,		DIS_SLA_IX,		DIS_SLA_IX, +/* 0x24 - 0x27 */    DIS_SLA_IX,	DIS_SLA_IX,		DIS_SLA_IX,		DIS_SLA_IX, +/* 0x28 - 0x2b */    DIS_SRA_IX,	DIS_SRA_IX,		DIS_SRA_IX,		DIS_SRA_IX, +/* 0x2c - 0x2f */    DIS_SRA_IX,	DIS_SRA_IX,		DIS_SRA_IX,		DIS_SRA_IX, + +/* 0x30 - 0x33 */    DIS_SLL_IX,	DIS_SLL_IX,		DIS_SLL_IX,		DIS_SLL_IX, +/* 0x34 - 0x37 */    DIS_SLL_IX,	DIS_SLL_IX,		DIS_SLL_IX,		DIS_SLL_IX, +/* 0x38 - 0x3b */    DIS_SRL_IX,	DIS_SRL_IX,		DIS_SRL_IX,		DIS_SRL_IX, +/* 0x3c - 0x3f */    DIS_SRL_IX,	DIS_SRL_IX,		DIS_SRL_IX,		DIS_SRL_IX, + +/* 0x40 - 0x43 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x44 - 0x47 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x48 - 0x4b */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x4c - 0x4f */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, + +/* 0x50 - 0x53 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x54 - 0x57 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x58 - 0x5b */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x5c - 0x5f */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, + +/* 0x60 - 0x63 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x64 - 0x67 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x68 - 0x6b */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x6c - 0x6f */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, + +/* 0x70 - 0x73 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x74 - 0x77 */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x78 - 0x7b */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, +/* 0x7c - 0x7f */    DIS_BIT_IX,DIS_BIT_IX,	DIS_BIT_IX,	DIS_BIT_IX, + +/* 0x80 - 0x83 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0x84 - 0x87 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0x88 - 0x8b */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0x8c - 0x8f */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, + +/* 0x90 - 0x93 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0x94 - 0x97 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0x98 - 0x9b */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0x9c - 0x9f */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, + +/* 0xa0 - 0xa3 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0xa4 - 0xa7 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0xa8 - 0xab */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0xac - 0xaf */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, + +/* 0xb0 - 0xb3 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0xb4 - 0xb7 */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0xb8 - 0xbb */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, +/* 0xbc - 0xbf */    DIS_RES_IX,DIS_RES_IX,	DIS_RES_IX,	DIS_RES_IX, + +/* 0xc0 - 0xc3 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xc4 - 0xc7 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xc8 - 0xcb */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xcc - 0xcf */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, + +/* 0xd0 - 0xd3 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xd4 - 0xd7 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xd8 - 0xdb */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xdc - 0xdf */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, + +/* 0xe0 - 0xe3 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xe4 - 0xe7 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xe8 - 0xeb */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xec - 0xef */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, + +/* 0xf0 - 0xf3 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xf4 - 0xf7 */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xf8 - 0xfb */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +/* 0xfc - 0xff */    DIS_SET_IX,DIS_SET_IX,	DIS_SET_IX,	DIS_SET_IX, +		    }; + +/* DIS_ED opcodes +*/ +DIS_OP_CALLBACK	dis_ED_opcode[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x04 - 0x07 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x08 - 0x0b */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0x0c - 0x0f */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0x10 - 0x13 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x14 - 0x17 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x18 - 0x1b */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0x1c - 0x1f */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0x20 - 0x23 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x24 - 0x27 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x28 - 0x2b */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0x2c - 0x2f */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0x30 - 0x33 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x34 - 0x37 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x38 - 0x3b */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0x3c - 0x3f */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0x40 - 0x43 */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_SBC_HL_R16,	DIS_ED_LD_ADDR_R16, +/* 0x44 - 0x47 */    DIS_NEG,	DIS_RETN,		DIS_IM_0,		DIS_LD_I_A, +/* 0x48 - 0x4b */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_ADC_HL_R16,	DIS_ED_LD_R16_ADDR, +/* 0x4c - 0x4f */    DIS_NEG,	DIS_RETI,		DIS_IM_0,		DIS_LD_R_A, + +/* 0x50 - 0x53 */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_SBC_HL_R16,	DIS_ED_LD_ADDR_R16, +/* 0x54 - 0x57 */    DIS_NEG,	DIS_RETN,		DIS_IM_1,		DIS_LD_A_I, +/* 0x58 - 0x5b */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_ADC_HL_R16,	DIS_ED_LD_R16_ADDR, +/* 0x5c - 0x5f */    DIS_NEG,	DIS_RETI,		DIS_IM_2,		DIS_LD_A_R, + +/* 0x60 - 0x63 */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_SBC_HL_R16,	DIS_ED_LD_ADDR_R16, +/* 0x64 - 0x67 */    DIS_NEG,	DIS_RETN,		DIS_IM_0,		DIS_RRD, +/* 0x68 - 0x6b */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_ADC_HL_R16,	DIS_ED_LD_R16_ADDR, +/* 0x6c - 0x6f */    DIS_NEG,	DIS_RETI,		DIS_IM_0,		DIS_RLD, + +/* 0x70 - 0x73 */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_SBC_HL_R16,	DIS_ED_LD_ADDR_R16, +/* 0x74 - 0x77 */    DIS_NEG,	DIS_RETN,		DIS_IM_1,		DIS_ED_NOP, +/* 0x78 - 0x7b */    DIS_IN_R8_C,	DIS_OUT_C_R8,	DIS_ADC_HL_R16,	DIS_ED_LD_R16_ADDR, +/* 0x7c - 0x7f */    DIS_NEG,	DIS_RETI,		DIS_IM_2,		DIS_ED_NOP, + +/* 0x80 - 0x83 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x84 - 0x87 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x88 - 0x8b */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0x8c - 0x8f */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0x90 - 0x93 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x94 - 0x97 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0x98 - 0x9b */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0x9c - 0x9f */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0xa0 - 0xa3 */    DIS_LDI,	DIS_CPI,		DIS_INI,		DIS_OUTI, +/* 0xa4 - 0xa7 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xa8 - 0xab */    DIS_LDD,	DIS_CPD,		DIS_IND,		DIS_OUTD,	 +/* 0xac - 0xaf */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0xb0 - 0xb3 */    DIS_LDIR,	DIS_CPIR,		DIS_INIR,		DIS_OTIR, +/* 0xb4 - 0xb7 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xb8 - 0xbb */    DIS_LDDR,	DIS_CPDR,		DIS_INDR,		DIS_OTDR,	 +/* 0xbc - 0xbf */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0xc0 - 0xc3 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xc4 - 0xc7 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xc8 - 0xcb */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0xcc - 0xcf */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0xd0 - 0xd3 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xd4 - 0xd7 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xd8 - 0xdb */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0xdc - 0xdf */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0xe0 - 0xe3 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xe4 - 0xe7 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xe8 - 0xeb */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0xec - 0xef */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 + +/* 0xf0 - 0xf3 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xf4 - 0xf7 */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP, +/* 0xf8 - 0xfb */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,	 +/* 0xfc - 0xff */    DIS_ED_NOP,	DIS_ED_NOP,		DIS_ED_NOP,		DIS_ED_NOP,		 +		    }; + +/* DIS_FD opcodes +*/ +DIS_OP_CALLBACK	dis_FD_opcode[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x04 - 0x07 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x08 - 0x0b */    DIS_FD_NOP,	DIS_ADD_IY_BC,	DIS_FD_NOP,		DIS_FD_NOP,	 +/* 0x0c - 0x0f */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP,		 + +/* 0x10 - 0x13 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x14 - 0x17 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x18 - 0x1b */    DIS_FD_NOP,	DIS_ADD_IY_DE,	DIS_FD_NOP,		DIS_FD_NOP,	 +/* 0x1c - 0x1f */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP,		 + +/* 0x20 - 0x23 */    DIS_FD_NOP,	DIS_LD_IY_WORD,	DIS_LD_ADDR_IY,	DIS_INC_IY, +/* 0x24 - 0x27 */    DIS_INC_IYH,	DIS_DEC_IYH,	DIS_LD_IYH_BYTE,	DIS_FD_NOP, +/* 0x28 - 0x2b */    DIS_FD_NOP,	DIS_ADD_IY_IY,	DIS_LD_IY_ADDR,	DIS_DEC_IY, +/* 0x2c - 0x2f */    DIS_INC_IYL,	DIS_DEC_IYL,	DIS_LD_IYL_BYTE,	DIS_FD_NOP, + +/* 0x30 - 0x33 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x34 - 0x37 */    DIS_INC_IIY,	DIS_DEC_IIY,	DIS_LD_IIY_BYTE,	DIS_FD_NOP, +/* 0x38 - 0x3b */    DIS_FD_NOP,	DIS_ADD_IY_SP,	DIS_FD_NOP,		DIS_FD_NOP, +/* 0x3c - 0x3f */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, + +/* 0x40 - 0x43 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x44 - 0x47 */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_FD_NOP, +/* 0x48 - 0x4b */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x4c - 0x4f */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_FD_NOP, + +/* 0x50 - 0x53 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x54 - 0x57 */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_FD_NOP, +/* 0x58 - 0x5b */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x5c - 0x5f */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_FD_NOP, + +/* 0x60 - 0x63 */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8, +/* 0x64 - 0x67 */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8, +/* 0x68 - 0x6b */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8, +/* 0x6c - 0x6f */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8, + +/* 0x70 - 0x73 */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8, +/* 0x74 - 0x77 */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_FD_NOP,		DIS_YLD_R8_R8, +/* 0x78 - 0x7b */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x7c - 0x7f */    DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_YLD_R8_R8,	DIS_FD_NOP, + +/* 0x80 - 0x83 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x84 - 0x87 */    DIS_YADD_R8,	DIS_YADD_R8,	DIS_YADD_R8,	DIS_FD_NOP, +/* 0x88 - 0x8b */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x8c - 0x8f */    DIS_YADC_R8,	DIS_YADC_R8,	DIS_YADC_R8,	DIS_FD_NOP, + +/* 0x90 - 0x93 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x94 - 0x97 */    DIS_YSUB_R8,	DIS_YSUB_R8,	DIS_YSUB_R8,	DIS_FD_NOP, +/* 0x98 - 0x9b */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0x9c - 0x9f */    DIS_YSBC_R8,	DIS_YSBC_R8,	DIS_YSBC_R8,	DIS_FD_NOP, + +/* 0xa0 - 0xa3 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xa4 - 0xa7 */    DIS_YAND_R8,	DIS_YAND_R8,	DIS_YAND_R8,	DIS_FD_NOP, +/* 0xa8 - 0xab */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xac - 0xaf */    DIS_YYOR_R8,	DIS_YYOR_R8,	DIS_YYOR_R8,	DIS_FD_NOP, + +/* 0xb0 - 0xb3 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xb4 - 0xb7 */    DIS_Y_OR_R8,	DIS_Y_OR_R8,	DIS_Y_OR_R8,	DIS_FD_NOP, +/* 0xb8 - 0xbb */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xbc - 0xbf */    DIS_YCP_R8,	DIS_YCP_R8,		DIS_YCP_R8,		DIS_FD_NOP, + +/* 0xc0 - 0xc3 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xc4 - 0xc7 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xc8 - 0xcb */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_CB_DECODE, +/* 0xcc - 0xcf */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, + +/* 0xd0 - 0xd3 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xd4 - 0xd7 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xd8 - 0xdb */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xdc - 0xdf */    DIS_FD_NOP,	DIS_FD_DD_DECODE,	DIS_FD_NOP,		DIS_FD_NOP, + +/* 0xe0 - 0xe3 */    DIS_FD_NOP,	DIS_POP_IY,		DIS_FD_NOP,		DIS_EY_ISP_IY, +/* 0xe4 - 0xe7 */    DIS_FD_NOP,	DIS_PUSH_IY,	DIS_FD_NOP,		DIS_FD_NOP, +/* 0xe8 - 0xeb */    DIS_FD_NOP,	DIS_JP_IY,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xec - 0xef */    DIS_FD_NOP,	DIS_FD_ED_DECODE,	DIS_FD_NOP,		DIS_FD_NOP, + +/* 0xf0 - 0xf3 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xf4 - 0xf7 */    DIS_FD_NOP,	DIS_FD_NOP,		DIS_FD_NOP,		DIS_FD_NOP, +/* 0xf8 - 0xfb */    DIS_FD_NOP,	DIS_LD_SP_IY,	DIS_FD_NOP,		DIS_FD_NOP, +/* 0xfc - 0xff */    DIS_FD_NOP,	DIS_FD_FD_DECODE,	DIS_FD_NOP,		DIS_FD_NOP, +		    }; + + +/* DIS_FD DIS_CB opcodes +*/ +DIS_OP_CALLBACK	dis_FD_CB_opcode[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_RLC_IY,	DIS_RLC_IY,		DIS_RLC_IY,		DIS_RLC_IY, +/* 0x04 - 0x07 */    DIS_RLC_IY,	DIS_RLC_IY,		DIS_RLC_IY,		DIS_RLC_IY, +/* 0x08 - 0x0b */    DIS_RRC_IY,	DIS_RRC_IY,		DIS_RRC_IY,		DIS_RRC_IY, +/* 0x0c - 0x0f */    DIS_RRC_IY,	DIS_RRC_IY,		DIS_RRC_IY,		DIS_RRC_IY, + +/* 0x10 - 0x13 */    DIS_RL_IY,	DIS_RL_IY,		DIS_RL_IY,		DIS_RL_IY,	 +/* 0x14 - 0x17 */    DIS_RL_IY,	DIS_RL_IY,		DIS_RL_IY,		DIS_RL_IY, +/* 0x18 - 0x1b */    DIS_RR_IY,	DIS_RR_IY,		DIS_RR_IY,		DIS_RR_IY,	 +/* 0x1c - 0x1f */    DIS_RR_IY,	DIS_RR_IY,		DIS_RR_IY,		DIS_RR_IY, + +/* 0x20 - 0x23 */    DIS_SLA_IY,	DIS_SLA_IY,		DIS_SLA_IY,		DIS_SLA_IY, +/* 0x24 - 0x27 */    DIS_SLA_IY,	DIS_SLA_IY,		DIS_SLA_IY,		DIS_SLA_IY, +/* 0x28 - 0x2b */    DIS_SRA_IY,	DIS_SRA_IY,		DIS_SRA_IY,		DIS_SRA_IY, +/* 0x2c - 0x2f */    DIS_SRA_IY,	DIS_SRA_IY,		DIS_SRA_IY,		DIS_SRA_IY, + +/* 0x30 - 0x33 */    DIS_SLL_IY,	DIS_SLL_IY,		DIS_SLL_IY,		DIS_SLL_IY, +/* 0x34 - 0x37 */    DIS_SLL_IY,	DIS_SLL_IY,		DIS_SLL_IY,		DIS_SLL_IY, +/* 0x38 - 0x3b */    DIS_SRL_IY,	DIS_SRL_IY,		DIS_SRL_IY,		DIS_SRL_IY, +/* 0x3c - 0x3f */    DIS_SRL_IY,	DIS_SRL_IY,		DIS_SRL_IY,		DIS_SRL_IY, + +/* 0x40 - 0x43 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x44 - 0x47 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x48 - 0x4b */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x4c - 0x4f */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, + +/* 0x50 - 0x53 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x54 - 0x57 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x58 - 0x5b */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x5c - 0x5f */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, + +/* 0x60 - 0x63 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x64 - 0x67 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x68 - 0x6b */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x6c - 0x6f */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, + +/* 0x70 - 0x73 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x74 - 0x77 */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x78 - 0x7b */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, +/* 0x7c - 0x7f */    DIS_BIT_IY,DIS_BIT_IY,	DIS_BIT_IY,	DIS_BIT_IY, + +/* 0x80 - 0x83 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0x84 - 0x87 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0x88 - 0x8b */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0x8c - 0x8f */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, + +/* 0x90 - 0x93 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0x94 - 0x97 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0x98 - 0x9b */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0x9c - 0x9f */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, + +/* 0xa0 - 0xa3 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0xa4 - 0xa7 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0xa8 - 0xab */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0xac - 0xaf */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, + +/* 0xb0 - 0xb3 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0xb4 - 0xb7 */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0xb8 - 0xbb */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, +/* 0xbc - 0xbf */    DIS_RES_IY,DIS_RES_IY,	DIS_RES_IY,	DIS_RES_IY, + +/* 0xc0 - 0xc3 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xc4 - 0xc7 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xc8 - 0xcb */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xcc - 0xcf */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, + +/* 0xd0 - 0xd3 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xd4 - 0xd7 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xd8 - 0xdb */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xdc - 0xdf */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, + +/* 0xe0 - 0xe3 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xe4 - 0xe7 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xe8 - 0xeb */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xec - 0xef */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, + +/* 0xf0 - 0xf3 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xf4 - 0xf7 */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xf8 - 0xfb */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +/* 0xfc - 0xff */    DIS_SET_IY,DIS_SET_IY,	DIS_SET_IY,	DIS_SET_IY, +		    }; + +/* DIS_First/single byte opcodes +*/ +DIS_OP_CALLBACK	dis_opcode_z80[0x100]= +		    { +/* 0x00 - 0x03 */    DIS_NOP,	DIS_LD_R16_WORD,	DIS_LD_R16_A,	DIS_INC_R16, +/* 0x04 - 0x07 */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_RLCA, +/* 0x08 - 0x0b */    DIS_EX_AF_AF,	DIS_ADD_HL_R16,	DIS_LD_A_R16,	DIS_DEC_R16,	 +/* 0x0c - 0x0f */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_RRCA,		 + +/* 0x10 - 0x13 */    DIS_DJNZ,	DIS_LD_R16_WORD,	DIS_LD_R16_A,	DIS_INC_R16, +/* 0x14 - 0x17 */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_RLA, +/* 0x18 - 0x1b */    DIS_JR,	DIS_ADD_HL_R16,	DIS_LD_A_R16,	DIS_DEC_R16,	 +/* 0x1c - 0x1f */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_RRA,		 + +/* 0x20 - 0x23 */    DIS_JR_CO,	DIS_LD_R16_WORD,	DIS_LD_ADDR_HL,	DIS_INC_R16, +/* 0x24 - 0x27 */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_DAA, +/* 0x28 - 0x2b */    DIS_JR_CO,	DIS_ADD_HL_R16,	DIS_LD_HL_ADDR,	DIS_DEC_R16,	 +/* 0x2c - 0x2f */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_CPL,		 + +/* 0x30 - 0x33 */    DIS_JR_CO,	DIS_LD_R16_WORD,	DIS_LD_ADDR_A,	DIS_INC_R16, +/* 0x34 - 0x37 */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_SCF, +/* 0x38 - 0x3b */    DIS_JR_CO,	DIS_ADD_HL_R16,	DIS_LD_A_ADDR,	DIS_DEC_R16,	 +/* 0x3c - 0x3f */    DIS_INC_R8,	DIS_DEC_R8,		DIS_LD_R8_BYTE,	DIS_CCF,		 + +/* 0x40 - 0x43 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x44 - 0x47 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x48 - 0x4b */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x4c - 0x4f */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, + +/* 0x50 - 0x53 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x54 - 0x57 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x58 - 0x5b */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x5c - 0x5f */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, + +/* 0x60 - 0x63 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x64 - 0x67 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x68 - 0x6b */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x6c - 0x6f */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, + +/* 0x70 - 0x73 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x74 - 0x77 */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_HALT,		DIS_LD_R8_R8, +/* 0x78 - 0x7b */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, +/* 0x7c - 0x7f */    DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8,	DIS_LD_R8_R8, + +/* 0x80 - 0x83 */    DIS_ADD_R8,	DIS_ADD_R8,		DIS_ADD_R8,		DIS_ADD_R8, +/* 0x84 - 0x87 */    DIS_ADD_R8,	DIS_ADD_R8,		DIS_ADD_R8,		DIS_ADD_R8, +/* 0x88 - 0x8b */    DIS_ADC_R8,	DIS_ADC_R8,		DIS_ADC_R8,		DIS_ADC_R8, +/* 0x8c - 0x8f */    DIS_ADC_R8,	DIS_ADC_R8,		DIS_ADC_R8,		DIS_ADC_R8, + +/* 0x90 - 0x93 */    DIS_SUB_R8,	DIS_SUB_R8,		DIS_SUB_R8,		DIS_SUB_R8, +/* 0x94 - 0x97 */    DIS_SUB_R8,	DIS_SUB_R8,		DIS_SUB_R8,		DIS_SUB_R8, +/* 0x98 - 0x9b */    DIS_SBC_R8,	DIS_SBC_R8,		DIS_SBC_R8,		DIS_SBC_R8, +/* 0x9c - 0x9f */    DIS_SBC_R8,	DIS_SBC_R8,		DIS_SBC_R8,		DIS_SBC_R8, + +/* 0xa0 - 0xa3 */    DIS_AND_R8,	DIS_AND_R8,		DIS_AND_R8,		DIS_AND_R8, +/* 0xa4 - 0xa7 */    DIS_AND_R8,	DIS_AND_R8,		DIS_AND_R8,		DIS_AND_R8, +/* 0xa8 - 0xab */    DIS_XOR_R8,	DIS_XOR_R8,		DIS_XOR_R8,		DIS_XOR_R8, +/* 0xac - 0xaf */    DIS_XOR_R8,	DIS_XOR_R8,		DIS_XOR_R8,		DIS_XOR_R8, + +/* 0xb0 - 0xb3 */    DIS_OR_R8,	DIS_OR_R8,		DIS_OR_R8,		DIS_OR_R8, +/* 0xb4 - 0xb7 */    DIS_OR_R8,	DIS_OR_R8,		DIS_OR_R8,		DIS_OR_R8, +/* 0xb8 - 0xbb */    DIS_CP_R8,	DIS_CP_R8,		DIS_CP_R8,		DIS_CP_R8, +/* 0xbc - 0xbf */    DIS_CP_R8,	DIS_CP_R8,		DIS_CP_R8,		DIS_CP_R8, + +/* 0xc0 - 0xc3 */    DIS_RET_CO,	DIS_POP_R16,	DIS_JP_CO,		DIS_JP, +/* 0xc4 - 0xc7 */    DIS_CALL_CO,	DIS_PUSH_R16,	DIS_ADD_A_BYTE,	DIS_RST, +/* 0xc8 - 0xcb */    DIS_RET_CO,	DIS_RET,		DIS_JP_CO,		DIS_CB_DECODE, +/* 0xcc - 0xcf */    DIS_CALL_CO,	DIS_CALL,		DIS_ADC_A_BYTE,	DIS_RST, + +/* 0xd0 - 0xd3 */    DIS_RET_CO,	DIS_POP_R16,	DIS_JP_CO,		DIS_OUT_BYTE_A, +/* 0xd4 - 0xd7 */    DIS_CALL_CO,	DIS_PUSH_R16,	DIS_SUB_A_BYTE,	DIS_RST, +/* 0xd8 - 0xdb */    DIS_RET_CO,	DIS_EXX,		DIS_JP_CO,		DIS_IN_A_BYTE, +/* 0xdc - 0xdf */    DIS_CALL_CO,	DIS_DD_DECODE,	DIS_SBC_A_BYTE,	DIS_RST, + +/* 0xe0 - 0xe3 */    DIS_RET_CO,	DIS_POP_R16,	DIS_JP_CO,		DIS_EX_ISP_HL, +/* 0xe4 - 0xe7 */    DIS_CALL_CO,	DIS_PUSH_R16,	DIS_AND_A_BYTE,	DIS_RST, +/* 0xe8 - 0xeb */    DIS_RET_CO,	DIS_JP_HL,		DIS_JP_CO,		DIS_EX_DE_HL, +/* 0xec - 0xef */    DIS_CALL_CO,	DIS_ED_DECODE,	DIS_XOR_A_BYTE,	DIS_RST, + +/* 0xf0 - 0xf3 */    DIS_RET_CO,	DIS_POP_R16,	DIS_JP_CO,		DIS_DI, +/* 0xf4 - 0xf7 */    DIS_CALL_CO,	DIS_PUSH_R16,	DIS_OR_A_BYTE,	DIS_RST, +/* 0xf8 - 0xfb */    DIS_RET_CO,	DIS_LD_SP_HL,	DIS_JP_CO,		DIS_EI, +/* 0xfc - 0xff */    DIS_CALL_CO,	DIS_FD_DECODE,	DIS_CP_A_BYTE,	DIS_RST, +		    }; + + +#endif + +/* END OF FILE */ diff --git a/source/zx81.c b/source/zx81.c new file mode 100644 index 0000000..df30dd7 --- /dev/null +++ b/source/zx81.c @@ -0,0 +1,828 @@ +/* +    ezx81 - X11 ZX81 emulator + +    Copyright (C) 2003  Ian Cowburn (ianc@noddybox.demon.co.uk) + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +    Provides the emulation for the ZX81 + +*/ +static const char ident[]="$Id$"; + +#if 0 +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "zx81.h" +#include "gfx.h" +#include "gui.h" +#include "config.h" +#include "util.h" +#include "exit.h" + +static const char ident_h[]=EZX81_ZX81H; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + +/* ---------------------------------------- STATICS +*/ +#define ROMLEN		0x2000 +#define ROM_SAVE	0x2fc +#define ROM_LOAD	0x347 + +#define ED_SAVE		0xf0 +#define ED_LOAD		0xf1 +#define ED_WAITKEY	0xf2 +#define ED_ENDWAITKEY	0xf3 +#define ED_PAUSE	0xf4 + +#define SLOW_TSTATES	16000 +#define FAST_TSTATES	64000 + +#define LASTK1		16421 +#define LASTK2		16422 +#define MARGIN		16424 +#define FRAMES		16436 +#define CDFLAG		16443 + +static Z80Val		FRAME_TSTATES=FAST_TSTATES; + +/* The ZX81 screen and memory +*/ +static int		waitkey=FALSE; +static int		started=FALSE; + +#define	SCR_W		256 +#define	SCR_H		192 +#define	TXT_W		32 +#define	TXT_H		24 + +#define OFF_X		(GFX_WIDTH-SCR_W)/2 +#define OFF_Y		(GFX_HEIGHT-SCR_H)/2 + +static Z80Byte		mem[0x10000]; + +static Z80Word		RAMBOT=0; +static Z80Word		RAMTOP=0; +static Z80Word		RAMLEN=0; + +#define DFILE		0x400c + +#define WORD(a)		(mem[a] | (Z80Word)mem[a+1]<<8) + +/* GFX vars +*/ +static Uint32		white; +static Uint32		black; + + +/* The keyboard +*/ +static Z80Byte		matrix[8]; + +typedef struct +{ +    SDLKey	key; +    int		m1,b1,m2,b2; +} MatrixMap; + +#define KY1(m,b)		m,1<<b,-1,-1 +#define KY2(m1,b1,m2,b2)	m1,1<<b1,m2,1<<b2 + +static const MatrixMap keymap[]= +{ +    {SDLK_1,		KY1(3,0)}, +    {SDLK_2,		KY1(3,1)}, +    {SDLK_3,		KY1(3,2)}, +    {SDLK_4,		KY1(3,3)}, +    {SDLK_5,		KY1(3,4)}, +    {SDLK_6,		KY1(4,4)}, +    {SDLK_7,		KY1(4,3)}, +    {SDLK_8,		KY1(4,2)}, +    {SDLK_9,		KY1(4,1)}, +    {SDLK_0,		KY1(4,0)}, + +    {SDLK_a,		KY1(1,0)}, +    {SDLK_b,		KY1(7,4)}, +    {SDLK_c,		KY1(0,3)}, +    {SDLK_d,		KY1(1,2)}, +    {SDLK_e,		KY1(2,2)}, +    {SDLK_f,		KY1(1,3)}, +    {SDLK_g,		KY1(1,4)}, +    {SDLK_h,		KY1(6,4)}, +    {SDLK_i,		KY1(5,2)}, +    {SDLK_j,		KY1(6,3)}, +    {SDLK_k,		KY1(6,2)}, +    {SDLK_l,		KY1(6,1)}, +    {SDLK_m,		KY1(7,2)}, +    {SDLK_n,		KY1(7,3)}, +    {SDLK_o,		KY1(5,1)}, +    {SDLK_p,		KY1(5,0)}, +    {SDLK_q,		KY1(2,0)}, +    {SDLK_r,		KY1(2,3)}, +    {SDLK_s,		KY1(1,1)}, +    {SDLK_t,		KY1(2,4)}, +    {SDLK_u,		KY1(5,3)}, +    {SDLK_v,		KY1(0,4)}, +    {SDLK_w,		KY1(2,1)}, +    {SDLK_x,		KY1(0,2)}, +    {SDLK_y,		KY1(5,4)}, +    {SDLK_z,		KY1(0,1)}, + +    {SDLK_RETURN,	KY1(6,0)}, +    {SDLK_SPACE,	KY1(7,0)}, + +    {SDLK_COMMA,	KY1(7,1)},	/* In the right place... */ +    {SDLK_PERIOD,	KY1(7,1)},	/* ...or the right key... */ + +    {SDLK_BACKSPACE,	KY2(0,0,4,0)}, +    {SDLK_DELETE,	KY2(0,0,4,0)}, +    {SDLK_UP,		KY2(0,0,4,3)}, +    {SDLK_DOWN,		KY2(0,0,4,4)}, +    {SDLK_LEFT,		KY2(0,0,3,4)}, +    {SDLK_RIGHT,	KY2(0,0,4,2)}, + +    {SDLK_RSHIFT,	KY1(0,0)}, +    {SDLK_LSHIFT,	KY1(0,0)}, + +    {SDLK_UNKNOWN,	0,0,0,0}, +}; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +#define PEEKW(addr)		(mem[addr] | (Z80Word)mem[addr+1]<<8) + +#define POKEW(addr,val)         do					\ +                                {					\ +                                    Z80Word wa=addr;			\ +                                    Z80Word wv=val;			\ +                                    mem[wa]=wv;				\ +                                    mem[wa+1]=wv>>8;			\ +                                } while(0) + +static void RomPatch(void) +{ +    static const Z80Byte save[]= +    { +    	0xed, ED_SAVE,		/* (SAVE)		*/ +	0xc3, 0x07, 0x02,	/* JP $0207		*/ +	0xff			/* End of patch		*/ +    }; + +    static const Z80Byte load[]= +    { +    	0xed, ED_LOAD,		/* (LOAD)		*/ +	0xc3, 0x07, 0x02,	/* JP $0207		*/ +	0xff			/* End of patch		*/ +    }; + +    static const Z80Byte fast_hack[]= +    { +	0xed, ED_WAITKEY,	/* (START KEY WAIT)	*/ +	0xcb,0x46,		/* L: bit 0,(hl)	*/ +	0x28,0xfc,		/* jr z,L		*/ +	0xed, ED_ENDWAITKEY,	/* (END KEY WAIT)	*/ +    	0x00,			/* nop			*/ +	0xff			/* End of patch		*/ +    }; + +    static const Z80Byte kbd_hack[]= +    { +	0x2a,0x25,0x40,		/* ld hl,(LASTK)	*/ +	0xc9,			/* ret			*/ +	0xff			/* End of patch		*/ +    }; + +    static const Z80Byte pause_hack[]= +    { +	0xed, ED_PAUSE,		/* (PAUSE)		*/ +    	0x00,			/* nop			*/ +	0xff			/* End of patch		*/ +    }; + +    int f; + +    for(f=0;save[f]!=0xff;f++) +    { +	mem[ROM_SAVE+f]=save[f]; +    } + +    for(f=0;load[f]!=0xff;f++) +    { +	mem[ROM_LOAD+f]=load[f]; +    } + +    for(f=0;fast_hack[f]!=0xff;f++) +    { +	mem[0x4ca+f]=fast_hack[f]; +    } + +    for(f=0;kbd_hack[f]!=0xff;f++) +    { +	mem[0x2bb+f]=kbd_hack[f]; +    } + +    for(f=0;pause_hack[f]!=0xff;f++) +    { +	mem[0xf3a+f]=pause_hack[f]; +    } + +    /* Trust me, we have a ZX81... Honestly. +    */ +    mem[0x21c]=0x00; +    mem[0x21d]=0x00; + +    /* Remove HALTs as we don't do interrupts +    */ +    mem[0x0079]=0; +    mem[0x02ec]=0; +} + +static char ToASCII(Z80Byte b) +{ +    if (b==0)			/* SPACE */ +    	return ' '; +     +    if (b==22)			/* Dash (-) */ +    	return '-'; + +    if (b==27)			/* Period (.) */ +    	return '.'; + +    if (b>=28 && b<=37)		/* 0-9 */ +    	return '0'+b-28; + +    if (b>=38 && b<=63)		/* A-Z */ +    	return 'a'+b-38; + +    return 0; +} + + +static const char *ConvertFilename(Z80Word addr) +{ +    static char buff[FILENAME_MAX]; +    char *p; + +    p=buff; +    *p=0; + +    if (addr>0x8000) +    { +    	return buff; +    } + +    do +    { +    	char c=ToASCII(mem[addr]&0x7f); + +	if (c) +	    *p++=c; + +    } while(mem[addr++]<0x80); + +    *p=0; + +    return buff; +} + + +static void LoadTape(Z80 *z80) +{ +    const char *p=ConvertFilename(z80->DE.w); +    char path[FILENAME_MAX]; +    FILE *fp; + +    if (strlen(p)==0) +    { +    	GUIMessage(eMessageBox,"ERROR","Can't load empty filename"); +	return; +    } + +    strcpy(path,SConfig(CONF_TAPEDIR)); +    strcat(path,"/"); +    strcat(path,p); +    strcat(path,".p"); + +    if (!(fp=fopen(path,"rb"))) +    { +    	GUIMessage(eMessageBox,"ERROR","Can't load file:\n%s",path); +	return; +    } + +    fread(mem+0x4009,1,0x4000,fp); +    fclose(fp); +} + + +static void SaveTape(Z80 *z80) +{ +    const char *p=ConvertFilename(z80->DE.w); +    char path[FILENAME_MAX]; +    FILE *fp; +    Z80Word start; +    Z80Word end; + +    if (strlen(p)==0) +    { +    	GUIMessage(eMessageBox,"ERROR","Can't save empty filename"); +	return; +    } + +    strcpy(path,SConfig(CONF_TAPEDIR)); +    strcat(path,"/"); +    strcat(path,p); +    strcat(path,".p"); + +    if (!(fp=fopen(path,"wb"))) +    { +    	GUIMessage(eMessageBox,"ERROR","Can't write file:\n%s",path); +	return; +    } + +    start=0x4009; +    end=(Z80Word)mem[0x4014]|(Z80Word)mem[0x4015]<<8; + +    while(start<=end) +    	putc(mem[start++],fp); + +    fclose(fp); +} + + +static void PrintZX81Char(int x,int y,int code,int base) +{ +    int cx,cy; +    Uint32 fg,bg; + +    x*=8; +    y*=8; + +    if (code&0x80) +    { +	fg=white; +	bg=black; +	code-=0x80; +    } +    else +    { +	fg=black; +	bg=white; +    } + +    base=base<<8; +    base+=code*8; + +    for(cy=0;cy<8;cy++) +    { +	for(cx=0;cx<8;cx++) +	{ +	    if (mem[base]&(1<<(7-cx))) +		GFXFastPlot(OFF_X+x+cx,OFF_Y+y+cy,fg); +	    else +		GFXFastPlot(OFF_X+x+cx,OFF_Y+y+cy,bg); +	} + +	base++; +    } +} + + +static void DrawScreen(Z80 *z80) +{ +    Z80Byte *scr=mem+WORD(DFILE); +    int x,y; + +    x=0; +    y=0; + +    while(y<TXT_H) +    { +	scr++; +	x=0; + +	while((*scr!=118)&&(x<TXT_W)) +	{ +	    PrintZX81Char(x,y,*scr++,z80->I); +	    x++; +	} + +	y++; +    } +} + + +static void DrawSnow(Z80 *z80) +{ +    int x,y; + +    x=0; +    y=0; + +    for(x=0;x<SCR_W;x++) +    { +	for(y=0;y<SCR_H;y++) +	{ +	    GFXFastPlot(OFF_X+x,OFF_Y+y,rand()&1 ? white:black); +	} +    } +} + + +/* Perform ZX81 housekeeping functions like updating FRAMES and updating LASTK +*/ +static void ZX81HouseKeeping(Z80 *z80) +{ +    static unsigned prev_lk1,prev_lk2; +    unsigned row; +    unsigned lastk1; +    unsigned lastk2; + +    /* British ZX81 +    */ +    mem[MARGIN]=55; + +    /* Update FRAMES +    */ +    if (FRAME_TSTATES==SLOW_TSTATES) +    { +    	Z80Word frame=PEEKW(FRAMES)&0x7fff; + +	if (frame) +	{ +	    frame--; +	} + +	POKEW(FRAMES,frame|0x8000); +    } + +    if (!started) +    { +    	prev_lk1=0; +    	prev_lk2=0; +	return; +    } + +    /* Update LASTK +    */ +    lastk1=0; +    lastk2=0; + +    for(row=0;row<8;row++) +    { +    	unsigned b; + +	b=(~matrix[row]&0x1f)<<1; + +	if (row==0) +	{ +	    unsigned shift; + +	    shift=b&2; +	    b&=~2; +	    b|=(shift>>1); +	} + +	if (b) +	{ +	    if (b>1) +	    { +		lastk1|=(1<<row); +	    } + +	    lastk2|=b; +	} +    } + +    /* if ((lastk1 || lastk2) && (lastk1!=prev_lk1 || lastk2!=prev_lk2)) */ +    if (lastk1 && (lastk1!=prev_lk1 || lastk2!=prev_lk2)) +    { +    	mem[CDFLAG]|=1; +    } + +    prev_lk1=lastk1; +    prev_lk2=lastk2; + +    mem[LASTK1]=lastk1^0xff; +    mem[LASTK2]=lastk2^0xff; +} + + +static int CheckTimers(Z80 *z80, Z80Val val) +{ +    if (val>=FRAME_TSTATES) +    { +	Z80ResetCycles(z80,val-FRAME_TSTATES); + +	GFXLock(); + +	if (started && ((mem[CDFLAG] & 0x80) || waitkey)) +	{ +	    DrawScreen(z80); +	    FRAME_TSTATES=SLOW_TSTATES; +	} +	else +	{ +	    DrawSnow(z80); +	    FRAME_TSTATES=FAST_TSTATES; +	} + +	/* Update FRAMES (if in SLOW) and scan the keyboard.  This only happens +	   once we've got to a decent point in the boot cycle (detected with +	   a valid stack pointer). +	*/ +	if (z80->SP<0x8000) +	{ +	    ZX81HouseKeeping(z80); +	} + +	GFXUnlock(); +	GFXEndFrame(TRUE); +	GFXStartFrame(); +    } + +    return TRUE; +} + + +static int EDCallback(Z80 *z80, Z80Val data) +{ +    Z80Word pause; + +    switch((Z80Byte)data) +    { +    	case ED_SAVE: +	    SaveTape(z80); +	    break; + +    	case ED_LOAD: +	    LoadTape(z80); +	    mem[CDFLAG]=0xc0; +	    break; + +	case ED_WAITKEY: +	    waitkey=TRUE; +	    started=TRUE; +	    break; + +	case ED_ENDWAITKEY: +	    waitkey=FALSE; +	    break; + +	case ED_PAUSE: +	    waitkey=TRUE; + +	    pause=z80->BC.w; + +	    while(pause-- && !(mem[CDFLAG]&1)) +	    { +		SDL_Event *e; + +		e=GFXGetKey(); + +		if (e) +		{ +		    ZX81KeyEvent(e); +		} + +	    	CheckTimers(z80,FRAME_TSTATES); +	    } + +	    waitkey=FALSE; +	    break; + +	default: +	    break; +    } + +    return TRUE; +} + + +/* ---------------------------------------- EXPORTED INTERFACES +*/ +void ZX81Init(Z80 *z80) +{ +    FILE *fp; +    Z80Word f; + +    if (!(fp=fopen(SConfig(CONF_ROMFILE),"rb"))) +    { +	GUIMessage(eMessageBox, +		   "ERROR","Failed to open ZX81 ROM\n%s",SConfig(CONF_ROMFILE)); +	Exit(""); +    } + +    if (fread(mem,1,ROMLEN,fp)!=ROMLEN) +    { +    	fclose(fp); +	GUIMessage(eMessageBox, +		   "ERROR","ROM file must be %d bytes long\n",ROMLEN); +	Exit(""); +    } + +    /* Patch the ROM +    */ +    RomPatch(); +    Z80LodgeCallback(z80,eZ80_EDHook,EDCallback); +    Z80LodgeCallback(z80,eZ80_Instruction,CheckTimers); + +    /* Mirror the ROM +    */ +    memcpy(mem+ROMLEN,mem,ROMLEN); + +    RAMBOT=0x4000; + +    /* Memory size (1 or 16K) +    */ +    if (IConfig(CONF_MEMSIZE)==16) +	RAMLEN=0x4000; +    else +	RAMLEN=0x400; + +    RAMTOP=RAMBOT+RAMLEN; + +    for(f=RAMBOT;f<=RAMTOP;f++) +    	mem[f]=0; + +    for(f=0;f<8;f++) +    	matrix[f]=0x1f; + +    white=GFXRGB(230,230,230); +    black=GFXRGB(0,0,0); + +    GFXStartFrame(); +} + + +void ZX81KeyEvent(SDL_Event *e) +{ +    const MatrixMap *m; + +    m=keymap; + +    while(m->key!=SDLK_UNKNOWN) +    { +	if (e->key.keysym.sym==m->key) +	{ +	    if (e->key.state==SDL_PRESSED) +	    { +		matrix[m->m1]&=~m->b1; + +		if (m->m2!=-1) +		    matrix[m->m2]&=~m->b2; +	    } +	    else +	    { +		matrix[m->m1]|=m->b1; + +		if (m->m2!=-1) +		    matrix[m->m2]|=m->b2; +	    } +	} + +	m++; +    } +} + + +Z80Byte ZX81ReadMem(Z80 *z80, Z80Word addr) +{ +    /* Hopefully by simply returning RET for ULA reads we save a lot of +       ROM patching shenanigans. +    */ +    if (addr>0x7fff) +    { +    	return 0xc9; +    } +    else +    { +	return mem[addr]; +    } +} + + +void ZX81WriteMem(Z80 *z80, Z80Word addr, Z80Byte val) +{ +    if (addr>=RAMBOT && addr<=RAMTOP) +    { +	mem[addr]=val; +    } +} + + +Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port) +{ +    Z80Byte b=0; + +    switch(port&0xff) +    { +    	case 0xfe:	/* ULA */ +	    /* Key matrix +	    */ +	    switch(port&0xff00) +	    { +	    	case 0xfe00: +		    b=matrix[0]; +		    break; +	    	case 0xfd00: +		    b=matrix[1]; +		    break; +	    	case 0xfb00: +		    b=matrix[2]; +		    break; +	    	case 0xf700: +		    b=matrix[3]; +		    break; +	    	case 0xef00: +		    b=matrix[4]; +		    break; +	    	case 0xdf00: +		    b=matrix[5]; +		    break; +	    	case 0xbf00: +		    b=matrix[6]; +		    break; +	    	case 0x7f00: +		    b=matrix[7]; +		    break; +	    } +	    break; + +	default: +	    break; +    } + +    return b; +} + + +void ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val) +{ +    switch(port&0xff) +    { +    	case 0xfd: +	    break; + +	case 0xfe: +	    break; +    } +} + + +Z80Byte ZX81ReadForDisassem(Z80 *z80, Z80Word addr) +{ +    return mem[addr&0x7fff]; +} + + +const char *ZX81Info(Z80 *z80) +{ +    static char buff[80]; + +    sprintf(buff,"T-State/frame: %lu",FRAME_TSTATES); +    return buff; +} + + +void ZX81Reset(Z80 *z80) +{ +    int f; + +    for(f=0;f<8;f++) +    	matrix[f]=0x1f; + +    Z80ResetCycles(z80,0); + +    started=FALSE; + +    GFXStartFrame(); +} + +#endif + + +/* END OF FILE */ | 
