/*****************************************************************************
 *
 *   z8000.c
 *   Portable Z8000(2) emulator
 *   Z8000 MAME interface
 *
 *   Copyright (C) 1998,1999,2000 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.
 *
 *****************************************************************************/

#include "driver.h"
#include "mamedbg.h"
#include "z8000.h"
#include "z8000cpu.h"

#define VERBOSE 0


#if VERBOSE
#define LOG(x)	logerror x
#else
#define LOG(x)
#endif

static UINT8 z8000_reg_layout[] = {
	Z8000_PC, Z8000_NSP, Z8000_FCW, Z8000_PSAP, Z8000_REFRESH, -1,
	Z8000_R0, Z8000_R1, Z8000_R2, Z8000_R3, Z8000_R4, Z8000_R5, Z8000_R6, Z8000_R7, -1,
	Z8000_R8, Z8000_R9, Z8000_R10,Z8000_R11,Z8000_R12,Z8000_R13,Z8000_R14,Z8000_R15,-1,
	Z8000_IRQ_REQ, Z8000_IRQ_SRV, Z8000_IRQ_VEC, 0
};

static UINT8 z8000_win_layout[] = {
	 0, 0,80, 4,	/* register window (top rows) */
	 0, 5,26,17,	/* disassembler window (left colums) */
	27, 5,53, 8,	/* memory #1 window (right, upper middle) */
	27,14,53, 8,	/* memory #2 window (right, lower middle) */
	 0,23,80, 1,	/* command line window (bottom rows) */
};

/* opcode execution table */
Z8000_exec *z8000_exec = NULL;

typedef union {
    UINT8   B[16]; /* RL0,RH0,RL1,RH1...RL7,RH7 */
    UINT16  W[16]; /* R0,R1,R2...R15 */
    UINT32  L[8];  /* RR0,RR2,RR4..RR14 */
    UINT64  Q[4];  /* RQ0,RQ4,..RQ12 */
}   z8000_reg_file;

typedef struct {
    UINT16  op[4];      /* opcodes/data of current instruction */
	UINT16	ppc;		/* previous program counter */
    UINT16  pc;         /* program counter */
    UINT16  psap;       /* program status pointer */
    UINT16  fcw;        /* flags and control word */
    UINT16  refresh;    /* refresh timer/counter */
    UINT16  nsp;        /* system stack pointer */
    UINT16  irq_req;    /* CPU is halted, interrupt or trap request */
    UINT16  irq_srv;    /* serviced interrupt request */
    UINT16  irq_vec;    /* interrupt vector */
    z8000_reg_file regs;/* registers */
	int nmi_state;		/* NMI line state */
	int irq_state[2];	/* IRQ line states (NVI, VI) */
    int (*irq_callback)(int irqline);
}   z8000_Regs;

int z8000_ICount;

/* current CPU context */
static z8000_Regs Z;

/* zero, sign and parity flags for logical byte operations */
static UINT8 z8000_zsp[256];

/* conversion table for Z8000 DAB opcode */
#include "z8000dab.h"

/**************************************************************************
 * This is the register file layout:
 *
 * BYTE        WORD         LONG           QUAD
 * msb   lsb       bits           bits           bits
 * RH0 - RL0   R 0 15- 0    RR 0  31-16    RQ 0  63-48
 * RH1 - RL1   R 1 15- 0          15- 0          47-32
 * RH2 - RL2   R 2 15- 0    RR 2  31-16          31-16
 * RH3 - RL3   R 3 15- 0          15- 0          15- 0
 * RH4 - RL4   R 4 15- 0    RR 4  31-16    RQ 4  63-48
 * RH5 - RL5   R 5 15- 0          15- 0          47-32
 * RH6 - RL6   R 6 15- 0    RR 6  31-16          31-16
 * RH7 - RL7   R 7 15- 0          15- 0          15- 0
 *             R 8 15- 0    RR 8  31-16    RQ 8  63-48
 *             R 9 15- 0          15- 0          47-32
 *             R10 15- 0    RR10  31-16          31-16
 *             R11 15- 0          15- 0          15- 0
 *             R12 15- 0    RR12  31-16    RQ12  63-48
 *             R13 15- 0          15- 0          47-32
 *             R14 15- 0    RR14  31-16          31-16
 *             R15 15- 0          15- 0          15- 0
 *
 * Note that for LSB_FIRST machines we have the case that the RR registers
 * use the lower numbered R registers in the higher bit positions.
 * And also the RQ registers use the lower numbered RR registers in the
 * higher bit positions.
 * That's the reason for the ordering in the following pointer table.
 **************************************************************************/
