** The generic versions of the macros for the implementation-dependent
** Z80 instructions.

** The file Z80_coding.i contains the definitions of the macros and
** register aliases used in the instruction emulation routines.
** If your assembler does not handle register aliasing, you will have to
** translate the aliases used below to the corresponding register names,
** as defined in the include file. Take great care when doing this.

** ======================================================================

** Notes on the refresh register
**
** The real behaviour of the R register seems impossible to emulate at a
** reasonable speed, since it increments at certain intervals providing
** certain parts of the CPU are free. Usually once per instruction, but
** sometimes twice. (If anybody finds a complete description of this,
** please send me a copy).
**
**  The R register is not incremented after each instruction; instead when
**  Ld A,R is executed the bits 0-6 have to be made up from some counter
**  like the Pseudo-PC or the system clock. Bit 7 is taken from the last
**  stored R.
**
**  When Ld R,A is executed, only bit 7 must be safely stored in the
**  Z80_R field of the control structure. Bits 0-6 may be treated in any
**  way by the implementer.
**
**  The file generic_macs.i provides a version of Ld A,R which uses the
**  Pseudo-PC to 'approximate R' as a non-machine specific way to do it.

** ---------------------------------------------------------------------

	IFD VERBOSE
	LIST
** Using the generic macros for the implementation-dependent routines.
	NOLIST
	ENDC


** The In instructions "read" a fixed value:
DEFAULT_IN = 00


	/* Macros can't be nested, so we do it like this: */

In_r_1C1_subm	MACRO	;Parameter: register
		move.b	#DEFAULT_IN,\1 ;this is where you "read" the value
		tst.b	\1	;V is cleared, N and Z tested
		putsr	d7
		eor.b	d7,d6
		and.w	#1,d6
		eor.b	d7,d6	;keep old carry
		parity	\1
		skip 1
		next
		ENDM
In_A_1C1_mac	MACRO
		In_r_1C1_subm	A
		ENDM
In_B_1C1_mac	MACRO
		In_r_1C1_subm	B
		ENDM
In_C_1C1_mac	MACRO
		In_r_1C1_subm	C
		ENDM
In_D_1C1_mac	MACRO
		In_r_1C1_subm	D
		ENDM
In_E_1C1_mac	MACRO
		In_r_1C1_subm	E
		ENDM
In_L_1C1_mac	MACRO
		In_r_1C1_subm	L
		ENDM

In_H_1C1_mac	MACRO
		swap d6		;save flags
		move.b	#DEFAULT_IN,d6	;"read" the value
		move.w	HL,(Work)
		move.b	d6,(Work)       ;V is cleared, N & Z tested
		putsr	d7
		or.b	Z80_Parity(TableB,d6.w),d7 ;set parity in d7
		move.w	(Work),HL
		swap	d6	;old flags back
		eor.b	d7,d6
		and.w	#1,d6
		eor.b	d7,d6	;keep old carry
		skip 1
		next
		ENDM

	;"Undocumented" instruction. Reads from the port but does not
	;store the value. Flags are affected by the read value as usual,
	;and this instruction is sometimes named "In F,(C)". The name
	;"In (HL),(C)" would be symmetric, but is not correct.
In_xx_1C1_mac	MACRO
		swap d6		;save flags
		move.b	#DEFAULT_IN,d6	;"read" the value
		tst.b	d6	;V is cleared, N & Z tested
		putsr	d7
		or.b	Z80_Parity(TableB,d6.w),d7 ;set parity in d7
		swap	d6	;forget the value, old flags back
		eor.b	d7,d6
		and.w	#1,d6
		eor.b	d7,d6	;keep old carry
		skip 1
		next
		ENDM
** ----
In_A_1n1_mac	MACRO
		getRPC	;d7="Real PC" is addressing the immediate data
		getz	d7,d7	;transfer the byte to d7
	;Now, the port address is formed from A (bits 15-8)
	;and d7 (bits 7-0).
		move.b	#DEFAULT_IN,A	;"read" the value.
		skip 1
		next
		ENDM
** ----

Ind_mac 	MACRO
		move.b	#DEFAULT_IN,d7
		putz	d7,HL
		decw	HL
		and.w	#%1011,d6
		decb	B
		bne.s	01$	;jump if not zero
		or.w	#%0100,d6
01$		skip 1
		next
		ENDM
** ----
Indr_mac	MACRO
		move.b	#DEFAULT_IN,d7
01$		putz	d7,HL
		decw	HL
		decb	B
		bne.s	01$	;loop
		or.w	#%0100,d6
		skip 1
		next
		ENDM
