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.
 
 
 
 
 
 

560 lines
12 KiB

;
;==================================================================================================
; 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_ROWS .EQU 4
LCD_COLS .EQU 20
;
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 ", SIZE="
DEVECHO LCD_COLS
DEVECHO "X"
DEVECHO LCD_ROWS
DEVECHO "\n"
;
;--------------------------------------------------------------------------------------------------
; HBIOS MODULE HEADER
;--------------------------------------------------------------------------------------------------
;
ORG_LCD .EQU $
;
.DW SIZ_LCD ; MODULE SIZE
.DW LCD_INITPHASE ; ADR OF INIT PHASE HANDLER
;
LCD_INITPHASE:
; INIT PHASE HANDLER, A=PHASE
CP HB_PHASE_PREINIT ; PREINIT PHASE?
JP Z,LCD_PREINIT ; DO PREINIT
CP HB_PHASE_INIT ; INIT PHASE?
JP Z,LCD_INIT ; DO INIT
RET ; DONE
;
; 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
EZ80_IO
OUT (LCD_FUNC),A
LD DE,50000/16 ; WAIT >40MS, WE USE 50MS
CALL VDELAY ; DO IT
LD A,LCD_FUNC_SET | %11000
EZ80_IO
OUT (LCD_FUNC),A
LD DE,5000/16 ; WAIT >4.1MS, WE USE 5MS
CALL VDELAY ; DO IT
LD A,LCD_FUNC_SET | %11000
EZ80_IO
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
;
; REGISTER DRIVER WITH HBIOS
LD BC,LCD_DISPATCH
CALL DSKY_SETDISP
;
; 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
RLCA ; 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
;
CALL LCD_EVT_CPUSPD
;
; 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=0x$")
LD A,LCDBASE
CALL PRTHEXBYTE
;
LD A,(LCD_PRESENT) ; GET PRESENCE FLAG
OR A ; SET FLAGS
JR Z,LCD_INIT1 ; HANDLE NOT PRESENT
;
CALL PC_SPACE
LD A,LCD_COLS
CALL PRTDEC8
PRTS("X$")
LD A,LCD_ROWS
CALL PRTDEC8
XOR A ; SIGNAL SUCCESS
RET ; DONE
;
LCD_INIT1:
PRTS(" NOT PRESENT$")
OR $FF
RET
;
; DSKY DEVICE FUNCTION DISPATCH ENTRY
; A: RESULT (OUT), 0=OK, Z=OK, NZ=ERR
; B: FUNCTION (IN)
;
LCD_DISPATCH:
LD A,B ; GET REQUESTED FUNCTION
AND $0F ; ISOLATE SUB-FUNCTION
JP Z,LCD_NULL ; RESET DSKY HARDWARE
DEC A
JP Z,LCD_NULL ; GET KEYPAD STATUS
DEC A
JP Z,LCD_NULL ; READ A KEY FROM THE KEYPAD
DEC A
JP Z,LCD_NULL ; DISPLAY A 32-BIT BINARY VALUE IN HEX
DEC A
JP Z,LCD_SHOWSEG ; DISPLAY SEGMENTS
DEC A
JP Z,LCD_NULL ; SET KEYPAD LEDS
DEC A
JP Z,LCD_NULL ; SET STATUS LED
DEC A
JP Z,LCD_NULL ; BEEP DSKY SPEAKER
DEC A
JP Z,LCD_DEVICE ; DEVICE INFO
DEC A
JP Z,LCD_MESSAGE ; HANDLE MESSAGE
DEC A
JP Z,LCD_EVENT ; HANDLE EVENT
SYSCHKERR(ERR_NOFUNC)
RET
;
;
;
LCD_NULL:
XOR A
RET
;
; DRAW DISPLAY USING DEBUG ALPHABET
; HL = SOURCE BUFFER
;
LCD_SHOWSEG:
XOR A
RET
;
; DEVICE INFORMATION
;
LCD_DEVICE:
LD D,DSKYDEV_LCD ; D := DEVICE TYPE
LD E,0 ; E := PHYSICAL DEVICE NUMBER
LD H,0 ; H := MODE
LD L,LCDBASE ; L := BASE I/O ADDRESS
XOR A ; SIGNAL SUCCESS
RET
;
; MESSAGE HANDLER
;
LCD_MESSAGE:
LD A,C ; GET MESSAGE ID
ADD A,A ; WORD OFFSET
LD HL,LCD_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
;
EX DE,HL
LD HL,$0300 ; ROW 3, COL 0
CALL LCD_GOTORC
CALL LCD_LINEOUT
XOR A ; SIGNAL SUCCESS
RET
;
; EVENT HANDLER
;
LCD_EVENT:
LD A,C ; EVENT ID
OR A ; 0=CPUSPD
JR Z,LCD_EVT_CPUSPD ; HANDLE CPU SPD CHANGE
DEC A ; 1=DSKACT
JR Z,LCD_EVT_DSKACT ; HANDLE DISK ACTIVITY
XOR A
RET
;
; CPU SPEED CHANGE
;
LCD_EVT_CPUSPD:
; "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
;
RET
;
; FORMAT: "Disk #99 R:12345678"
; 01234567890123456789
;
LCD_EVT_DSKACT:
;
LD HL,$0300 ; ROW 3, COL 0
CALL LCD_GOTORC ; SET DISPLAY ADDRESS
;
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_EVT_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_EVT_DSKACT0 ; GO AHEAD
LD A,'R' ; OTHERWISE READ
LCD_EVT_DSKACT0:
CALL LCD_OUTD ; SEND CHAR (COL 10)
;
LD A,':' ; SEPARATOR
CALL LCD_OUTD ; SEND TO DISPLAY (COL 11)
;
LD HL,HB_DSKADR+3 ; END OF DWORD (MSB)
LD B,4 ; DO 4 BYTES
;
LCD_EVT_DSKACT1:
LD A,(HL) ; GET BYTE
CALL LCD_EVT_DSKACT_BYTE ; SEND TO DISPLAY (COLS 12-19)
DEC HL ; DEC PTR
DJNZ LCD_EVT_DSKACT1 ; DO ALL 4 BYTES
RET
;
LCD_EVT_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
EZ80_IO
OUT (LCD_FUNC),A ; POINT TO FIRST BYTE
CALL LCD_DELAY ; WAIT
LD A,C ; TEST VALUE
EZ80_IO
OUT (LCD_DATA),A ; WRITE IT
CALL LCD_DELAY ; WAIT
LD A,LCD_FUNC_DDADR
EZ80_IO
OUT (LCD_FUNC),A ; POINT TO FIRST BYTE
CALL LCD_DELAY
EZ80_IO
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
;
; DELAY USED DURING NORMAL I/O
; REQUIRED FOR HIGH SPEED CPU OPERATION
;
#DEFINE LCD_XDELAY EX (SP),HL \ EX (SP),HL
;
; SEND FUNCTION CODE IN A
;
LCD_OUTF:
PUSH AF ; SAVE CODE
LCD_OUTF1:
LCD_XDELAY
EZ80_IO
IN A,(LCD_STAT) ; GET STATUS
AND $80 ; ISOLATE BUSY FLAG
JR NZ,LCD_OUTF1 ; LOOP TILL NOT BUSY
POP AF ; RECOVER CODE
LCD_XDELAY
EZ80_IO
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:
LCD_XDELAY
EZ80_IO
IN A,(LCD_STAT) ; GET STATUS
AND $80 ; ISOLATE BUSY FLAG
JR NZ,LCD_OUTD1 ; LOOP TILL NOT BUSY
POP AF ; RECOVER BYTE
LCD_XDELAY
EZ80_IO
OUT (LCD_DATA),A ; SEND IT
RET ; DONE
;
; SEND STRING, BLANK PAD TO END OF LINE
; ASSUMES WRITING TO FIRST COLUMN
;
LCD_LINEOUT:
LD B,LCD_COLS
CALL LCD_OUTDS
LCD_LINEOUT1:
LD A,' '
CALL LCD_OUTD
DJNZ LCD_LINEOUT1
RET
;
; 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
DEC B ; PADDING COUNTER FOR ABOVE
CALL LCD_OUTD ; SEND IT
JR LCD_OUTDS ; LOOP AS NEEDED
;
; GET DATA BYTE INTO A
;
LCD_IND:
LCD_XDELAY
EZ80_IO
IN A,(LCD_STAT) ; GET STATUS
AND $80 ; ISOLATE BUSY FLAG
JR NZ,LCD_IND ; LOOP TILL NOT BUSY
POP AF ; RECOVER BYTE
LCD_XDELAY
EZ80_IO
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_ROWSIDX ; POINT TO ROWS INDEX 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_ROWSIDX .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 CONFIG, 0
LCD_STR_IO .DB "Disk #", 0
LCD_STR_XPU .DB " CPU",0
LCD_STR_MHZ .DB " MHz",0
;
; INDEXED AS PER CPT_xxx
LCD_CPU .DW LCD_CPU_Z80
.DW LCD_CPU_Z180
.DW LCD_CPU_Z180K
.DW LCD_CPU_Z180N
.DW LCD_CPU_Z280
.DW LCD_CPU_EZ80
;
LCD_CPU_Z80 .DB "Z80",0
LCD_CPU_Z180 .DB "Z180",0
LCD_CPU_Z180K .DB "Z180K",0
LCD_CPU_Z180N .DB "Z180N",0
LCD_CPU_Z280 .DB "Z280",0
LCD_CPU_EZ80 .DB "eZ80",0
;
LCD_MSGTBL:
.DW LCD_MSG_LDR_SEL
.DW LCD_MSG_LDR_BOOT
.DW LCD_MSG_LDR_LOAD
.DW LCD_MSG_LDR_GO
.DW LCD_MSG_MON_RDY
.DW LCD_MSG_MON_BOOT
;
LCD_MSG_LDR_SEL .DB "Ready",0
LCD_MSG_LDR_BOOT .DB "Boot...",0
LCD_MSG_LDR_LOAD .DB "Load...",0
LCD_MSG_LDR_GO .DB "Go...",0
LCD_MSG_MON_RDY .DB "-CPU UP-",0
LCD_MSG_MON_BOOT .DB "Boot!",0
;
;--------------------------------------------------------------------------------------------------
; HBIOS MODULE TRAILER
;--------------------------------------------------------------------------------------------------
;
END_LCD .EQU $
SIZ_LCD .EQU END_LCD - ORG_LCD
;
MEMECHO "LCD occupies "
MEMECHO SIZ_LCD
MEMECHO " bytes.\n"