; ;================================================================================================== ; HARDWARE SUPPORT FOR HITACHI HD44780 OR EQUIVALENT ;================================================================================================== ; ; CURRENTLY ASSUMES A 20X4 DISPLAY ; ; TYPICAL PORTS USED ON RCBUS ECOSYSTEM: ; ; PRIMARY ALT ; FUNCTION $DA $AA ; DATA $DB $AB ; LCD_FUNC .EQU LCDBASE + 0 ; WRITE LCD_STAT .EQU LCDBASE + 0 ; READ LCD_DATA .EQU LCDBASE + 1 ; READ/WRITE ; LCD_FUNC_CLEAR .EQU $01 ; CLEAR DISPLAY LCD_FUNC_HOME .EQU $02 ; HOME CURSOR & REMOVE ALL SHIFTING LCD_FUNC_ENTRY .EQU $04 ; SET CUR DIR AND DISPLAY SHIFT LCD_FUNC_DISP .EQU $08 ; DISP, CUR, BLINK ON/OFF LCD_FUNC_SHIFT .EQU $10 ; MOVE CUR / SHIFT DISP LCD_FUNC_SET .EQU $20 ; SET INTERFACE PARAMS LCD_FUNC_CGADR .EQU $40 ; SET CGRAM ADRESS LCD_FUNC_DDADR .EQU $80 ; SET DDRAM ADDRESS ; DEVECHO "LCD: IO=" DEVECHO LCDBASE DEVECHO "\n" ; ; HARDWARE RESET PRIOR TO ROMWBW CONSOLE INITIALIZATION ; LCD_PREINIT: ; ; RESET LCD CONTROLLER, DELAYS ARE FIXED, BUSY FLAG ; CANNOT BE USED YET, CONTROLLER MAY NOT EXIST! LD A,LCD_FUNC_SET | %11000 OUT (LCD_FUNC),A LD DE,50000/16 ; WAIT >40MS, WE USE 50MS CALL VDELAY ; DO IT LD A,LCD_FUNC_SET | %11000 OUT (LCD_FUNC),A LD DE,5000/16 ; WAIT >4.1MS, WE USE 5MS CALL VDELAY ; DO IT LD A,LCD_FUNC_SET | %11000 OUT (LCD_FUNC),A LD DE,5000/16 ; WAIT >4.1MS, WE USE 5MS CALL VDELAY ; DO IT ; ; TEST FOR PRESENCE... CALL LCD_DETECT ; PROBE FOR HARDWARE LD A,(LCD_PRESENT) ; GET PRESENCE FLAG OR A ; SET FLAGS RET Z ; BAIL OUT IF NOT PRESENT ; ; WE CAN NOW DO NORMAL I/O W/ BUSY FLAG LD DE,LCD_INIT_SEQ ; INIT SEQUENCE CALL LCD_OUTFS ; SEND IT ; ; PUT SOMETHING ON THE DISPLAY LD DE,LCD_STR_BAN CALL LCD_OUTDS ; ; SECOND LINE ; CPU TYPE LD HL,$0100 ; ROW 2, COL 0 CALL LCD_GOTORC LD HL,LCD_CPU LD A,(HB_CPUTYPE) ; GET CPU TYPE RRCA ; WORD OFFSET CALL ADDHLA ; ADD OFFSET LD E,(HL) ; GET LSB INC HL ; BUMP LD D,(HL) ; GET MSB CALL LCD_OUTDS LD DE,LCD_STR_XPU CALL LCD_OUTDS ; ; "12.345 MHz" RIGHT JUSTIFIED LD HL,$010A ; ROW 2, COL 10 CALL LCD_GOTORC LD HL,(CB_CPUKHZ) PUSH HL LD BC,10000 ; 10 MHZ SBC HL,BC ; SUBTRACT JR NC,LCD_PREINIT1 LD A,' ' ; EXTRA PAD CALL LCD_OUTD LCD_PREINIT1: POP HL CALL LCD_PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA LD DE,LCD_STR_MHZ CALL LCD_OUTDS ; ; THIRD LINE LD HL,$0200 ; ROW 2, COL 0 CALL LCD_GOTORC LD DE,LCD_STR_CFG CALL LCD_OUTDS ; XOR A ; SIGNAL SUCCESS RET ; DONE ; ; POST CONSOLE INITIALIZATION ; LCD_INIT: CALL NEWLINE ; FORMATTING PRTS("LCD: IO=$") LD A,LCDBASE CALL PRTHEXBYTE ; LD A,(LCD_PRESENT) ; GET PRESENCE FLAG OR A ; SET FLAGS JR Z,LCD_INIT1 ; HANDLE NOT PRESENT XOR A ; SIGNAL SUCCESS RET ; DONE ; LCD_INIT1: PRTS(" NOT PRESENT$") OR $FF RET ; ; CALLED FROM HBIOS RIGHT BEFORE A DISK ACCESS ; HL: ADDRESS OF 32-BIT SECTOR NUMBER (LITTLE-ENDIAN) ; ; FORMAT: "Disk #99 R:12345678" ; 01234567890123456789 ; LCD_DSKACT: ; SAVE EVERYTHING PUSH AF PUSH BC PUSH DE PUSH HL ; LD A,(LCD_PRESENT) ; GET PRESENCE FLAG OR A ; SET FLAGS JR Z,LCD_DSKACT_Z ; HANDLE NOT PRESENT ; PUSH HL LD HL,$0300 ; ROW 3, COL 0 CALL LCD_GOTORC ; SET DISPLAY ADDRESS POP HL ; LD DE,LCD_STR_IO ; PREFIX CALL LCD_OUTDS ; SEND TO DISPLAY (COLS 0-5) ; LD A,(HB_DSKUNIT) ; GET DISK UNIT NUM CALL LCD_DSKACT_BYTE ; SEND TO DISPLAY (COLS 6-7) HEX??? ; LD A,' ' ; SEPARATOR CALL LCD_OUTD ; SEND TO DISPLAY (COL 8) CALL LCD_OUTD ; SEND TO DISPLAY (COL 9) ; LD A,(HB_DSKFUNC) ; ACTIVE DISK FUNCTION CP BF_DIOWRITE ; WRITE? LD A,'W' ; ASSUME WRITE JR Z,LCD_DSKACT0 ; GO AHEAD LD A,'R' ; OTHERWISE READ LCD_DSKACT0: CALL LCD_OUTD ; SEND CHAR (COL 10) ; LD A,':' ; SEPARATOR CALL LCD_OUTD ; SEND TO DISPLAY (COL 11) ; LD A,3 ; POINT TO CALL ADDHLA ; END OF DWORD (MSB) LD B,4 ; DO 4 BYTES ; LCD_DSKACT1: LD A,(HL) ; GET BYTE CALL LCD_DSKACT_BYTE ; SEND TO DISPLAY (COLS 12-19) DEC HL ; DEC PTR DJNZ LCD_DSKACT1 ; DO ALL 4 BYTES ; LCD_DSKACT_Z: ; CLEAN UP AND GO AWAY POP HL POP DE POP BC POP AF RET ; LCD_DSKACT_BYTE: PUSH AF ; SAVE BYTE RRCA ; DO TOP NIBBLE FIRST RRCA RRCA RRCA CALL HEXCONV ; CONVERT NIBBLE TO ASCII CALL LCD_OUTD ; SEND TO DISPLAY POP AF ; RECOVER CURRENT BYTE CALL HEXCONV ; CONVERT NIBBLE TO ASCII CALL LCD_OUTD ; SEND TO DISPLAY RET ; DONE ; ; DETECT PRESENCE OF LCD CONTROLLER BY WRITING AND READING BACK ; TEST VALUES IN THE CONTROLLER RAM. ; WE DO NOT USE THE NORMAL READ/WRITE ROUTINES BECAUSE WE DO ; NOT WANT TO STALL WAITING ON THE BUSY FLAG IF THE CONTROLLER ; IS NOT PRESENT ; LCD_DETECT: ; FIRST PASS W/ TEST VALUE $AA LD C,$AA CALL LCD_DETECT_PASS JR NZ,LCD_DETECT1 ; ; SECOND PASS W/ TEST VALUE $55 LD C,$55 CALL LCD_DETECT_PASS JR NZ,LCD_DETECT1 ; ; LCD PRESENT OR $FF JR LCD_DETECT_Z ; LCD_DETECT1: ; LCD NOT PRESENT XOR A JR LCD_DETECT_Z ; LCD_DETECT_Z: LD (LCD_PRESENT),A RET ; ; WRITE AND READBACK VALUE IN C TO THE FIRST BYTE OF DDRAM ; RETURN WITH COMPARE RESULT ; LCD_DETECT_PASS: CALL LCD_DELAY ; WAIT LD A,LCD_FUNC_DDADR OUT (LCD_FUNC),A ; POINT TO FIRST BYTE CALL LCD_DELAY ; WAIT LD A,C ; TEST VALUE OUT (LCD_DATA),A ; WRITE IT CALL LCD_DELAY ; WAIT LD A,LCD_FUNC_DDADR OUT (LCD_FUNC),A ; POINT TO FIRST BYTE CALL LCD_DELAY IN A,(LCD_DATA) ; GET VALUE CP C ; AS WRITTEN? RET ; ; DELAY USED DURING DETECT, >37US ; LCD_DELAY: CALL DELAY ; 16US CALL DELAY ; 16US JP DELAY ; 16US, TOTAL 48US ; ; SEND FUNCTION CODE IN A ; LCD_OUTF: PUSH AF ; SAVE CODE LCD_OUTF1: IN A,(LCD_STAT) ; GET STATUS AND $80 ; ISOLATE BUSY FLAG JR NZ,LCD_OUTF1 ; LOOP TILL NOT BUSY POP AF ; RECOVER CODE OUT (LCD_FUNC),A ; SEND IT RET ; DONE ; ; SEND FUNCTION STRING ; DE=STRING ADDRESS, NULL TERMINATED ; LCD_OUTFS: LD A,(DE) ; NEXT BYTE TO SEND OR A ; SET FLAGS RET Z ; DONE WHEN NULL REACHED INC DE ; BUMP POINTER CALL LCD_OUTF ; SEND IT JR LCD_OUTFS ; LOOP AS NEEDED ; ; SEND DATA BYTE IN A ; LCD_OUTD: PUSH AF ; SAVE BYTE LCD_OUTD1: IN A,(LCD_STAT) ; GET STATUS AND $80 ; ISOLATE BUSY FLAG JR NZ,LCD_OUTD1 ; LOOP TILL NOT BUSY POP AF ; RECOVER BYTE OUT (LCD_DATA),A ; SEND IT RET ; DONE ; ; SEND DATA STRING ; DE=STRING ADDRESS, NULL TERMINATED ; LCD_OUTDS: LD A,(DE) ; NEXT BYTE TO SEND OR A ; SET FLAGS RET Z ; DONE WHEN NULL REACHED INC DE ; BUMP POINTER CALL LCD_OUTD ; SEND IT JR LCD_OUTDS ; LOOP AS NEEDED ; ; GET DATA BYTE INTO A ; LCD_IND: IN A,(LCD_STAT) ; GET STATUS AND $80 ; ISOLATE BUSY FLAG JR NZ,LCD_IND ; LOOP TILL NOT BUSY POP AF ; RECOVER BYTE IN A,(LCD_DATA) ; GET IT RET ; DONE ; ; GOTO ROW(H),COL(L) ; LCD_GOTORC: PUSH HL ; SAVE INCOMING LD A,H ; ROW # TO A LD HL,LCD_ROWS ; POINT TO ROWS TABLE CALL ADDHLA ; INDEX TO ROW ENTRY LD A,(HL) ; GET RWO START POP HL ; RECOVER INCOMING ADD A,L ; ADD COLUMN ADD A,LCD_FUNC_DDADR ; APPLY FUNCTION BIT JR LCD_OUTF ; AND SEND IT ; ; PRINT VALUE OF HL AS THOUSANDTHS, IE. 0.000 ; LCD_PRTD3M: PUSH BC PUSH DE PUSH HL LD E,'0' LD BC,-10000 CALL LCD_PRTD3M1 LD E,0 LD BC,-1000 CALL LCD_PRTD3M1 LD A,'.' CALL LCD_OUTD LD BC,-100 CALL LCD_PRTD3M1 LD C,-10 CALL LCD_PRTD3M1 LD C,-1 CALL LCD_PRTD3M1 POP HL POP DE POP BC RET LCD_PRTD3M1: LD A,'0' - 1 LCD_PRTD3M2: INC A ADD HL,BC JR C,LCD_PRTD3M2 SBC HL,BC CP E JR Z,LCD_PRTD3M3 LD E,0 CALL LCD_OUTD LCD_PRTD3M3: RET ; ; DATA STORAGE ; LCD_PRESENT .DB 0 ; NON-ZERO WHEN HARDWARE DETECTED ; LCD_ROWS .DB $00,$40,$14,$54 ; ROW START INDEX ; LCD_INIT_SEQ: .DB LCD_FUNC_SET | %11000 ; FUNCTION SET, 2 LINES, 5X8 FONT .DB LCD_FUNC_DISP ; DISPLAY OFF .DB LCD_FUNC_CLEAR ; CLEAR DISPLAY, HOME CURSOR .DB LCD_FUNC_ENTRY | $02 ; INCREMENT, NO SHIFT .DB LCD_FUNC_DISP | $04 ; DISPLAY ON, NO CURSOR, NO BLINK .DB $00 ; TERMINATOR ; LCD_STR_BAN .DB "RomWBW v", BIOSVER, 0 LCD_STR_CFG .DB "Build: ", CONFIG, 0 LCD_STR_IO .DB "Disk #", 0 LCD_STR_XPU .DB " CPU",0 LCD_STR_SPD .DB "12.345",0 LCD_STR_MHZ .DB " MHz",0 ; LCD_CPU .DW LCD_CPU_Z80 .DW LCD_CPU_Z180 .DW LCD_CPU_Z180K .DW LCD_CPU_Z180N .DW LCD_CPU_Z280 ; LCD_CPU_Z80 .DB "Z80",0 LCD_CPU_Z180 .DB "Z180",0 LCD_CPU_Z180K .DB "Z180-K",0 LCD_CPU_Z180N .DB "Z180-N",0 LCD_CPU_Z280 .DB "Z280",0