#ifdef	LSB_FIRST
	/* pointers to byte (8bit) registers */
	static UINT8	*pRB[16] =
	{
		&Z.regs.B[ 7],&Z.regs.B[ 5],&Z.regs.B[ 3],&Z.regs.B[ 1],
		&Z.regs.B[15],&Z.regs.B[13],&Z.regs.B[11],&Z.regs.B[ 9],
		&Z.regs.B[ 6],&Z.regs.B[ 4],&Z.regs.B[ 2],&Z.regs.B[ 0],
		&Z.regs.B[14],&Z.regs.B[12],&Z.regs.B[10],&Z.regs.B[ 8]
	};

	static UINT16	*pRW[16] =
	{
        &Z.regs.W[ 3],&Z.regs.W[ 2],&Z.regs.W[ 1],&Z.regs.W[ 0],
        &Z.regs.W[ 7],&Z.regs.W[ 6],&Z.regs.W[ 5],&Z.regs.W[ 4],
        &Z.regs.W[11],&Z.regs.W[10],&Z.regs.W[ 9],&Z.regs.W[ 8],
        &Z.regs.W[15],&Z.regs.W[14],&Z.regs.W[13],&Z.regs.W[12]
    };

    /* pointers to long (32bit) registers */
	static UINT32	*pRL[16] =
	{
		&Z.regs.L[ 1],&Z.regs.L[ 1],&Z.regs.L[ 0],&Z.regs.L[ 0],
		&Z.regs.L[ 3],&Z.regs.L[ 3],&Z.regs.L[ 2],&Z.regs.L[ 2],
		&Z.regs.L[ 5],&Z.regs.L[ 5],&Z.regs.L[ 4],&Z.regs.L[ 4],
		&Z.regs.L[ 7],&Z.regs.L[ 7],&Z.regs.L[ 6],&Z.regs.L[ 6]
    };

#else	/* MSB_FIRST */

    /* pointers to byte (8bit) registers */
	static UINT8	*pRB[16] =
	{
		&Z.regs.B[ 0],&Z.regs.B[ 2],&Z.regs.B[ 4],&Z.regs.B[ 6],
		&Z.regs.B[ 8],&Z.regs.B[10],&Z.regs.B[12],&Z.regs.B[14],
		&Z.regs.B[ 1],&Z.regs.B[ 3],&Z.regs.B[ 5],&Z.regs.B[ 7],
		&Z.regs.B[ 9],&Z.regs.B[11],&Z.regs.B[13],&Z.regs.B[15]
	};

	/* pointers to word (16bit) registers */
	static UINT16	*pRW[16] =
	{
		&Z.regs.W[ 0],&Z.regs.W[ 1],&Z.regs.W[ 2],&Z.regs.W[ 3],
		&Z.regs.W[ 4],&Z.regs.W[ 5],&Z.regs.W[ 6],&Z.regs.W[ 7],
		&Z.regs.W[ 8],&Z.regs.W[ 9],&Z.regs.W[10],&Z.regs.W[11],
		&Z.regs.W[12],&Z.regs.W[13],&Z.regs.W[14],&Z.regs.W[15]
	};

	/* pointers to long (32bit) registers */
	static UINT32	*pRL[16] =
	{
		&Z.regs.L[ 0],&Z.regs.L[ 0],&Z.regs.L[ 1],&Z.regs.L[ 1],
		&Z.regs.L[ 2],&Z.regs.L[ 2],&Z.regs.L[ 3],&Z.regs.L[ 3],
		&Z.regs.L[ 4],&Z.regs.L[ 4],&Z.regs.L[ 5],&Z.regs.L[ 5],
		&Z.regs.L[ 6],&Z.regs.L[ 6],&Z.regs.L[ 7],&Z.regs.L[ 7]
	};

#endif

