**
**	file: generic_macs.i
**
** The generic versions of the macros for the implementation-dependent Z80
** instructions.

	IFD VERBOSE
	LIST
** Using the macros in the generic_macs.i file for the implementation-
** dependent routines.
	NOLIST
	ENDC

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

** 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.

** Notation for describing instructions:
**
**	r  = 8-bit register (A, B, C, D, E, H, L)
**	rr = 16-bit register pair (BC, DE, HL, SP)
**	ii = 16-bit index register (IX, IY)
**	qq = 16-bit register pair (BC, DE, HL, AF)
**	n  = 8-bit immediate data
**	nn = 16-bit immediate data
**	s  = 8-bit source
**	ss = 16-bit source
**	m  = 8-bit addressing mode
**	e  = 8-bit relative jump offset (signed, immediate data)
**	d  = 8-bit indexing displacement (signed, immediate data)
**	pq = 16-bit address (immediate data)
**	p  = 8-bit address (immediate data)
**	cc = condition code
**
** Flag effects notation:
**
**	- = not affected
**	* = straightforward dependence on machine state and result
**	0 = reset by operation
**	1 = set by operation
**	? = the effect on the flag is 'random'
**	+ = special case, see instruction notes
**
** Label notation:	Underscore used for SPACE, comma and +
**
**			1 (one) used for ( and )

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

** Quick 680x0 reference:
**
**	CCR bits:	4 3 2 1 0
**			X N Z V C	(Note that 'N' is Z80 'S'.)

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

** The IN instructions "read" a fixed value:

DEFAULT_IN = 00

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


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

**	IN r,(C)
**
**	r <- PORT(C)
**
**	Bits 0-7 of the address bus are given by the C register, and
**	bits 8-15 by the B register.
**
**	Flags:	S Z H P N C
**		* * 0 * 0 -
**
**	Note: 'In x,(C)' is a (mostly) undocumented version of this
**	instruction. It reads from the port but does not store the
**	value. The flags are affected by the read value as usual, and
**	the instruction is sometimes referred to as 'In F,(C)'. The name
**	'In (HL),(C)' would be symmetric with the bit pattern, but is
**	not correct.

	; Macros can't be nested, so we define a sublevel macro:

in_r_1C1	MACRO
	; --- don't edit above ---
		clr.w	tmpD0		;bits 8-15 reset for parity index
		move.b	#DEFAULT_IN,tmpD0	;"read" a value (bits 0-7)
		putccr	tmpD1		;N and Z tested, V and C cleared
		and.w	#1,stCCR	;keep old Carry
		or.w	tmpD1,stCCR	;insert the other flags
		parity	tmpD0		;set V according to parity
		move.b	tmpD0,Z80_\1(TableB)
	IFD BCDFLAGS
		clr.b	Z80_BCDF(TableB)	;clear H and N
	ENDC
	; --- don't edit below ---
		skip 1
		next

		ENDM


In_B_1C1_mac	MACRO
		in_r_1C1 B	;don't edit
		ENDM

In_C_1C1_mac	MACRO
		in_r_1C1 C	;don't edit
		ENDM

In_D_1C1_mac	MACRO
		in_r_1C1 D	;don't edit
		ENDM

In_E_1C1_mac	MACRO
		in_r_1C1 E	;don't edit
		ENDM


In_H_1C1_mac	MACRO
	; --- don't edit above ---
		clr.w	tmpD0
		move.b	#DEFAULT_IN,tmpD0
		putccr	tmpD1
		and.w	#1,stCCR
		or.w	tmpD1,stCCR
		parity	tmpD0
	IFNE PROCESSOR<68030
		move.b	tmpD0,(Work)
		move.w	(Work),tmpD0	;move value to bits 8-15
	ELSE
		lsl.w	#8,tmpD0	;move value to bits 8-15
	ENDC ;IFNE PROCESSOR<68030
		move.b	HL,tmpD0	;insert L in bits 0-7
		move.w	tmpD0,HL	;set new HL
	IFD BCDFLAGS
		clr.b	Z80_BCDF(TableB)
	ENDC
	; --- don't edit below ---
		skip 1
		next
		ENDM


