; ;================================================================================================== ; 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" ; ;-------------------------------------------------------------------------------------------------- ; HBIOS MODULE HEADER ;-------------------------------------------------------------------------------------------------- ; ORG_ICM .EQU $ ; .DW SIZ_ICM ; MODULE SIZE .DW ICM_INITPHASE ; ADR OF INIT PHASE HANDLER ; ICM_INITPHASE: ; INIT PHASE HANDLER, A=PHASE CP HB_PHASE_PREINIT ; PREINIT PHASE? JP Z,ICM_PREINIT ; DO PREINIT CP HB_PHASE_INIT ; INIT PHASE? JP Z,ICM_INIT ; DO INIT RET ; DONE ; ;__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! " ; ;-------------------------------------------------------------------------------------------------- ; HBIOS MODULE TRAILER ;-------------------------------------------------------------------------------------------------- ; END_ICM .EQU $ SIZ_ICM .EQU END_ICM - ORG_ICM ; MEMECHO "ICM occupies " MEMECHO SIZ_ICM MEMECHO " bytes.\n"