home *** CD-ROM | disk | FTP | other *** search
- ** 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
-
- ** ======================================================================
-