org &3000
OFFSET &F000
;
;Decent keyboard routine used by SDX
;
; Special version for REMEMOTECH or REMEMOrizer
; Modified Feb 2012, A.Key
; It uses debounce values suitable for the current CPU speed
; modified for MTXplus+ MA 2015

.CPMlastDr
DB 0
.CPMlastAsc
DB 0
.CPMlastkey
DB 0
.CPMkbFlag
DB 0
.CPMautoCt
DB 0,0
.CPMctyslt
DB 0



;##############################
.CPMshif
LD A,191
LD (CPMlastDr),A
OUT (DR),A ;Z IMPLIES }CPMshifT
IN A,(SENSE1)
BIT 6,A
RET Z
BIT 0,A
RET
; ####### Read keyboard entry point ######
.CPMKBDIN  
LD (CPMSAVESP),SP
LD SP,CPMKBDq
PUSH BC
.CPMKBDIN2
LD B,3 
.CPMKBDIN3
CALL CPMKBDq
JR Z,CPMKBDIN2
LD A,(CPMlastkey)
LD C,A
.CPMKBDIN4
CALL CPMKBDq
LD A,(CPMlastkey)
CP C
JR NZ,CPMKBDIN2
DJNZ CPMKBDIN4
LD A,(CPMlastAsc)
POP BC
LD SP,(CPMSAVESP)
RET

; ####### keyboard ready entry point ######
.CPMKBD_READY

.CPMKBDSTS
LD (CPMSAVESP),SP
LD SP,CPMSTACK
CALL CPMKBDq
LD A,0
JR Z,CPMKBSTEND
LD (CPMlastkey),A
DEC A
.CPMKBSTEND
LD SP,(CPMSAVESP)
RET

.CPMSAVESP
DB 0,0
.CPMKBDSTK
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
.CPMSTACK   

.CPMKBDq   
PUSH    HL
PUSH    BC
PUSH    DE

.CPMAUTORP
LD HL,CPMautoCt

LD D,(HL)
INC HL
LD E,(HL)
;LD   A,&88
;CP   D
;JR   Z,CPMENDAUT
BIT 7,D                 ; changed for REEMOTECH
                        ; original jumps to ENDAUT if D=088H
JR NZ,CPMENDAUT            ; previously there was no key
LD A,D
OR E
JR Z,CPMzero               ; at zero, so cause fake release
DEC DE
LD (hl),E
DEC HL
LD (HL),D
LD A,D
OR E
JR NZ,CPMENDAUT            ; if get to zero, fall through to cause fake release
.CPMzero
LD (CPMlastkey),A

.CPMENDAUT
CALL CPMkstart
JR NZ,CPMKBDEX
LD A,0
.CPMKBDEX
POP     DE
POP BC
POP HL
RET    

.CPMkstart
LD A,251
LD (CPMlastDr),A
OUT (DR),A
IN A,(SENSE1)
BIT 0,A
JR Z,CPMCNTRL
CALL CPMkbNormal
RET

.CPMCNTRL
CALL CPMkbNormal
RET Z
AND &1F
LD (CPMlastAsc),A
RET

.CPMkbNormal
CALL CPMshif
JR Z,CPMNshifT         ;NORMAL shifT
CALL CPMSCAN
RET Z
LD D,A
LD BC,CPMBASE
CALL CPMLOOK
LD B,A
CP 127
JR Z,CPMKB8
CP 32
CCF
.CPMKB8
LD A,(CPMkbFlag)
JR C,CPMKBN999
BIT 2,A
JR NZ,CPMNSH1
.CPMKBN999
BIT 7,A
LD A,B
JR Z,CPMNCONT

