/*****************************************************************************
 *
 *   i8085.c
 *   Portable I8085A emulator V1.2
 *
 *   Copyright Juergen Buchmueller, all rights reserved.
 *   Partially based on information out of Z80Em by Marcel De Kogel
 *
 * changes in V1.3
 *   - Added undocumented opcodes for the 8085A, based on a german
 *     book about microcomputers: "Mikrocomputertechnik mit dem
 *     Prozessor 8085A".
 *   - This book also suggest that INX/DCX should modify the X flag bit
 *     for a LSB to MSB carry and
 *   - that jumps take 10 T-states only when they're executed, 7 when
 *     they're skipped.
 *     Thanks for the info and a copy of the tables go to Timo Sachsenberg
 *     <timo.sachsenberg@student.uni-tuebingen.de>
 * changes in V1.2
 *   - corrected cycle counts for these classes of opcodes
 *     Thanks go to Jim Battle <frustum@pacbell.bet>
 *
 *                  808x     Z80
 *     DEC A           5       4    \
 *     INC A           5       4     \
 *     LD A,B          5       4      >-- Z80 is faster
 *     JP (HL)         5       4     /
 *     CALL cc,nnnn: 11/17   10/17  /
 *
 *     INC HL          5       6    \
 *     DEC HL          5       6     \
 *     LD SP,HL        5       6      \
 *     ADD HL,BC      10      11       \
 *     INC (HL)       10      11        >-- 8080 is faster
 *     DEC (HL)       10      11       /
 *     IN A,(#)       10      11      /
 *     OUT (#),A      10      11     /
 *     EX (SP),HL     18      19    /
 *
 *   Copyright Juergen Buchmueller, all rights reserved.
 *   You can contact me at juergen@mame.net or pullmoll@stop1984.com
 *
 *   - This source code is released as freeware for non-commercial purposes
 *     as part of the M.A.M.E. (Multiple Arcade Machine Emulator) project.
 *     The licensing terms of MAME apply to this piece of code for the MAME
 *     project and derviative works, as defined by the MAME license. You
 *     may opt to make modifications, improvements or derivative works under
 *     that same conditions, and the MAME project may opt to keep
 *     modifications, improvements or derivatives under their terms exclusively.
 *
 *   - Alternatively you can choose to apply the terms of the "GPL" (see
 *     below) to this - and only this - piece of code or your derivative works.
 *     Note that in no case your choice can have any impact on any other
 *     source code of the MAME project, or binary, or executable, be it closely
 *     or losely related to this piece of code.
 *
 *  -  At your choice you are also free to remove either licensing terms from
 *     this file and continue to use it under only one of the two licenses. Do this
 *     if you think that licenses are not compatible (enough) for you, or if you
 *     consider either license 'too restrictive' or 'too free'.
 *
 *  -  GPL (GNU General Public License)
 *     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.
 *
 *
 * Revisions:
 *
 * xx-xx-2002 Acho A. Tang
 *
 * - 8085 emulation was in fact never used. It's been treated as a plain 8080.
 * - protected IRQ0 vector from being overwritten
 * - modified interrupt handler to properly process 8085-specific IRQ's
 * - corrected interrupt masking, RIM and SIM behaviors according to Intel's documentation
 *
 * 20-Jul-2002 Krzysztof Strzecha
 *
 * - SBB r instructions should affect parity flag.
 *   Fixed only for non x86 asm version (#define i8080_EXACT 1).
 *   There are probably more opcodes which should affect this flag, but don't.
 * - JPO nnnn and JPE nnnn opcodes in disassembler were misplaced. Fixed.
 * - Undocumented i8080 opcodes added:
 *   08h, 10h, 18h, 20h, 28h, 30h, 38h  -  NOP
 *   0CBh                               -  JMP
 *   0D9h                               -  RET
 *   0DDh, 0EDh, 0FDh                   -  CALL
 *   Thanks for the info go to Anton V. Ignatichev.
 *
 * 08-Dec-2002 Krzysztof Strzecha
 *
 * - ADC r instructions should affect parity flag.
 *   Fixed only for non x86 asm version (#define i8080_EXACT 1).
 *   There are probably more opcodes which should affect this flag, but don't.
 *
 * 05-Sep-2003 Krzysztof Strzecha
 *
 * - INR r, DCR r, ADD r, SUB r, CMP r instructions should affect parity flag.
 *   Fixed only for non x86 asm version (#define i8080_EXACT 1).
 *
 * 23-Dec-2006 Tomasz Slanina
 *
 * - SIM fixed
 *
 * 28-Jan-2007 Zsolt Vasvari
 *
 * - Removed archaic i8080_EXACT flag.
 *
 * 08-June-2008 Miodrag Milanovic
 *
 * - Flag setting fix for some instructions and cycle count update
 *
 * August 2009, hap
 *
 * - removed DAA table
 * - fixed accidental double memory reads due to macro overuse
 * - fixed cycle deduction on unconditional CALL / RET
 * - added cycle tables and cleaned up big switch source layout (1 tab = 4 spaces)
 * - removed HLT cycle eating (earlier, HLT after EI could theoretically fail)
 * - fixed parity flag on add/sub/cmp
 * - renamed temp register XX to official name WZ
 * - renamed flags from Z80 style S Z Y H X V N C  to  S Z X5 H X3 P V C, and
 *   fixed X5 / V flags where accidentally broken due to flag names confusion
 *
 * 21-Aug-2009, Curt Coder
 *
 * - added 8080A variant
 * - refactored callbacks to use devcb
 *
 *****************************************************************************/

#include "debugger.h"
#include "i8085.h"
#include "i8085cpu.h"

#define VERBOSE 0

#define LOG(x) do { if (VERBOSE) logerror x; } while (0)

#define CPUTYPE_8080	0
#define CPUTYPE_8085	1



/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/

typedef struct _i8085_state i8085_state;
struct _i8085_state
{
	i8085_config 		config;

	devcb_resolved_write8		out_status_func;
	devcb_resolved_write_line	out_inte_func;
	devcb_resolved_read_line	in_sid_func;
	devcb_resolved_write_line	out_sod_func;

	int 				cputype;		/* 0 8080, 1 8085A */
	PAIR				PC,SP,AF,BC,DE,HL,WZ;
	UINT8				HALT;
	UINT8				IM; 			/* interrupt mask (8085A only) */
	UINT8   			STATUS;			/* status word */

	UINT8				after_ei;		/* post-EI processing; starts at 2, check for ints at 0 */
	UINT8				nmi_state;		/* raw NMI line state */
	UINT8				irq_state[4];	/* raw IRQ line states */
	UINT8				trap_pending;	/* TRAP interrupt latched? */
	UINT8				trap_im_copy;	/* copy of IM register when TRAP was taken */
	UINT8				sod_state;		/* state of the SOD line */

	UINT8				ietemp;			/* import/export temp space */

	cpu_irq_callback 	irq_callback;
	const device_config *device;
	const address_space *program;
	const address_space *io;
	cpu_state_table 	state;
	int					icount;
};



/***************************************************************************
    CPU STATE DESCRIPTION
***************************************************************************/

