/***************************************************************************

    asap.c
    Core implementation for the portable ASAP emulator.
    ASAP = Atari Simplified Architecture Processor

    Written by Aaron Giles
    Special thanks to Mike Albaugh for clarification on a couple of fine points.

***************************************************************************/

#include "debugger.h"
#include "asap.h"


/***************************************************************************
    CONSTANTS
***************************************************************************/

#define PS_CFLAG			0x00000001
#define PS_VFLAG			0x00000002
#define PS_ZFLAG			0x00000004
#define PS_NFLAG			0x00000008
#define PS_IFLAG			0x00000010
#define PS_PFLAG			0x00000020

#define EXCEPTION_RESET		0
#define EXCEPTION_TRAP0		1
#define EXCEPTION_TRAPF		2
#define EXCEPTION_INTERRUPT	3


#define REGBASE				0xffe0


#define SET_C_ADD(a,b)		(asap.cflag = (UINT32)(b) > (UINT32)(~(a)))
#define SET_C_SUB(a,b)		(asap.cflag = (UINT32)(b) <= (UINT32)(a))
#define SET_V_ADD(r,a,b)	(asap.vflag = ~((a) ^ (b)) & ((a) ^ (r)))
#define SET_V_SUB(r,a,b)	(asap.vflag =  ((a) ^ (b)) & ((a) ^ (r)))
#define SET_ZN(r)			(asap.znflag = (r))
#define SET_ZNCV_ADD(r,a,b)	SET_ZN(r); SET_C_ADD(a,b); SET_V_ADD(r,a,b)
#define SET_ZNCV_SUB(r,a,b)	SET_ZN(r); SET_C_SUB(a,b); SET_V_SUB(r,a,b)

#define SET_VFLAG(val)		(asap.vflag = (val) << 31)
#define SET_CFLAG(val)		(asap.cflag = (val))

#define GET_FLAGS(r)		((r)->cflag | \
							 (((r)->vflag >> 30) & PS_VFLAG) | \
							 (((r)->znflag == 0) << 2) | \
							 (((r)->znflag >> 28) & PS_NFLAG) | \
							 ((r)->iflag << 4) | \
							 ((r)->pflag << 5))

#define SET_FLAGS(r,v)		do { \
								(r)->cflag = (v) & PS_CFLAG; \
								(r)->vflag = ((v) & PS_VFLAG) << 30; \
								(r)->znflag = ((v) & PS_ZFLAG) ? 0 : ((v) & PS_NFLAG) ? -1 : 1; \
								(r)->iflag = ((v) & PS_IFLAG) >> 4; \
								(r)->pflag = ((v) & PS_PFLAG) >> 5; \
							} while (0);


/***************************************************************************
    STRUCTURES & TYPEDEFS
***************************************************************************/

/* ASAP Registers */
typedef struct
{
	/* core registers */
	UINT32		r[32];
	UINT32		pc;

	/* expanded flags */
	UINT32		pflag;
	UINT32		iflag;
	UINT32		cflag;
	UINT32		vflag;
	UINT32		znflag;

	/* internal stuff */
	PAIR		op;
	UINT32		ppc;
	UINT32		nextpc;
	UINT8		irq_state;
	int			interrupt_cycles;
	int 		(*irq_callback)(int irqline);
} asap_regs;



/***************************************************************************
    PRIVATE GLOBAL VARIABLES
***************************************************************************/

static asap_regs asap;

static void (**opcode)(void);
static UINT32 *src2val;

static int asap_icount;



/***************************************************************************
    OPCODE TABLE
***************************************************************************/

static void noop(void);
static void trap0(void);
static void bsp(void);
static void bmz(void);
static void bgt(void);
static void ble(void);
static void bge(void);
static void blt(void);
static void bhi(void);
static void bls(void);
static void bcc(void);
static void bcs(void);
static void bpl(void);
static void bmi(void);
static void bne(void);
static void beq(void);
static void bvc(void);
static void bvs(void);
static void bsr(void);
static void bsr_0(void);
static void lea(void);
static void lea_c(void);
static void lea_c0(void);
static void leah(void);
static void leah_c(void);
static void leah_c0(void);
static void subr(void);
static void subr_c(void);
static void subr_c0(void);
static void xor(void);
static void xor_c(void);
static void xor_c0(void);
static void xorn(void);
static void xorn_c(void);
static void xorn_c0(void);
static void add(void);
static void add_c(void);
static void add_c0(void);
static void sub(void);
static void sub_c(void);
static void sub_c0(void);
static void addc(void);
static void addc_c(void);
static void addc_c0(void);
static void subc(void);
static void subc_c(void);
static void subc_c0(void);
static void and(void);
static void and_c(void);
static void and_c0(void);
static void andn(void);
static void andn_c(void);
static void andn_c0(void);
static void or(void);
static void or_c(void);
static void or_c0(void);
static void orn(void);
static void orn_c(void);
static void orn_c0(void);
static void ld(void);
static void ld_0(void);
static void ld_c(void);
static void ld_c0(void);
static void ldh(void);
static void ldh_0(void);
static void ldh_c(void);
static void ldh_c0(void);
static void lduh(void);
static void lduh_0(void);
static void lduh_c(void);
static void lduh_c0(void);
static void sth(void);
static void sth_0(void);
static void sth_c(void);
static void sth_c0(void);
static void st(void);
static void st_0(void);
static void st_c(void);
static void st_c0(void);
static void ldb(void);
static void ldb_0(void);
static void ldb_c(void);
static void ldb_c0(void);
static void ldub(void);
static void ldub_0(void);
static void ldub_c(void);
static void ldub_c0(void);
static void stb(void);
static void stb_0(void);
static void stb_c(void);
static void stb_c0(void);
static void ashr(void);
static void ashr_c(void);
static void ashr_c0(void);
static void lshr(void);
static void lshr_c(void);
static void lshr_c0(void);
static void ashl(void);
static void ashl_c(void);
static void ashl_c0(void);
static void rotl(void);
static void rotl_c(void);
static void rotl_c0(void);
static void getps(void);
static void putps(void);
static void jsr(void);
static void jsr_0(void);
static void jsr_c(void);
static void jsr_c0(void);
static void trapf(void);

