You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

544 lines
14 KiB

;
;==================================================================================================
; DSKY V1 ICM7218 (DISPLAY AND KEYBOARD) ROUTINES
;==================================================================================================
;
; THE ICM MAY COINCIDE ON THE SAME PPI BUS AS A PPISD. IT MAY NOT
; SHARE A PPI BUS WITH A PPIDE. SEE PPI_BUS.TXT FOR MORE INFORMATION.
;
; LED SEGMENTS (BIT VALUES)
;
; +--40--+
; 02 20
; +--04--+
; 08 10
; +--01--+ 80
;
; ICM SCAN CODES ARE ONE BYTE: CCRRRRRR
; BITS 7-6 IDENTFY THE COLUMN OF THE KEY PRESSED
; BITS 5-0 ARE A BITMAP, WITH A BIT ON TO INDICATE ROW OF KEY PRESSED
;
; ____PC0________PC1________PC2________PC3____
; PB5 | $20 [D] $60 [E] $A0 [F] $E0 [BO]
; PB4 | $10 [A] $50 [B] $90 [C] $D0 [GO]
; PB3 | $08 [7] $48 [8] $88 [9] $C8 [EX]
; PB2 | $04 [4] $44 [5] $84 [6] $C4 [DE]
; PB1 | $02 [1] $42 [2] $82 [3] $C2 [EN]
; PB0 | $01 [FW] $41 [0] $81 [BK] $C1 [CL]
;
;
ICM_PPIA .EQU ICMPPIBASE + 0 ; PORT A
ICM_PPIB .EQU ICMPPIBASE + 1 ; PORT B
ICM_PPIC .EQU ICMPPIBASE + 2 ; PORT C
ICM_PPIX .EQU ICMPPIBASE + 3 ; PPI CONTROL PORT
;
ICM_ROWS .EQU 1 ; DISPLAY ROWS
ICM_COLS .EQU 8 ; DISPLAY COLUMNS
;
DEVECHO "ICM: IO="
DEVECHO ICMPPIBASE
DEVECHO ", SIZE="
DEVECHO ICM_COLS
DEVECHO "X"
DEVECHO ICM_ROWS
DEVECHO "\n"
;
;__ICM_INIT________________________________________________________________________________________
;
; CONFIGURE PARALLEL PORT AND CLEAR KEYPAD BUFFER
;__________________________________________________________________________________________________
;
ICM_PREINIT:
;
; RESET PRESENCE FLAG
XOR A ; ASSUME NOT PRESENT
LD (ICM_PRESENT),A ; SAVE IT
;
OR $FF ; SIGNAL TO WAIT FOR KEY RELEASE
LD (ICM_KEYBUF),A ; SET IT
;
; PPI PORT B IS NORMALLY SET TO INPUT, BUT HERE WE
; TEMPORARILY SET IT TO OUTPUT. WHILE IN OUTPUT MODE, WE
; WRITE A VALUE OF $FF WHICH WILL BE PERSISTED BY THE PPI
; CHIP BUS HOLD CIRCUIT IF THERE IS NO ICM PRESENT. SO,
; WE CAN SUBSEQUENTLY TEST FOR PPIB=$FF TO SEE IF THERE IS
; NO ICM AND PREVENT PROBLEMS WITH PHANTOM ICM KEY PRESSES.
; IF A ICM IS PRESENT, IT WILL SIMPLY OVERPOWER THE PPI
; BUS HOLD CIRCUIT.
LD A,$80 ; PA OUT, PB OUT, PC OUT
OUT (ICM_PPIX),A
LD A,$FF ; SET PPIB=$FF, BUS HOLD
OUT (ICM_PPIB),A
;
LD A,$82 ; PA OUT, PB IN, PC OUT
OUT (ICM_PPIX),A
;
;IN A,(ICM_PPIB) ; *DEBUG*
;CALL PRTHEXBYTE ; *DEBUG*
;
IN A,(ICM_PPIB) ; READ PPIB
XOR $FF ; INVERT RESULT
;
CALL ICM_RESET
;
RET Z ; BAIL OUT NOW IF NOT PRESENT
;
; RECORD HARDWARE PRESENT
LD A,$FF
LD (ICM_PRESENT),A
;
; REGISTER DRIVER WITH HBIOS
LD BC,ICM_DISPATCH
CALL DSKY_SETDISP
;
CALL ICM_SHOWVER
;
RET
;
ICM_SHOWVER:
LD HL,ICM_VERSTR
LD DE,ICM_BUF
LD BC,ICM_COLS
LDIR
LD HL,ICM_BUF + 5
LD A,RMJ
LD A,(ICM_SEGMAP + RMJ)
OR $80
LD (HL),A
INC HL
LD A,(ICM_SEGMAP + RMN)
OR $80
LD (HL),A
INC HL
LD A,(ICM_SEGMAP + RUP)
LD (HL),A
;
; DISPLAY VERSION ON ICM
LD C,0
LD B,8
LD HL,ICM_BUF
CALL ICM_PUTBUF
RET
;
ICM_INIT:
CALL NEWLINE ; FORMATTING
PRTS("ICM:$") ; FORMATTING
;
PRTS(" IO=0x$") ; FORMATTING
LD A,ICMPPIBASE ; GET BASE PORT
CALL PRTHEXBYTE ; PRINT BASE PORT
;
LD A,(ICM_PRESENT) ; PRESENT?
OR A ; SET FLAGS
JR NZ,ICM_INIT1 ; YES, CONTINUE
PRTS(" NOT PRESENT$") ; NOT PRESENT
RET
;
ICM_INIT1:
CALL PC_SPACE
LD A,ICM_COLS
CALL PRTDEC8
LD A,'X'
CALL COUT
LD A,ICM_ROWS
CALL PRTDEC8
RET
;
; ICM DEVICE FUNCTION DISPATCH ENTRY
; A: RESULT (OUT), 0=OK, Z=OK, NZ=ERR
; B: FUNCTION (IN)
;
ICM_DISPATCH:
LD A,B ; GET REQUESTED FUNCTION
AND $0F ; ISOLATE SUB-FUNCTION
JP Z,ICM_RESET ; RESET DSKY HARDWARE
DEC A
JP Z,ICM_STAT ; GET KEYPAD STATUS
DEC A
JP Z,ICM_GETKEY ; READ A KEY FROM THE KEYPAD
DEC A
JP Z,ICM_SHOWHEX ; DISPLAY A 32-BIT BINARY VALUE IN HEX
DEC A
JP Z,ICM_SHOWSEG ; DISPLAY SEGMENTS
DEC A
JP Z,ICM_KEYLEDS ; SET KEYPAD LEDS
DEC A
JP Z,ICM_STATLED ; SET STATUS LED
DEC A
JP Z,ICM_BEEP ; BEEP DSKY SPEAKER
DEC A
JP Z,ICM_DEVICE ; DEVICE INFO
DEC A
JP Z,ICM_MESSAGE ; HANDLE MESSAGE
DEC A
JP Z,ICM_EVENT ; HANDLE EVENT
SYSCHKERR(ERR_NOFUNC)
RET
;
;
;
ICM_RESET:
PUSH AF
LD A,$70 ; PPISD AND 7218 INACTIVE
OUT (ICM_PPIC),A
POP AF
RET
;
; CHECK FOR KEY PRESS, SAVE RAW VALUE, RETURN STATUS
;
ICM_STAT:
LD A,(ICM_KEYBUF) ; GET CURRENT BUF VAL
CP $FF ; $FF MEANS WE ARE WAITING FOR PREV KEY TO BE RELEASED
JR Z,ICM_STAT1 ; CHECK FOR PREV KEY RELEASE
OR A ; DO WE HAVE A SCAN CODE BUFFERED ALREADY?
RET NZ ; IF SO, WE ARE DONE
JR ICM_STAT2 ; OTHERWISE, DO KEY CHECK
ICM_STAT1:
; WAITING FOR PREVIOUS KEY RELEASE
CALL ICM_KEY ; SCAN
JR Z,ICM_STAT2 ; IF ZERO, PREV KEY RELEASED, CONTINUE
XOR A ; SIGNAL NO KEY PRESSED
RET ; AND DONE
ICM_STAT2:
CALL ICM_KEY ; SCAN
LD (ICM_KEYBUF),A ; SAVE RESULT
RET ; RETURN WITH ZF SET APPROPRIATELY
;
; WAIT FOR A ICM KEYPRESS AND RETURN
;
ICM_GETKEY:
CALL ICM_STAT ; CHECK STATUS
JR Z,ICM_GETKEY ; LOOP IF NOTHING READY
LD A,(ICM_KEYBUF)
LD B,24 ; SIZE OF DECODE TABLE
LD C,0 ; INDEX
LD HL,ICM_KEYMAP ; POINT TO BEGINNING OF TABLE
ICM_GETKEY1:
CP (HL) ; MATCH?
JR Z,ICM_GETKEY2 ; FOUND, DONE
INC HL
INC C ; BUMP INDEX
DJNZ ICM_GETKEY1 ; LOOP UNTIL EOT
ICM_GETKEY1A:
LD A,$FF ; NOT FOUND ERR, RETURN $FF
RET
ICM_GETKEY2:
LD A,$FF ; SET KEY BUF TO $FF
LD (ICM_KEYBUF),A ; DO IT
; RETURN THE INDEX POSITION WHERE THE SCAN CODE WAS FOUND
LD E,C ; RETURN INDEX VALUE
XOR A ; SIGNAL SUCCESS
RET
;
; DISPLAY HEX VALUE FROM DE:HL
;
ICM_SHOWHEX:
LD BC,ICM_TMP32 ; POINT TO HEX BUFFER
CALL ST32 ; STORE 32-BIT BINARY THERE
LD HL,ICM_TMP32 ; FROM: BINARY VALUE (HL)
LD DE,ICM_BUF ; TO: SEGMENT BUFFER (DE)
CALL ICM_BIN2SEG ; CONVERT
LD HL,ICM_BUF ; POINT TO SEGMENT BUFFER
CALL ICM_PUTBUF ; DO IT
XOR A ; SUCCESS
RET ; AND RETURN
;
; ICM SHOW BUFFER
; HL: ADDRESS OF BUFFER
;
ICM_SHOWSEG:
; CONVERT FROM DBG ALPHABET TO SEG CODES
LD B,ICM_COLS ; DO FOR ALL CHARS
LD DE,ICM_BUF ; DESTINATION BUFFER
ICM_SHOWSEG1:
LD A,(HL) ; GET SOURCE VALUE
INC HL ; BUMP FOR NEXT TIME
PUSH AF ; SAVE IT
AND $80 ; ISOLATE HI BIT (DP)
LD C,A ; SAVE IN C
POP AF ; RECOVER ORIGINAL
AND $7F ; REMOVE HI BIT (DP)
PUSH HL ; SAVE IT
LD HL,ICM_SEGMAP ; POINT TO XLAT MAP
CALL ADDHLA ; OFFSET BY VALUE
LD A,(HL) ; GET NEW VALUE
OR C ; RECOMBINE WITH DP BIT
LD (DE),A ; SAVE IT
INC DE ; BUMP PTR
POP HL ; RESTORE SOURCE PTR
DJNZ ICM_SHOWSEG1 ; LOOP TILL DONE
;
; DISPLAY CONVERTED BUFFER
LD HL,ICM_BUF ; BUFFER
CALL ICM_PUTBUF ; DO IT
XOR A ; SIGNAL SUCCESS
RET
;
;
;
ICM_KEYLEDS:
ICM_STATLED:
ICM_BEEP:
XOR A ; PRETEND SUCCESS
RET
;
; DEVICE INFORMATION
;
ICM_DEVICE:
LD D,DSKYDEV_ICM ; D := DEVICE TYPE
LD E,0 ; E := PHYSICAL DEVICE NUMBER
LD H,0 ; H := MODE
LD L,ICMPPIBASE ; L := BASE I/O ADDRESS
XOR A ; SIGNAL SUCCESS
RET
;
; MESSAGE HANDLER
;
ICM_MESSAGE:
LD A,C ; GET MESSAGE ID
ADD A,A ; WORD OFFSET
LD HL,ICM_MSGTBL ; START OF MESSAGE TABLE
CALL ADDHLA ; ADD OFFSET
LD A,(HL) ; SAVE LSB
INC HL ; BUMP TO MSB
LD H,(HL) ; GET MSB
LD L,A ; GET LSB
;
; HL HAS POINTER TO MESSAGE
CALL ICM_PUTBUF ; DISPLAY IT
XOR A ; SIGNAL SUCCESS
RET
;
; EVENT HANDLER
;
ICM_EVENT:
LD A,C ; EVENT ID
OR A ; 0=CPUSPD
JR Z,ICM_EVT_CPUSPD ; HANDLE CPU SPD CHANGE
DEC A ; 1=DSKACT
JR Z,ICM_EVT_DSKACT ; HANDLE DISK ACTIVITY
XOR A
RET
;
; CPU SPEED CHANGE
;
ICM_EVT_CPUSPD:
XOR A
RET
;
; DISK ACTIVITY
;
ICM_EVT_DSKACT:
;
; USE DISK UNIT NUMBER FOR MSB
LD A,(HB_DSKUNIT) ; GET DISK UNIT NUM
LD (HB_DSKADR+3),A ; REPLACE HIGH BYTE W/ DISK #
;
; CONVERT TO SEGMENT DISPLAY
LD HL,HB_DSKADR ; INPUT POINTER
LD DE,ICM_BUF ; BUF FOR OUTPUT
CALL ICM_BIN2SEG ; CONVERT TO SEG DISPLAY
;
; DECIMAL POINT FOR DISK UNIT SEPARATION
LD HL,ICM_BUF+1 ; SECOND CHAR OF DISP
SET 7,(HL) ; TURN ON DECIMAL PT
;
; DECIMAL POINT TO INDICATE WRITE ACTION
LD A,(HB_DSKFUNC) ; GET CURRENT I/O FUNCTION
CP BF_DIOWRITE ; IS IT A WRITE?
JR NZ,ICM_EVT_DSKACT2 ; IF NOT, SKIP
LD HL,ICM_BUF+7 ; POINT TO CHAR 7
SET 7,(HL) ; SET WRITE DOT
;
ICM_EVT_DSKACT2:
; UPDATE DISPLAY
LD HL,ICM_BUF ; SEG DISPLAY BUF TO HL
CALL ICM_PUTBUF
;
XOR A
RET
;
;__ICM_KEY_________________________________________________________________________________________
;
; CHECK FOR KEY PRESS W/ DEBOUNCE
;__________________________________________________________________________________________________
;
ICM_KEY:
CALL ICM_SCAN ; INITIAL KEY PRESS SCAN
LD E,A ; SAVE INITIAL SCAN VALUE
ICM_KEY1:
; MAX BOUNCE TIME FOR OMRON B3F IS 3MS
PUSH DE ; SAVE DE
LD DE,300 ; ~3MS DELAY
CALL VDELAY ; DO IT
CALL ICM_SCAN ; REPEAT SCAN
POP DE ; RESTORE DE
RET Z ; IF NOTHING PRESSED, DONE
CP E ; SAME?
JR ICM_KEY2 ; YES, READY TO RETURN
LD E,A ; OTHERWISE, SAVE NEW SCAN VAL
JR ICM_KEY1 ; AND LOOP UNTIL STABLE VALUE
ICM_KEY2:
OR A ; SET FLAGS BASED ON VALUE
RET ; AND DONE
;
;__ICM_SCAN________________________________________________________________________________________
;
; SCAN KEYPAD AND RETURN RAW SCAN CODE (RETURNS ZERO IF NO KEY PRESSED)
;__________________________________________________________________________________________________
;
ICM_SCAN:
LD B,4 ; 4 COLUMNS
LD C,$01 ; FIRST COLUMN
LD E,0 ; INITIAL COL ID
ICM_SCAN1:
LD A,C ; COL TO A
OR $70 ; KEEP PPISD AND 7218 INACTIVE
OUT (ICM_PPIC),A ; ACTIVATE COL
IN A,(ICM_PPIB) ; READ ROW BITS
AND $3F ; MASK, WE ONLY HAVE 6 ROWS, OTHERS UNDEFINED
JR NZ,ICM_SCAN2 ; IF NOT ZERO, GOT SOMETHING
RLC C ; NEXT COL
INC E ; BUMP COL ID
DJNZ ICM_SCAN1 ; LOOP THROUGH ALL COLS
XOR A ; NOTHING FOUND, RETURN ZERO
JP ICM_RESET ; RETURN VIA RESET
ICM_SCAN2:
RRC E ; MOVE COL ID
RRC E ; ... TO HIGH BITS 6 & 7
OR E ; COMBINE WITH ROW
JP ICM_RESET ; RETURN VIA RESET
;
;__ICM_PUTBUF______________________________________________________________________________________
;
; WRITE BUFFER AT HL TO SEGMENT DISPLAY
;__________________________________________________________________________________________________
;
ICM_PUTBUF:
LD A,82H ; SETUP PPI
OUT (ICM_PPIX),A
CALL ICM_COFF
LD A,$F0 ; 7218 -> (DATA COMING, NO DECODE)
OUT (ICM_PPIA),A
CALL ICM_STROBEC ; STROBE COMMAND
LD B,ICM_COLS ; NUMBER OF DIGITS
LD C,ICM_PPIA
ICM_HEXOUT2:
LD A,(HL)
XOR $80 ; FIX DOT POLARITY
OUT (C),A
INC HL
DEC B
JP Z,ICM_STROBE ; DO FINAL STROBE AND RETURN
CALL ICM_STROBE ; STROBE BYTE VALUE
JR ICM_HEXOUT2
ICM_STROBEC: ; COMMAND STROBE
LD A,80H | 30H
JP ICM_STROBE0
ICM_STROBE: ; DATA STROBE
LD A,00H | 30H ; SET WRITE STROBE
ICM_STROBE0:
OUT (ICM_PPIC),A ; OUT TO PORTC
CALL DLY2 ; DELAY
ICM_COFF:
LD A,40H | 30H ; QUIESCE
OUT (ICM_PPIC),A ; OUT TO PORTC
XOR A ; SIGNAL SUCCESS
RET
;
;_KEYMAP_TABLE_____________________________________________________________________________________
;
ICM_KEYMAP:
; POS $00 $01 $02 $03 $04 $05 $06 $07
; KEY [0] [1] [2] [3] [4] [5] [6] [7]
.DB $41, $02, $42, $82, $04, $44, $84, $08
;
; POS $08 $09 $0A $0B $0C $0D $0E $0F
; KEY [8] [9] [A] [B] [C] [D] [E] [F]
.DB $48, $88, $10, $50, $90, $20, $60, $A0
;
; POS $10 $11 $12 $13 $14 $15 $16 $17
; KEY [FW] [BK] [CL] [EN] [DE] [EX] [GO] [BO]
.DB $01, $81, $C1, $C2, $C4, $C8, $D0, $E0
;
; KBD WORKING STORAGE
;
ICM_KEYBUF .DB 0
;
;==================================================================================================
; UTILTITY FUNCTIONS
;==================================================================================================
;
; CONVERT 32 BIT BINARY TO 8 BYTE HEX SEGMENT DISPLAY
;
; HL: ADR OF 32 BIT BINARY
; DE: ADR OF DEST LED SEGMENT DISPLAY BUFFER (8 BYTES)
;
ICM_BIN2SEG:
LD B,4 ; 4 BYTES OF INPUT
LD A,B ; PUT IN ACCUM
CALL ADDHLA ; PROCESS FROM END (LITTLE ENDIAN)
ICM_BIN2SEG1:
DEC HL ; DEC PTR (LITTLE ENDIAN)
LD A,(HL) ; HIGH NIBBLE
RRCA \ RRCA \ RRCA \ RRCA ; ROTATE BITS
CALL ICM_BIN2SEG_NIB ; CONVERT NIBBLE INTO OUTPUT BUF
LD A,(HL) ; LOW NIBBLE
CALL ICM_BIN2SEG_NIB ; CONVERT NIBBLE INTO OUTPUT BUF
DJNZ ICM_BIN2SEG1 ; LOOP FOR ALL INPUT BYTES
RET ; DONE
;
ICM_BIN2SEG_NIB:
PUSH HL ; SAVE HL
LD HL,ICM_SEGMAP ; POINT TO SEG MAP TABLE
AND $0F ; ISOLATE LOW NIBBLE
CALL ADDHLA ; OFFSET INTO TABLE
LD A,(HL) ; LOAD VALUE FROM TABLE
POP HL ; RESTORE HL
LD (DE),A ; SAVE VALUE TO OUTPUT BUF
INC DE ; BUMP TO NEXT OUTPUT BYTE
RET ; DONE
;
;==================================================================================================
; STORAGE
;==================================================================================================
;
; SEG DISPLAY WORKING STORAGE
;
ICM_PRESENT .DB 0
ICM_BUF .FILL ICM_COLS
ICM_TMP32 .FILL 4,0 ; TEMP DWORD
;
ICM_VERSTR .DB $3E,$7F,$0A,$7B,$57,$00,$00,$00 ; "HBIOS "
;
ICM_SEGMAP:
;
; POS $00 $01 $02 $03 $04 $05 $06 $07
; GLYPH '0' '1' '2' '3' '4' '5' '6' '7'
.DB $7B, $30, $6D, $75, $36, $57, $5F, $70
;
; POS $08 $09 $0A $0B $0C $0D $0E $0F
; GLYPH '8' '9' 'A' 'B' 'C' 'D' 'E' 'F'
.DB $7F, $76, $7E, $1F, $4B, $3D, $4F, $4E
;
; POS $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $1A
; GLYPH ' ' '-' '.' 'P' 'o' 'r' 't' 'A' 'd' 'r' 'G'
.DB $00, $04, $00, $6E, $1D, $0C, $0F, $7E, $3D, $0C, $5F
;
ICM_MSGTBL:
.DW ICM_MSG_LDR_SEL
.DW ICM_MSG_LDR_BOOT
.DW ICM_MSG_LDR_LOAD
.DW ICM_MSG_LDR_GO
.DW ICM_MSG_MON_RDY
.DW ICM_MSG_MON_BOOT
;
ICM_MSG_LDR_SEL .DB $7F,$1D,$1D,$0F,$6C,$00,$00,$00 ; "Boot? "
ICM_MSG_LDR_BOOT .DB $7F,$1D,$1D,$0F,$80,$80,$80,$00 ; "Boot... "
ICM_MSG_LDR_LOAD .DB $0B,$1D,$7E,$3D,$80,$80,$80,$00 ; "Load... "
ICM_MSG_LDR_GO .DB $5F,$1D,$80,$80,$80,$00,$00,$00 ; "Go... "
ICM_MSG_MON_RDY .DB $04,$4B,$6E,$3B,$00,$3B,$6E,$04 ; "-CPU UP-"
ICM_MSG_MON_BOOT .DB $7F,$1D,$1D,$0F,$B0,$00,$00,$00 ; "Boot! "