In_L_1C1_mac	MACRO
	; --- don't edit above ---
		clr.w	tmpD0
		move.b	#DEFAULT_IN,tmpD0
		putccr	tmpD1
		and.w	#1,stCCR
		or.w	tmpD1,stCCR
		parity	tmpD0
		move.b	tmpD0,HL	;set L to 'read' value
	IFD BCDFLAGS
		clr.b	Z80_BCDF(TableB)
	ENDC
	; --- don't edit below ---
		skip 1
		next
		ENDM


In_A_1C1_mac	MACRO
	; --- don't edit above ---
		move.b	#DEFAULT_IN,A
		putccr	tmpD0
		and.w	#1,stCCR
		or.w	tmpD0,stCCR
		parity	A
	IFD BCDFLAGS
		clr.b	Z80_BCDF(TableB)
	ENDC
	; --- don't edit below ---
		skip 1
		next
		ENDM


In_x_1C1_mac	MACRO
	; --- don't edit above ---
		clr.w	tmpD0
		move.b	#DEFAULT_IN,tmpD0
		putccr	tmpD1
		and.w	#1,stCCR
		or.b	tmpD1,stCCR
		parity	tmpD0
		;The read value is discarded.
	IFD BCDFLAGS
		clr.b	Z80_BCDF(TableB)	;clear H and N
	ENDC
	; --- don't edit below ---
		skip 1
		next
		ENDM

** -----

**	IN A,(n)
**
**	A <- PORT(n)
**
**	Bits 0-7 of the address bus are given by the immediate 'n' byte,
**	and bits 8-15 by the value of the A register before the operation.
**
**	Flags:	not affected

In_A_1n1_mac	MACRO
	; --- don't edit above ---
	** Section commented out since 'n' is not of any use here:
	**	getRPC	tmpD0		;get address of immediate data
	**	getz	tmpD0,tmpD0	;'n' in tmpD0
		move.b	#DEFAULT_IN,A	;"read" the value.
	; --- don't edit below ---
		skip 1
		next
		ENDM

** -----

**	IND
**
**	B <- B - 1, (HL) <- PORT(C), HL <- HL - 1
**
**	Bits 0-7 of the address bus are given by the C register, and
**	bits 8-15 by the value of the B register after the decrement.
**
**	Flags:	S Z H V N C
**		? * ? ? 1 -
**
**	Z is set if B is 0 after the instruction, otherwise reset.

** Note that S, V and H are unaffected in this implementation.

Ind_mac 	MACRO
	; --- don't edit above ---
		moveq	#DEFAULT_IN,tmpD1	;'read' the value
		putz	tmpD1,HL	;write value (putz uses tmpD0)
		decw	HL		;HL <- HL - 1
		and.w	#$FFFB,stCCR	;clear Z
		decb	Z80_B(TableB)	;B <- B - 1
		bne.s	01$
		or.w	#4,stCCR	;set Z if B = 0
01$
	IFD BCDFLAGS
		bset	#1,Z80_BCDF(TableB)	;set N
	ENDC
	; --- don't edit below ---
		skip 1
		next
		ENDM

** -----

**	INDR
**
**	B <- B - 1, (HL) <- PORT(C), HL <- HL - 1, repeated until B = 0
**
**	Bits 0-7 of the address bus are given by the C register, and
**	bits 8-15 by the value of the B register after the decrement.
**
**	Flags:	S Z H V N C
**		? 1 ? ? 1 -

** Note that S, V and H are unaffected in this implementation.

Indr_mac	MACRO
	; --- don't edit above ---
		moveq	#DEFAULT_IN,tmpD1	;'read' the value
		putz	tmpD1,HL	;write value (putz uses tmpD0)
		decw	HL		;HL <- HL - 1
		decb	Z80_B(TableB)	;B <- B - 1
		bne.s	01$

	; --- don't edit below ---
		or.w	#4,stCCR	;set Z
	IFD BCDFLAGS
		bset	#1,Z80_BCDF(TableB)	;set N
	ENDC
		skip 1		;proceed with the following instruction
		next

