/*
	Z80.h: C header file for the Z80 emulator. Corresponds to the
	information in Z80.i and Z80_struct.i.

	All (or most) of these types have to be defined (with proper
	size and sign): BYTE, UBYTE, WORD, UWORD, LONG and ULONG.

	If Z80_ENVDATA is defined, the last entry in the Z80_Control
	structure will be a structure named Envdata, of the type 'struct
	Z80_Envdata', which is then assumed to be defined.

	Note that the layout of structure entries is strongly dependent
	on the 680x0-architecture (i.e. big-endian and word-aligned word
	or longword accesses), and must correspond exactly to the layout
	in the Z80_struct.i assembler include file.

*/
#ifndef Z80_H
#define Z80_H


	/* All sizes and offsets are in bytes. */


/*  The amount of bytes needed for the Z80 memory space
*/
#define Z80_MEMSIZE	0x10000


#define Z80_LBUFSIZE	16  /* Uninteresting to the normal user */
#define Z80_HBUFSIZE	16


/*  The size of the memory used for the cache.
    The allocated memory must be word-aligned!
*/
#define Z80_CACHESIZE	((2*Z80_MEMSIZE)+Z80_LBUFSIZE+Z80_HBUFSIZE)


/*  The space needed for memory control attributes
*/
#define Z80_ATTRMEMSIZE Z80_MEMSIZE



/*  Memory write access control attributes:

	Memory attribute values (unsigned byte):

		0		write allowed (no detection)
		1 to 126	user-defined handler call
		127		read-only

	Call Z80_SetMemAttr (described below) to set these attributes.
	In particular, bit 7 of each attribute byte is used internally
	and should not be modified or interpreted as part of the value.

	If an attempt is made to write to an address whose attribute is
	in the range 1 to 126, then if the field Z80_MemHandler is
	nonzero, a call is made to the address it points to. If it is
	zero, the value is written as if the attribute was 0.

	The user memory handler is called with the following parameters:

		d0 contains the exception number (longword, range -128
		   to 127).

		d1 contains the value (longword, range -128 to 127).

		d2 contains the Z80 address (longword, range -32768 to
		   32767).

		a0 is scratch (address of user handler).

	All other registers must be protected before they are modified.

	The handler should return the following values:

		d0 (longword) nonzero if value should be written, zero
		   if not.

		d1 (low byte) contains the value.

	Changes to d2 and a0 have no effect.

	The user-defined handler call has some overhead, and is not
	recommended for memory addresses/areas that are written to very
	often, like bit-mapped display memory. More suitable
	applications are e.g. memory-mapped I/O and character-mapped
	display memory.

	For certain reasons, it is not possible to extract any
	information about the current Z80 CPU status during a memory
	handler call. Single-step procedures in combination with memory
	write access checking could be used for such purposes.

	Example in C:

		Z80_SetMemAttr(Control, 0x4000, 0x1B00, Z80_MEM_ROM);

	Flags the area from $4000 to $5AFF as ROM.
*/

/* (These values are hard-coded internally.)
*/
#define Z80_MEM_ROM	127
#define Z80_MEM_RAM	0



/*  The emulation control structure:
*/
struct Z80_Control {

  /* Private */
    LONG    Workspace;	/* temporary storage, byte swapping and so on */

  /* Read-only */
    UBYTE   Parity[256];	/* Parity translation table */

  /* Public */
    BYTE *  Memory;	/* Pointer to the Z80 address space memory */
    WORD *  CacheMem;	/* Pointer to the cache memory */
    BYTE *  AttrMem;	/* Pointer to the attribute memory */
    void *  MemHandler; /* Pointer to user memory exception handler */

  /* Read-only */
    BYTE *  Zero;	/* Pointer to Z80 address 0. The (signed) word-
			   sized Z80 registers (like HL) can be used as
			   offsets from this base to access the Z80
			   memory space.
			*/
    WORD *  CacheZero;	/* Corresponds to Zero in cache memory */
    BYTE *  AttrZero;	/* Corresponds to Zero in attribute memory */

    WORD    Running;	/* Nonzero if running, zero if not */


    /*	The CPU status substructure:

	None of these entries should be accessed unless the emulator is
	stopped, since their contents then may not reflect the actual
	CPU status, and modifications may have no effect. Some are never
	updated or read from except upon exiting and resuming.
    */

    struct CpuStatus {
	union {
	  WORD w;	/* AF can be word-accessed as s.CPU.AF.w */
	  struct {
	    BYTE A;
	    BYTE F;
	  } b;		/* ...or byte accessed as s.CPU.AF.b.A (or F) */
	} AF;

	union {
	  WORD w;	/* BC can be word-accessed as s.CPU.BC.w */
	  struct {
	    BYTE B;
	    BYTE C;
	  } b;		/* ...or byte accessed as s.CPU.BC.b.B (or C) */
	} BC;

	union {
	  WORD w;	/* DE can be word-accessed as s.CPU.DE.w */
	  struct {
	    BYTE D;
	    BYTE E;
	  } b;		/* ...or byte accessed as s.CPU.DE.b.D (or E) */
	} DE;