** ----
Ini_mac 	MACRO
		move.b	#DEFAULT_IN,d7
		putz	d7,HL
		incw	HL
		and.w	#%1011,d6
		decb	B
		bne.s	01$	;jump if not zero
		or.w	#%0100,d6
01$		skip 1
		next
		ENDM
** ----
Inir_mac	MACRO
		move.b	#DEFAULT_IN,d7
01$		putz	d7,HL
		incw	HL
		decb	B
		bne.s	01$	;loop
		or.w	#%0100,d6
		skip 1
		next
		ENDM
** ----
Ld_A_R_mac	MACRO
		getRPC	;take bits from RPC (since PPC is always even)
		move.b	Z80_R(TableB),A
		eor.w	d7,d6
		and.w	#80,d6	;keep bit 7 of stored R
		eor.w	d7,d6	;V is cleared, Z and N tested.
		putsr	d7
		eor.w	d7,d6
		and.w	#1,d6	;keep old carry
		eor.w	d7,d6
		tst.b	Z80_IFF(TableB)    ;test IFF2
		beq.s	01$	;jump if IFF2 clear
		or.w	#%0010,d6	;set V if IFF2 set
01$		skip 1
		next
		ENDM
** ----
Ld_R_A_mac	MACRO
		move.b	A,Z80_R(TableB)	;(the bits 6-0 are never reused)
		skip 1
		next
		ENDM
** ----

** The Out instructions don't "output" anything, but merely change
** registers and flags as needed.

** It is OK for Otir and Otdr to be a bit inefficient. The real Z80
** instruction does a complete re-execution each time it loops.
** If that is done here as well, the block output timing will be nicer.

Otdr_mac	MACRO
01$		getz	HL,d7
		;d7 holds the byte to be output,
		;BC the port address.
		;place "output" here
		decw	HL
		decb	B
		bne.s	01$	;loop
		or.w	#%0100,d6	;Set Z
		skip 1
		next
		ENDM
** ----
Otir_mac	MACRO
01$		getz	HL,d7
		;d7 holds the byte to be output,
		;BC the port address.
		;place "output" here
		incw	HL
		decb	B
		bne.s	01$	;loop
		or.w	#%0100,d6	;Set Z
		skip 1
		next
		ENDM
** ----
Out_1C1_r_mac	MACRO	;Parameter: register
		;"output" to BC
		skip 1
		next
		ENDM

Out_1C1_H_mac	MACRO
		;"output" to BC
		skip 1
		next
		ENDM
** ----
	;"Undocumented" instruction. Seems to output a zero value
	;to the port. The name "Out (C),(HL)" would be symmetric,
	;but is not correct.
Out_1C1_xx_mac	MACRO
		;"output" a zero to port BC
		skip 1
		next
		ENDM
** ----
Out_1n1_A_mac	MACRO
		getRPC
		getz	d7,d7	;get immediate data to d7
		;"output" A to address given by d7 (bits 7-0)
		;(bits 15-8 seem tobe undefined)
		skip 1
		next
		ENDM
** ----
Outd_mac	MACRO
		getz	HL,d7
		;"output" value in d7 to BC
		decw	HL
		and.w	#%1011,d6	;Clear Z
		decb	B
		bne.s	01$	;jump if not zero
		or.w	#%0100,d6	;Set Z
$01		skip 1
		next
		ENDM
** ----
Outi_mac	MACRO
		getz	HL,d7
		;"output" value in d7 to BC
		incw	HL
		and.w	#%1011,d6	;Clear Z
		decb	B
		bne.s	01$	;jump if not zero
		or.w	#%0100,d6	;Set Z
01$		skip 1
		next
		ENDM
** ----

** The Reti and Retn instructions do not themselves cause any signalling,
** but interrupt-controlling hardware could be watching the bus to see
** when an interrupt finishes.

Reti_mac	MACRO
		;Do any "hardware" emulation first.
		getz	ZSP,1(Work)
		incw	ZSP
		getz	ZSP,(Work)
		incw	ZSP
		move.w	(Work),d7
		makePPC
		testreq
		ENDM
** ----
Retn_mac	MACRO
		;Do any "hardware" emulation first.
		getz	ZSP,1(Work)
		incw	ZSP
		getz	ZSP,(Work)
		incw	ZSP
		move.w	(Work),d7
		makePPC
		move.b	Z80_IFF(TableB),d7
		asr.b	#1,d7		;IFF2 -> IFF1 -> bit 5
		and.b	#$C0,d7 	;reset bits 5-0
		move.b	d7,Z80_IFF(TableB)
		testreq
		ENDM

** ======================================================================