static void (*opcodetable[32][4])(void) =
{
	{	trap0,		trap0,		trap0,		trap0		},
	{	NULL,		NULL,		NULL,		NULL		},
	{	bsr,		bsr_0,		bsr,		bsr_0		},
	{	lea,		noop,		lea_c,		lea_c0		},
	{	leah,		noop,		leah_c,		leah_c0		},
	{	subr,		noop,		subr_c,		subr_c0		},
	{	xor,		noop,		xor_c,		xor_c0		},
	{	xorn,		noop,		xorn_c,		xorn_c0		},
	{	add,		noop,		add_c,		add_c0		},
	{	sub,		noop,		sub_c,		sub_c0		},
	{	addc,		noop,		addc_c,		addc_c0		},
	{	subc,		noop,		subc_c,		subc_c0		},
	{	and,		noop,		and_c,		and_c0		},
	{	andn,		noop,		andn_c,		andn_c0		},
	{	or,			noop,		or_c,		or_c0		},
	{	orn,		noop,		orn_c,		orn_c0		},
	{	ld,			ld_0,		ld_c,		ld_c0		},
	{	ldh,		ldh_0,		ldh_c,		ldh_c0		},
	{	lduh,		lduh_0,		lduh_c,		lduh_c0		},
	{	sth,		sth_0,		sth_c,		sth_c0		},
	{	st,			st_0,		st_c,		st_c0		},
	{	ldb,		ldb_0,		ldb_c,		ldb_c0		},
	{	ldub,		ldub_0,		ldub_c,		ldub_c0		},
	{	stb,		stb_0,		stb_c,		stb_c0		},
	{	ashr,		noop,		ashr_c,		ashr_c0		},
	{	lshr,		noop,		lshr_c,		lshr_c0		},
	{	ashl,		noop,		ashl_c,		ashl_c0		},
	{	rotl,		noop,		rotl_c,		rotl_c0		},
	{	getps,		noop,		getps,		noop		},
	{	putps,		putps,		putps,		putps		},
	{	jsr,		jsr_0,		jsr_c,		jsr_c0		},
	{	trapf,		trapf,		trapf,		trapf		}
};

static void (*conditiontable[16])(void) =
{
	bsp, bmz, bgt, ble, bge, blt, bhi, bls,
	bcc, bcs, bpl, bmi, bne, beq, bvc, bvs
};



/***************************************************************************
    MEMORY ACCESSORS
***************************************************************************/

#define ROPCODE(pc)		cpu_readop32(pc)
#define UPDATEPC()		change_pc(asap.pc)


INLINE UINT8 READBYTE(offs_t address)
{
	/* no alignment issues with bytes */
	return program_read_byte_32le(address);
}

INLINE UINT16 READWORD(offs_t address)
{
	/* aligned reads are easy */
	if (!(address & 1))
		return program_read_word_32le(address);

	/* misaligned reads are tricky */
	return program_read_dword_32le(address & ~3) >> (address & 3);
}

INLINE UINT32 READLONG(offs_t address)
{
	/* aligned reads are easy */
	if (!(address & 3))
		return program_read_dword_32le(address);

	/* misaligned reads are tricky */
	return program_read_dword_32le(address & ~3) >> (address & 3);
}

INLINE void WRITEBYTE(offs_t address, UINT8 data)
{
	/* no alignment issues with bytes */
	program_write_byte_32le(address, data);
}

INLINE void WRITEWORD(offs_t address, UINT16 data)
{
	/* aligned writes are easy */
	if (!(address & 1))
	{
		program_write_word_32le(address, data);
		return;
	}

	/* misaligned writes are tricky */
	if (!(address & 2))
	{
		program_write_byte_32le(address + 1, data);
		program_write_byte_32le(address + 2, data >> 8);
	}
	else
		program_write_byte_32le(address + 1, data);
}

INLINE void WRITELONG(offs_t address, UINT32 data)
{
	/* aligned writes are easy */
	if (!(address & 3))
	{
		program_write_dword_32le(address, data);
		return;
	}

	/* misaligned writes are tricky */
	switch (address & 3)
	{
		case 1:
			program_write_byte_32le(address, data);
			program_write_word_32le(address + 1, data >> 8);
			break;
		case 2:
			program_write_word_32le(address, data);
			break;
		case 3:
			program_write_byte_32le(address, data);
			break;
	}
}



/***************************************************************************
    EXCEPTION HANDLING
***************************************************************************/

INLINE void generate_exception(int exception)
{
	asap.pflag = asap.iflag;
	asap.iflag = 0;

	src2val[REGBASE + 30] = asap.pc;
	src2val[REGBASE + 31] = (asap.nextpc == ~0) ? asap.pc + 4 : asap.nextpc;

	asap.pc = 0x40 * exception;
	asap.nextpc = ~0;
	UPDATEPC();

	asap.interrupt_cycles++;
}



/***************************************************************************
    IRQ HANDLING
***************************************************************************/

INLINE void check_irqs(void)
{
	if (asap.irq_state && asap.iflag)
	{
		generate_exception(EXCEPTION_INTERRUPT);
		if (asap.irq_callback)
			(*asap.irq_callback)(ASAP_IRQ0);
	}
}


static void set_irq_line(int irqline, int state)
{
	asap.irq_state = (state != CLEAR_LINE);
	check_irqs();
}



/***************************************************************************
    CONTEXT SWITCHING
***************************************************************************/

static void asap_get_context(void *dst)
{
	/* copy the context */
	if (dst)
	{
		if (src2val)
			memcpy(&asap.r[0], &src2val[REGBASE], 32 * sizeof(UINT32));
		*(asap_regs *)dst = asap;
	}
}


static void asap_set_context(void *src)
{
	/* copy the context */
	if (src)
	{
		asap = *(asap_regs *)src;
		if (src2val)
			memcpy(&src2val[REGBASE], &asap.r[0], 32 * sizeof(UINT32));
		UPDATEPC();

		/* check for IRQs */
		check_irqs();
	}
}



/***************************************************************************
    INITIALIZATION AND SHUTDOWN
***************************************************************************/

static void init_tables(void)
{
	/* allocate opcode table */
	if (!opcode)
		opcode = auto_malloc(32 * 32 * 2 * sizeof(void *));

	/* fill opcode table */
	if (opcode)
	{
		int op, dst, cond;

		for (op = 0; op < 32; op++)
			for (dst = 0; dst < 32; dst++)
				for (cond = 0; cond < 2; cond++)
					if (op == 1)
						opcode[(op << 6) + (dst << 1) + cond] = conditiontable[dst & 15];
					else if (cond && dst == 0)
						opcode[(op << 6) + (dst << 1) + cond] = opcodetable[op][3];
					else if (cond)
						opcode[(op << 6) + (dst << 1) + cond] = opcodetable[op][2];
					else if (dst == 0)
						opcode[(op << 6) + (dst << 1) + cond] = opcodetable[op][1];
					else
						opcode[(op << 6) + (dst << 1) + cond] = opcodetable[op][0];
	}

	/* allocate src2 table */
	if (!src2val)
		src2val = auto_malloc(65536 * sizeof(UINT32));

	/* fill scr2 table */
	if (src2val)
	{
		int i;

		for (i = 0; i < REGBASE; i++)
			src2val[i] = i;
		memcpy(&src2val[REGBASE], &asap.r[0], 32 * sizeof(UINT32));
	}
}