	union {
	  WORD w;	/* HL can be word-accessed as s.CPU.HL.w */
	  struct {
	    BYTE H;
	    BYTE L;
	  } b;		/* ...or byte accessed as s.CPU.HL.b.H (or L) */
	} HL;

	union {
	  WORD w;	/* A'F' can be word-accessed as s.CPU.alt_AF.w */
	  struct {
	    BYTE A;
	    BYTE F;
	  } b;		/* ...or byte accessed as s.CPU.alt_AF.b.A (or F) */
	} alt_AF;

	union {
	  WORD w;	/* B'C' can be word-accessed as s.CPU.alt_BC.w */
	  struct {
	    BYTE B;
	    BYTE C;
	  } b;		/* ...or byte accessed as s.CPU.alt_BC.b.B (or C) */
	} alt_BC;

	union {
	  WORD w;	/* D'E' can be word-accessed as s.CPU.alt_DE.w */
	  struct {
	    BYTE D;
	    BYTE E;
	  } b;		/* ...or byte accessed as s.CPU.alt_DE.b.D (or E) */
	} alt_DE;

	union {
	  WORD w;	/* H'L' can be word-accessed as s.CPU.alt_HL.w */
	  struct {
	    BYTE H;
	    BYTE L;
	  } b;		/* ...or byte accessed as s.CPU.alt_HL.b.H (or L) */
	} alt_HL;

	union {
	  WORD w;	/* IX can be word-accessed as s.CPU.IX.w */
	  struct {
	    BYTE H;
	    BYTE L;
	  } b;		/* ...or byte accessed as s.CPU.IX.b.H (or L) */
	} IX;

	union {
	  WORD w;	/* IY can be word-accessed as s.CPU.IY.w */
	  struct {
	    BYTE H;
	    BYTE L;
	  } b;		/* ...or byte accessed as s.CPU.IY.b.H (or L) */
	} IY;

	WORD	SP;
	WORD	PC;

	BYTE	IFF;	/* IFF2 in bit 7, IFF1 in bit 6 */
	BYTE	IMF;	/* Interrupt mode flip flops (bits 0-1) */
	BYTE	I;
	BYTE	R;

	/* These could be inspected. If nonzero, a request has been
	   received but not yet served.
	*/
	BYTE	INT;	/* INT signal */
	BYTE	NMI;	/* NMI signal */
	BYTE	RESET;	/* RESET signal */
	BYTE	EXIT;	/* EXIT signal */


    } CPU;		/* End of the CPU status substructure */


  /* Private: */
    WORD    ReqV;	/* Request vector (offset from InstrBase) */
    UWORD   alt_CCR;	/* This is the internal F' in CCR format */
    BYTE    BCDF;	/* The H and N flags of F (bits 1 and 4) */
    BYTE    alt_BCDF;	/* The H and N flags of F' (bits 1 and 4) */


#ifdef Z80_ENVDATA

  /* User environment data area. Should be word-aligned here.
  */
    struct Z80_Envdata Envdata;

#endif

};  /* End of the Z80_Control structure definition */



		/* Function prototypes and documentation */

/*  Initialisation:

    Before beginning emulation, the control structure must be
    initialised by calling Z80_Init() with a pointer to the structure.
    This also initialises the cache memory.
      The fields Z80_Memory and Z80_CacheMem must be initialised to
    point to allocated memory. If the memory write access checking
    feature is used, the field Z80_AttrMem must also be initialised, and
    if Z80_MemHandler is nonzero it is assumed to be a pointer to a user
    memory exception handler. See the memory attribute definitions above
    for details.
      The user environment data area is not changed. All other fields
    (apart from those mentioned above) are automatically initialised to
    zero. The CPU status substructure is set up as after a reset.
      The returned value is nonzero if an error occurred, and zero
    otherwise.
*/

int Z80_Init(struct Z80_Control *);


/*  Cold start:

    The emulator is started 'from scratch' with a CPU reset through a
    call to Z80_Coldstart(). A pointer to a control structure must be
    given, and the structure must be initialised (see Z80_Init above).
      The return value is nonzero if an error occurred, and zero
    otherwise.
*/

int Z80_Coldstart(struct Z80_Control *);


/*  Warm start:

    The emulation is resumed as if nothing happened since the last exit
    (unless the saved processor status has been manipulated). A pointer
    to a control structure must be given. Changes to other fields than
    the CPU status substructure entries are not recommended; calling
    Z80_Continue() does not guarantee that such changes have any effect
    (see Z80_NewSettings() below).
      The return value is the same as for Z80_Coldstart.
*/

int Z80_Continue(struct Z80_Control *);