/* pointers to quad word (64bit) registers */
static UINT64   *pRQ[16] = {
    &Z.regs.Q[ 0],&Z.regs.Q[ 0],&Z.regs.Q[ 0],&Z.regs.Q[ 0],
    &Z.regs.Q[ 1],&Z.regs.Q[ 1],&Z.regs.Q[ 1],&Z.regs.Q[ 1],
    &Z.regs.Q[ 2],&Z.regs.Q[ 2],&Z.regs.Q[ 2],&Z.regs.Q[ 2],
    &Z.regs.Q[ 3],&Z.regs.Q[ 3],&Z.regs.Q[ 3],&Z.regs.Q[ 3]};

INLINE UINT16 RDOP(void)
{
	UINT16 res = cpu_readop16(PC);
    PC += 2;
    return res;
}

INLINE UINT8 RDMEM_B(UINT16 addr)
{
	return program_read_byte_16be(addr);
}

INLINE UINT16 RDMEM_W(UINT16 addr)
{
	addr &= ~1;
	return program_read_word_16be(addr);
}

INLINE UINT32 RDMEM_L(UINT16 addr)
{
	UINT32 result;
	addr &= ~1;
	result = program_read_word_16be(addr) << 16;
	return result + program_read_word_16be(addr + 2);
}

INLINE void WRMEM_B(UINT16 addr, UINT8 value)
{
	program_write_byte_16be(addr, value);
}

INLINE void WRMEM_W(UINT16 addr, UINT16 value)
{
	addr &= ~1;
	program_write_word_16be(addr, value);
}

INLINE void WRMEM_L(UINT16 addr, UINT32 value)
{
	addr &= ~1;
	program_write_word_16be(addr, value >> 16);
	program_write_word_16be((UINT16)(addr + 2), value & 0xffff);
}

INLINE UINT8 RDPORT_B(int mode, UINT16 addr)
{
	if( mode == 0 )
	{
		return io_read_byte_8(addr);
	}
	else
	{
		/* how to handle MMU reads? */
		return 0x00;
	}
}

INLINE UINT16 RDPORT_W(int mode, UINT16 addr)
{
	if( mode == 0 )
	{
		return io_read_byte_8((UINT16)(addr)) +
			  (io_read_byte_8((UINT16)(addr+1)) << 8);
	}
	else
	{
		/* how to handle MMU reads? */
		return 0x0000;
	}
}

INLINE UINT32 RDPORT_L(int mode, UINT16 addr)
{
	if( mode == 0 )
	{
		return	io_read_byte_8((UINT16)(addr)) +
			   (io_read_byte_8((UINT16)(addr+1)) <<  8) +
			   (io_read_byte_8((UINT16)(addr+2)) << 16) +
			   (io_read_byte_8((UINT16)(addr+3)) << 24);
	}
	else
	{
		/* how to handle MMU reads? */
		return 0x00000000;
	}
}

INLINE void WRPORT_B(int mode, UINT16 addr, UINT8 value)
{
	if( mode == 0 )
	{
        io_write_byte_8(addr,value);
	}
	else
	{
		/* how to handle MMU writes? */
    }
}

INLINE void WRPORT_W(int mode, UINT16 addr, UINT16 value)
{
	if( mode == 0 )
	{
		io_write_byte_8((UINT16)(addr),value & 0xff);
		io_write_byte_8((UINT16)(addr+1),(value >> 8) & 0xff);
	}
	else
	{
		/* how to handle MMU writes? */
    }
}

INLINE void WRPORT_L(int mode, UINT16 addr, UINT32 value)
{
	if( mode == 0 )
	{
		io_write_byte_8((UINT16)(addr),value & 0xff);
		io_write_byte_8((UINT16)(addr+1),(value >> 8) & 0xff);
		io_write_byte_8((UINT16)(addr+2),(value >> 16) & 0xff);
		io_write_byte_8((UINT16)(addr+3),(value >> 24) & 0xff);
	}
	else
	{
		/* how to handle MMU writes? */
	}
}

#include "z8000ops.c"
#include "z8000tbl.c"

