I am currently working on a ZX81 emulator with a twist. This one runs in on a Coleco Adam. I have a good chunk of it working, I get it up to the 'K" prompt but I am stuck with keyboard input. Since the Adam is a Z80 system with free RAM in the right area I am able to load the ZXROM at 0h, my emulator code at 2000h and have 16k free memory from 4000h - 7999h (i will probably use 32k when done). I have gone into the ZX81 ROM and nop'ed all IN's and OUT's for now and am using the NMI to jump to my emulator which copies the D_FILE to the Adam's video processor and allows me to debug as needed. I have been trying to replace the keyboard scanning routine with my own. What I am doing is leaving the ZXROM when the keyboard is scanned to my emulator so I can return a keypress if there is one. That is where I am lost. The scan routine is supposed to exit with H holding the column press and L holding the row pressed but I just can't seem to figure out exactly what the ZXROM expects H & L to be. Here is the code in question:
Code: Select all
; ----------------------------------
; THE 'KEYBOARD SCANNING' SUBROUTINE
; ----------------------------------
; The keyboard is read during the vertical sync interval while no video is
; being displayed. Reading a port with address bit 0 low i.e. $FE starts the
; vertical sync pulse.
;; KEYBOARD
L02BB: LD HL,$FFFF ; (16) prepare a buffer to take key.
LD BC,$FEFE ; (20) set BC to port $FEFE. The B register,
; with its single reset bit also acts as
; an 8-counter.
IN A,(C) ; (11) read the port - all 16 bits are put on
; the address bus. Start VSYNC pulse.
OR $01 ; (7) set the rightmost bit so as to ignore
; the SHIFT key.
;; EACH-LINE
L02C5: OR $E0 ; [7] OR %11100000
LD D,A ; [4] transfer to D.
CPL ; [4] complement - only bits 4-0 meaningful now.
CP $01 ; [7] sets carry if A is zero.
SBC A,A ; [4] $FF if $00 else zero.
OR B ; [7] $FF or port FE,FD,FB....
AND L ; [4] unless more than one key, L will still be
; $FF. if more than one key is pressed then A is
; now invalid.
LD L,A ; [4] transfer to L.
; now consider the column identifier.
LD A,H ; [4] will be $FF if no previous keys.
AND D ; [4] 111xxxxx
LD H,A ; [4] transfer A to H
; since only one key may be pressed, H will, if valid, be one of
; 11111110, 11111101, 11111011, 11110111, 11101111
; reading from the outer column, say Q, to the inner column, say T.
RLC B ; [8] rotate the 8-counter/port address.
; sets carry if more to do.
IN A,(C) ; [10] read another half-row.
; all five bits this time.
JR C,L02C5 ; [12](7) loop back, until done, to EACH-LINE
; The last row read is SHIFT,Z,X,C,V for the second time.
RRA ; (4) test the shift key - carry will be reset
; if the key is pressed.
RL H ; (8) rotate left H picking up the carry giving
; column values -
; $FD, $FB, $F7, $EF, $DF.
; or $FC, $FA, $F6, $EE, $DE if shifted.
; We now have H identifying the column and L identifying the row in the
; keyboard matrix.
; This is a good time to test if this is an American or British machine.
; The US machine has an extra diode that causes bit 6 of a byte read from
; a port to be reset.
RLA ; (4) compensate for the shift test.
RLA ; (4) rotate bit 7 out.
RLA ; (4) test bit 6.
SBC A,A ; (4) $FF or $00 {USA}
AND $18 ; (7) $18 or $00
ADD A,$1F ; (7) $37 or $1F
; result is either 31 (USA) or 55 (UK) blank lines above and below the TV
; picture.
LD ($4028),A ; (13) update system variable MARGIN
RET ; (10) return
Code: Select all
; ----------------------------------
; THE 'KEYBOARD SCANNING' SUBROUTINE
; ----------------------------------
; The keyboard is read during the vertical sync interval while no video is
; being displayed. Reading a port with address bit 0 low i.e. $FE starts the
; vertical sync pulse.
;; KEYBOARD
L02BB:
call jpKEY ; @#@ Call the zx81emu keyboard routine
jr GotKey ; @#@ Skip all the scanning stuff
nop ; @#@ filler
; @#@ LD HL,$FFFF ; (16) prepare a buffer to take key.
; @#@ LD BC,$FEFE ; (20) set BC to port $FEFE. The B register,
; @#@ ; with its single reset bit also acts as
; @#@ ; an 8-counter.
.fill 2,0 ; @#@ Pad to fill for the in
; @#@ IN A,(C) ; (11) read the port - all 16 bits are put on
; the address bus. Start VSYNC pulse.
OR $01 ; (7) set the rightmost bit so as to ignore
; the SHIFT key.
;; EACH-LINE
L02C5: OR $E0 ; [7] OR %11100000
LD D,A ; [4] transfer to D.
CPL ; [4] complement - only bits 4-0 meaningful now.
CP $01 ; [7] sets carry if A is zero.
SBC A,A ; [4] $FF if $00 else zero.
OR B ; [7] $FF or port FE,FD,FB....
AND L ; [4] unless more than one key, L will still be
; $FF. if more than one key is pressed then A is
; now invalid.
LD L,A ; [4] transfer to L.
; now consider the column identifier.
LD A,H ; [4] will be $FF if no previous keys.
AND D ; [4] 111xxxxx
LD H,A ; [4] transfer A to H
; since only one key may be pressed, H will, if valid, be one of
; 11111110, 11111101, 11111011, 11110111, 11101111
; reading from the outer column, say Q, to the inner column, say T.
RLC B ; [8] rotate the 8-counter/port address.
; sets carry if more to do.
.fill 2,0 ; @#@ Pad to fill for the in
; @#@ IN A,(C) ; [10] read another half-row.
; @#@ ; all five bits this time.
JR C,L02C5 ; [12](7) loop back, until done, to EACH-LINE
; The last row read is SHIFT,Z,X,C,V for the second time.
RRA ; (4) test the shift key - carry will be reset
; if the key is pressed.
RL H ; (8) rotate left H picking up the carry giving
; column values -
; $FD, $FB, $F7, $EF, $DF.
; or $FC, $FA, $F6, $EE, $DE if shifted.
GotKey: ; @#@ Skip point
; We now have H identifying the column and L identifying the row in the
; keyboard matrix.
; This is a good time to test if this is an American or British machine.
; The US machine has an extra diode that causes bit 6 of a byte read from
; a port to be reset.
RLA ; (4) compensate for the shift test.
RLA ; (4) rotate bit 7 out.
RLA ; (4) test bit 6.
SBC A,A ; (4) $FF or $00 {USA}
AND $18 ; (7) $18 or $00
ADD A,$1F ; (7) $37 or $1F
; result is either 31 (USA) or 55 (UK) blank lines above and below the TV
; picture.
LD ($4028),A ; (13) update system variable MARGIN
RET ; (10) return
Code: Select all
; ******************************************
;
; Keyboard handler
;
; ******************************************
KEY.Handler: .module KEY.Handler
ld bc,0fefeh
ld hl,(_hl)
dec l
ld (_hl),hl
ld a,l
cp 255
jr nz,_cont1
dec h
ld (_hl),hl
_cont1:
ld hl,(_hl)
ret
_hl: .dw 65535