01$	;the following handles the instruction loop
		getRPC	tmpD0
		decw	tmpD0	;get real-PC address of first opcode byte
		makePPC tmpD0	;recalculate PPC
		testreq 	;handle exception or thread-to-loop
		ENDM

** -----

**	INI
**
**	B <- B - 1, (HL) <- PORT(C), HL <- HL + 1
**
**	Bits 0-7 of the address bus are given by the C register, and
**	bits 8-15 by the value of the B register after the decrement.
**
**	Flags:	S Z H V N C
**		? * ? ? 1 -
**
**	Z is set if B is 0 after the instruction, otherwise reset.

** Note that S, V and H are unaffected in this implementation.

Ini_mac 	MACRO
	; --- don't edit above ---
		moveq	#DEFAULT_IN,tmpD1	;'read' the value
		putz	tmpD1,HL	;write value (putz uses tmpD0)
		incw	HL		;HL <- HL + 1
		and.w	#$FFFB,stCCR	;clear Z
		decb	Z80_B(TableB)	;B <- B - 1
		bne.s	01$
		or.w	#4,stCCR	;set Z if B = 0
01$
	IFD BCDFLAGS
		bset	#1,Z80_BCDF(TableB)	;set N
	ENDC
	; --- don't edit below ---
		skip 1
		next
		ENDM

** -----

**	INIR
**
**	B <- B - 1, (HL) <- PORT(C), HL <- HL + 1, repeated until B = 0
**
**	Bits 0-7 of the address bus are given by the C register, and
**	bits 8-15 by the value of the B register after the decrement.
**
**	Flags:	S Z H V N C
**		? 1 ? ? 1 -

** Note that S, V and H are unaffected in this implementation.

Inir_mac	MACRO
	; --- don't edit above ---
		moveq	#DEFAULT_IN,tmpD1	;'read' the value
		putz	tmpD1,HL	;write value (putz uses tmpD0)
		incw	HL		;HL <- HL + 1
		decb	Z80_B(TableB)	;B <- B - 1
		bne.s	01$

	; --- don't edit below ---
		or.w	#4,stCCR	;set Z
	IFD BCDFLAGS
		bset	#1,Z80_BCDF(TableB)	;set N
	ENDC
		skip 1		;proceed with the following instruction
		next

01$	;the following handles the instruction loop
		getRPC	tmpD0
		decw	tmpD0	;get real-PC address of first opcode byte
		makePPC tmpD0	;recalculate PPC
		testreq 	;handle exception or thread-to-loop
		ENDM

** -----

**	LD A,R
**
**	A <- R
**
**	Flags:	S Z H V N C
**		* * 0 + 0 -	P/V is set to the value of IFF2

**  Note on the refresh register emulation:
**
**  The R register is not incremented after each instruction; instead when
**  Ld A,R is executed the bits 0-6 have to be generated in some other,
**  pseudo-random way (since R is sometimes used as a pseudo-random
**  number). Bit 7 is only updated by 'Ld R,A' instructions.

Ld_A_R_mac	MACRO
	; --- don't edit above ---
		;To calculate a fairly random R, we use the old R
		;value as a 'seed', exclusive-or it with the ackumulator,
		;rotate it left one bit position and add 7.
		move.b	Z80_R(TableB),tmpD0	;keep old R in tmpD0
		eor.b	tmpD0,A
		rol.b	A
		addq.b	#7,A

		eor.b	tmpD0,A 	;join bit 7 of stored R...
		and.w	#$7F,A		;with bits 0-6 of calculated value
		eor.b	tmpD0,A 	;Z and N tested, V and C cleared
		putccr	tmpD0
		and.w	#1,stCCR	;keep old C
		or.w	tmpD0,stCCR	;insert other flags
		tst.b	Z80_IFF(TableB) ;test IFF2 (bit 7 = sign bit)
		bpl.s	01$
		or.w	#2,stCCR	;set V if IFF2 was set