INLINE void set_irq(int type)
{
    switch ((type >> 8) & 255)
    {
        case Z8000_TRAP >> 8:
            if (IRQ_SRV >= Z8000_TRAP)
                return; /* double TRAP.. very bad :( */
            IRQ_REQ = type;
            break;
        case Z8000_NMI >> 8:
            if (IRQ_SRV >= Z8000_NMI)
                return; /* no NMIs inside trap */
            IRQ_REQ = type;
            break;
        case Z8000_SEGTRAP >> 8:
            if (IRQ_SRV >= Z8000_SEGTRAP)
                return; /* no SEGTRAPs inside NMI/TRAP */
            IRQ_REQ = type;
            break;
        case Z8000_NVI >> 8:
            if (IRQ_SRV >= Z8000_NVI)
                return; /* no NVIs inside SEGTRAP/NMI/TRAP */
            IRQ_REQ = type;
            break;
        case Z8000_VI >> 8:
            if (IRQ_SRV >= Z8000_VI)
                return; /* no VIs inside NVI/SEGTRAP/NMI/TRAP */
            IRQ_REQ = type;
            break;
        case Z8000_SYSCALL >> 8:
            LOG(("Z8K#%d SYSCALL $%02x\n", cpu_getactivecpu(), type & 0xff));
            IRQ_REQ = type;
            break;
        default:
            logerror("Z8000 invalid Cause_Interrupt %04x\n", type);
            return;
    }
    /* set interrupt request flag, reset HALT flag */
    IRQ_REQ = type & ~Z8000_HALT;
}


INLINE void Interrupt(void)
{
    UINT16 fcw = FCW;

    if (IRQ_REQ & Z8000_NVI)
    {
        int type = (*Z.irq_callback)(0);
        set_irq(type);
    }

    if (IRQ_REQ & Z8000_VI)
    {
        int type = (*Z.irq_callback)(1);
        set_irq(type);
    }

   /* trap ? */
   if ( IRQ_REQ & Z8000_TRAP )
   {
        CHANGE_FCW(fcw | F_S_N);/* swap to system stack */
        PUSHW( SP, PC );        /* save current PC */
        PUSHW( SP, fcw );       /* save current FCW */
        PUSHW( SP, IRQ_REQ );   /* save interrupt/trap type tag */
        IRQ_SRV = IRQ_REQ;
        IRQ_REQ &= ~Z8000_TRAP;
        PC = TRAP;
        LOG(("Z8K#%d trap $%04x\n", cpu_getactivecpu(), PC ));
   }
   else
   if ( IRQ_REQ & Z8000_SYSCALL )
   {
        CHANGE_FCW(fcw | F_S_N);/* swap to system stack */
        PUSHW( SP, PC );        /* save current PC */
        PUSHW( SP, fcw );       /* save current FCW */
        PUSHW( SP, IRQ_REQ );   /* save interrupt/trap type tag */
        IRQ_SRV = IRQ_REQ;
        IRQ_REQ &= ~Z8000_SYSCALL;
        PC = SYSCALL;
        LOG(("Z8K#%d syscall $%04x\n", cpu_getactivecpu(), PC ));
   }
   else
   if ( IRQ_REQ & Z8000_SEGTRAP )
   {
        CHANGE_FCW(fcw | F_S_N);/* swap to system stack */
        PUSHW( SP, PC );        /* save current PC */
        PUSHW( SP, fcw );       /* save current FCW */
        PUSHW( SP, IRQ_REQ );   /* save interrupt/trap type tag */
        IRQ_SRV = IRQ_REQ;
        IRQ_REQ &= ~Z8000_SEGTRAP;
        PC = SEGTRAP;
        LOG(("Z8K#%d segtrap $%04x\n", cpu_getactivecpu(), PC ));
   }
   else
   if ( IRQ_REQ & Z8000_NMI )
   {
        CHANGE_FCW(fcw | F_S_N);/* swap to system stack */
        PUSHW( SP, PC );        /* save current PC */
        PUSHW( SP, fcw );       /* save current FCW */
        PUSHW( SP, IRQ_REQ );   /* save interrupt/trap type tag */
        IRQ_SRV = IRQ_REQ;
        fcw = RDMEM_W( NMI );
        PC = RDMEM_W( NMI + 2 );
        IRQ_REQ &= ~Z8000_NMI;
        CHANGE_FCW(fcw);
        PC = NMI;
        LOG(("Z8K#%d NMI $%04x\n", cpu_getactivecpu(), PC ));
    }
    else
    if ( (IRQ_REQ & Z8000_NVI) && (FCW & F_NVIE) )
    {
        CHANGE_FCW(fcw | F_S_N);/* swap to system stack */
        PUSHW( SP, PC );        /* save current PC */
        PUSHW( SP, fcw );       /* save current FCW */
        PUSHW( SP, IRQ_REQ );   /* save interrupt/trap type tag */
        IRQ_SRV = IRQ_REQ;
        fcw = RDMEM_W( NVI );
        PC = RDMEM_W( NVI + 2 );
        IRQ_REQ &= ~Z8000_NVI;
        CHANGE_FCW(fcw);
        LOG(("Z8K#%d NVI $%04x\n", cpu_getactivecpu(), PC ));
    }
    else
    if ( (IRQ_REQ & Z8000_VI) && (FCW & F_VIE) )
    {
        CHANGE_FCW(fcw | F_S_N);/* swap to system stack */
        PUSHW( SP, PC );        /* save current PC */
        PUSHW( SP, fcw );       /* save current FCW */
        PUSHW( SP, IRQ_REQ );   /* save interrupt/trap type tag */
        IRQ_SRV = IRQ_REQ;
        fcw = RDMEM_W( IRQ_VEC );
        PC = RDMEM_W( VEC00 + 2 * (IRQ_REQ & 0xff) );
        IRQ_REQ &= ~Z8000_VI;
        CHANGE_FCW(fcw);
        LOG(("Z8K#%d VI [$%04x/$%04x] fcw $%04x, pc $%04x\n", cpu_getactivecpu(), IRQ_VEC, VEC00 + VEC00 + 2 * (IRQ_REQ & 0xff), FCW, PC ));
    }
}