#define I8085_STATE_ENTRY(_name, _format, _member, _datamask, _flags) \
	CPU_STATE_ENTRY(I8085_##_name, #_name, _format, i8085_state, _member, _datamask, ~0, _flags)

static const cpu_state_entry state_array[] =
{
	I8085_STATE_ENTRY(PC,  "%04X", PC.w.l, 0xffff, 0)
	I8085_STATE_ENTRY(GENPC, "%04X", PC.w.l, 0xffff, CPUSTATE_NOSHOW)
//  I8085_STATE_ENTRY(GENPCBASE, "%04X", prvpc.w.l, 0xffff, CPUSTATE_NOSHOW)

	I8085_STATE_ENTRY(SP,  "%04X", SP.w.l, 0xffff, 0)
	I8085_STATE_ENTRY(GENSP, "%04X", SP.w.l, 0xffff, CPUSTATE_NOSHOW)

	I8085_STATE_ENTRY(A, "%02X", AF.b.l, 0xff, CPUSTATE_NOSHOW)
	I8085_STATE_ENTRY(B, "%02X", BC.b.h, 0xff, CPUSTATE_NOSHOW)
	I8085_STATE_ENTRY(C, "%02X", BC.b.l, 0xff, CPUSTATE_NOSHOW)
	I8085_STATE_ENTRY(D, "%02X", DE.b.h, 0xff, CPUSTATE_NOSHOW)
	I8085_STATE_ENTRY(E, "%02X", DE.b.l, 0xff, CPUSTATE_NOSHOW)
	I8085_STATE_ENTRY(H, "%02X", HL.b.h, 0xff, CPUSTATE_NOSHOW)
	I8085_STATE_ENTRY(L, "%02X", HL.b.l, 0xff, CPUSTATE_NOSHOW)

	I8085_STATE_ENTRY(AF, "%04X", AF.w.l, 0xffff, 0)
	I8085_STATE_ENTRY(BC, "%04X", BC.w.l, 0xffff, 0)
	I8085_STATE_ENTRY(DE, "%04X", DE.w.l, 0xffff, 0)
	I8085_STATE_ENTRY(HL, "%04X", HL.w.l, 0xffff, 0)

	I8085_STATE_ENTRY(STATUS, "%02X", STATUS, 0xff, 0)
	I8085_STATE_ENTRY(SOD, "%1u", sod_state, 0x1, 0)
	I8085_STATE_ENTRY(SID, "%1u", ietemp, 0x1, CPUSTATE_EXPORT | CPUSTATE_IMPORT)
	I8085_STATE_ENTRY(INTE, "%1u", ietemp, 0x1, CPUSTATE_EXPORT | CPUSTATE_IMPORT)
};

static const cpu_state_table state_table_template =
{
	NULL,						/* pointer to the base of state (offsets are relative to this) */
	0,							/* subtype this table refers to */
	ARRAY_LENGTH(state_array),	/* number of entries */
	state_array					/* array of entries */
};



/***************************************************************************
    MACROS
***************************************************************************/

#define IS_8080(c)			((c)->cputype == CPUTYPE_8080)
#define IS_8085(c)			((c)->cputype == CPUTYPE_8085)



/***************************************************************************
    STATIC TABLES
***************************************************************************/

/* cycles lookup */
static const UINT8 lut_cycles_8080[256]={
/*      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  */
/* 0 */ 4, 10,7, 5, 5, 5, 7, 4, 4, 10,7, 5, 5, 5, 7, 4,
/* 1 */ 4, 10,7, 5, 5, 5, 7, 4, 4, 10,7, 5, 5, 5, 7, 4,
/* 2 */ 4, 10,16,5, 5, 5, 7, 4, 4, 10,16,5, 5, 5, 7, 4,
/* 3 */ 4, 10,13,5, 10,10,10,4, 4, 10,13,5, 5, 5, 7, 4,
/* 4 */ 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5,
/* 5 */ 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5,
/* 6 */ 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5,
/* 7 */ 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 5,
/* 8 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
/* 9 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
/* A */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
/* B */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
/* C */ 5, 10,10,10,11,11,7, 11,5, 10,10,10,11,11,7, 11,
/* D */ 5, 10,10,10,11,11,7, 11,5, 10,10,10,11,11,7, 11,
/* E */ 5, 10,10,18,11,11,7, 11,5, 5, 10,5, 11,11,7, 11,
/* F */ 5, 10,10,4, 11,11,7, 11,5, 5, 10,4, 11,11,7, 11 };
static const UINT8 lut_cycles_8085[256]={
/*      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  */
/* 0 */ 4, 10,7, 6, 4, 4, 7, 4, 10,10,7, 6, 4, 4, 7, 4,
/* 1 */ 7, 10,7, 6, 4, 4, 7, 4, 10,10,7, 6, 4, 4, 7, 4,
/* 2 */ 7, 10,16,6, 4, 4, 7, 4, 10,10,16,6, 4, 4, 7, 4,
/* 3 */ 7, 10,13,6, 10,10,10,4, 10,10,13,6, 4, 4, 7, 4,
/* 4 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
/* 5 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
/* 6 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
/* 7 */ 7, 7, 7, 7, 7, 7, 5, 7, 4, 4, 4, 4, 4, 4, 7, 4,
/* 8 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
/* 9 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
/* A */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
/* B */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
/* C */ 6, 10,10,10,11,12,7, 12,6, 10,10,12,11,11,7, 12,
/* D */ 6, 10,10,10,11,12,7, 12,6, 10,10,10,11,10,7, 12,
/* E */ 6, 10,10,16,11,12,7, 12,6, 6, 10,5, 11,10,7, 12,
/* F */ 6, 10,10,4, 11,12,7, 12,6, 6, 10,4, 11,10,7, 12 };

/* special cases (partially taken care of elsewhere):
               base c    taken?   not taken?
M_RET  8080    5         +6(11)   -0            (conditional)
M_RET  8085    6         +6(12)   -0            (conditional)
M_JMP  8080    10        +0       -0
M_JMP  8085    10        +0       -3(7)
M_CALL 8080    11        +6(17)   -0
M_CALL 8085    11        +7(18)   -2(9)

*/
static UINT8 lut_cycles[256];

/* flags lookup */
static UINT8 ZS[256];
static UINT8 ZSP[256];



/***************************************************************************
    FUNCTION PROTOTYPES
***************************************************************************/

static void execute_one(i8085_state *cpustate, int opcode);



/***************************************************************************
    INLINE FUNCTIONS
***************************************************************************/

INLINE i8085_state *get_safe_token(const device_config *device)
{
	assert(device != NULL);
	assert(device->token != NULL);
	assert(device->type == CPU);
	assert(cpu_get_type(device) == CPU_8080 ||
		   cpu_get_type(device) == CPU_8085A);
	return (i8085_state *)device->token;
}

INLINE void set_sod(i8085_state *cpustate, int state)
{
	if (state != 0 && cpustate->sod_state == 0)
	{
		cpustate->sod_state = 1;
		devcb_call_write_line(&cpustate->out_sod_func, cpustate->sod_state);
	}
	else if (state == 0 && cpustate->sod_state != 0)
	{
		cpustate->sod_state = 0;
		devcb_call_write_line(&cpustate->out_sod_func, cpustate->sod_state);
	}
}


INLINE void set_inte(i8085_state *cpustate, int state)
{
	if (state != 0 && (cpustate->IM & IM_IE) == 0)
	{
		cpustate->IM |= IM_IE;
		devcb_call_write_line(&cpustate->out_inte_func, 1);
	}
	else if (state == 0 && (cpustate->IM & IM_IE) != 0)
	{
		cpustate->IM &= ~IM_IE;
		devcb_call_write_line(&cpustate->out_inte_func, 0);
	}
}


INLINE void set_status(i8085_state *cpustate, UINT8 status)
{
	if (status != cpustate->STATUS)
		devcb_call_write8(&cpustate->out_status_func, 0, status);

	cpustate->STATUS = status;
}


INLINE UINT8 get_rim_value(i8085_state *cpustate)
{
	UINT8 result = cpustate->IM;
	int sid = devcb_call_read_line(&cpustate->in_sid_func);

	/* copy live RST5.5 and RST6.5 states */
	result &= ~(IM_I65 | IM_I55);
	if (cpustate->irq_state[I8085_RST65_LINE]) result |= IM_I65;
	if (cpustate->irq_state[I8085_RST55_LINE]) result |= IM_I55;

	/* fetch the SID bit if we have a callback */
	result = (result & 0x7f) | (sid ? 0x80 : 0);

	return result;
}


INLINE void break_halt_for_interrupt(i8085_state *cpustate)
{
	/* de-halt if necessary */
	if (cpustate->HALT)
	{
		cpustate->PC.w.l++;
		cpustate->HALT = 0;
		set_status(cpustate, 0x26);	/* int ack while halt */
	}
	else
		set_status(cpustate, 0x23);	/* int ack */
}


INLINE UINT8 ROP(i8085_state *cpustate)
{
	set_status(cpustate, 0xa2); // instruction fetch
	return memory_decrypted_read_byte(cpustate->program, cpustate->PC.w.l++);
}

INLINE UINT8 ARG(i8085_state *cpustate)
{
	return memory_raw_read_byte(cpustate->program, cpustate->PC.w.l++);
}

INLINE UINT16 ARG16(i8085_state *cpustate)
{
	UINT16 w;
	w  = memory_raw_read_byte(cpustate->program, cpustate->PC.d);
	cpustate->PC.w.l++;
	w += memory_raw_read_byte(cpustate->program, cpustate->PC.d) << 8;
	cpustate->PC.w.l++;
	return w;
}

INLINE UINT8 RM(i8085_state *cpustate, UINT32 a)
{
	set_status(cpustate, 0x82); // memory read
	return memory_read_byte_8le(cpustate->program, a);
}

INLINE void WM(i8085_state *cpustate, UINT32 a, UINT8 v)
{
	set_status(cpustate, 0x00); // memory write
	memory_write_byte_8le(cpustate->program, a, v);
}


static void check_for_interrupts(i8085_state *cpustate)
{
	/* TRAP is the highest priority */
	if (cpustate->trap_pending)
	{
		/* the first RIM after a TRAP reflects the original IE state; remember it here,
           setting the high bit to indicate it is valid */
		cpustate->trap_im_copy = cpustate->IM | 0x80;

		/* reset the pending state */
		cpustate->trap_pending = FALSE;

		/* break out of HALT state and call the IRQ ack callback */
		break_halt_for_interrupt(cpustate);
		if (cpustate->irq_callback != NULL)
			(*cpustate->irq_callback)(cpustate->device, INPUT_LINE_NMI);

		/* push the PC and jump to $0024 */
		M_PUSH(PC);
		cpustate->IM &= ~IM_IE;
		cpustate->PC.w.l = ADDR_TRAP;
		cpustate->icount -= 11;
	}

	/* followed by RST7.5 */
	else if ((cpustate->IM & IM_I75) && !(cpustate->IM & IM_M75) && (cpustate->IM & IM_IE))
	{
		/* reset the pending state (which is CPU-visible via the RIM instruction) */
		cpustate->IM &= ~IM_I75;

		/* break out of HALT state and call the IRQ ack callback */
		break_halt_for_interrupt(cpustate);
		if (cpustate->irq_callback != NULL)
			(*cpustate->irq_callback)(cpustate->device, I8085_RST75_LINE);

		/* push the PC and jump to $003C */
		M_PUSH(PC);
		cpustate->IM &= ~IM_IE;
		cpustate->PC.w.l = ADDR_RST75;
		cpustate->icount -= 11;
	}

	/* followed by RST6.5 */
	else if (cpustate->irq_state[I8085_RST65_LINE] && !(cpustate->IM & IM_M65) && (cpustate->IM & IM_IE))
	{
		/* break out of HALT state and call the IRQ ack callback */
		break_halt_for_interrupt(cpustate);
		if (cpustate->irq_callback != NULL)
			(*cpustate->irq_callback)(cpustate->device, I8085_RST65_LINE);

		/* push the PC and jump to $0034 */
		M_PUSH(PC);
		cpustate->IM &= ~IM_IE;
		cpustate->PC.w.l = ADDR_RST65;
		cpustate->icount -= 11;
	}

	/* followed by RST5.5 */
	else if (cpustate->irq_state[I8085_RST55_LINE] && !(cpustate->IM & IM_M55) && (cpustate->IM & IM_IE))
	{
		/* break out of HALT state and call the IRQ ack callback */
		break_halt_for_interrupt(cpustate);
		if (cpustate->irq_callback != NULL)
			(*cpustate->irq_callback)(cpustate->device, I8085_RST55_LINE);

		/* push the PC and jump to $002C */
		M_PUSH(PC);
		cpustate->IM &= ~IM_IE;
		cpustate->PC.w.l = ADDR_RST55;
		cpustate->icount -= 11;
	}

	/* followed by classic INTR */
	else if (cpustate->irq_state[I8085_INTR_LINE] && (cpustate->IM & IM_IE))
	{
		UINT32 vector = 0;

		/* break out of HALT state and call the IRQ ack callback */
		break_halt_for_interrupt(cpustate);
		if (cpustate->irq_callback != NULL)
			vector = (*cpustate->irq_callback)(cpustate->device, I8085_INTR_LINE);

		/* use the resulting vector as an opcode to execute */
		cpustate->IM &= ~IM_IE;
		switch (vector & 0xff0000)
		{
			case 0xcd0000:	/* CALL nnnn */
				cpustate->icount -= 7;
				M_PUSH(PC);
			case 0xc30000:	/* JMP  nnnn */
				cpustate->icount -= 10;
				cpustate->PC.d = vector & 0xffff;
				break;

			default:
				LOG(("i8085 take int $%02x\n", vector));
				execute_one(cpustate, vector & 0xff);
				break;
		}
	}
}


static void execute_one(i8085_state *cpustate, int opcode)
{
	cpustate->icount -= lut_cycles[opcode];

	switch (opcode)
	{
		case 0x00:														break;	/* NOP  */
		case 0x01:	cpustate->BC.w.l = ARG16(cpustate);					break;	/* LXI  B,nnnn */
		case 0x02:	WM(cpustate, cpustate->BC.d, cpustate->AF.b.h);		break;	/* STAX B */
		case 0x03:	cpustate->BC.w.l++;											/* INX  B */
					if (IS_8085(cpustate)) { if (cpustate->BC.w.l == 0x0000) cpustate->AF.b.l |= X5F; else cpustate->AF.b.l &= ~X5F; }
					break;
		case 0x04:	M_INR(cpustate->BC.b.h);							break;	/* INR  B */
		case 0x05:	M_DCR(cpustate->BC.b.h);							break;	/* DCR  B */
		case 0x06:	M_MVI(cpustate->BC.b.h);							break;	/* MVI  B,nn */
		case 0x07:	M_RLC;												break;	/* RLC  */

		case 0x08:	if (IS_8085(cpustate)) { M_DSUB(cpustate); }				/* DSUB */
					/* else { ; } */											/* NOP  undocumented */
					break;
		case 0x09:	M_DAD(BC);											break;	/* DAD  B */
		case 0x0a:	cpustate->AF.b.h = RM(cpustate, cpustate->BC.d);	break;	/* LDAX B */
		case 0x0b:	cpustate->BC.w.l--;											/* DCX  B */
					if (IS_8085(cpustate)) { if (cpustate->BC.w.l == 0xffff) cpustate->AF.b.l |= X5F; else cpustate->AF.b.l &= ~X5F; }
					break;
		case 0x0c:	M_INR(cpustate->BC.b.l);							break;	/* INR  C */
		case 0x0d:	M_DCR(cpustate->BC.b.l);							break;	/* DCR  C */
		case 0x0e:	M_MVI(cpustate->BC.b.l);							break;	/* MVI  C,nn */
		case 0x0f:	M_RRC;												break;	/* RRC  */

		case 0x10:	if (IS_8085(cpustate)) {									/* ASRH */
						cpustate->AF.b.l = (cpustate->AF.b.l & ~CF) | (cpustate->HL.b.l & CF);
						cpustate->HL.w.l = (cpustate->HL.w.l >> 1);
					} /* else { ; } */											/* NOP  undocumented */
					break;
		case 0x11:	cpustate->DE.w.l = ARG16(cpustate);					break;	/* LXI  D,nnnn */
		case 0x12:	WM(cpustate, cpustate->DE.d, cpustate->AF.b.h);		break;	/* STAX D */
		case 0x13:	cpustate->DE.w.l++;											/* INX  D */
					if (IS_8085(cpustate)) { if (cpustate->DE.w.l == 0x0000) cpustate->AF.b.l |= X5F; else cpustate->AF.b.l &= ~X5F; }
					break;
		case 0x14:	M_INR(cpustate->DE.b.h);							break;	/* INR  D */
		case 0x15:	M_DCR(cpustate->DE.b.h);							break;	/* DCR  D */
		case 0x16:	M_MVI(cpustate->DE.b.h);							break;	/* MVI  D,nn */
		case 0x17:	M_RAL;												break;	/* RAL  */

		case 0x18:	if (IS_8085(cpustate)) {									/* RLDE */
						cpustate->AF.b.l = (cpustate->AF.b.l & ~(CF | VF)) | (cpustate->DE.b.h >> 7);
						cpustate->DE.w.l = (cpustate->DE.w.l << 1) | (cpustate->DE.w.l >> 15);
						if (0 != (((cpustate->DE.w.l >> 15) ^ cpustate->AF.b.l) & CF)) cpustate->AF.b.l |= VF;
					} /* else { ; } */											/* NOP  undocumented */
					break;
		case 0x19:	M_DAD(DE);											break;	/* DAD  D */
		case 0x1a:	cpustate->AF.b.h = RM(cpustate, cpustate->DE.d);	break;	/* LDAX D */
		case 0x1b:	cpustate->DE.w.l--;											/* DCX  D */
					if (IS_8085(cpustate)) { if (cpustate->DE.w.l == 0xffff) cpustate->AF.b.l |= X5F; else cpustate->AF.b.l &= ~X5F; }
					break;
		case 0x1c:	M_INR(cpustate->DE.b.l);							break;	/* INR  E */
		case 0x1d:	M_DCR(cpustate->DE.b.l);							break;	/* DCR  E */
		case 0x1e:	M_MVI(cpustate->DE.b.l);							break;	/* MVI  E,nn */
		case 0x1f:	M_RAR;												break;	/* RAR  */

		case 0x20:	if (IS_8085(cpustate)) {									/* RIM  */
						cpustate->AF.b.h = get_rim_value(cpustate);

						/* if we have remembered state from taking a TRAP, fix up the IE flag here */
						if (cpustate->trap_im_copy & 0x80) cpustate->AF.b.h = (cpustate->AF.b.h & ~IM_IE) | (cpustate->trap_im_copy & IM_IE);
						cpustate->trap_im_copy = 0;
					} /* else { ; } */											/* NOP  undocumented */
					break;
		case 0x21:	cpustate->HL.w.l = ARG16(cpustate);					break;	/* LXI  H,nnnn */
		case 0x22:	cpustate->WZ.w.l = ARG16(cpustate);							/* SHLD nnnn */
					WM(cpustate, cpustate->WZ.d, cpustate->HL.b.l); cpustate->WZ.w.l++;
					WM(cpustate, cpustate->WZ.d, cpustate->HL.b.h);
					break;
		case 0x23:	cpustate->HL.w.l++;											/* INX  H */
					if (IS_8085(cpustate)) { if (cpustate->HL.w.l == 0x0000) cpustate->AF.b.l |= X5F; else cpustate->AF.b.l &= ~X5F; }
					break;
		case 0x24:	M_INR(cpustate->HL.b.h);							break;	/* INR  H */
		case 0x25:	M_DCR(cpustate->HL.b.h);							break;	/* DCR  H */
		case 0x26:	M_MVI(cpustate->HL.b.h);							break;	/* MVI  H,nn */
		case 0x27:	cpustate->WZ.b.h = cpustate->AF.b.h;						/* DAA  */
					if (cpustate->AF.b.l&VF) {
						if ((cpustate->AF.b.l&HF) | ((cpustate->AF.b.h&0xf)>9)) cpustate->WZ.b.h-=6;
						if ((cpustate->AF.b.l&CF) | (cpustate->AF.b.h>0x99)) cpustate->WZ.b.h-=0x60;
					}
					else {
						if ((cpustate->AF.b.l&HF) | ((cpustate->AF.b.h&0xf)>9)) cpustate->WZ.b.h+=6;
						if ((cpustate->AF.b.l&CF) | (cpustate->AF.b.h>0x99)) cpustate->WZ.b.h+=0x60;
					}

					cpustate->AF.b.l=(cpustate->AF.b.l&3) | (cpustate->AF.b.h&0x28) | (cpustate->AF.b.h>0x99) | ((cpustate->AF.b.h^cpustate->WZ.b.h)&0x10) | ZSP[cpustate->WZ.b.h];
					cpustate->AF.b.h=cpustate->WZ.b.h;

					if (IS_8080(cpustate)) cpustate->AF.b.l &= 0xd5; // Ignore not used flags
					break;

		case 0x28:	if (IS_8085(cpustate)) {									/* LDEH nn */
						cpustate->WZ.d = ARG(cpustate);
						cpustate->DE.d = (cpustate->HL.d + cpustate->WZ.d) & 0xffff;
					} /* else { ; } */											/* NOP  undocumented */
					break;
		case 0x29:	M_DAD(HL);											break;	/* DAD  H */
		case 0x2a:	cpustate->WZ.d = ARG16(cpustate);							/* LHLD nnnn */
					cpustate->HL.b.l = RM(cpustate, cpustate->WZ.d); cpustate->WZ.w.l++;
					cpustate->HL.b.h = RM(cpustate, cpustate->WZ.d);
					break;
		case 0x2b:	cpustate->HL.w.l--;											/* DCX  H */
					if (IS_8085(cpustate)) { if (cpustate->HL.w.l == 0xffff) cpustate->AF.b.l |= X5F; else cpustate->AF.b.l &= ~X5F; }
					break;
		case 0x2c:	M_INR(cpustate->HL.b.l);							break;	/* INR  L */
		case 0x2d:	M_DCR(cpustate->HL.b.l);							break;	/* DCR  L */
		case 0x2e:	M_MVI(cpustate->HL.b.l);							break;	/* MVI  L,nn */
		case 0x2f:	cpustate->AF.b.h ^= 0xff;									/* CMA  */
					if (IS_8085(cpustate)) cpustate->AF.b.l |= HF | VF;
					break;

		case 0x30:	if (IS_8085(cpustate)) {									/* SIM  */
						/* if bit 3 is set, bits 0-2 become the new masks */
						if (cpustate->AF.b.h & 0x08) {
							cpustate->IM &= ~(IM_M55 | IM_M65 | IM_M75 | IM_I55 | IM_I65);
							cpustate->IM |= cpustate->AF.b.h & (IM_M55 | IM_M65 | IM_M75);

							/* update live state based on the new masks */
							if ((cpustate->IM & IM_M55) == 0 && cpustate->irq_state[I8085_RST55_LINE]) cpustate->IM |= IM_I55;
							if ((cpustate->IM & IM_M65) == 0 && cpustate->irq_state[I8085_RST65_LINE]) cpustate->IM |= IM_I65;
						}

						/* bit if 4 is set, the 7.5 flip-flop is cleared */
						if (cpustate->AF.b.h & 0x10) cpustate->IM &= ~IM_I75;

						/* if bit 6 is set, then bit 7 is the new SOD state */
						if (cpustate->AF.b.h & 0x40) set_sod(cpustate, cpustate->AF.b.h >> 7);

						/* check for revealed interrupts */
						check_for_interrupts(cpustate);
					} /* else { ; } */											/* NOP  undocumented */
					break;
		case 0x31:	cpustate->SP.w.l = ARG16(cpustate);					break;	/* LXI  SP,nnnn */
		case 0x32:	cpustate->WZ.d = ARG16(cpustate);							/* STAX nnnn */
					WM(cpustate, cpustate->WZ.d, cpustate->AF.b.h);
					break;
		case 0x33:	cpustate->SP.w.l++;											/* INX  SP */
					if (IS_8085(cpustate)) { if (cpustate->SP.w.l == 0x0000) cpustate->AF.b.l |= X5F; else cpustate->AF.b.l &= ~X5F; }
					break;
		case 0x34:	cpustate->WZ.b.l = RM(cpustate, cpustate->HL.d);			/* INR  M */
					M_INR(cpustate->WZ.b.l);
					WM(cpustate, cpustate->HL.d, cpustate->WZ.b.l);
					break;
		case 0x35:	cpustate->WZ.b.l = RM(cpustate, cpustate->HL.d);			/* DCR  M */
					M_DCR(cpustate->WZ.b.l);
					WM(cpustate, cpustate->HL.d, cpustate->WZ.b.l);
					break;
		case 0x36:	cpustate->WZ.b.l = ARG(cpustate);							/* MVI  M,nn */
					WM(cpustate, cpustate->HL.d, cpustate->WZ.b.l);
					break;
		case 0x37:	cpustate->AF.b.l = (cpustate->AF.b.l & 0xfe) | CF;	break;	/* STC  */

		case 0x38:	if (IS_8085(cpustate)) {									/* LDES nn */
						cpustate->WZ.d = ARG(cpustate);
						cpustate->DE.d = (cpustate->SP.d + cpustate->WZ.d) & 0xffff;
					} /* else { ; } */											/* NOP  undocumented */
					break;
		case 0x39:	M_DAD(SP);											break;	/* DAD  SP */
		case 0x3a:	cpustate->WZ.d = ARG16(cpustate);							/* LDAX nnnn */
					cpustate->AF.b.h = RM(cpustate, cpustate->WZ.d);
					break;
		case 0x3b:	cpustate->SP.w.l--;											/* DCX  SP */
					if (IS_8085(cpustate)) { if (cpustate->SP.w.l == 0xffff) cpustate->AF.b.l |= X5F; else cpustate->AF.b.l &= ~X5F; }
					break;
		case 0x3c:	M_INR(cpustate->AF.b.h);							break;	/* INR  A */
		case 0x3d:	M_DCR(cpustate->AF.b.h);							break;	/* DCR  A */
		case 0x3e:	M_MVI(cpustate->AF.b.h);							break;	/* MVI  A,nn */
		case 0x3f:	cpustate->AF.b.l = (cpustate->AF.b.l & 0xfe) | (~cpustate->AF.b.l & CF); break; /* CMC  */

		case 0x40:														break;	/* MOV  B,B */
		case 0x41:	cpustate->BC.b.h = cpustate->BC.b.l;				break;	/* MOV  B,C */
		case 0x42:	cpustate->BC.b.h = cpustate->DE.b.h;				break;	/* MOV  B,D */
		case 0x43:	cpustate->BC.b.h = cpustate->DE.b.l;				break;	/* MOV  B,E */
		case 0x44:	cpustate->BC.b.h = cpustate->HL.b.h;				break;	/* MOV  B,H */
		case 0x45:	cpustate->BC.b.h = cpustate->HL.b.l;				break;	/* MOV  B,L */
		case 0x46:	cpustate->BC.b.h = RM(cpustate, cpustate->HL.d);	break;	/* MOV  B,M */
		case 0x47:	cpustate->BC.b.h = cpustate->AF.b.h;				break;	/* MOV  B,A */

		case 0x48:	cpustate->BC.b.l = cpustate->BC.b.h;				break;	/* MOV  C,B */
		case 0x49:														break;	/* MOV  C,C */
		case 0x4a:	cpustate->BC.b.l = cpustate->DE.b.h;				break;	/* MOV  C,D */
		case 0x4b:	cpustate->BC.b.l = cpustate->DE.b.l;				break;	/* MOV  C,E */
		case 0x4c:	cpustate->BC.b.l = cpustate->HL.b.h;				break;	/* MOV  C,H */
		case 0x4d:	cpustate->BC.b.l = cpustate->HL.b.l;				break;	/* MOV  C,L */
		case 0x4e:	cpustate->BC.b.l = RM(cpustate, cpustate->HL.d);	break;	/* MOV  C,M */
		case 0x4f:	cpustate->BC.b.l = cpustate->AF.b.h;				break;	/* MOV  C,A */

		case 0x50:	cpustate->DE.b.h = cpustate->BC.b.h;				break;	/* MOV  D,B */
		case 0x51:	cpustate->DE.b.h = cpustate->BC.b.l;				break;	/* MOV  D,C */
		case 0x52:														break;	/* MOV  D,D */
		case 0x53:	cpustate->DE.b.h = cpustate->DE.b.l;				break;	/* MOV  D,E */
		case 0x54:	cpustate->DE.b.h = cpustate->HL.b.h;				break;	/* MOV  D,H */
		case 0x55:	cpustate->DE.b.h = cpustate->HL.b.l;				break;	/* MOV  D,L */
		case 0x56:	cpustate->DE.b.h = RM(cpustate, cpustate->HL.d);	break;	/* MOV  D,M */
		case 0x57:	cpustate->DE.b.h = cpustate->AF.b.h;				break;	/* MOV  D,A */

		case 0x58:	cpustate->DE.b.l = cpustate->BC.b.h;				break;	/* MOV  E,B */
		case 0x59:	cpustate->DE.b.l = cpustate->BC.b.l;				break;	/* MOV  E,C */
		case 0x5a:	cpustate->DE.b.l = cpustate->DE.b.h;				break;	/* MOV  E,D */
		case 0x5b:														break;	/* MOV  E,E */
		case 0x5c:	cpustate->DE.b.l = cpustate->HL.b.h;				break;	/* MOV  E,H */
		case 0x5d:	cpustate->DE.b.l = cpustate->HL.b.l;				break;	/* MOV  E,L */
		case 0x5e:	cpustate->DE.b.l = RM(cpustate, cpustate->HL.d);	break;	/* MOV  E,M */
		case 0x5f:	cpustate->DE.b.l = cpustate->AF.b.h;				break;	/* MOV  E,A */

		case 0x60:	cpustate->HL.b.h = cpustate->BC.b.h;				break;	/* MOV  H,B */
		case 0x61:	cpustate->HL.b.h = cpustate->BC.b.l;				break;	/* MOV  H,C */
		case 0x62:	cpustate->HL.b.h = cpustate->DE.b.h;				break;	/* MOV  H,D */
		case 0x63:	cpustate->HL.b.h = cpustate->DE.b.l;				break;	/* MOV  H,E */
		case 0x64:														break;	/* MOV  H,H */
		case 0x65:	cpustate->HL.b.h = cpustate->HL.b.l;				break;	/* MOV  H,L */
		case 0x66:	cpustate->HL.b.h = RM(cpustate, cpustate->HL.d);	break;	/* MOV  H,M */
		case 0x67:	cpustate->HL.b.h = cpustate->AF.b.h;				break;	/* MOV  H,A */

		case 0x68:	cpustate->HL.b.l = cpustate->BC.b.h;				break;	/* MOV  L,B */
		case 0x69:	cpustate->HL.b.l = cpustate->BC.b.l;				break;	/* MOV  L,C */
		case 0x6a:	cpustate->HL.b.l = cpustate->DE.b.h;				break;	/* MOV  L,D */
		case 0x6b:	cpustate->HL.b.l = cpustate->DE.b.l;				break;	/* MOV  L,E */
		case 0x6c:	cpustate->HL.b.l = cpustate->HL.b.h;				break;	/* MOV  L,H */
		case 0x6d:														break;	/* MOV  L,L */
		case 0x6e:	cpustate->HL.b.l = RM(cpustate, cpustate->HL.d);	break;	/* MOV  L,M */
		case 0x6f:	cpustate->HL.b.l = cpustate->AF.b.h;				break;	/* MOV  L,A */

		case 0x70:	WM(cpustate, cpustate->HL.d, cpustate->BC.b.h);		break;	/* MOV  M,B */
		case 0x71:	WM(cpustate, cpustate->HL.d, cpustate->BC.b.l);		break;	/* MOV  M,C */
		case 0x72:	WM(cpustate, cpustate->HL.d, cpustate->DE.b.h);		break;	/* MOV  M,D */
		case 0x73:	WM(cpustate, cpustate->HL.d, cpustate->DE.b.l);		break;	/* MOV  M,E */
		case 0x74:	WM(cpustate, cpustate->HL.d, cpustate->HL.b.h);		break;	/* MOV  M,H */
		case 0x75:	WM(cpustate, cpustate->HL.d, cpustate->HL.b.l);		break;	/* MOV  M,L */
		case 0x76:	cpustate->PC.w.l--; cpustate->HALT = 1;						/* HLT */
					set_status(cpustate, 0x8a); // halt acknowledge
					break;
		case 0x77:	WM(cpustate, cpustate->HL.d, cpustate->AF.b.h);		break;	/* MOV  M,A */

		case 0x78:	cpustate->AF.b.h = cpustate->BC.b.h;				break;	/* MOV  A,B */
		case 0x79:	cpustate->AF.b.h = cpustate->BC.b.l;				break;	/* MOV  A,C */
		case 0x7a:	cpustate->AF.b.h = cpustate->DE.b.h;				break;	/* MOV  A,D */
		case 0x7b:	cpustate->AF.b.h = cpustate->DE.b.l;				break;	/* MOV  A,E */
		case 0x7c:	cpustate->AF.b.h = cpustate->HL.b.h;				break;	/* MOV  A,H */
		case 0x7d:	cpustate->AF.b.h = cpustate->HL.b.l;				break;	/* MOV  A,L */
		case 0x7e:	cpustate->AF.b.h = RM(cpustate, cpustate->HL.d);	break;	/* MOV  A,M */
		case 0x7f:														break;	/* MOV  A,A */

		case 0x80:	M_ADD(cpustate->BC.b.h);							break;	/* ADD  B */
		case 0x81:	M_ADD(cpustate->BC.b.l);							break;	/* ADD  C */
		case 0x82:	M_ADD(cpustate->DE.b.h);							break;	/* ADD  D */
		case 0x83:	M_ADD(cpustate->DE.b.l);							break;	/* ADD  E */
		case 0x84:	M_ADD(cpustate->HL.b.h);							break;	/* ADD  H */
		case 0x85:	M_ADD(cpustate->HL.b.l);							break;	/* ADD  L */
		case 0x86:	cpustate->WZ.b.l = RM(cpustate, cpustate->HL.d); M_ADD(cpustate->WZ.b.l); break; /* ADD  M */
		case 0x87:	M_ADD(cpustate->AF.b.h);							break;	/* ADD  A */

		case 0x88:	M_ADC(cpustate->BC.b.h);							break;	/* ADC  B */
		case 0x89:	M_ADC(cpustate->BC.b.l);							break;	/* ADC  C */
		case 0x8a:	M_ADC(cpustate->DE.b.h);							break;	/* ADC  D */
		case 0x8b:	M_ADC(cpustate->DE.b.l);							break;	/* ADC  E */
		case 0x8c:	M_ADC(cpustate->HL.b.h);							break;	/* ADC  H */
		case 0x8d:	M_ADC(cpustate->HL.b.l);							break;	/* ADC  L */
		case 0x8e:	cpustate->WZ.b.l = RM(cpustate, cpustate->HL.d); M_ADC(cpustate->WZ.b.l); break; /* ADC  M */
		case 0x8f:	M_ADC(cpustate->AF.b.h);							break;	/* ADC  A */

		case 0x90:	M_SUB(cpustate->BC.b.h);							break;	/* SUB  B */
		case 0x91:	M_SUB(cpustate->BC.b.l);							break;	/* SUB  C */
		case 0x92:	M_SUB(cpustate->DE.b.h);							break;	/* SUB  D */
		case 0x93:	M_SUB(cpustate->DE.b.l);							break;	/* SUB  E */
		case 0x94:	M_SUB(cpustate->HL.b.h);							break;	/* SUB  H */
		case 0x95:	M_SUB(cpustate->HL.b.l);							break;	/* SUB  L */
		case 0x96:	cpustate->WZ.b.l = RM(cpustate, cpustate->HL.d); M_SUB(cpustate->WZ.b.l); break; /* SUB  M */
		case 0x97:	M_SUB(cpustate->AF.b.h);							break;	/* SUB  A */

		case 0x98:	M_SBB(cpustate->BC.b.h);							break;	/* SBB  B */
		case 0x99:	M_SBB(cpustate->BC.b.l);							break;	/* SBB  C */
		case 0x9a:	M_SBB(cpustate->DE.b.h);							break;	/* SBB  D */
		case 0x9b:	M_SBB(cpustate->DE.b.l);							break;	/* SBB  E */
		case 0x9c:	M_SBB(cpustate->HL.b.h);							break;	/* SBB  H */
		case 0x9d:	M_SBB(cpustate->HL.b.l);							break;	/* SBB  L */
		case 0x9e:	cpustate->WZ.b.l = RM(cpustate, cpustate->HL.d); M_SBB(cpustate->WZ.b.l); break; /* SBB  M */
		case 0x9f:	M_SBB(cpustate->AF.b.h);							break;	/* SBB  A */

		case 0xa0:	M_ANA(cpustate->BC.b.h);							break;	/* ANA  B */
		case 0xa1:	M_ANA(cpustate->BC.b.l);							break;	/* ANA  C */
		case 0xa2:	M_ANA(cpustate->DE.b.h);							break;	/* ANA  D */
		case 0xa3:	M_ANA(cpustate->DE.b.l);							break;	/* ANA  E */
		case 0xa4:	M_ANA(cpustate->HL.b.h);							break;	/* ANA  H */
		case 0xa5:	M_ANA(cpustate->HL.b.l);							break;	/* ANA  L */
		case 0xa6:	cpustate->WZ.b.l = RM(cpustate, cpustate->HL.d); M_ANA(cpustate->WZ.b.l); break; /* ANA  M */
		case 0xa7:	M_ANA(cpustate->AF.b.h);							break;	/* ANA  A */

		case 0xa8:	M_XRA(cpustate->BC.b.h);							break;	/* XRA  B */
		case 0xa9:	M_XRA(cpustate->BC.b.l);							break;	/* XRA  C */
		case 0xaa:	M_XRA(cpustate->DE.b.h);							break;	/* XRA  D */
		case 0xab:	M_XRA(cpustate->DE.b.l);							break;	/* XRA  E */
		case 0xac:	M_XRA(cpustate->HL.b.h);							break;	/* XRA  H */
		case 0xad:	M_XRA(cpustate->HL.b.l);							break;	/* XRA  L */
		case 0xae:	cpustate->WZ.b.l = RM(cpustate, cpustate->HL.d); M_XRA(cpustate->WZ.b.l); break; /* XRA  M */
		case 0xaf:	M_XRA(cpustate->AF.b.h);							break;	/* XRA  A */

		case 0xb0:	M_ORA(cpustate->BC.b.h);							break;	/* ORA  B */
		case 0xb1:	M_ORA(cpustate->BC.b.l);							break;	/* ORA  C */
		case 0xb2:	M_ORA(cpustate->DE.b.h);							break;	/* ORA  D */
		case 0xb3:	M_ORA(cpustate->DE.b.l);							break;	/* ORA  E */
		case 0xb4:	M_ORA(cpustate->HL.b.h);							break;	/* ORA  H */
		case 0xb5:	M_ORA(cpustate->HL.b.l);							break;	/* ORA  L */
		case 0xb6:	cpustate->WZ.b.l = RM(cpustate, cpustate->HL.d); M_ORA(cpustate->WZ.b.l); break; /* ORA  M */
		case 0xb7:	M_ORA(cpustate->AF.b.h);							break;	/* ORA  A */

		case 0xb8:	M_CMP(cpustate->BC.b.h);							break;	/* CMP  B */
		case 0xb9:	M_CMP(cpustate->BC.b.l);							break;	/* CMP  C */
		case 0xba:	M_CMP(cpustate->DE.b.h);							break;	/* CMP  D */
		case 0xbb:	M_CMP(cpustate->DE.b.l);							break;	/* CMP  E */
		case 0xbc:	M_CMP(cpustate->HL.b.h);							break;	/* CMP  H */
		case 0xbd:	M_CMP(cpustate->HL.b.l);							break;	/* CMP  L */
		case 0xbe:	cpustate->WZ.b.l = RM(cpustate, cpustate->HL.d); M_CMP(cpustate->WZ.b.l); break; /* CMP  M */
		case 0xbf:	M_CMP(cpustate->AF.b.h);							break;	/* CMP  A */

		case 0xc0:	M_RET( !(cpustate->AF.b.l & ZF) );					break;	/* RNZ  */
		case 0xc1:	M_POP(BC);											break;	/* POP  B */
		case 0xc2:	M_JMP( !(cpustate->AF.b.l & ZF) );					break;	/* JNZ  nnnn */
		case 0xc3:	M_JMP(1);											break;	/* JMP  nnnn */
		case 0xc4:	M_CALL( !(cpustate->AF.b.l & ZF) );					break;	/* CNZ  nnnn */
		case 0xc5:	M_PUSH(BC);											break;	/* PUSH B */
		case 0xc6:	cpustate->WZ.b.l = ARG(cpustate); M_ADD(cpustate->WZ.b.l); break; /* ADI  nn */
		case 0xc7:	M_RST(0);											break;	/* RST  0 */

		case 0xc8:	M_RET( cpustate->AF.b.l & ZF );						break;	/* RZ   */
		case 0xc9:	M_POP(PC);											break;	/* RET  */
		case 0xca:	M_JMP( cpustate->AF.b.l & ZF );						break;	/* JZ   nnnn */
		case 0xcb:	if (IS_8085(cpustate)) {									/* RST  V */
						if (cpustate->AF.b.l & VF) { M_RST(8); }
						else cpustate->icount += 6; // RST not taken
					} else { M_JMP(1); }										/* JMP  nnnn undocumented */
					break;
		case 0xcc:	M_CALL( cpustate->AF.b.l & ZF );					break;	/* CZ   nnnn */
		case 0xcd:	M_CALL(1);											break;	/* CALL nnnn */
		case 0xce:	cpustate->WZ.b.l = ARG(cpustate); M_ADC(cpustate->WZ.b.l); break; /* ACI  nn */
		case 0xcf:	M_RST(1);											break;	/* RST  1 */

		case 0xd0:	M_RET( !(cpustate->AF.b.l & CF) );					break;	/* RNC  */
		case 0xd1:	M_POP(DE);											break;	/* POP  D */
		case 0xd2:	M_JMP( !(cpustate->AF.b.l & CF) );					break;	/* JNC  nnnn */
		case 0xd3:	M_OUT;												break;	/* OUT  nn */
		case 0xd4:	M_CALL( !(cpustate->AF.b.l & CF) );					break;	/* CNC  nnnn */
		case 0xd5:	M_PUSH(DE);											break;	/* PUSH D */
		case 0xd6:	cpustate->WZ.b.l = ARG(cpustate); M_SUB(cpustate->WZ.b.l); break; /* SUI  nn */
		case 0xd7:	M_RST(2);											break;	/* RST  2 */

		case 0xd8:	M_RET( cpustate->AF.b.l & CF );						break;	/* RC   */
		case 0xd9:	if (IS_8085(cpustate)) {									/* SHLX */
						cpustate->WZ.w.l = cpustate->DE.w.l;
						WM(cpustate, cpustate->WZ.d, cpustate->HL.b.l); cpustate->WZ.w.l++;
						WM(cpustate, cpustate->WZ.d, cpustate->HL.b.h);
					} else { M_POP(PC); }										/* RET  undocumented */
					break;
		case 0xda:	M_JMP( cpustate->AF.b.l & CF );						break;	/* JC   nnnn */
		case 0xdb:	M_IN;												break;	/* IN   nn */
		case 0xdc:	M_CALL( cpustate->AF.b.l & CF );					break;	/* CC   nnnn */
		case 0xdd:	if (IS_8085(cpustate)) { M_JMP( !(cpustate->AF.b.l & X5F) ); } /* JNX  nnnn */
					else { M_CALL(1); }											/* CALL nnnn undocumented */
					break;
		case 0xde:	cpustate->WZ.b.l = ARG(cpustate); M_SBB(cpustate->WZ.b.l); break; /* SBI  nn */
		case 0xdf:	M_RST(3);											break;	/* RST  3 */

		case 0xe0:	M_RET( !(cpustate->AF.b.l & PF) );					break;	/* RPO    */
		case 0xe1:	M_POP(HL);											break;	/* POP  H */
		case 0xe2:	M_JMP( !(cpustate->AF.b.l & PF) );					break;	/* JPO  nnnn */
		case 0xe3:	M_POP(WZ); M_PUSH(HL);										/* XTHL */
					cpustate->HL.d = cpustate->WZ.d;
					break;
		case 0xe4:	M_CALL( !(cpustate->AF.b.l & PF) );					break;	/* CPO  nnnn */
		case 0xe5:	M_PUSH(HL);											break;	/* PUSH H */
		case 0xe6:	cpustate->WZ.b.l = ARG(cpustate); M_ANA(cpustate->WZ.b.l); break; /* ANI  nn */
		case 0xe7:	M_RST(4);											break;	/* RST  4 */

		case 0xe8:	M_RET( cpustate->AF.b.l & PF );						break;	/* RPE  */
		case 0xe9:	cpustate->PC.d = cpustate->HL.w.l;					break;	/* PCHL */
		case 0xea:	M_JMP( cpustate->AF.b.l & PF );						break;	/* JPE  nnnn */
		case 0xeb:	cpustate->WZ.d = cpustate->DE.d;							/* XCHG */
					cpustate->DE.d = cpustate->HL.d;
					cpustate->HL.d = cpustate->WZ.d;
					break;
		case 0xec:	M_CALL( cpustate->AF.b.l & PF );					break;	/* CPE  nnnn */
		case 0xed:	if (IS_8085(cpustate)) {									/* LHLX */
						cpustate->WZ.w.l = cpustate->DE.w.l;
						cpustate->HL.b.l = RM(cpustate, cpustate->WZ.d); cpustate->WZ.w.l++;
						cpustate->HL.b.h = RM(cpustate, cpustate->WZ.d);
					} else { M_CALL(1); }										/* CALL nnnn undocumented */
					break;
		case 0xee:	cpustate->WZ.b.l = ARG(cpustate); M_XRA(cpustate->WZ.b.l); break; /* XRI  nn */
		case 0xef:	M_RST(5);											break;	/* RST  5 */

		case 0xf0:	M_RET( !(cpustate->AF.b.l&SF) );					break;	/* RP   */
		case 0xf1:	M_POP(AF);											break;	/* POP  A */
		case 0xf2:	M_JMP( !(cpustate->AF.b.l & SF) );					break;	/* JP   nnnn */
		case 0xf3:	set_inte(cpustate, 0);								break;	/* DI   */
		case 0xf4:	M_CALL( !(cpustate->AF.b.l & SF) );					break;	/* CP   nnnn */
		case 0xf5:	M_PUSH(AF);											break;	/* PUSH A */
		case 0xf6:	cpustate->WZ.b.l = ARG(cpustate); M_ORA(cpustate->WZ.b.l); break; /* ORI  nn */
		case 0xf7:	M_RST(6);											break;	/* RST  6 */

		case 0xf8:	M_RET( cpustate->AF.b.l & SF );						break;	/* RM   */
		case 0xf9:	cpustate->SP.d = cpustate->HL.d;					break;	/* SPHL */
		case 0xfa:	M_JMP( cpustate->AF.b.l & SF );						break;	/* JM   nnnn */
		case 0xfb:	set_inte(cpustate, 1); cpustate->after_ei = 2;		break;	/* EI */
		case 0xfc:	M_CALL( cpustate->AF.b.l & SF );					break;	/* CM   nnnn */
		case 0xfd:	if (IS_8085(cpustate)) { M_JMP( cpustate->AF.b.l & X5F ); }	/* JX   nnnn */
					else { M_CALL(1); }											/* CALL nnnn undocumented */
					break;
		case 0xfe:	cpustate->WZ.b.l = ARG(cpustate); M_CMP(cpustate->WZ.b.l); break; /* CPI  nn */
		case 0xff:	M_RST(7);											break;	/* RST  7 */
	}
}


/***************************************************************************
    COMMON EXECUTION
***************************************************************************/

static CPU_EXECUTE( i808x )
{
	i8085_state *cpustate = get_safe_token(device);

	cpustate->icount = cycles;

	/* check for TRAPs before diving in (can't do others because of after_ei) */
	if (cpustate->trap_pending || cpustate->after_ei == 0)
		check_for_interrupts(cpustate);

	do
	{
		debugger_instruction_hook(device, cpustate->PC.d);

		/* the instruction after an EI does not take an interrupt, so
           we cannot check immediately; handle post-EI behavior here */
		if (cpustate->after_ei != 0 && --cpustate->after_ei == 0)
			check_for_interrupts(cpustate);

		/* here we go... */
		execute_one(cpustate, ROP(cpustate));

	} while (cpustate->icount > 0);

	return cycles - cpustate->icount;
}



/***************************************************************************
    CORE INITIALIZATION
***************************************************************************/

static void init_tables (int type)
{
	UINT8 zs;
	int i, p;
	for (i = 0; i < 256; i++)
	{
		/* cycles */
		lut_cycles[i] = type?lut_cycles_8085[i]:lut_cycles_8080[i];

		/* flags */
		zs = 0;
		if (i==0) zs |= ZF;
		if (i&128) zs |= SF;
		p = 0;
		if (i&1) ++p;
		if (i&2) ++p;
		if (i&4) ++p;
		if (i&8) ++p;
		if (i&16) ++p;
		if (i&32) ++p;
		if (i&64) ++p;
		if (i&128) ++p;
		ZS[i] = zs;
		ZSP[i] = zs | ((p&1) ? 0 : PF);
	}
}


static void init_808x_common(const device_config *device, cpu_irq_callback irqcallback, int type)
{
	i8085_state *cpustate = get_safe_token(device);

	init_tables(type);

	/* set up the state table */
	cpustate->state = state_table_template;
	cpustate->state.baseptr = cpustate;
	cpustate->state.subtypemask = 1 << type;

	if (device->static_config != NULL)
		cpustate->config = *(i8085_config *)device->static_config;
	cpustate->cputype = type;
	cpustate->irq_callback = irqcallback;
	cpustate->device = device;

	cpustate->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM);
	cpustate->io = memory_find_address_space(device, ADDRESS_SPACE_IO);

	/* resolve callbacks */
	devcb_resolve_write8(&cpustate->out_status_func, &cpustate->config.out_status_func, device);
	devcb_resolve_write_line(&cpustate->out_inte_func, &cpustate->config.out_inte_func, device);
	devcb_resolve_read_line(&cpustate->in_sid_func, &cpustate->config.in_sid_func, device);
	devcb_resolve_write_line(&cpustate->out_sod_func, &cpustate->config.out_sod_func, device);

	/* register for state saving */
	state_save_register_device_item(device, 0, cpustate->PC.w.l);
	state_save_register_device_item(device, 0, cpustate->SP.w.l);
	state_save_register_device_item(device, 0, cpustate->AF.w.l);
	state_save_register_device_item(device, 0, cpustate->BC.w.l);
	state_save_register_device_item(device, 0, cpustate->DE.w.l);
	state_save_register_device_item(device, 0, cpustate->HL.w.l);
	state_save_register_device_item(device, 0, cpustate->HALT);
	state_save_register_device_item(device, 0, cpustate->IM);
	state_save_register_device_item(device, 0, cpustate->STATUS);
	state_save_register_device_item(device, 0, cpustate->after_ei);
	state_save_register_device_item(device, 0, cpustate->nmi_state);
	state_save_register_device_item_array(device, 0, cpustate->irq_state);
	state_save_register_device_item(device, 0, cpustate->trap_pending);
	state_save_register_device_item(device, 0, cpustate->trap_im_copy);
	state_save_register_device_item(device, 0, cpustate->sod_state);
}

