home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 2
/
FFMCD02.bin
/
new
/
misc
/
emu
/
z80
/
machine_macs.i
< prev
next >
Wrap
Text File
|
1993-12-21
|
11KB
|
545 lines
** Machine-specific macros for the implementation-dependent
** Z80 instructions.
** These are intended for the Spectrum emulator only.
XREF _SOUNDDATA
INCLUDE "envdata.i"
** ---------------------------------------------------------------------
** I/O ports on the ZX Spectrum
**
** In general:
**
** The address bits 0 to 4 are usually set. At most one of them
** should be reset at any time. A reset bit signals an I/O operation.
** Bits 5 to 7 are normally set, and are not used by the standard
** hardware. The address bits 8 to 15 are in some cases (e.g. when
** reading the keyboard) used to give more information. Usually they
** are ignored.
**
** Port xxFE (bit 0 reset)
** General I/O port
** Input:
** Bit 7 Unknown
** Bit 6 Value of EAR port
** Bit 5 Unknown
** Bits 4 to 0 Keyboard data
**
** The keyboard rows are ordered from 0 (Caps Shift to V) through
** 3 (1 to 5), 4 (0 to 6) and 7 (Space to B).
** The bits 0 to 4 represent keys in a row, where bit 0 is the
** outermost key. A bit is low if the key is pressed, and high if
** it is not pressed.
** The address bits 8 to 15 correspond to rows 0 to 7 respectively,
** and specify which rows will be read. A reset bit means the row
** will be read. The selected rows are bitwise combined. In the
** result, each bit is reset if one of the bits in the same position
** was reset, and set if none of them were reset. Taking the bit
** pattern 11111 and bitwise AND:ing with all selected rows would
** give the same result.
** The value of bit 6 is not affected by the high address bits.
**
** Output:
** Bits 7 to 5 Not used
** Bit 4 Speaker control
** Bit 3 MIC port control
** Bits 2 to 0 Border colour code
**
** The speaker and MIC ports are active low.
** The colour codes are specified as on/off flags for the RGB
** components, where bits 2 through 0 correspond to Green, Red and
** Blue respectively, giving totally 8 different colours. There is
** no Bright mode flag for the border.
**
** Port xxFD (bit 1 reset)
** Used for Microdrive, Networking or RS232C. I have no details.
** Input:
** Output:
**
** Port xxFB (bit 2 reset)
** ZX Printer control port
** Input:
** Bit 7 High when stylus is in write position.
** Bit 6 Low only if the printer is present.
** Bits 5 to 0 Unknown
**
** Output:
** Bit 7 High "for the actual printing".
** Bits 6 to 3 Unknown
** Bit 2 Low starts the motor.
** Bit 1 High slows the motor.
** Bit 0 Unknown
**
** Port xxF7 (bit 3 reset)
** Used for Microdrive, Networking or RS232C. I have no details.
** Input:
** Output:
**
** Port xxEF (bit 4 reset)
** Used for Microdrive, Networking or RS232C. I have no details.
** Input:
** Output:
**
** Port xx1F (bits 0 to 4 set, bits 5 to 7 reset)
** Kempston interface port (external hardware)
** Input:
** Bits 7 to 5 Unknown
** Bit 4 Fire
** Bit 3 Up
** Bit 2 Down
** Bit 1 Left
** Bit 0 Right
**
** Bits 4 to 0 are active high.
**
** Output: Unknown
**
** ---------------------------------------------------------------------
** The keyboard data:
** An array of 8 bytes (0 to 7) corresponding exactly to the
** keyboard rows 0 to 7. Bits 5 to 7 are zero.
Kbd = Z80_Envdata+Envd_Kbd ;offset from control structure base
** ---------------------------------------------------------------------
IFD VERBOSE
LIST
** Compiling the machine.i file designed for the ZX Spectrum emulator.
NOLIST
ENDC
** A default read value, used by some lazy routines like Inir:
DEFAULT_IN = $FF
;Macro for fast keyboard data reading.
;RowSpec (register) corresponds to high byte of I/O address.
;Dest (register) must be $FF before macro call.
KBD_READ MACRO ;RowSpec, Dest
add.b \1,\1
bcs.s .7set
and.b Kbd+7(TableB),\2 ;row 7
.7set add.b \1,\1
bcs.s .6set
and.b Kbd+6(TableB),\2
.6set add.b \1,\1
bcs.s .5set
and.b Kbd+5(TableB),\2
.5set add.b \1,\1
bcs.s .4set
and.b Kbd+4(TableB),\2
.4set add.b \1,\1
bcs.s .3set
and.b Kbd+3(TableB),\2
.3set add.b \1,\1
bcs.s .2set
and.b Kbd+2(TableB),\2
.2set add.b \1,\1
bcs.s .1set
and.b Kbd+1(TableB),\2
.1set add.b \1,\1
bcs.s .0set
and.b Kbd+0(TableB),\2 ;row 0
.0set
ENDM
**
** The instruction macros themselves:
**
;sadly, one can't nest macros.
In_r_1C1_subm MACRO
cmp.b #$fe,C
st \1 ;flags unaffected
bne.s .end
move.b B,d7
KBD_READ d7,\1
.end tst.b \1 ;V cleared
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.w #$00ff,d6 ;for parity indexing
cmp.b #$fe,C
bne.s .end
move.b B,d7
KBD_READ d7,d6
.end move.w HL,(Work)
move.b d6,(Work) ;V cleared,N & Z tested
putsr d7
or.b Z80_Parity(TableB,d6.w),d7 ;set parity in d7
move.w (Work),HL
swap d6 ;get old flags
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.w #$00ff,d6 ;for parity indexing
cmp.b #$fe,C
bne.s .end
move.b B,d7
KBD_READ d7,d6
.end tst.b d6 ;V cleared,N & Z tested
putsr d7
or.b Z80_Parity(TableB,d6.w),d7 ;set parity in d7
swap d6 ;forget the value, get old flags
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
getz d7,d7
cmp.b #$fe,d7
bne.s .notFE
move.b A,d7
st A
KBD_READ d7,A
.end skip 1
next
.notFE st A
bra.s .end
ENDM
** ----
** The block In instructions do not bother to 'read ports'.
** They simply "read" the default in value.
Ind_mac MACRO
move.b #DEFAULT_IN,d7
putz d7,HL
decw HL
and.w #%1011,d6
decb B
bne.s .nz
or.w #%0100,d6
.nz skip 1
next
ENDM
** ----
Indr_mac MACRO
move.b #DEFAULT_IN,d7
.loop putz d7,HL
decw HL
decb B
bne.s .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 .nz
or.w #%0100,d6
.nz skip 1
next
ENDM
** ----
Inir_mac MACRO
move.b #DEFAULT_IN,d7
.loop putz d7,HL
incw HL
decb B
bne.s .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 .clear
or.w #%0010,d6 ;set V if IFF2 set
.clear 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
** ----
** 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
.loop getz HL,d7
cmp.b #$fe,C
bne.s .end
and.b #$10,d7 ;speaker(0 or 16)
add.b d7,d7
move.b d7,_SOUNDDATA
move.b d7,_SOUNDDATA+1
getz HL,d7
and.b #8,d7 ;mic(0 or 8)
add.b d7,d7
add.b d7,d7
move.b d7,_SOUNDDATA+2
move.b d7,_SOUNDDATA+3
.end decw HL
decb B
bne.s .loop
or.w #%0100,d6 ;Set Z
skip 1
next
ENDM
** ---
Otir_mac MACRO
.loop getz HL,d7
cmp.b #$fe,C
bne.s .end
and.b #$10,d7 ;speaker(0 or 16)
add.b d7,d7
move.b d7,_SOUNDDATA
move.b d7,_SOUNDDATA+1
getz HL,d7
and.b #8,d7 ;mic(0 or 8)
add.b d7,d7
add.b d7,d7
move.b d7,_SOUNDDATA+2
move.b d7,_SOUNDDATA+3
.end incw HL
decb B
bne.s .loop
or.w #%0100,d6 ;Set Z
skip 1
next
ENDM
** ----
;no macro nesting, sadly
Out_1C1_r_subm MACRO
cmp.b #$fe,C
bne.s .end
move.b \1,d7 ;sp