static void z8000_reset(void *param)
{
	memset(&Z, 0, sizeof(z8000_Regs));
	FCW = RDMEM_W( 2 ); /* get reset FCW */
	PC	= RDMEM_W( 4 ); /* get reset PC  */
	change_pc(PC);
}

static void z8000_exit(void)
{
	z8000_deinit();
}

static int z8000_execute(int cycles)
{
    z8000_ICount = cycles;

    do
    {
        /* any interrupt request pending? */
        if (IRQ_REQ)
			Interrupt();

		CALL_MAME_DEBUG;

		if (IRQ_REQ & Z8000_HALT)
        {
            z8000_ICount = 0;
        }
        else
        {
            Z8000_exec *exec;
            Z.op[0] = RDOP();
            exec = &z8000_exec[Z.op[0]];

            if (exec->size > 1)
                Z.op[1] = RDOP();
            if (exec->size > 2)
                Z.op[2] = RDOP();

            z8000_ICount -= exec->cycles;
            (*exec->opcode)();

        }
    } while (z8000_ICount > 0);

    return cycles - z8000_ICount;

}

static void z8000_get_context(void *dst)
{
	if( dst )
		*(z8000_Regs*)dst = Z;
}

static void z8000_set_context(void *src)
{
	if( src )
	{
		Z = *(z8000_Regs*)src;
		change_pc(PC);
	}
}

static void set_irq_line(int irqline, int state)
{
	if (irqline == INPUT_LINE_NMI)
	{
		if (Z.nmi_state == state)
			return;

	    Z.nmi_state = state;

	    if (state != CLEAR_LINE)
		{
			if (IRQ_SRV >= Z8000_NMI)	/* no NMIs inside trap */
				return;
			IRQ_REQ = Z8000_NMI;
			IRQ_VEC = NMI;
		}
	}
	else if (irqline < 2)
	{
		Z.irq_state[irqline] = state;
		if (irqline == 0)
		{
			if (state == CLEAR_LINE)
			{
				if (!(FCW & F_NVIE))
					IRQ_REQ &= ~Z8000_NVI;
			}
			else
			{
				if (FCW & F_NVIE)
					IRQ_REQ |= Z8000_NVI;
	        }
		}
		else
		{
			if (state == CLEAR_LINE)
			{
				if (!(FCW & F_VIE))
					IRQ_REQ &= ~Z8000_VI;
			}
			else
			{
				if (FCW & F_VIE)
					IRQ_REQ |= Z8000_VI;
			}
		}
	}
}


static offs_t z8000_dasm(char *buffer, offs_t pc)
{
#ifdef MAME_DEBUG
    return DasmZ8000(buffer,pc);
#else
	sprintf( buffer, "$%04X", cpu_readop16(pc) );
	return 2;
#endif
}



/**************************************************************************
 * Generic set_info
 **************************************************************************/