static CPU_INIT( i8080 )
{
	init_808x_common(device, irqcallback, CPUTYPE_8080);
}

static CPU_INIT( i8085 )
{
	init_808x_common(device, irqcallback, CPUTYPE_8085);
}



/***************************************************************************
    COMMON RESET
***************************************************************************/

static CPU_RESET( i808x )
{
	i8085_state *cpustate = get_safe_token(device);

	cpustate->PC.d = 0;
	cpustate->HALT = 0;
	cpustate->IM &= ~IM_I75;
	cpustate->IM |= IM_M55 | IM_M65 | IM_M75;
	cpustate->after_ei = FALSE;
	cpustate->trap_pending = FALSE;
	cpustate->trap_im_copy = 0;
	set_inte(cpustate, 0);
	set_sod(cpustate, 0);
}



/***************************************************************************
    COMMON STATE IMPORT/EXPORT
***************************************************************************/

static CPU_IMPORT_STATE( i808x )
{
	i8085_state *cpustate = get_safe_token(device);

	switch (entry->index)
	{
		case I8085_SID:
			if (cpustate->ietemp)
				cpustate->IM |= IM_SID;
			else
				cpustate->IM &= ~IM_SID;
			break;

		case I8085_INTE:
			if (cpustate->ietemp)
				cpustate->IM |= IM_IE;
			else
				cpustate->IM &= ~IM_IE;
			break;

		default:
			fatalerror("CPU_IMPORT_STATE(i808x) called for unexpected value\n");
			break;
	}
}