static void asap_init(int index, int clock, const void *config, int (*irqcallback)(int))
{
	init_tables();
	asap.irq_callback = irqcallback;
}

static void asap_reset(void)
{
	/* initialize the state */
	src2val[REGBASE + 0] = 0;
	asap.pc = 0;
	asap.iflag = 0;

	asap.ppc = 0;
	asap.nextpc = ~0;
	asap.irq_state = 0;
	asap.interrupt_cycles = 0;
	asap.irq_callback = NULL;

	UPDATEPC();
}


static void asap_exit(void)
{
	opcode = NULL;
	src2val = NULL;
}



/***************************************************************************
    CORE EXECUTION LOOP
***************************************************************************/

INLINE void fetch_instruction(void)
{
	/* debugging */
	asap.ppc = asap.pc;
	CALL_MAME_DEBUG;

	/* instruction fetch */
	asap.op.d = ROPCODE(asap.pc);
	asap.pc += 4;
}

INLINE void execute_instruction(void)
{
	/* parse the instruction */
	(*opcode[asap.op.d >> 21])();
}

static int asap_execute(int cycles)
{
	/* count cycles and interrupt cycles */
	asap_icount = cycles;
	asap_icount -= asap.interrupt_cycles;
	asap.interrupt_cycles = 0;
	UPDATEPC();

	/* core execution loop */
	do
	{
		/* fetch and execute the next instruction */
		fetch_instruction();
		execute_instruction();

		/* fetch and execute the next instruction */
		fetch_instruction();
		execute_instruction();

		/* fetch and execute the next instruction */
		fetch_instruction();
		execute_instruction();

		/* fetch and execute the next instruction */
		fetch_instruction();
		execute_instruction();

		asap_icount -= 4;

	} while (asap_icount > 0);

	/* eat any new interrupt cycles */
	asap_icount -= asap.interrupt_cycles;
	asap.interrupt_cycles = 0;
	return cycles - asap_icount;
}



/***************************************************************************
    DEBUGGER DEFINITIONS
***************************************************************************/

static UINT8 asap_reg_layout[] =
{
	ASAP_PC,		ASAP_PS,		-1,
	ASAP_R0,	 	ASAP_R16,		-1,
	ASAP_R1, 		ASAP_R17,		-1,
	ASAP_R2, 		ASAP_R18,		-1,
	ASAP_R3, 		ASAP_R19,		-1,
	ASAP_R4, 		ASAP_R20,		-1,
	ASAP_R5, 		ASAP_R21,		-1,
	ASAP_R6, 		ASAP_R22,		-1,
	ASAP_R7, 		ASAP_R23,		-1,
	ASAP_R8,		ASAP_R24,		-1,
	ASAP_R9,		ASAP_R25,		-1,
	ASAP_R10,		ASAP_R26,		-1,
	ASAP_R11,		ASAP_R27,		-1,
	ASAP_R12,		ASAP_R28,		-1,
	ASAP_R13,		ASAP_R29,		-1,
	ASAP_R14,		ASAP_R30,		-1,
	ASAP_R15,		ASAP_R31,		0
};

static UINT8 asap_win_layout[] =
{
	 0, 0,30,17,	/* register window (top rows) */
	31, 0,48,14,	/* disassembler window (left colums) */
	 0,18,30, 4,	/* memory #1 window (right, upper middle) */
	31,15,48, 7,	/* memory #2 window (right, lower middle) */
	 0,23,80, 1,	/* command line window (bottom rows) */
};



/***************************************************************************
    DISASSEMBLY HOOK
***************************************************************************/

static offs_t asap_dasm(char *buffer, offs_t pc)
{
#ifdef MAME_DEBUG
	extern unsigned dasmasap(char *, unsigned);
    return dasmasap(buffer, pc);
#else
	sprintf(buffer, "$%04X", ROPCODE(pc));
	return 2;
#endif
}



/***************************************************************************
    HELPER MACROS
***************************************************************************/

#define OPCODE		(asap.op.d >> 27)
#define DSTREG		((asap.op.d >> 22) & 31)
#define DSTVAL		src2val[REGBASE + DSTREG]
#define SRC1REG		((asap.op.d >> 16) & 31)
#define SRC1VAL		src2val[REGBASE + SRC1REG]
#define SRC2VAL		src2val[asap.op.w.l]



/***************************************************************************
    OPCODES
***************************************************************************/

static void noop(void)
{
}

/**************************** TRAP 0 ******************************/

static void trap0(void)
{
	generate_exception(EXCEPTION_TRAP0);
}

/**************************** Bcc ******************************/