static void z8000_set_info(UINT32 state, union cpuinfo *info)
{
	switch (state)
	{
		/* --- the following bits of info are set as 64-bit signed integers --- */
		case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI:	set_irq_line(INPUT_LINE_NMI, info->i);	break;
		case CPUINFO_INT_INPUT_STATE + 0:				set_irq_line(0, info->i);				break;
		case CPUINFO_INT_INPUT_STATE + 1:				set_irq_line(1, info->i);				break;

		case CPUINFO_INT_PC:							PC = info->i; change_pc(PC);	 		break;
		case CPUINFO_INT_REGISTER + Z8000_PC:			PC = info->i;							break;
		case CPUINFO_INT_SP:
		case CPUINFO_INT_REGISTER + Z8000_NSP:			NSP = info->i;							break;
		case CPUINFO_INT_REGISTER + Z8000_FCW:			FCW = info->i;							break;
		case CPUINFO_INT_REGISTER + Z8000_PSAP:			PSAP = info->i;							break;
		case CPUINFO_INT_REGISTER + Z8000_REFRESH:		REFRESH = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_IRQ_REQ:		IRQ_REQ = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_IRQ_SRV:		IRQ_SRV = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_IRQ_VEC:		IRQ_VEC = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R0:			RW( 0) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R1:			RW( 1) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R2:			RW( 2) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R3:			RW( 3) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R4:			RW( 4) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R5:			RW( 5) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R6:			RW( 6) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R7:			RW( 7) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R8:			RW( 8) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R9:			RW( 9) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R10:			RW(10) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R11:			RW(11) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R12:			RW(12) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R13:			RW(13) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R14:			RW(14) = info->i;						break;
		case CPUINFO_INT_REGISTER + Z8000_R15:			RW(15) = info->i;						break;

		/* --- the following bits of info are set as pointers to data or functions --- */
		case CPUINFO_PTR_IRQ_CALLBACK:					Z.irq_callback = info->irqcallback;		break;
	}
}



/**************************************************************************
 * Generic get_info
 **************************************************************************/