static CPU_EXPORT_STATE( i808x )
{
	i8085_state *cpustate = get_safe_token(device);

	switch (entry->index)
	{
		case I8085_SID:
			{
			int sid = devcb_call_read_line(&cpustate->in_sid_func);

			cpustate->ietemp = ((cpustate->IM & IM_SID) != 0);
			cpustate->ietemp = (sid != 0);
			}
			break;

		case I8085_INTE:
			cpustate->ietemp = ((cpustate->IM & IM_IE) != 0);
			break;

		default:
			fatalerror("CPU_EXPORT_STATE(i808x) called for unexpected value\n");
			break;
	}
}



/***************************************************************************
    COMMON SET INFO
***************************************************************************/

static void i808x_set_irq_line(i8085_state *cpustate, int irqline, int state)
{
	int newstate = (state != CLEAR_LINE);

	/* NMI is edge-triggered */
	if (irqline == INPUT_LINE_NMI)
	{
		if (!cpustate->nmi_state && newstate)
			cpustate->trap_pending = TRUE;
		cpustate->nmi_state = newstate;
	}

	/* RST7.5 is edge-triggered */
	else if (irqline == I8085_RST75_LINE)
	{
		if (!cpustate->irq_state[I8085_RST75_LINE] && newstate)
			cpustate->IM |= IM_I75;
		cpustate->irq_state[I8085_RST75_LINE] = newstate;
	}

	/* remaining sources are level triggered */
	else if (irqline < ARRAY_LENGTH(cpustate->irq_state))
		cpustate->irq_state[irqline] = state;
}