static void bsp(void)
{
	if ((INT32)asap.znflag > 0)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void bmz(void)
{
	if ((INT32)asap.znflag <= 0)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void bgt(void)
{
	if (asap.znflag != 0 && (INT32)(asap.znflag ^ asap.vflag) >= 0)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void ble(void)
{
	if (asap.znflag == 0 || (INT32)(asap.znflag ^ asap.vflag) < 0)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void bge(void)
{
	if ((INT32)(asap.znflag ^ asap.vflag) >= 0)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void blt(void)
{
	if ((INT32)(asap.znflag ^ asap.vflag) < 0)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void bhi(void)
{
	if (asap.znflag != 0 && asap.cflag)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void bls(void)
{
	if (asap.znflag == 0 || !asap.cflag)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void bcc(void)
{
	if (!asap.cflag)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void bcs(void)
{
	if (asap.cflag)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void bpl(void)
{
	if ((INT32)asap.znflag >= 0)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void bmi(void)
{
	if ((INT32)asap.znflag < 0)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void bne(void)
{
	if (asap.znflag != 0)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void beq(void)
{
	if (asap.znflag == 0)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void bvc(void)
{
	if ((INT32)asap.vflag >= 0)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

static void bvs(void)
{
	if ((INT32)asap.vflag < 0)
	{
		asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

		fetch_instruction();
		asap.pc = asap.nextpc;
		asap.nextpc = ~0;
		/*UPDATEPC();*/

		execute_instruction();
		asap_icount--;
	}
}

/**************************** BSR ******************************/

static void bsr(void)
{
	DSTVAL = asap.pc + 4;
	asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

	fetch_instruction();
	asap.pc = asap.nextpc;
	asap.nextpc = ~0;
	/*UPDATEPC();*/

	execute_instruction();
	asap_icount--;
}

static void bsr_0(void)
{
	asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);

	fetch_instruction();
	asap.pc = asap.nextpc;
	asap.nextpc = ~0;
	/*UPDATEPC();*/

	execute_instruction();
	asap_icount--;
}

/**************************** LEA ******************************/

static void lea(void)
{
	DSTVAL = SRC1VAL + (SRC2VAL << 2);
}

static void lea_c(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src1 + (src2 << 2);

	SET_ZNCV_ADD(dst, src1, src2);
	if (src1 & 0xc0000000)
		SET_CFLAG(1);
	if (((src1 ^ (src1 >> 1)) & 0x20000000) || (src1 ^ (src1 >> 2)) & 0x20000000)
		SET_VFLAG(1);
	DSTVAL = dst;
}

static void lea_c0(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src1 + (src2 << 2);

	SET_ZNCV_ADD(dst, src1, src2);
	if (src1 & 0xc0000000)
		SET_CFLAG(1);
	if (((src1 ^ (src1 >> 1)) & 0x20000000) || (src1 ^ (src1 >> 2)) & 0x20000000)
		SET_VFLAG(1);
}

/**************************** LEAH ******************************/

static void leah(void)
{
	DSTVAL = SRC1VAL + (SRC2VAL << 1);
}

static void leah_c(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src1 + (src2 << 1);

	SET_ZNCV_ADD(dst, src1, src2);
	if (src1 & 0x80000000)
		SET_CFLAG(1);
	if ((src1 ^ (src1 >> 1)) & 0x40000000)
		SET_VFLAG(1);
	DSTVAL = dst;
}

static void leah_c0(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src1 + (src2 << 1);

	SET_ZNCV_ADD(dst, src1, src2);
	if (src1 & 0x80000000)
		SET_CFLAG(1);
	if ((src1 ^ (src1 >> 1)) & 0x40000000)
		SET_VFLAG(1);
}

/**************************** SUBR ******************************/

static void subr(void)
{
	DSTVAL = SRC2VAL - SRC1VAL;
}

static void subr_c(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src2 - src1;

	SET_ZNCV_SUB(dst, src2, src1);
	DSTVAL = dst;
}

static void subr_c0(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src2 - src1;

	SET_ZNCV_SUB(dst, src2, src1);
}

/**************************** XOR ******************************/

static void xor(void)
{
	DSTVAL = SRC1VAL ^ SRC2VAL;
}

static void xor_c(void)
{
	UINT32 dst = SRC1VAL ^ SRC2VAL;
	SET_ZN(dst);
	DSTVAL = dst;
}

static void xor_c0(void)
{
	UINT32 dst = SRC1VAL ^ SRC2VAL;
	SET_ZN(dst);
}

/**************************** XOR ******************************/

static void xorn(void)
{
	DSTVAL = SRC1VAL ^ ~SRC2VAL;
}

static void xorn_c(void)
{
	UINT32 dst = SRC1VAL ^ ~SRC2VAL;
	SET_ZN(dst);
	DSTVAL = dst;
}

static void xorn_c0(void)
{
	UINT32 dst = SRC1VAL ^ ~SRC2VAL;
	SET_ZN(dst);
}

/**************************** ADD ******************************/

static void add(void)
{
	DSTVAL = SRC1VAL + SRC2VAL;
}

static void add_c(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src1 + src2;

	SET_ZNCV_ADD(dst, src1, src2);
	DSTVAL = dst;
}

static void add_c0(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src1 + src2;

	SET_ZNCV_ADD(dst, src1, src2);
}

/**************************** ADD ******************************/

static void sub(void)
{
	DSTVAL = SRC1VAL - SRC2VAL;
}

static void sub_c(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src1 - src2;

	SET_ZNCV_SUB(dst, src1, src2);
	DSTVAL = dst;
}

static void sub_c0(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src1 - src2;

	SET_ZNCV_SUB(dst, src1, src2);
}

/**************************** ADDC ******************************/

static void addc(void)
{
	DSTVAL = SRC1VAL + SRC2VAL + asap.cflag;
}

static void addc_c(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src1 + src2 + asap.cflag;

	SET_ZNCV_ADD(dst, src1, src2);
	DSTVAL = dst;
}

static void addc_c0(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src1 + src2 + asap.cflag;

	SET_ZNCV_ADD(dst, src1, src2);
}

/**************************** SUBC ******************************/

static void subc(void)
{
	DSTVAL = SRC1VAL - SRC2VAL - 1 + asap.cflag;
}

static void subc_c(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src1 - src2 - 1 + asap.cflag;

	SET_ZNCV_SUB(dst, src1, src2);
	DSTVAL = dst;
}

static void subc_c0(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL;
	UINT32 dst = src1 - src2 - 1 + asap.cflag;

	SET_ZNCV_SUB(dst, src1, src2);
}

/**************************** AND ******************************/

static void and(void)
{
	DSTVAL = SRC1VAL & SRC2VAL;
}

static void and_c(void)
{
	UINT32 dst = SRC1VAL & SRC2VAL;
	SET_ZN(dst);
	DSTVAL = dst;
}

static void and_c0(void)
{
	UINT32 dst = SRC1VAL & SRC2VAL;
	SET_ZN(dst);
}

/**************************** ANDN ******************************/

static void andn(void)
{
	DSTVAL = SRC1VAL & ~SRC2VAL;
}

static void andn_c(void)
{
	UINT32 dst = SRC1VAL & ~SRC2VAL;
	SET_ZN(dst);
	DSTVAL = dst;
}

static void andn_c0(void)
{
	UINT32 dst = SRC1VAL & ~SRC2VAL;
	SET_ZN(dst);
}

/**************************** OR ******************************/

static void or(void)
{
	DSTVAL = SRC1VAL | SRC2VAL;
}

static void or_c(void)
{
	UINT32 dst = SRC1VAL | SRC2VAL;
	SET_ZN(dst);
	DSTVAL = dst;
}

static void or_c0(void)
{
	UINT32 dst = SRC1VAL | SRC2VAL;
	SET_ZN(dst);
}

/**************************** ORN ******************************/

static void orn(void)
{
	DSTVAL = SRC1VAL | ~SRC2VAL;
}

static void orn_c(void)
{
	UINT32 dst = SRC1VAL | ~SRC2VAL;
	SET_ZN(dst);
	DSTVAL = dst;
}

static void orn_c0(void)
{
	UINT32 dst = SRC1VAL | ~SRC2VAL;
	SET_ZN(dst);
}

/**************************** LD ******************************/

static void ld(void)
{
	DSTVAL = READLONG(SRC1VAL + (SRC2VAL << 2));
}

static void ld_0(void)
{
	READLONG(SRC1VAL + (SRC2VAL << 2));
}

static void ld_c(void)
{
	UINT32 dst = READLONG(SRC1VAL + (SRC2VAL << 2));
	SET_ZN(dst);
	DSTVAL = dst;
}

static void ld_c0(void)
{
	UINT32 dst = READLONG(SRC1VAL + (SRC2VAL << 2));
	SET_ZN(dst);
}

/**************************** LDH ******************************/

static void ldh(void)
{
	DSTVAL = (INT16)READWORD(SRC1VAL + (SRC2VAL << 1));
}

static void ldh_0(void)
{
	READWORD(SRC1VAL + (SRC2VAL << 1));
}

static void ldh_c(void)
{
	UINT32 dst = (INT16)READWORD(SRC1VAL + (SRC2VAL << 1));
	SET_ZN(dst);
	DSTVAL = dst;
}

static void ldh_c0(void)
{
	UINT32 dst = (INT16)READWORD(SRC1VAL + (SRC2VAL << 1));
	SET_ZN(dst);
}

/**************************** LDUH ******************************/

static void lduh(void)
{
	DSTVAL = READWORD(SRC1VAL + (SRC2VAL << 1));
}

static void lduh_0(void)
{
	READWORD(SRC1VAL + (SRC2VAL << 1));
}

static void lduh_c(void)
{
	UINT32 dst = READWORD(SRC1VAL + (SRC2VAL << 1));
	SET_ZN(dst);
	DSTVAL = dst;
}

static void lduh_c0(void)
{
	UINT32 dst = READWORD(SRC1VAL + (SRC2VAL << 1));
	SET_ZN(dst);
}

/**************************** STH ******************************/

static void sth(void)
{
	WRITEWORD(SRC1VAL + (SRC2VAL << 1), DSTVAL);
}

static void sth_0(void)
{
	WRITEWORD(SRC1VAL + (SRC2VAL << 1), 0);
}

static void sth_c(void)
{
	UINT32 dst = (UINT16)DSTVAL;
	SET_ZN(dst);
	WRITEWORD(SRC1VAL + (SRC2VAL << 1), dst);
}

static void sth_c0(void)
{
	SET_ZN(0);
	WRITEWORD(SRC1VAL + (SRC2VAL << 1), 0);
}

/**************************** ST ******************************/

static void st(void)
{
	WRITELONG(SRC1VAL + (SRC2VAL << 2), DSTVAL);
}

static void st_0(void)
{
	WRITELONG(SRC1VAL + (SRC2VAL << 2), 0);
}

static void st_c(void)
{
	UINT32 dst = DSTVAL;
	SET_ZN(dst);
	WRITELONG(SRC1VAL + (SRC2VAL << 2), dst);
}

static void st_c0(void)
{
	SET_ZN(0);
	WRITELONG(SRC1VAL + (SRC2VAL << 2), 0);
}

/**************************** LDB ******************************/

static void ldb(void)
{
	DSTVAL = (INT8)READBYTE(SRC1VAL + SRC2VAL);
}

static void ldb_0(void)
{
	READBYTE(SRC1VAL + SRC2VAL);
}

static void ldb_c(void)
{
	UINT32 dst = (INT8)READBYTE(SRC1VAL + SRC2VAL);
	SET_ZN(dst);
	DSTVAL = dst;
}

static void ldb_c0(void)
{
	UINT32 dst = (INT8)READBYTE(SRC1VAL + SRC2VAL);
	SET_ZN(dst);
}

/**************************** LDUB ******************************/

static void ldub(void)
{
	DSTVAL = READBYTE(SRC1VAL + SRC2VAL);
}

static void ldub_0(void)
{
	READBYTE(SRC1VAL + SRC2VAL);
}

static void ldub_c(void)
{
	UINT32 dst = READBYTE(SRC1VAL + SRC2VAL);
	SET_ZN(dst);
	DSTVAL = dst;
}

static void ldub_c0(void)
{
	UINT32 dst = READBYTE(SRC1VAL + SRC2VAL);
	SET_ZN(dst);
}

/**************************** STB ******************************/

static void stb(void)
{
	WRITEBYTE(SRC1VAL + SRC2VAL, DSTVAL);
}

static void stb_0(void)
{
	WRITEBYTE(SRC1VAL + SRC2VAL, 0);
}

static void stb_c(void)
{
	UINT32 dst = (UINT8)DSTVAL;
	SET_ZN(dst);
	WRITEBYTE(SRC1VAL + SRC2VAL, dst);
}

static void stb_c0(void)
{
	SET_ZN(0);
	WRITEBYTE(SRC1VAL + SRC2VAL, 0);
}

/**************************** ASHR ******************************/

static void ashr(void)
{
	UINT32 src2 = SRC2VAL;
	DSTVAL = (src2 < 32) ? ((INT32)SRC1VAL >> src2) : ((INT32)SRC1VAL >> 31);
}

static void ashr_c(void)
{
	UINT32 src2 = SRC2VAL;
	asap.cflag = 0;
	if (src2 < 32)
	{
		UINT32 src1 = SRC1VAL;
		UINT32 dst = (INT32)src1 >> src2;
		SET_ZN(dst);
		if (src2 != 0)
		{
			src1 = src1 << (32 - src2);
			asap.cflag = src1 >> 31;
		}
		DSTVAL = dst;
	}
	else
	{
		UINT32 dst = (INT32)SRC1VAL >> 31;
		SET_ZN(dst);
		DSTVAL = dst;
	}
}

static void ashr_c0(void)
{
	UINT32 src2 = SRC2VAL;
	asap.cflag = 0;
	if (src2 < 32)
	{
		UINT32 src1 = SRC1VAL;
		UINT32 dst = (INT32)src1 >> src2;
		SET_ZN(dst);
		if (src2 != 0)
		{
			src1 = src1 << (32 - src2);
			asap.cflag = src1 >> 31;
		}
	}
	else
	{
		UINT32 dst = (INT32)SRC1VAL >> 31;
		SET_ZN(dst);
	}
}

/**************************** LSHR ******************************/

static void lshr(void)
{
	UINT32 src2 = SRC2VAL;
	DSTVAL = (src2 < 32) ? (SRC1VAL >> src2) : (SRC1VAL >> 31);
}

static void lshr_c(void)
{
	UINT32 src2 = SRC2VAL;
	asap.cflag = 0;
	if (src2 < 32)
	{
		UINT32 src1 = SRC1VAL;
		UINT32 dst = src1 >> src2;
		SET_ZN(dst);
		if (src2 != 0)
		{
			src1 = src1 << (32 - src2);
			asap.cflag = src1 >> 31;
		}
		DSTVAL = dst;
	}
	else
	{
		UINT32 dst = SRC1VAL >> 31;
		SET_ZN(dst);
		DSTVAL = dst;
	}
}

static void lshr_c0(void)
{
	UINT32 src2 = SRC2VAL;
	asap.cflag = 0;
	if (src2 < 32)
	{
		UINT32 src1 = SRC1VAL;
		UINT32 dst = src1 >> src2;
		SET_ZN(dst);
		if (src2 != 0)
		{
			src1 = src1 << (32 - src2);
			asap.cflag = src1 >> 31;
		}
	}
	else
	{
		SET_ZN(0);
		DSTVAL = 0;
	}
}

/**************************** ASHL ******************************/

static void ashl(void)
{
	UINT32 src2 = SRC2VAL;
	DSTVAL = (src2 < 32) ? (SRC1VAL << src2) : 0;
}

static void ashl_c(void)
{
	UINT32 src2 = SRC2VAL;
	asap.cflag = asap.vflag = 0;
	if (src2 < 32)
	{
		UINT32 src1 = SRC1VAL;
		UINT32 dst = src1 << src2;
		SET_ZN(dst);
		if (src2 != 0)
		{
			src1 = (INT32)src1 >> (32 - src2);
			asap.cflag = src1 & PS_CFLAG;
			asap.vflag = (src1 != ((INT32)dst >> 31)) << 31;
		}
		DSTVAL = dst;
	}
	else
	{
		SET_ZN(0);
		DSTVAL = 0;
	}
}

static void ashl_c0(void)
{
	UINT32 src2 = SRC2VAL;
	asap.cflag = asap.vflag = 0;
	if (src2 < 32)
	{
		UINT32 src1 = SRC1VAL;
		UINT32 dst = src1 << src2;
		SET_ZN(dst);
		if (src2 != 0)
		{
			src1 = (INT32)src1 >> (32 - src2);
			asap.cflag = src1 & PS_CFLAG;
			asap.vflag = (src1 != ((INT32)dst >> 31)) << 31;
		}
	}
	else
		SET_ZN(0);
}

/**************************** ROTL ******************************/

static void rotl(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL & 31;
	DSTVAL = (src1 << src2) | (src1 >> (32 - src2));
}

static void rotl_c(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL & 31;
	UINT32 dst = (src1 << src2) | (src1 >> (32 - src2));
	SET_ZN(dst);
	DSTVAL = dst;
}

static void rotl_c0(void)
{
	UINT32 src1 = SRC1VAL;
	UINT32 src2 = SRC2VAL & 31;
	UINT32 dst = (src1 << src2) | (src1 >> (32 - src2));
	SET_ZN(dst);
}

/**************************** GETPS ******************************/

static void getps(void)
{
	DSTVAL = GET_FLAGS(&asap);
}

/**************************** PUTPS ******************************/

static void putps(void)
{
	UINT32 src2 = SRC2VAL & 0x3f;
	SET_FLAGS(&asap, src2);
	check_irqs();
}

/**************************** JSR ******************************/

static void jsr(void)
{
	DSTVAL = asap.pc + 4;
	asap.nextpc = SRC1VAL + (SRC2VAL << 2);

	fetch_instruction();
	asap.pc = asap.nextpc;
	asap.nextpc = ~0;
	UPDATEPC();

	execute_instruction();
	asap_icount--;
}

static void jsr_0(void)
{
	asap.nextpc = SRC1VAL + (SRC2VAL << 2);

	fetch_instruction();
	asap.pc = asap.nextpc;
	asap.nextpc = ~0;
	UPDATEPC();

	execute_instruction();
	asap_icount--;
}

static void jsr_c(void)
{
	DSTVAL = asap.pc + 4;
	asap.nextpc = SRC1VAL + (SRC2VAL << 2);
	asap.iflag = asap.pflag;

	fetch_instruction();
	asap.pc = asap.nextpc;
	asap.nextpc = ~0;
	UPDATEPC();

	execute_instruction();
	asap_icount--;
	check_irqs();
}

static void jsr_c0(void)
{
	asap.nextpc = SRC1VAL + (SRC2VAL << 2);
	asap.iflag = asap.pflag;

	fetch_instruction();
	asap.pc = asap.nextpc;
	asap.nextpc = ~0;
	UPDATEPC();

	execute_instruction();
	asap_icount--;
	check_irqs();
}

/**************************** TRAP F ******************************/

static void trapf(void)
{
	generate_exception(EXCEPTION_TRAPF);
}


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

static void asap_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 + ASAP_IRQ0:	set_irq_line(ASAP_IRQ0, info->i);				break;

		case CPUINFO_INT_PC:
		case CPUINFO_INT_REGISTER + ASAP_PC:	asap.pc = info->i;								break;
		case CPUINFO_INT_REGISTER + ASAP_PS:	SET_FLAGS(&asap, info->i); 						break;

		case CPUINFO_INT_REGISTER + ASAP_R0:	src2val[REGBASE + 0] = info->i;					break;
		case CPUINFO_INT_REGISTER + ASAP_R1:	src2val[REGBASE + 1] = info->i;					break;
		case CPUINFO_INT_REGISTER + ASAP_R2:	src2val[REGBASE + 2] = info->i;					break;
		case CPUINFO_INT_REGISTER + ASAP_R3:	src2val[REGBASE + 3] = info->i;					break;
		case CPUINFO_INT_REGISTER + ASAP_R4:	src2val[REGBASE + 4] = info->i;					break;
		case CPUINFO_INT_REGISTER + ASAP_R5:	src2val[REGBASE + 5] = info->i;					break;
		case CPUINFO_INT_REGISTER + ASAP_R6:	src2val[REGBASE + 6] = info->i;					break;
		case CPUINFO_INT_REGISTER + ASAP_R7:	src2val[REGBASE + 7] = info->i;					break;
		case CPUINFO_INT_REGISTER + ASAP_R8:	src2val[REGBASE + 8] = info->i;					break;
		case CPUINFO_INT_REGISTER + ASAP_R9:	src2val[REGBASE + 9] = info->i;					break;
		case CPUINFO_INT_REGISTER + ASAP_R10:	src2val[REGBASE + 10] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R11:	src2val[REGBASE + 11] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R12:	src2val[REGBASE + 12] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R13:	src2val[REGBASE + 13] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R14:	src2val[REGBASE + 14] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R15:	src2val[REGBASE + 15] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R16:	src2val[REGBASE + 16] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R17:	src2val[REGBASE + 17] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R18:	src2val[REGBASE + 18] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R19:	src2val[REGBASE + 19] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R20:	src2val[REGBASE + 20] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R21:	src2val[REGBASE + 21] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R22:	src2val[REGBASE + 22] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R23:	src2val[REGBASE + 23] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R24:	src2val[REGBASE + 24] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R25:	src2val[REGBASE + 25] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R26:	src2val[REGBASE + 26] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R27:	src2val[REGBASE + 27] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R28:	src2val[REGBASE + 28] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R29:	src2val[REGBASE + 29] = info->i;				break;
		case CPUINFO_INT_REGISTER + ASAP_R30:	src2val[REGBASE + 30] = info->i;				break;
		case CPUINFO_INT_SP:
		case CPUINFO_INT_REGISTER + ASAP_R31:	src2val[REGBASE + 31] = info->i;				break;
	}
}



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

void asap_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(asap);					break;
		case CPUINFO_INT_INPUT_LINES:					info->i = 1;							break;
		case CPUINFO_INT_DEFAULT_IRQ_VECTOR:			info->i = 0;							break;
		case CPUINFO_INT_ENDIANNESS:					info->i = CPU_IS_LE;					break;
		case CPUINFO_INT_CLOCK_DIVIDER:					info->i = 1;							break;
		case CPUINFO_INT_MIN_INSTRUCTION_BYTES:			info->i = 4;							break;
		case CPUINFO_INT_MAX_INSTRUCTION_BYTES:			info->i = 4;							break;
		case CPUINFO_INT_MIN_CYCLES:					info->i = 1;							break;
		case CPUINFO_INT_MAX_CYCLES:					info->i = 2;							break;

		case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM:	info->i = 32;					break;
		case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32;					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 = 0;					break;
		case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: 		info->i = 0;					break;
		case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: 		info->i = 0;					break;

		case CPUINFO_INT_INPUT_STATE + ASAP_IRQ0:		info->i = asap.irq_state;				break;

		case CPUINFO_INT_PREVIOUSPC:					info->i = asap.ppc;						break;

		case CPUINFO_INT_PC:
		case CPUINFO_INT_REGISTER + ASAP_PC:			info->i = asap.pc;						break;
		case CPUINFO_INT_REGISTER + ASAP_PS:			info->i = GET_FLAGS(&asap);				break;

		case CPUINFO_INT_REGISTER + ASAP_R0:			info->i = src2val[REGBASE + 0];			break;
		case CPUINFO_INT_REGISTER + ASAP_R1:			info->i = src2val[REGBASE + 1];			break;
		case CPUINFO_INT_REGISTER + ASAP_R2:			info->i = src2val[REGBASE + 2];			break;
		case CPUINFO_INT_REGISTER + ASAP_R3:			info->i = src2val[REGBASE + 3];			break;
		case CPUINFO_INT_REGISTER + ASAP_R4:			info->i = src2val[REGBASE + 4];			break;
		case CPUINFO_INT_REGISTER + ASAP_R5:			info->i = src2val[REGBASE + 5];			break;
		case CPUINFO_INT_REGISTER + ASAP_R6:			info->i = src2val[REGBASE + 6];			break;
		case CPUINFO_INT_REGISTER + ASAP_R7:			info->i = src2val[REGBASE + 7];			break;
		case CPUINFO_INT_REGISTER + ASAP_R8:			info->i = src2val[REGBASE + 8];			break;
		case CPUINFO_INT_REGISTER + ASAP_R9:			info->i = src2val[REGBASE + 9];			break;
		case CPUINFO_INT_REGISTER + ASAP_R10:			info->i = src2val[REGBASE + 10];		break;
		case CPUINFO_INT_REGISTER + ASAP_R11:			info->i = src2val[REGBASE + 11];		break;
		case CPUINFO_INT_REGISTER + ASAP_R12:			info->i = src2val[REGBASE + 12];		break;
		case CPUINFO_INT_REGISTER + ASAP_R13:			info->i = src2val[REGBASE + 13];		break;
		case CPUINFO_INT_REGISTER + ASAP_R14:			info->i = src2val[REGBASE + 14];		break;
		case CPUINFO_INT_REGISTER + ASAP_R15:			info->i = src2val[REGBASE + 15];		break;
		case CPUINFO_INT_REGISTER + ASAP_R16:			info->i = src2val[REGBASE + 16];		break;
		case CPUINFO_INT_REGISTER + ASAP_R17:			info->i = src2val[REGBASE + 17];		break;
		case CPUINFO_INT_REGISTER + ASAP_R18:			info->i = src2val[REGBASE + 18];		break;
		case CPUINFO_INT_REGISTER + ASAP_R19:			info->i = src2val[REGBASE + 19];		break;
		case CPUINFO_INT_REGISTER + ASAP_R20:			info->i = src2val[REGBASE + 20];		break;
		case CPUINFO_INT_REGISTER + ASAP_R21:			info->i = src2val[REGBASE + 21];		break;
		case CPUINFO_INT_REGISTER + ASAP_R22:			info->i = src2val[REGBASE + 22];		break;
		case CPUINFO_INT_REGISTER + ASAP_R23:			info->i = src2val[REGBASE + 23];		break;
		case CPUINFO_INT_REGISTER + ASAP_R24:			info->i = src2val[REGBASE + 24];		break;
		case CPUINFO_INT_REGISTER + ASAP_R25:			info->i = src2val[REGBASE + 25];		break;
		case CPUINFO_INT_REGISTER + ASAP_R26:			info->i = src2val[REGBASE + 26];		break;
		case CPUINFO_INT_REGISTER + ASAP_R27:			info->i = src2val[REGBASE + 27];		break;
		case CPUINFO_INT_REGISTER + ASAP_R28:			info->i = src2val[REGBASE + 28];		break;
		case CPUINFO_INT_REGISTER + ASAP_R29:			info->i = src2val[REGBASE + 29];		break;
		case CPUINFO_INT_REGISTER + ASAP_R30:			info->i = src2val[REGBASE + 30];		break;
		case CPUINFO_INT_REGISTER + ASAP_R31:			info->i = src2val[REGBASE + 31];		break;

		/* --- the following bits of info are returned as pointers to data or functions --- */
		case CPUINFO_PTR_SET_INFO:						info->setinfo = asap_set_info;			break;
		case CPUINFO_PTR_GET_CONTEXT:					info->getcontext = asap_get_context;	break;
		case CPUINFO_PTR_SET_CONTEXT:					info->setcontext = asap_set_context;	break;
		case CPUINFO_PTR_INIT:							info->init = asap_init;					break;
		case CPUINFO_PTR_RESET:							info->reset = asap_reset;				break;
		case CPUINFO_PTR_EXIT:							info->exit = asap_exit;					break;
		case CPUINFO_PTR_EXECUTE:						info->execute = asap_execute;			break;
		case CPUINFO_PTR_BURN:							info->burn = NULL;						break;
		case CPUINFO_PTR_DISASSEMBLE:					info->disassemble = asap_dasm;			break;
		case CPUINFO_PTR_INSTRUCTION_COUNTER:			info->icount = &asap_icount;			break;
		case CPUINFO_PTR_REGISTER_LAYOUT:				info->p = asap_reg_layout;				break;
		case CPUINFO_PTR_WINDOW_LAYOUT:					info->p = asap_win_layout;				break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case CPUINFO_STR_NAME:							strcpy(info->s = cpuintrf_temp_str(), "ASAP"); break;
		case CPUINFO_STR_CORE_FAMILY:					strcpy(info->s = cpuintrf_temp_str(), "Atari ASAP"); break;
		case CPUINFO_STR_CORE_VERSION:					strcpy(info->s = cpuintrf_temp_str(), "1.0"); 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) Aaron Giles 2000-2004"); break;

		case CPUINFO_STR_FLAGS:							strcpy(info->s = cpuintrf_temp_str(), " "); break;

		case CPUINFO_STR_REGISTER + ASAP_PC:  			sprintf(info->s = cpuintrf_temp_str(), "PC: %08X", asap.pc); break;
		case CPUINFO_STR_REGISTER + ASAP_PS:  			sprintf(info->s = cpuintrf_temp_str(), "PS: %08X", GET_FLAGS(&asap)); break;

		case CPUINFO_STR_REGISTER + ASAP_R0:			sprintf(info->s = cpuintrf_temp_str(), "R0: %08X", asap.r[0]); break;
		case CPUINFO_STR_REGISTER + ASAP_R1:			sprintf(info->s = cpuintrf_temp_str(), "R1: %08X", asap.r[1]); break;
		case CPUINFO_STR_REGISTER + ASAP_R2:			sprintf(info->s = cpuintrf_temp_str(), "R2: %08X", asap.r[2]); break;
		case CPUINFO_STR_REGISTER + ASAP_R3:			sprintf(info->s = cpuintrf_temp_str(), "R3: %08X", asap.r[3]); break;
		case CPUINFO_STR_REGISTER + ASAP_R4:			sprintf(info->s = cpuintrf_temp_str(), "R4: %08X", asap.r[4]); break;
		case CPUINFO_STR_REGISTER + ASAP_R5:			sprintf(info->s = cpuintrf_temp_str(), "R5: %08X", asap.r[5]); break;
		case CPUINFO_STR_REGISTER + ASAP_R6:			sprintf(info->s = cpuintrf_temp_str(), "R6: %08X", asap.r[6]); break;
		case CPUINFO_STR_REGISTER + ASAP_R7:			sprintf(info->s = cpuintrf_temp_str(), "R7: %08X", asap.r[7]); break;
		case CPUINFO_STR_REGISTER + ASAP_R8:			sprintf(info->s = cpuintrf_temp_str(), "R8: %08X", asap.r[8]); break;
		case CPUINFO_STR_REGISTER + ASAP_R9:			sprintf(info->s = cpuintrf_temp_str(), "R9: %08X", asap.r[9]); break;
		case CPUINFO_STR_REGISTER + ASAP_R10:			sprintf(info->s = cpuintrf_temp_str(), "R10:%08X", asap.r[10]); break;
		case CPUINFO_STR_REGISTER + ASAP_R11:			sprintf(info->s = cpuintrf_temp_str(), "R11:%08X", asap.r[11]); break;
		case CPUINFO_STR_REGISTER + ASAP_R12:			sprintf(info->s = cpuintrf_temp_str(), "R12:%08X", asap.r[12]); break;
		case CPUINFO_STR_REGISTER + ASAP_R13:			sprintf(info->s = cpuintrf_temp_str(), "R13:%08X", asap.r[13]); break;
		case CPUINFO_STR_REGISTER + ASAP_R14:			sprintf(info->s = cpuintrf_temp_str(), "R14:%08X", asap.r[14]); break;
		case CPUINFO_STR_REGISTER + ASAP_R15:			sprintf(info->s = cpuintrf_temp_str(), "R15:%08X", asap.r[15]); break;
		case CPUINFO_STR_REGISTER + ASAP_R16:			sprintf(info->s = cpuintrf_temp_str(), "R16:%08X", asap.r[16]); break;
		case CPUINFO_STR_REGISTER + ASAP_R17:			sprintf(info->s = cpuintrf_temp_str(), "R17:%08X", asap.r[17]); break;
		case CPUINFO_STR_REGISTER + ASAP_R18:			sprintf(info->s = cpuintrf_temp_str(), "R18:%08X", asap.r[18]); break;
		case CPUINFO_STR_REGISTER + ASAP_R19:			sprintf(info->s = cpuintrf_temp_str(), "R19:%08X", asap.r[19]); break;
		case CPUINFO_STR_REGISTER + ASAP_R20:			sprintf(info->s = cpuintrf_temp_str(), "R20:%08X", asap.r[20]); break;
		case CPUINFO_STR_REGISTER + ASAP_R21:			sprintf(info->s = cpuintrf_temp_str(), "R21:%08X", asap.r[21]); break;
		case CPUINFO_STR_REGISTER + ASAP_R22:			sprintf(info->s = cpuintrf_temp_str(), "R22:%08X", asap.r[22]); break;
		case CPUINFO_STR_REGISTER + ASAP_R23:			sprintf(info->s = cpuintrf_temp_str(), "R23:%08X", asap.r[23]); break;
		case CPUINFO_STR_REGISTER + ASAP_R24:			sprintf(info->s = cpuintrf_temp_str(), "R24:%08X", asap.r[24]); break;
		case CPUINFO_STR_REGISTER + ASAP_R25:			sprintf(info->s = cpuintrf_temp_str(), "R25:%08X", asap.r[25]); break;
		case CPUINFO_STR_REGISTER + ASAP_R26:			sprintf(info->s = cpuintrf_temp_str(), "R26:%08X", asap.r[26]); break;
		case CPUINFO_STR_REGISTER + ASAP_R27:			sprintf(info->s = cpuintrf_temp_str(), "R27:%08X", asap.r[27]); break;
		case CPUINFO_STR_REGISTER + ASAP_R28:			sprintf(info->s = cpuintrf_temp_str(), "R28:%08X", asap.r[28]); break;
		case CPUINFO_STR_REGISTER + ASAP_R29:			sprintf(info->s = cpuintrf_temp_str(), "R29:%08X", asap.r[29]); break;
		case CPUINFO_STR_REGISTER + ASAP_R30:			sprintf(info->s = cpuintrf_temp_str(), "R30:%08X", asap.r[30]); break;
		case CPUINFO_STR_REGISTER + ASAP_R31:			sprintf(info->s = cpuintrf_temp_str(), "R31:%08X", asap.r[31]); break;
	}
}