/*  Refreshing the internal data after modifications:

    This subroutine makes the emulator update the private fields of the
    control structure when any of the public fields outside the CPU
    status substructure have been modified, for instance if the
    Z80_Memory field is changed. It must not be called while the
    emulator is running.
      It takes a pointer to the control structure as parameter. The
    returned value is nonzero if an error occurred, and zero otherwise.

    Memory reallocation example:

    Call Z80_EXITreq() and make sure the emulator has stopped before
    reallocating memory (remember to copy the old memory contents to the
    new areas), then update the corresponding entries in the control
    structure (Z80_Memory, Z80_Cachemem and Z80_Attrmem). Calling
    Z80_NewSettings() will then make sure that Z80_Continue() will
    properly resume the emulation from the new addresses.

      Note that the control structure itself can be moved whenever the
    emulator is not running, without doing anything other than passing
    the new address to Z80_Continue().
*/

int Z80_NewSettings(struct Z80_Control *);



/*  Request making subroutines:

    These routines emulate the CPU request lines (including requests to
    halt the emulation). Requests are currently only tested for after
    flow control instructions and memory wrap-around, but that seems to
    be quite sufficient.
      A request overrides those of lower priority. The priority order
    (from highest to lowest) is: EXIT, RESET, BUSRQ, NMI and INT. BUSRQ
    is currently not implemented. The status of other requests is stored
    while one request is handled, and no requests are lost.
      Note that the emulation clears a signal automatically after it has
    been detected and acted upon (or has been ignored). A possible
    future extension is to include a complete model of the CPU pins.
      The requests could be called from hardware interrupts, keypresses,
    menus or whatever. They all take a pointer to the control structure
    as parameter, and return nothing. They are not sensitive to
    concurrent accessing of the shared data (no protected mode or
    semaphores needed).
*/


void Z80_EXITreq(struct Z80_Control *);

/*  Tells the emulation that it should halt and return from the call.
      The same mechanism as is used for communicating emulated hardware
    signals to the CPU emulation is also used to ask the emulation to
    store its internal data and return from the call. Therefore,
    stopping the emulation 'from the outside' is done through just
    another request call.
      The 'Running' field of the emulation control structure can be
    inspected to see when the emulation has stopped.
*/


void Z80_INTreq(struct Z80_Control *);

/*  Emulates pulling the INT line low.
*/


void Z80_NMIreq(struct Z80_Control *);

/*  Emulates a Non-Maskable Interrupt. (Negative edge triggered on a
    real Z80.)
*/


void Z80_RESETreq(struct Z80_Control *);

/*  Emulates pulling the RESET line low.
*/


	/* Utility functions */

/*  Routines to access the Z80 address space:

    These routines mirror any memory changes in the cache and handle the
    wraparound of addresses transparently. I recommend that they are used
    rather than writing directly into the Z80 address space. They do *not*
    respect any memory protection attributes - a write always takes effect.
      All need a pointer to the control structure and a word-sized Z80
    address (for block functions this is the block start address).

	Z80_SetByte() is passed a byte value to be written. It returns
	nothing.

	Z80_SetWordLH() is passed a (big-endian) word-sized value and
	writes it (little-endian) to Z80 memory. It returns nothing.

	Z80_GetByte() returns the read byte value.

	Z80_GetWordLH() reads a (little-endian) word-sized value and
	returns it (in big-endian form).

    All block functions are passed the block size as an unsigned
    longword. They return nothing.

	Z80_SetBlock() is also passed the byte value to be written.

	Z80_ReadBlock() and Z80_WriteBlock() are passed the buffer
	address (in the 680x0 address space) as a void pointer.

    All Z80 address arithmetic is word-sized. For instance, calling
    Z80_SetWordLH(CtrlPtr, 0xffff, 0x1234) will store 0x34 in Z80
    address 0xffff and 0x12 in address 0x0000. The block functions will
    also wrap at $ffff.
*/

void Z80_SetByte(struct Z80_Control *, UWORD addr, BYTE val);


void Z80_SetWordLH(struct Z80_Control *, UWORD addr, UWORD val);


BYTE Z80_GetByte(struct Z80_Control *, UWORD addr);


WORD Z80_GetWordLH(struct Z80_Control *, UWORD addr);


void Z80_SetBlock(struct Z80_Control *,
    UWORD start_addr, ULONG size, BYTE val);


void Z80_ReadBlock(struct Z80_Control *,
    void *buffer, UWORD start_addr, ULONG size);


void Z80_WriteBlock(struct Z80_Control *,
    void *buffer, UWORD start_addr, ULONG size);


/*  Accessing memory attributes:

    Z80_SetMemAttr() sets the memory attributes for a block of Z80
    memory to a specific value. It takes a pointer to the control
    structure, a (word-sized) Z80 block start address, the block size
    (an unsigned longword) and the attribute value (a byte) as
    parameters. Nothing is returned.

    Z80_GetMemAttr() returns the memory attribute value for a single
    address. It takes a pointer to the control structure and a
    (word-sized) Z80 address as parameters. It returns a byte-sized
    attribute value.

    For ranges of attribute values, see the section on memory attributes
    above.
*/

void Z80_SetMemAttr(struct Z80_Control *,
    UWORD start_addr, ULONG size, BYTE value);


BYTE Z80_GetMemAttr(struct Z80_Control *, UWORD addr);



#endif	/* ifndef Z80_H */