static CPU_SET_INFO( i808x )
{
	i8085_state *cpustate = get_safe_token(device);
	switch (state)
	{
		/* --- the following bits of info are set as 64-bit signed integers --- */
		case CPUINFO_INT_INPUT_STATE + I8085_INTR_LINE:
		case CPUINFO_INT_INPUT_STATE + I8085_RST55_LINE:
		case CPUINFO_INT_INPUT_STATE + I8085_RST65_LINE:
		case CPUINFO_INT_INPUT_STATE + I8085_RST75_LINE:
		case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI:
			i808x_set_irq_line(cpustate, state - CPUINFO_INT_INPUT_STATE, info->i);
			break;
	}
}



/***************************************************************************
    8085/COMMON GET INFO
***************************************************************************/

CPU_GET_INFO( i8085 )
{
	i8085_state *cpustate = (device != NULL && device->token != NULL) ? get_safe_token(device) : NULL;
	switch (state)
	{
		/* --- the following bits of info are returned as 64-bit signed integers --- */
		case CPUINFO_INT_CONTEXT_SIZE:					info->i = sizeof(i8085_state);			break;
		case CPUINFO_INT_INPUT_LINES:					info->i = 4;							break;
		case CPUINFO_INT_DEFAULT_IRQ_VECTOR:			info->i = 0xff;							break;
		case DEVINFO_INT_ENDIANNESS:					info->i = ENDIANNESS_LITTLE;			break;
		case CPUINFO_INT_CLOCK_MULTIPLIER:				info->i = 1;							break;
		case CPUINFO_INT_CLOCK_DIVIDER:					info->i = 2;							break;
		case CPUINFO_INT_MIN_INSTRUCTION_BYTES:			info->i = 1;							break;
		case CPUINFO_INT_MAX_INSTRUCTION_BYTES:			info->i = 3;							break;
		case CPUINFO_INT_MIN_CYCLES:					info->i = 4;							break;
		case CPUINFO_INT_MAX_CYCLES:					info->i = 16;							break;

		case CPUINFO_INT_DATABUS_WIDTH_PROGRAM:			info->i = 8;							break;
		case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: 		info->i = 16;							break;
		case CPUINFO_INT_ADDRBUS_SHIFT_PROGRAM: 		info->i = 0;							break;
		case CPUINFO_INT_DATABUS_WIDTH_IO:				info->i = 8;							break;
		case CPUINFO_INT_ADDRBUS_WIDTH_IO: 				info->i = 8;							break;
		case CPUINFO_INT_ADDRBUS_SHIFT_IO: 				info->i = 0;							break;

		/* --- the following bits of info are returned as pointers to functions --- */
		case CPUINFO_FCT_SET_INFO:		info->setinfo = CPU_SET_INFO_NAME(i808x);				break;
		case CPUINFO_FCT_INIT:			info->init = CPU_INIT_NAME(i8085);						break;
		case CPUINFO_FCT_RESET:			info->reset = CPU_RESET_NAME(i808x);					break;
		case CPUINFO_FCT_EXECUTE:		info->execute = CPU_EXECUTE_NAME(i808x);				break;
		case CPUINFO_FCT_DISASSEMBLE:	info->disassemble = CPU_DISASSEMBLE_NAME(i8085);		break;
		case CPUINFO_FCT_IMPORT_STATE:	info->import_state = CPU_IMPORT_STATE_NAME(i808x);		break;
		case CPUINFO_FCT_EXPORT_STATE:	info->export_state = CPU_EXPORT_STATE_NAME(i808x);		break;

		/* --- the following bits of info are returned as pointers --- */
		case CPUINFO_PTR_INSTRUCTION_COUNTER:			info->icount = &cpustate->icount;		break;
		case CPUINFO_PTR_STATE_TABLE:					info->state_table = &cpustate->state;	break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case DEVINFO_STR_NAME:							strcpy(info->s, "8085A");				break;
		case DEVINFO_STR_FAMILY:						strcpy(info->s, "MCS-85");				break;
		case DEVINFO_STR_VERSION:						strcpy(info->s, "1.1");					break;
		case DEVINFO_STR_SOURCE_FILE:					strcpy(info->s, __FILE__);				break;
		case DEVINFO_STR_CREDITS:						strcpy(info->s, "Copyright Juergen Buchmueller, all rights reserved."); break;

		case CPUINFO_STR_FLAGS:
			sprintf(info->s, "%c%c%c%c%c%c%c%c",
				cpustate->AF.b.l & 0x80 ? 'S':'.',
				cpustate->AF.b.l & 0x40 ? 'Z':'.',
				cpustate->AF.b.l & 0x20 ? 'X':'.', // X5
				cpustate->AF.b.l & 0x10 ? 'H':'.',
				cpustate->AF.b.l & 0x08 ? '?':'.',
				cpustate->AF.b.l & 0x04 ? 'P':'.',
				cpustate->AF.b.l & 0x02 ? 'V':'.',
				cpustate->AF.b.l & 0x01 ? 'C':'.');
			break;
	}
}