;
LD HL,CPMALPHA             ;3
LD E,D                  ;1
LD D,0                  ;2
ADD HL,DE               ;1
LD A,(HL)               ;1
LD D,E                  ;1
AND A                   ;1
LD A,B                  ;1
JR NZ,CPMNORM1             ;2      ;RETURN WITH LOWER-CASE IFF ALPHA=1
;                                       ;(CHECK FOR CHARS 160 AND 29
.CPMnsh1
LD A,D
JR CPMnsh2 
.CPMNshifT
CALL CPMSCAN
RET Z
.CPMnsh2
LD BC,CPMUPPER
CALL CPMLOOK
.CPMNCONT
LD B,A
.CPMNORM1
CP 160
JR NZ,CPMNORM2
.CPMNORM11
LD A,(CPMkbFlag) ;GET FLAGS
XOR &80
LD (CPMkbFlag),A
XOR A
RET

.CPMNORM2
CP 29        ;28 =SCROLL/PAGE
RET NZ       ;NORMAL CHAR
LD E,A       ;save 28
LD A,(CPMkbFlag)
BIT 5,A
JR Z,CPMNORM3
DEC E
.CPMNORM3
XOR 32
LD (CPMkbFlag),A
.CPMNORM4
LD A,E
LD (CPMlastAsc),A
AND A
RET

;MATRIX SCAN
.CPMSCAN
LD B,8        ;B=8=DRIVE COUNTER 
xor a         ;a=0 reset carry
ld c,a        ;SENSE COUNTER=0
dec a         ;a=ff
.CPMSCAN2
RLA           ;A=FE,FD,FB,F7,EF,DF,BF,7F
PUSH AF       ;SAVE DRIVE
LD (CPMlastDr),A
OUT (DR),A
IN A,(SENSE1)
CP &FF        ;IF FF THEN NO SENSE.TRY OTHER DRIVE
JR Z,CPMSCAN3
.CPMCHECK1
PUSH AF       ;SAVE SENSE
.CPMCH10
LD A,2        ;CHECK FOR CPMshifT
CP B          ;IF B=2 THEN RESET CPMshifTS
JR NZ,CPMCH11
POP AF
SET 6,A
JR CPMCH13

.CPMCH11
LD A,6        ;CHECK FOR CNTRL
CP B
JR Z,CPMCH12
POP AF
JR CPMVALID

.CPMCH12
POP AF        ;RESTORE SENSE
.CPMCH13
SET 0,A       ;RESET ALPHA,CPMshifT AND CONTROL
.CPMCH14
CP &FF        ;TRY AGAIN AFTER ELIMINATING ODD KEYS
JR Z,CPMSCAN3    ;IF STILL 0 THEN TRY OTHER DRIVE
  ;VALID KEY FOUND
.CPMVALID
POP DE        ;REMOVE DRIVE
LD C,0
.CPMCH15
RRCA
JR NC,CPMENDSCAN ;B=1-8,C=0-7
INC C
JR CPMCH15

.CPMSCAN3
IN A,(SENSE2) ;SECOND DRIVE
AND 03
CP 3
JR Z,CPMSCAN4
.CPMCHECK2
AND A
ADD A,7
LD C,A        ;C=8 OR 9
POP AF
JR CPMENDSCAN

.CPMSCAN4
POP AF        ;RESTORE DRIVE
DJNZ CPMSCAN2    ;MOVE TO NEXT DRIVE
LD C,0
.CPMENDSCAN
LD A,C
ADD A,A
ADD A,A
ADD A,A
ADD A,B
LD HL,CPMautoCt
JR NZ,CPMDEB1
PUSH AF

ld a,&88           ;remove this if using speed check
LD   (HL),A
POP AF
INC  HL
LD (HL),0
DEC HL
JR Z,CPMDEB2
.CPMDEB1
RES 7,(HL)          ; key => set to 00800H
LD B,A
LD A,(CPMlastkey)
CP B
LD A,B
.CPMDEB2
LD (CPMlastkey),A
RET Z
PUSH AF
XOR A
CP (HL)
JR NZ,CPMENDATO
.CPMFAST
SET 1,(HL)          ; repeat quickly => set to 00200H
.CPMENDATO
POP AF
RET

;re-memorizor keyboard delay tables, might need when/if 16 mhz+ is working
.CPMDELTAB
DB &B0,&98,&90,&8C,&8A,&88,&87,&86


.CPMlook
LD   H,&00          ;LOOK UP IN TABLE SPECIFIED BY BC
LD   L,A
ADD  HL,BC
LD   A,(HL)
LD   (CPMlastAsc),A
RET

.CPMbase
.CPMKeytable
DB   &00
DB   &7A,&00,&61,&A0,&71,&00,&1B,&31
DB   &63,&78,&64,&73,&65,&77,&32,&33
DB   &62,&76,&67,&66,&74,&72,&34,&35
DB   &6D,&6E,&6A,&68,&75,&79,&36,&37
DB   &2E,&2C,&6C,&6B,&6F,&69,&38,&39
DB   &5F,&2F,&3A,&3B,&40,&70,&30,&2D
DB   &15,&00,&0D,&5D,&0A,&5B,&5E,&5C
DB   &0C,&0A,&1A,&19,&08,&0B,&05,&1D
DB   &83,&87,&82,&86,&85,&81,&84,&80
DB   &20,&00,&00,&00,&7F,&09,&08,&03
.CPMupper
DB   &00
DB   &5A,&00,&41,&A0,&51,&00,&1B,&21
DB   &43,&58,&44,&53,&45,&57,&22,&23
DB   &42,&56,&47,&46,&54,&52,&24,&25
DB   &4D,&4E,&4A,&48,&55,&59,&26,&27
DB   &3E,&3C,&4C,&4B,&4F,&49,&28,&29
DB   &5F,&3F,&2A,&2B,&60,&50,&30,&3D
DB   &30,&00,&0D,&7D,&0A,&7B,&7E,&7C
DB   &0D,&2E,&32,&33,&31,&35,&38,&37
DB   &8B,&8F,&8A,&8E,&8D,&89,&8C,&88
DB   &20,&00,&00,&00,&36,&34,&08,&39

.CPMALPHA
DB      1
DB      0,1,0,1,0,1,1,1
DB      0,0,0,0,0,0,1,1
DB      0,0,0,0,0,0,1,1
DB      0,0,0,0,0,0,1,1
DB      1,1,0,0,0,0,1,1
DB      1,1,1,1,1,0,1,1
DB      1,1,1,1,1,1,1,1
DB      1,1,1,1,1,1,1,1
DB      1,1,1,1,1,1,1,1
DB      1,1,1,1,1,1,1,1


END