01$
		move.b	A,Z80_R(TableB) ;store new R (bit 7 preserved)
	IFD BCDFLAGS
		clr.b	Z80_BCDF(TableB)	;reset H and N
	ENDC
	; --- don't edit below ---
		skip 1
		next
		ENDM

** -----

**	OTDR
**
**	B <- B - 1, PORT(C) <- (HL), HL <- HL - 1, repeated until B = 0
**
**	Bits 0-7 of the address bus are given by the C register, and
**	bits 8-15 by the value of the B register after the decrement.
**
**	Flags:	S Z H V N C
**		? 1 ? ? 1 -

** Note that S, V and H are unaffected in this implementation.

Otdr_mac	MACRO
	; --- don't edit above ---
	** Section commented out since (HL) is not of any use here:
	**	getz	HL,tmpD0	;get (HL)

		decw	HL		;HL <- HL - 1
		decb	Z80_B(TableB)	;B <- B - 1
		bne.s	01$

	; --- don't edit below ---
		or.w	#4,stCCR	;set Z
	IFD BCDFLAGS
		bset	#1,Z80_BCDF(TableB)	;set N
	ENDC
		skip 1		;proceed with the following instruction
		next

01$	;the following handles the instruction loop
		getRPC	tmpD0
		decw	tmpD0	;get real-PC address of first opcode byte
		makePPC tmpD0	;recalculate PPC
		testreq 	;handle exception or thread-to-loop
		ENDM

** -----

**	OTIR
**
**	B <- B - 1, PORT(C) <- (HL), HL <- HL + 1, repeated until B = 0
**
**	Bits 0-7 of the address bus are given by the C register, and
**	bits 8-15 by the value of the B register after the decrement.
**
**	Flags:	S Z H V N C
**		? 1 ? ? 1 -

** Note that S, V and H are unaffected in this implementation.

Otir_mac	MACRO
	; --- don't edit above ---
	** Section commented out since (HL) is not of any use here:
	**	getz	HL,tmpD0	;get (HL)

		incw	HL		;HL <- HL + 1
		decb	Z80_B(TableB)	;B <- B - 1
		bne.s	01$

	; --- don't edit below ---
		or.w	#4,stCCR	;set Z
	IFD BCDFLAGS
		bset	#1,Z80_BCDF(TableB)	;set N
	ENDC
		skip 1		;proceed with the following instruction
		next

01$	;the following handles the instruction loop
		getRPC	tmpD0
		decw	tmpD0	;get real-PC address of first opcode byte
		makePPC tmpD0	;recalculate PPC
		testreq 	;handle exception or thread-to-loop
		ENDM

** -----

**	OUT (C),r
**
**	PORT(C) <- r
**
**	Bits 0-7 of the address bus are given by the C register, and
**	bits 8-15 by the B register.
**
**	Flags:	not affected
**
**	Note: 'Out (C),x' is an undocumented version of this
**	instruction. It seems to output a zero value to the port. The
**	name 'Out (C),(HL)' would be symmetric with the bit pattern,
**	but is not correct.

	; Macros can't be nested, so we define a sublevel macro:

out_r_1C1	MACRO	;Parameter: register
	; --- don't edit above ---
		;nothing to do here
	; --- don't edit below ---
		skip 1
		next

		ENDM


Out_1C1_B_mac	MACRO
		out_r_1C1 B	;don't edit
		ENDM

Out_1C1_C_mac	MACRO
		out_r_1C1 C	;don't edit
		ENDM

Out_1C1_D_mac	MACRO
		out_r_1C1 D	;don't edit
		ENDM

Out_1C1_E_mac	MACRO
		out_r_1C1 E	;don't edit
		ENDM


Out_1C1_H_mac	MACRO
	; --- don't edit above ---
		;nothing to do here
	; --- don't edit below ---
		skip 1
		next
		ENDM


Out_1C1_L_mac	MACRO
	; --- don't edit above ---
		;nothing to do here
	; --- don't edit below ---
		skip 1
		next
		ENDM


