/*
cpm-i386

Written by D'Arcy J.M. Cain
darcy@druid

This file is the header used by the CP/M emulator when running under
the following machine(s):

	System V Rel 3.2 on Intel 80386 processor

Link this file to cpm.h on the above system.  Other entries will be added
as they are tested.

To use this program on systems which differ from the above in significant
ways, a header must be created such that the Z80 registers can be accessed
using the following register names:
	A, B, C, D, E, H, L, BC, DE, HL, IX, IY, SP, PC, AF and FLAGS
In addition the following flags sould be available:
	CARRY, BCD, PARITY, HALF_CARRY, ZERO and SIGN
Also the HL, SP, IX and IY registers should have a H and L version for
accessing half-words and TEMP should be a scratch variable accessed the
same way.  See below for examples.

There should also be a variable IFF and an array of 0x10000 (65,536) bytes
called ram.

The two variables psw_bank and gr_bank should allow register context
switching for the AF register and the general registers

*/

#ifdef	COMPILE_TEST
#define	CPM_DEBUG
#endif

typedef	unsigned char	byte;
typedef unsigned short	word;
/* We use unsigned short to guarantee two byte words and roll-over */

#define	lonyb(v)	(v & 0xf)
#define	hinyb(v)	((v >> 4) & 0xf)
#define	when		break; case

typedef union {
	word	af;
	struct {
		byte	flags, a;
	} b;
	struct {
		unsigned int	carry:1;
		unsigned int	bcd:1;
		unsigned int	parity:1;
		unsigned int	x1:1;
		unsigned int	half:1;
		unsigned int	x2:1;
		unsigned int	zero:1;
		unsigned int	sign:1;
	} bits;
} ACC;

typedef union {
	struct {
		word	bc;
		word	de;
		word	hl;
	} w;
	struct {
		byte	c, b;
		byte	e, d;
		byte	l, h;
	} b;
} GR;

typedef union {
	unsigned char	half[2];
	unsigned short	whole;
} REG;

#define	TEMPH	(reg.half[1])
#define	TEMPL	(reg.half[0])
#define	TEMP	(reg.whole)
#define	SPH		(sp.half[1])
#define	SPL		(sp.half[0])
#define	SP		(sp.whole)
#define IXH		(ix.half[1])
#define IXL		(ix.half[0])
#define IX		(ix.whole)
#define IYH		(iy.half[1])
#define IYL		(iy.half[0])
#define IY		(iy.whole)

#ifdef	CPM_DATA
ACC		acc[2];
GR		gr[2];
word	PC;
byte	R, IV;
int		gr_bank = 0, acc_bank = 0, IFF = 1;
REG		reg, sp, ix, iy;

#ifdef	COMPILE_TEST
byte	ram[0x10000] = {
	0x00,				/* 0000: nop */
	0x21, 0x00, 0x10,	/* 0001: ld hl, 1000h */
	0xe5,				/* 0004: push hl */
	0x3e, 0xbb,			/* 0005: ld a, 0bbh */
	0x87,				/* 0007: add a, a */
	0x8f,				/* 0008: adc a, a */
	0x3d,				/* 0009: dec a */
	0x2f,				/* 000a: cpl */
	0xb8,				/* 000b: cp b */
	0xcc, 0x14, 0x00,	/* 000c: call z, 0014h */
	0xbf,				/* 000f: cp a */
	0xcc, 0x14, 0x00,	/* 0010: call z, 0014h */
	0x00,				/* 0013: nop */
	0xc3, 0x19, 0x00,	/* 0014: jp 0019h */
	0x18, 0x03,			/* 0x17: jr 001bh */
	0x18, 0xfd,			/* 0x19: jr 0014h */
	0xc9,				/* 001b: ret */
	0x00 };				/* 0015: nop */
#define		TEST_SIZE	24
#else
byte	ram[0x10000];
#endif

byte	page_zero[] = {
	0xc3, 0x03, 0xff,	/* JP BIOS+3 */
	0x00, 0x00,			/* reserved */
	0xc3, 0xc0, 0xfe,	/* JP BDOS */
};

#else
extern ACC	acc[];
extern GR	gr[];
extern word	PC;
extern byte	R, IV, ram[];
extern int	gr_bank, acc_bank, IFF;
extern REG	reg, sp, ix, iy;
#endif

#define		AF			(acc[acc_bank].af)
#define		A			(acc[acc_bank].b.a)
#define		FLAGS		(acc[acc_bank].b.flags)
#define		CARRY		(acc[acc_bank].bits.carry)
#define		BCD			(acc[acc_bank].bits.bcd)
#define		PARITY		(acc[acc_bank].bits.parity)
#define		OVERFLOW	(acc[acc_bank].bits.parity)
#define		HALF_CARRY	(acc[acc_bank].bits.half)
#define		ZERO		(acc[acc_bank].bits.zero)
#define		SIGN		(acc[acc_bank].bits.sign)

#define		B			(gr[gr_bank].b.b)
#define		C			(gr[gr_bank].b.c)
#define		D			(gr[gr_bank].b.d)
#define		E			(gr[gr_bank].b.e)
#define		H			(gr[gr_bank].b.h)
#define		L			(gr[gr_bank].b.l)
#define		BC			(gr[gr_bank].w.bc)
#define		DE			(gr[gr_bank].w.de)
#define		HL			(gr[gr_bank].w.hl)

#define		BDOS		0xfec0
#define		BIOS		0xff00
#define		bios(x)		(BIOS + (x * 3))

#define		MAX_DRIVES	16

int			decode(void);
const char	*dasm(const byte *buf);
