mirror of https://github.com/wwarthen/RomWBW.git
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.
386 lines
11 KiB
386 lines
11 KiB
;___XIO________________________________________________________________________________________________________________
|
|
;
|
|
; DIRECT SERIAL I/O
|
|
;
|
|
; PROVIDES INTERFACE TO PLATFORM BASE SERIAL I/O DEVICE
|
|
; ALLOWS USER MESSAGING/INTERACTION PRIOR TO AND DURING HBIOS INIT
|
|
;______________________________________________________________________________________________________________________
|
|
;
|
|
;
|
|
#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2))
|
|
;
|
|
UARTIOB .EQU $68
|
|
;
|
|
SIO_RBR .EQU UARTIOB + 0 ; DLAB=0: RCVR BUFFER REG (READ ONLY)
|
|
SIO_THR .EQU UARTIOB + 0 ; DLAB=0: XMIT HOLDING REG (WRITE ONLY)
|
|
SIO_IER .EQU UARTIOB + 1 ; DLAB=0: INT ENABLE REG
|
|
SIO_IIR .EQU UARTIOB + 2 ; INT IDENT REGISTER (READ ONLY)
|
|
SIO_FCR .EQU UARTIOB + 2 ; FIFO CONTROL REG (WRITE ONLY)
|
|
SIO_LCR .EQU UARTIOB + 3 ; LINE CONTROL REG
|
|
SIO_MCR .EQU UARTIOB + 4 ; MODEM CONTROL REG
|
|
SIO_LSR .EQU UARTIOB + 5 ; LINE STATUS REG
|
|
SIO_MSR .EQU UARTIOB + 6 ; MODEM STATUS REG
|
|
SIO_SCR .EQU UARTIOB + 7 ; SCRATCH REGISTER
|
|
SIO_DLL .EQU UARTIOB + 0 ; DLAB=1: DIVISOR LATCH (LS)
|
|
SIO_DLM .EQU UARTIOB + 1 ; DLAB=1: DIVISOR LATCH (MS)
|
|
;
|
|
;XIO_DIV .EQU (UARTOSC / (16 * CONBAUD))
|
|
;
|
|
#ENDIF
|
|
|
|
#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_N8PC) | (PLATFORM == PLT_MK4))
|
|
#ENDIF
|
|
|
|
XIO_INIT: ; MINIMAL UART INIT
|
|
|
|
#IF (PLATFORM == PLT_UNA)
|
|
; SHOULD UNA SERIAL I/O BE RESET HERE???
|
|
#ENDIF
|
|
|
|
#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_N8PC) | (PLATFORM == PLT_MK4))
|
|
|
|
; INIT ASCI0 WITH BASIC VALUES AND FAILSAFE DIVISOR
|
|
LD A,$66 ; IGNORE CTS/DCD, NO BREAK DETECT
|
|
OUT0 (Z180_ASEXT0),A ; -> ASEXT0
|
|
LD A,$64 ; ENABLE XMT/RCV, 8 DATA, NO PARITY, 1 STOP
|
|
OUT0 (Z180_CNTLA0),A ; -> CNTLA0
|
|
;LD A,$20 ; FAILSAFE VALUE, 38400 BAUD AT 18.432 MHZ
|
|
;LD A,$22 ; FAILSAFE VALUE, 9600 BAUD AT 18.432 MHZ
|
|
;OUT0 (Z180_CNTLB0),A ; -> CNTLB0
|
|
|
|
; TRY TO IMPLEMENT CONFIGURED BAUD RATE
|
|
LD HL,XIOCFG ; SERIAL CONFIG WORD
|
|
LD A,H ; BYTE W/ ENCODED BAUD RATE
|
|
AND $1F ; ISOLATE BITS
|
|
LD L,A ; MOVE TO L
|
|
LD H,0 ; CLEAR MSB
|
|
CALL XIO_CNTLB ; DERIVE CNTLB VALUE
|
|
JR Z,XIO_INIT1 ; SUCCESS, IMPLEMENT IT
|
|
LD C,$21 + Z180_CLKDIV ; FAILSAFE VALUE, 9600 BAUD IF OSC=18.432 MHZ
|
|
|
|
XIO_INIT1:
|
|
LD A,C ; MOVE VALUE TO ACCUM
|
|
OUT0 (Z180_CNTLB0),A ; AND SET THE VALUE
|
|
#ENDIF
|
|
|
|
#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2))
|
|
|
|
LD DE,XIOCFG ; SERIAL CONFIG WORD
|
|
CALL XIO_COMPDIV ; COMPUTE DIVISOR TO BC
|
|
|
|
LD A,$80 ; LCR := DLAB ON
|
|
OUT (SIO_LCR),A ; SET LCR
|
|
;LD A,XIO_DIV % $100 ; BAUD RATE DIVISOR (LSB)
|
|
LD A,C ; LOW BYTE OF DIVISOR
|
|
OUT (SIO_DLL),A ; SET DIVISOR (LSB)
|
|
;LD A,XIO_DIV / $100 ; BAUD RATE DIVISOR (MSB)
|
|
LD A,B ; HIGH BYTE OF DIVISOR
|
|
OUT (SIO_DLM),A ; SET DIVISOR (MSB)
|
|
LD A,03H ; VALUE FOR LCR AND MCR
|
|
OUT (SIO_LCR),A ; LCR := 3, DLAB OFF, 8 DATA, 1 STOP, NO PARITY
|
|
OUT (SIO_MCR),A ; MCR := 3, DTR ON, RTS ON
|
|
LD A,6 ; DISABLE & RESET FIFO'S
|
|
OUT (SIO_FCR),A ; DO IT
|
|
|
|
#ENDIF
|
|
|
|
RET
|
|
;
|
|
XIO_SYNC: ; WAIT FOR FOR PENDING DATA IN FIFO TO CLEAR
|
|
;
|
|
#IF (PLATFORM == PLT_UNA)
|
|
; NOT SURE ANYTHING IS POSSIBLE HERE...
|
|
#ENDIF
|
|
|
|
#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_N8PC) | (PLATFORM == PLT_MK4))
|
|
; IMPLEMENT THIS... OR MAYBE NOT.
|
|
#ENDIF
|
|
|
|
#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2))
|
|
LD DE,CPUMHZ * 25 ; FAILSAFE TIMEOUT COUNTER
|
|
XIO_SYNC1:
|
|
IN A,(SIO_LSR) ; GET LINE STATUS REGISTER
|
|
BIT 6,A ; TEST BIT 6 (TRANSMITTER EMPTY)
|
|
JR NZ,XIO_SYNC2 ; EMPTY, MOVE ON
|
|
DEC DE ; DECREMENT TIMEOUT COUNTER
|
|
LD A,D ; TEST TIMEOUT COUNTER
|
|
OR E ; ... FOR ZERO
|
|
JR NZ,XIO_SYNC1 ; LOOP UNTIL TIMEOUT
|
|
XIO_SYNC2:
|
|
#ENDIF
|
|
|
|
RET
|
|
;
|
|
XIO_CRLF2: ; OUTPUT 2 NEWLINES
|
|
CALL XIO_CRLF ; SEND CRLF, FALL THRU FOR ANOTHER
|
|
XIO_CRLF: ; OUTPUT A NEWLINE
|
|
LD A,13 ; A = CR
|
|
CALL XIO_OUTC ; WRITE IT
|
|
LD A,10 ; A = LF
|
|
JR XIO_OUTC ; WRITE IT AND RETURN
|
|
;
|
|
XIO_SPACE: ; OUTPUT A SPACE CHARACTER
|
|
LD A,' '
|
|
JR XIO_OUTC
|
|
;
|
|
XIO_DOT: ; OUTPUT A DOT (MARK PROGRESS)
|
|
LD A,'.'
|
|
;
|
|
XIO_OUTC: ; OUTPUT BYTE IN A
|
|
|
|
#IF (PLATFORM == PLT_UNA)
|
|
PUSH BC ; PRESERVE BC
|
|
PUSH DE ; PRESERVE DE
|
|
LD BC,$0012 ; UNA UNIT = 0, FUNC = WRITE CHAR
|
|
LD E,A ; CHAR TO E
|
|
CALL $FFFD ; DO IT (RST 08 NOT SETUP YET)
|
|
POP DE ; RESTORE DE
|
|
POP BC ; RESTORE BC
|
|
RET ; DONE
|
|
#ENDIF
|
|
|
|
#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_N8PC) | (PLATFORM == PLT_MK4))
|
|
PUSH AF ; SAVE INCOMING BYTE
|
|
XIO_OUTC1:
|
|
IN0 A,(Z180_STAT0) ; GET LINE STATUS
|
|
AND $02 ; ISOLATE TDRE
|
|
JR Z,XIO_OUTC1 ; LOOP TILL READY (EMPTY)
|
|
POP AF ; RECOVER INCOMING BYTE TO OUTPUT
|
|
OUT0 (Z180_TDR0),A ; WRITE THE CHAR TO ASCI
|
|
RET
|
|
#ENDIF
|
|
|
|
#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2))
|
|
PUSH AF ; SAVE INCOMING BYTE
|
|
XIO_OUTC1:
|
|
IN A,(SIO_LSR) ; READ LINE STATUS REGISTER
|
|
AND $20 ; ISOLATE THRE
|
|
JR Z,XIO_OUTC1 ; LOOP TILL READY (EMPTY)
|
|
POP AF ; RECOVER BYTE TO WRITE
|
|
OUT (SIO_THR),A ; WRITE THE CHAR TO UART
|
|
RET
|
|
#ENDIF
|
|
;
|
|
XIO_INC: ; INPUT BYTE TO A
|
|
|
|
#IF (PLATFORM == PLT_UNA)
|
|
PUSH BC ; PRESERVE BC
|
|
PUSH DE ; PRESERVE DE
|
|
LD BC,$0011 ; UNA UNIT = 0, FUNC = READ CHAR
|
|
CALL $FFFD ; DO IT (RST 08 NOT SETUP YET)
|
|
LD A,E ; CHAR TO A
|
|
POP DE ; RESTORE DE
|
|
POP BC ; RESTORE BC
|
|
RET ; DONE
|
|
#ENDIF
|
|
|
|
#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_N8PC) | (PLATFORM == PLT_MK4))
|
|
XIO_INC1:
|
|
IN0 A,(Z180_STAT0) ; READ LINE STATUS
|
|
AND $80 ; ISOLATE RDRF
|
|
JR Z,XIO_INC1 ; LOOP TILL CHAR AVAILABLE
|
|
IN0 A,(Z180_RDR0) ; READ THE CHAR
|
|
RET
|
|
#ENDIF
|
|
|
|
#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2))
|
|
XIO_INC1:
|
|
IN A,(SIO_LSR) ; READ LINE STATUS REGISTER
|
|
AND $01 ; ISOLATE RDR
|
|
JR Z,XIO_INC1 ; LOOP TILL CHAR AVAILABLE
|
|
IN A,(SIO_RBR) ; READ THE CHAR
|
|
RET
|
|
#ENDIF
|
|
;
|
|
XIO_IST: ; INPUT STATUS TO A (NUM CHARS WAITING)
|
|
|
|
#IF (PLATFORM == PLT_UNA)
|
|
PUSH BC ; PRESERVE BC
|
|
PUSH DE ; PRESERVE DE
|
|
LD BC,$0013 ; UNA UNIT = 0, FUNC = READ CHAR
|
|
CALL $FFFD ; DO IT (RST 08 NOT SETUP YET)
|
|
LD A,E ; CHAR TO A
|
|
OR A ; UPDATE ZF
|
|
POP DE ; RESTORE DE
|
|
POP BC ; RESTORE BC
|
|
RET ; DONE
|
|
#ENDIF
|
|
|
|
#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_N8PC) | (PLATFORM == PLT_MK4))
|
|
IN0 A,(Z180_STAT0) ; READ LINE STATUS
|
|
AND $80 ; ISOLATE RDRF
|
|
RET Z ; NO CHARS WAITING, A=0, Z SET
|
|
LD A,1 ; SIGNAL 1 CHAR WAITING
|
|
OR A ; UPDATE ZF
|
|
RET
|
|
#ENDIF
|
|
|
|
#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2))
|
|
IN A,(SIO_LSR) ; READ LINE STATUS REGISTER
|
|
AND $01 ; ISOLATE RDR
|
|
RET Z ; NO CHARS WAITING, A=0, Z SET
|
|
LD A,1 ; SIGNAL 1 CHAR WAITING
|
|
OR A ; UPDATE ZF
|
|
RET
|
|
#ENDIF
|
|
;
|
|
XIO_OUTS: ; OUTPUT '$' TERMINATED STRING AT ADDRESS IN HL
|
|
LD A,(HL) ; GET NEXT BYTE
|
|
CP '$' ; END OF STRING?
|
|
RET Z ; YES, GET OUT
|
|
CALL XIO_OUTC ; OTHERWISE, WRITE IT
|
|
INC HL ; POINT TO NEXT BYTE
|
|
JR XIO_OUTS ; AND LOOP
|
|
|
|
#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2))
|
|
;
|
|
; COMPUTE DIVISOR TO BC
|
|
;
|
|
XIO_COMPDIV:
|
|
; WE WANT TO DETERMINE A DIVISOR FOR THE UART CLOCK
|
|
; THAT RESULTS IN THE DESIRED BAUD RATE.
|
|
; BAUD RATE = UART CLK / DIVISOR, OR TO SOLVE FOR DIVISOR
|
|
; DIVISOR = UART CLK / BAUDRATE.
|
|
; THE UART CLOCK IS THE UART OSC PRESCALED BY 16. ALSO, WE CAN
|
|
; TAKE ADVANTAGE OF ENCODED BAUD RATES ALWAYS BEING A FACTOR OF 75.
|
|
; SO, WE CAN USE (UART OSC / 16 / 75) / (BAUDRATE / 75)
|
|
;
|
|
; FIRST WE DECODE THE BAUDRATE, BUT WE USE A CONSTANT OF 1 INSTEAD
|
|
; OF THE NORMAL 75. THIS PRODUCES (BAUDRATE / 75).
|
|
;
|
|
LD A,D ; GET CONFIG MSB
|
|
AND $1F ; ISOLATE ENCODED BAUD RATE
|
|
LD L,A ; PUT IN L
|
|
LD H,0 ; H IS ALWAYS ZERO
|
|
LD DE,1 ; USE 1 FOR ENCODING CONSTANT
|
|
CALL DECODE ; DE:HL := BAUD RATE, ERRORS IGNORED
|
|
EX DE,HL ; DE := (BAUDRATE / 75), DISCARD HL
|
|
LD HL,UARTOSC / 16 / 75 ; HL := (UART OSC / 16 / 75)
|
|
JP XIO_DIV16 ; BC := HL/DE == DIVISOR AND RETURN
|
|
;
|
|
#ENDIF
|
|
;
|
|
;
|
|
;
|
|
#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_N8PC) | (PLATFORM == PLT_MK4))
|
|
;
|
|
; DERIVE A CNTLB VALUE BASED ON AN ENCODED BAUD RATE AND CURRENT CPU SPEED
|
|
; ENTRY: HL = ENCODED BAUD RATE
|
|
; EXIT: C = CNTLB VALUE, A=0/Z IFF SUCCESS
|
|
;
|
|
; DESIRED DIVISOR == CPUHZ / BAUD
|
|
; DUE TO ENCODING BAUD IS ALWAYS DIVISIBLE BY 75
|
|
; Z180 DIVISOR IS ALWAYS A FACTOR OF 160
|
|
;
|
|
; X = (CPU_HZ / 160) / 75 ==> SIMPLIFIED ==> X = CPU_KHZ / 12
|
|
; X = X / (BAUD / 75)
|
|
; IF X % 3 == 0, THEN (PS=1, X := X / 3) ELSE PS=0
|
|
; IF X % 4 == 0, THEN (DR=1, X := X / 4) ELSE DR=0
|
|
; SS := LOG2(X)
|
|
;
|
|
XIO_CNTLB:
|
|
LD DE,1 ; USE DECODE CONSTANT OF 1 TO GET BAUD RATE ALREADY DIVIDED BY 75
|
|
CALL DECODE ; DECODE THE BAUDATE INTO DE:HL, DE IS DISCARDED
|
|
;CALL TSTPT
|
|
RET NZ ; ABORT ON ERROR
|
|
PUSH HL ; HL HAS (BAUD / 75), SAVE IT
|
|
;LD HL,(HCB + HCB_CPUKHZ) ; GET CPU CLK IN KHZ
|
|
LD HL,CPUKHZ ; CPU CLK IN KHZ
|
|
;LD HL,9216 ; *DEBUG*
|
|
|
|
; DUE TO THE LIMITED DIVISORS POSSIBLE WITH CNTLB, YOU PRETTY MUCH
|
|
; NEED TO USE A CPU SPEED THAT IS A MULTIPLE OF 128KHZ. BELOW, WE
|
|
; ATTEMPT TO ROUND THE CPU SPEED DETECTED TO A MULTIPLE OF 128KHZ
|
|
; WITH ROUNDING. THIS JUST MAXIMIZES OUR CHANCES OF SUCCESS COMPUTING
|
|
; THE DIVISOR.
|
|
LD DE,$0040 ; HALF OF 128 IS 64
|
|
ADD HL,DE ; ADD FOR ROUNDING
|
|
LD A,L ; MOVE TO ACCUM
|
|
AND $80 ; STRIP LOW ORDER 7 BITS
|
|
LD L,A ; ... AND PUT IT BACK
|
|
|
|
LD DE,12 ; PREPARE TO DIVIDE BY 12
|
|
CALL XIO_DIV16 ; BC := (CPU_KHZ / 12), REM IN HL, ZF
|
|
;CALL TSTPT
|
|
POP DE ; RESTORE (BAUD / 75)
|
|
RET NZ ; ABORT IF REMAINDER
|
|
PUSH BC ; MOVE WORKING VALUE
|
|
POP HL ; ... BACK TO HL
|
|
CALL XIO_DIV16 ; BC := X / (BAUD / 75)
|
|
;CALL TSTPT
|
|
RET NZ ; ABORT IF REMAINDER
|
|
;
|
|
; DETERMINE PS BIT BY ATTEMPTING DIVIDE BY 3
|
|
PUSH BC ; SAVE WORKING VALUE ON STACK
|
|
PUSH BC ; MOVE WORKING VALUE
|
|
POP HL ; ... TO HL
|
|
LD DE,3 ; SETUP TO DIVIDE BY 3
|
|
CALL XIO_DIV16 ; BC := X / 3, REM IN HL, ZF
|
|
;CALL TSTPT
|
|
POP HL ; HL := PRIOR WORKING VALUE
|
|
LD E,0 ; INIT E := 0 AS WORKING CNTLB VALUE
|
|
JR NZ,XIO_CNTLB1 ; DID NOT WORK, LEAVE PS==0, SKIP AHEAD
|
|
SET 5,E ; SET PS BIT
|
|
PUSH BC ; MOVE NEW WORKING
|
|
POP HL ; ... VALUE TO HL
|
|
;
|
|
XIO_CNTLB1:
|
|
;CALL TSTPT
|
|
; DETERMINE DR BIT BY ATTEMPTING DIVIDE BY 4
|
|
LD A,L ; LOAD LSB OF WORKING VALUE
|
|
AND $03 ; ISOLATE LOW ORDER BITS
|
|
JR NZ,XIO_CNTLB2 ; NOT DIVISIBLE BY 4, SKIP AHEAD
|
|
SET 3,E ; SET PS BIT
|
|
SRL H ; DIVIDE HL BY 4
|
|
RR L ; ...
|
|
SRL H ; ...
|
|
RR L ; ...
|
|
;
|
|
XIO_CNTLB2:
|
|
;CALL TSTPT
|
|
; DETERMINE SS BITS BY RIGHT SHIFTING AND INCREMENTING
|
|
LD B,7 ; LOOP COUNTER, MAX VALUE OF SS IS 7
|
|
LD C,E ; MOVE WORKING CNTLB VALUE TO C
|
|
XIO_CNTLB3:
|
|
BIT 0,L ; CAN WE SHIFT AGAIN?
|
|
JR NZ,XIO_CNTLB4 ; NOPE, DONE
|
|
SRL H ; IMPLEMENT THE
|
|
RR L ; ... SHIFT OPERATION
|
|
INC C ; INCREMENT SS BITS
|
|
DJNZ XIO_CNTLB3 ; LOOP IF MORE SHIFTING POSSIBLE
|
|
;
|
|
; AT THIS POINT HL MUST BE EQUAL TO 1 OR WE FAILED!
|
|
DEC HL ; IF HL == 1, SHOULD BECOME ZERO
|
|
LD A,H ; TEST HL
|
|
OR L ; ... FOR ZERO
|
|
RET NZ ; ABORT IF NOT ZERO
|
|
;
|
|
XIO_CNTLB4:
|
|
;CALL TSTPT
|
|
XOR A
|
|
RET
|
|
;
|
|
#ENDIF
|
|
;
|
|
; COMPUTE HL / DE = BC W/ REMAINDER IN HL & ZF
|
|
;
|
|
XIO_DIV16:
|
|
LD A,H ; HL -> AC
|
|
LD C,L ; ...
|
|
LD HL,0 ; INIT HL
|
|
LD B,16 ; INIT LOOP COUNT
|
|
XIO_DIV16A:
|
|
SCF
|
|
RL C
|
|
RLA
|
|
ADC HL,HL
|
|
SBC HL,DE
|
|
JR NC,XIO_DIV16B
|
|
ADD HL,DE
|
|
DEC C
|
|
XIO_DIV16B:
|
|
DJNZ XIO_DIV16A ; LOOP AS NEEDED
|
|
LD B,A ; AC -> BC
|
|
LD A,H ; SET ZF
|
|
OR L ; ... BASED ON REMAINDER
|
|
RET ; DONE
|
|
|