Out_1C1_A_mac	MACRO
	; --- don't edit above ---
		;nothing to do here
	; --- don't edit below ---
		skip 1
		next
		ENDM


Out_1C1_x_mac	MACRO
	; --- don't edit above ---
		;nothing to do here
	; --- don't edit below ---
		skip 1
		next
		ENDM

** -----

**	OUT (n),A
**
**	PORT(n) <- A
**
**	Bits 0-7 of the address bus are given by the immediate 'n' byte,
**	and bits 8-15 by the value of the A register before the operation.
**
**	Flags:	not affected

Out_1n1_A_mac	MACRO
	; --- don't edit above ---
	** Section commented out since 'n' is not of any use here:
	**	getRPC	tmpD0		;get address of immediate data
	**	getz	tmpD0,tmpD0	;'n' in tmpD0
		;nothing to do here
	; --- don't edit below ---
		skip 1
		next
		ENDM

** -----

**	OUTD
**
**	B <- B - 1, PORT(C) <- (HL), HL <- HL - 1
**
**	Bits 0-7 of the address bus are given by the C register, and
**	bits 8-15 by the value of the B register after the decrement.
**
**	Flags:	S Z H V N C
**		? * ? ? 1 -
**
**	Z is set if B is 0 after the instruction, otherwise reset.

** Note that S, V and H are unaffected in this implementation.

Outd_mac	MACRO
	; --- don't edit above ---
	** Section commented out since (HL) is not of any use here:
	**	getz	HL,tmpD0	;get (HL)

		decw	HL		;HL <- HL - 1
		and.w	#$FFFB,stCCR	;clear Z
		decb	Z80_B(TableB)	;B <- B - 1
		bne.s	01$
		or.w	#4,stCCR	;set Z if B = 0
01$
	IFD BCDFLAGS
		bset	#1,Z80_BCDF(TableB)	;set N
	ENDC
	; --- don't edit below ---
		skip 1
		next
		ENDM

** -----

**	OUTI
**
**	B <- B - 1, PORT(C) <- (HL), HL <- HL + 1
**
**	Bits 0-7 of the address bus are given by the C register, and
**	bits 8-15 by the value of the B register after the decrement.
**
**	Flags:	S Z H V N C
**		? * ? ? 1 -
**
**	Z is set if B is 0 after the instruction, otherwise reset.

** Note that S, V and H are unaffected in this implementation.

Outi_mac	MACRO
	; --- don't edit above ---
	** Section commented out since (HL) is not of any use here:
	**	getz	HL,tmpD0	;get (HL)

		incw	HL		;HL <- HL + 1
		and.w	#$FFFB,stCCR	;clear Z
		decb	Z80_B(TableB)	;B <- B - 1
		bne.s	01$
		or.w	#4,stCCR	;set Z if B = 0
01$
	IFD BCDFLAGS
		bset	#1,Z80_BCDF(TableB)	;set N
	ENDC
	; --- don't edit below ---
		skip 1
		next
		ENDM

** -----

**	RETI
**
**	PC [L] <- (SP), PC [H] <- (SP+1), SP <- SP + 2
**
**	Flags:	not affected
**
**	Note: The RETI instruction does not in itself cause any
**	signalling, but a common scheme is to have interrupt-controlling
**	hardware snoop the bus to see when an interrupt finishes.

Reti_mac	MACRO
	; --- don't edit above ---
		;Perform any "hardware" emulation first.

		getz	ZSP,tmpD1	;get PC [L]
		incw	ZSP
	IFNE PROCESSOR<68030
		getz	ZSP,(Work)
		move.w	(Work),tmpD0	;get PC [H]
	ELSE
		getz	ZSP,tmpD0
		lsl.w	#8,tmpD0	;get PC [H]
	ENDC ;IFNE PROCESSOR<68030
		move.b	tmpD1,tmpD0	;make complete address
		incw	ZSP
		makePPC tmpD0
	; --- don't edit below ---
		testreq 	;handle exception or thread to next
		ENDM

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