/***************************************************************************
    8080-SPECIFIC GET INFO
***************************************************************************/

CPU_GET_INFO( i8080 )
{
	switch (state)
	{
		/* --- the following bits of info are returned as 64-bit signed integers --- */
		case CPUINFO_INT_CLOCK_DIVIDER:					info->i = 1;							break;
		case CPUINFO_INT_INPUT_LINES:					info->i = 1;							break;

		/* --- the following bits of info are returned as pointers to functions --- */
		case CPUINFO_FCT_INIT:			info->init = CPU_INIT_NAME(i8080);						break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case DEVINFO_STR_NAME:							strcpy(info->s, "8080");				break;
		case DEVINFO_STR_FAMILY:						strcpy(info->s, "MCS-80");				break;

		default:										CPU_GET_INFO_CALL(i8085); break;
	}
}


/***************************************************************************
    8080A-SPECIFIC GET INFO
***************************************************************************/

CPU_GET_INFO( i8080a )
{
	switch (state)
	{
		/* --- the following bits of info are returned as 64-bit signed integers --- */
		case CPUINFO_INT_CLOCK_DIVIDER:					info->i = 1;							break;
		case CPUINFO_INT_INPUT_LINES:					info->i = 1;							break;

		/* --- the following bits of info are returned as pointers to functions --- */
		case CPUINFO_FCT_INIT:			info->init = CPU_INIT_NAME(i8080);						break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case DEVINFO_STR_NAME:							strcpy(info->s, "8080A");				break;
		case DEVINFO_STR_FAMILY:						strcpy(info->s, "MCS-80");				break;

		default:										CPU_GET_INFO_CALL(i8085); break;
	}
}