void z8000_get_info(UINT32 state, union cpuinfo *info)
{
	switch (state)
	{
		/* --- the following bits of info are returned as 64-bit signed integers --- */
		case CPUINFO_INT_CONTEXT_SIZE:					info->i = sizeof(Z);					break;
		case CPUINFO_INT_INPUT_LINES:					info->i = 2;							break;
		case CPUINFO_INT_DEFAULT_IRQ_VECTOR:			info->i = 0xff;							break;
		case CPUINFO_INT_ENDIANNESS:					info->i = CPU_IS_BE;					break;
		case CPUINFO_INT_CLOCK_DIVIDER:					info->i = 1;							break;
		case CPUINFO_INT_MIN_INSTRUCTION_BYTES:			info->i = 2;							break;
		case CPUINFO_INT_MAX_INSTRUCTION_BYTES:			info->i = 6;							break;
		case CPUINFO_INT_MIN_CYCLES:					info->i = 1;							break;
		case CPUINFO_INT_MAX_CYCLES:					info->i = 16;							break;

		case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM:	info->i = 16;					break;
		case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16;					break;
		case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0;					break;
		case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA:	info->i = 0;					break;
		case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: 	info->i = 0;					break;
		case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: 	info->i = 0;					break;
		case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO:		info->i = 8;					break;
		case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: 		info->i = 16;					break;
		case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: 		info->i = 0;					break;

		case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI:	info->i = Z.nmi_state;					break;
		case CPUINFO_INT_INPUT_STATE + 0:				info->i = Z.irq_state[0];				break;
		case CPUINFO_INT_INPUT_STATE + 1:				info->i = Z.irq_state[1];				break;

		case CPUINFO_INT_PREVIOUSPC:					info->i = PPC;							break;

		case CPUINFO_INT_PC:
		case CPUINFO_INT_REGISTER + Z8000_PC:			info->i = PC;							break;
		case CPUINFO_INT_SP:
        case CPUINFO_INT_REGISTER + Z8000_NSP:			info->i = NSP;							break;
        case CPUINFO_INT_REGISTER + Z8000_FCW:			info->i = FCW;							break;
		case CPUINFO_INT_REGISTER + Z8000_PSAP:			info->i = PSAP;							break;
		case CPUINFO_INT_REGISTER + Z8000_REFRESH:		info->i = REFRESH;						break;
		case CPUINFO_INT_REGISTER + Z8000_IRQ_REQ:		info->i = IRQ_REQ;						break;
		case CPUINFO_INT_REGISTER + Z8000_IRQ_SRV:		info->i = IRQ_SRV;						break;
		case CPUINFO_INT_REGISTER + Z8000_IRQ_VEC:		info->i = IRQ_VEC;						break;
		case CPUINFO_INT_REGISTER + Z8000_R0:			info->i = RW( 0);						break;
		case CPUINFO_INT_REGISTER + Z8000_R1:			info->i = RW( 1);						break;
		case CPUINFO_INT_REGISTER + Z8000_R2:			info->i = RW( 2);						break;
		case CPUINFO_INT_REGISTER + Z8000_R3:			info->i = RW( 3);						break;
		case CPUINFO_INT_REGISTER + Z8000_R4:			info->i = RW( 4);						break;
		case CPUINFO_INT_REGISTER + Z8000_R5:			info->i = RW( 5);						break;
		case CPUINFO_INT_REGISTER + Z8000_R6:			info->i = RW( 6);						break;
		case CPUINFO_INT_REGISTER + Z8000_R7:			info->i = RW( 7);						break;
		case CPUINFO_INT_REGISTER + Z8000_R8:			info->i = RW( 8);						break;
		case CPUINFO_INT_REGISTER + Z8000_R9:			info->i = RW( 9);						break;
		case CPUINFO_INT_REGISTER + Z8000_R10:			info->i = RW(10);						break;
		case CPUINFO_INT_REGISTER + Z8000_R11:			info->i = RW(11);						break;
		case CPUINFO_INT_REGISTER + Z8000_R12:			info->i = RW(12);						break;
		case CPUINFO_INT_REGISTER + Z8000_R13:			info->i = RW(13);						break;
		case CPUINFO_INT_REGISTER + Z8000_R14:			info->i = RW(14);						break;
		case CPUINFO_INT_REGISTER + Z8000_R15:			info->i = RW(15);						break;

		/* --- the following bits of info are returned as pointers to data or functions --- */
		case CPUINFO_PTR_SET_INFO:						info->setinfo = z8000_set_info;				break;
		case CPUINFO_PTR_GET_CONTEXT:					info->getcontext = z8000_get_context;			break;
		case CPUINFO_PTR_SET_CONTEXT:					info->setcontext = z8000_set_context;			break;
		case CPUINFO_PTR_INIT:							info->init = z8000_init;					break;
		case CPUINFO_PTR_RESET:							info->reset = z8000_reset;					break;
		case CPUINFO_PTR_EXIT:							info->exit = z8000_exit;					break;
		case CPUINFO_PTR_EXECUTE:						info->execute = z8000_execute;				break;
		case CPUINFO_PTR_BURN:							info->burn = NULL;						break;
		case CPUINFO_PTR_DISASSEMBLE:					info->disassemble = z8000_dasm;					break;
		case CPUINFO_PTR_IRQ_CALLBACK:					info->irqcallback = Z.irq_callback;			break;
		case CPUINFO_PTR_INSTRUCTION_COUNTER:			info->icount = &z8000_ICount;				break;
		case CPUINFO_PTR_REGISTER_LAYOUT:				info->p = z8000_reg_layout;				break;
		case CPUINFO_PTR_WINDOW_LAYOUT:					info->p = z8000_win_layout;				break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case CPUINFO_STR_NAME:							strcpy(info->s = cpuintrf_temp_str(), "Z8002"); break;
		case CPUINFO_STR_CORE_FAMILY:					strcpy(info->s = cpuintrf_temp_str(), "Zilog Z8000"); break;
		case CPUINFO_STR_CORE_VERSION:					strcpy(info->s = cpuintrf_temp_str(), "1.1"); break;
		case CPUINFO_STR_CORE_FILE:						strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
		case CPUINFO_STR_CORE_CREDITS:					strcpy(info->s = cpuintrf_temp_str(), "Copyright (C) 1998,1999 Juergen Buchmueller, all rights reserved."); break;

		case CPUINFO_STR_FLAGS:
			sprintf(info->s = cpuintrf_temp_str(), "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
				Z.fcw & 0x8000 ? 's':'.',
				Z.fcw & 0x4000 ? 'n':'.',
				Z.fcw & 0x2000 ? 'e':'.',
				Z.fcw & 0x1000 ? '2':'.',
				Z.fcw & 0x0800 ? '1':'.',
				Z.fcw & 0x0400 ? '?':'.',
				Z.fcw & 0x0200 ? '?':'.',
				Z.fcw & 0x0100 ? '?':'.',
				Z.fcw & 0x0080 ? 'C':'.',
				Z.fcw & 0x0040 ? 'Z':'.',
				Z.fcw & 0x0020 ? 'S':'.',
				Z.fcw & 0x0010 ? 'V':'.',
				Z.fcw & 0x0008 ? 'D':'.',
				Z.fcw & 0x0004 ? 'H':'.',
				Z.fcw & 0x0002 ? '?':'.',
				Z.fcw & 0x0001 ? '?':'.');
            break;

		case CPUINFO_STR_REGISTER + Z8000_PC:			sprintf(info->s = cpuintrf_temp_str(), "PC :%04X", Z.pc); break;
		case CPUINFO_STR_REGISTER + Z8000_NSP:			sprintf(info->s = cpuintrf_temp_str(), "SP :%04X", Z.nsp); break;
		case CPUINFO_STR_REGISTER + Z8000_FCW:			sprintf(info->s = cpuintrf_temp_str(), "FCW:%04X", Z.fcw); break;
		case CPUINFO_STR_REGISTER + Z8000_PSAP:			sprintf(info->s = cpuintrf_temp_str(), "NSP:%04X", Z.psap); break;
		case CPUINFO_STR_REGISTER + Z8000_REFRESH:		sprintf(info->s = cpuintrf_temp_str(), "REFR:%04X", Z.refresh); break;
		case CPUINFO_STR_REGISTER + Z8000_IRQ_REQ:		sprintf(info->s = cpuintrf_temp_str(), "IRQR:%04X", Z.irq_req); break;
		case CPUINFO_STR_REGISTER + Z8000_IRQ_SRV:		sprintf(info->s = cpuintrf_temp_str(), "IRQS:%04X", Z.irq_srv); break;
		case CPUINFO_STR_REGISTER + Z8000_IRQ_VEC:		sprintf(info->s = cpuintrf_temp_str(), "IRQV:%04X", Z.irq_vec); break;
#ifdef	LSB_FIRST
#define REG_XOR 3
#else
#define REG_XOR 0
#endif
		case CPUINFO_STR_REGISTER + Z8000_R0:			sprintf(info->s = cpuintrf_temp_str(), "R0 :%04X", Z.regs.W[ 0^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R1:			sprintf(info->s = cpuintrf_temp_str(), "R1 :%04X", Z.regs.W[ 1^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R2:			sprintf(info->s = cpuintrf_temp_str(), "R2 :%04X", Z.regs.W[ 2^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R3:			sprintf(info->s = cpuintrf_temp_str(), "R3 :%04X", Z.regs.W[ 3^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R4:			sprintf(info->s = cpuintrf_temp_str(), "R4 :%04X", Z.regs.W[ 4^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R5:			sprintf(info->s = cpuintrf_temp_str(), "R5 :%04X", Z.regs.W[ 5^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R6:			sprintf(info->s = cpuintrf_temp_str(), "R6 :%04X", Z.regs.W[ 6^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R7:			sprintf(info->s = cpuintrf_temp_str(), "R7 :%04X", Z.regs.W[ 7^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R8:			sprintf(info->s = cpuintrf_temp_str(), "R8 :%04X", Z.regs.W[ 8^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R9:			sprintf(info->s = cpuintrf_temp_str(), "R9 :%04X", Z.regs.W[ 9^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R10:			sprintf(info->s = cpuintrf_temp_str(), "R10:%04X", Z.regs.W[10^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R11:			sprintf(info->s = cpuintrf_temp_str(), "R11:%04X", Z.regs.W[11^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R12:			sprintf(info->s = cpuintrf_temp_str(), "R12:%04X", Z.regs.W[12^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R13:			sprintf(info->s = cpuintrf_temp_str(), "R13:%04X", Z.regs.W[13^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R14:			sprintf(info->s = cpuintrf_temp_str(), "R14:%04X", Z.regs.W[14^REG_XOR]); break;
		case CPUINFO_STR_REGISTER + Z8000_R15:			sprintf(info->s = cpuintrf_temp_str(), "R15:%04X", Z.regs.W[15^REG_XOR]); break;
	}
}
