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.
 
 
 
 
 
 

288 lines
8.8 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))
;
SIO_RBR .EQU UART0IOB + 0 ; DLAB=0: RCVR BUFFER REG (READ ONLY)
SIO_THR .EQU UART0IOB + 0 ; DLAB=0: XMIT HOLDING REG (WRITE ONLY)
SIO_IER .EQU UART0IOB + 1 ; DLAB=0: INT ENABLE REG
SIO_IIR .EQU UART0IOB + 2 ; INT IDENT REGISTER (READ ONLY)
SIO_FCR .EQU UART0IOB + 2 ; FIFO CONTROL REG (WRITE ONLY)
SIO_LCR .EQU UART0IOB + 3 ; LINE CONTROL REG
SIO_MCR .EQU UART0IOB + 4 ; MODEM CONTROL REG
SIO_LSR .EQU UART0IOB + 5 ; LINE STATUS REG
SIO_MSR .EQU UART0IOB + 6 ; MODEM STATUS REG
SIO_SCR .EQU UART0IOB + 7 ; SCRATCH REGISTER
SIO_DLL .EQU UART0IOB + 0 ; DLAB=1: DIVISOR LATCH (LS)
SIO_DLM .EQU UART0IOB + 1 ; DLAB=1: DIVISOR LATCH (MS)
;
#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_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,$22 ; FAILSAFE VALUE, 9600 BAUD AT 18.432 MHZ
OUT0 (Z180_CNTLB0),A ; -> CNTLB0
; TRY TO IMPLEMENT CONFIGURED BAUD RATE
LD HL,ASCI0CFG ; 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 NZ,XIO_INIT1 ; BYPASS ON FAILURE
LD A,C ; PUT INT C
OUT0 (Z180_CNTLB0),A ; AND SET THE VALUE
#ENDIF
#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2))
;XIO_DIV .EQU (UARTOSC / (16 * CONBAUD))
LD DE,UART0CFG ; 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
XIO_INIT1:
RET
;
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
;
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 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
RET ; DONE
#ENDIF
#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4))
PUSH AF ; SAVE INCOMING BYTE
XIO_OUTC1:
IN0 A,(Z180_STAT0)
AND $02
JR Z,XIO_OUTC1
POP AF
OUT0 (Z180_TDR0),A
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_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
;
; 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
;
;
;
#IF ((PLATFORM == PLT_N8) | (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 SET INDICATES SUCCESS
;
; GIVEN DIVISOR = CLK HZ / BAUD
; LET LOOKUP = DIVISOR / 160
; LOOKUP = CLK / BAUD / 160
; LET KCLK = CLK / 1000, SO CLK = KCLK * 1000
; LOOKUP = KCLK * 1000 / BAUD / 160
; OR, LOOKUP = (KCLK / 12) / (BAUD / 75)
;
; SO, WE USE (CPUKHZ / 12) / (BAUD RATE / 75) TO GET LOOKUP VALUE
; THEN LOOKUP THE CORRECT CNTLB0 VALUE
;
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
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 DE,12 ; PREPARE TO DIVIDE BY 12
CALL XIO_DIV16 ; BC := (CPU CLK KHZ / 12), REMAINDER IN HL, ZF
POP DE ; RESTORE DENOMINATOR
JR NZ,XIO_CNTLB2 ; ABORT IF REMAINDER
PUSH BC ; MOVE VALUE
POP HL ; ... TO HL NUMERATOR
CALL XIO_DIV16 ; BC := LOOKUP VALUE, REMAINDER IN HL, ZF
JR NZ,XIO_CNTLB2 ; ABORT IF REMAINDER
PUSH BC ; MOVE LOOKUP VALUE
POP DE ; TO DE
LD B,XIO_LKUPCNT ; INIT LOOP COUNT
LD HL,XIO_LKUP ; POINT TO START OF TABLE
XIO_CNTLB0:
LD A,(HL) ; GET BYTE TO COMPARE
INC HL ; INCREMENT HL FOR NEXT
CP E ; COMPARE LSB
JR NZ,XIO_CNTLB1 ; NO MATCH, LOOP
LD A,(HL) ; GET BYTE TO COMPARE
CP D ; COMPARE MSB
JR NZ,XIO_CNTLB1 ; NO MATCH, LOOP
; MATCH FOUND
INC HL ; POINT TO CNTLB VALUE
LD C,(HL) ; LOAD IN C
XOR A ; SIGNAL SUCCESS
RET ; AND DONE
XIO_CNTLB1:
INC HL ; BUMP TO
INC HL ; ... NEXT ENTRY
DJNZ XIO_CNTLB0 ; LOOP IF MORE TO CHECK
XIO_CNTLB2:
OR $FF ; NOT FOUND, SET ERROR
RET ; AND RETURN
;
; LOOKUP PS BIT PS DIV DR BIT DR DIV SS BITS SS DIV DIVISOR CNTLB
; ------ ------ ------ ------ ------ ------- ------ ------- --------
; 1 0 10 0 16 0 1 160 XX0X0000
; 2 0 10 0 16 1 2 320 XX0X0001
; 3 1 30 0 16 0 1 480 XX1X0000
; 4 0 10 0 16 2 4 640 XX0X0010
; 6 1 30 0 16 1 2 960 XX1X0001
; 8 0 10 0 16 3 8 1280 XX0X0011
; 12 1 30 0 16 2 4 1920 XX1X0010
; 16 0 10 0 16 4 16 2560 XX0X0100
; 24 1 30 0 16 3 8 3840 XX1X0011
; 32 0 10 0 16 5 32 5120 XX0X0101
; 48 1 30 0 16 4 16 7680 XX1X0100
; 64 0 10 0 16 6 64 10240 XX0X0110
; 96 1 30 0 16 5 32 15360 XX1X0101
; 128 0 10 1 64 5 32 20480 XX0X1101
; 192 1 30 0 16 6 64 30720 XX1X0110
; 256 0 10 1 64 6 64 40960 XX0X1110
; 384 1 30 1 64 5 32 61440 XX1X1101
; 768 1 30 1 64 6 64 122880 XX1X1110
;
XIO_LKUP: ; LOOKUP CNTLB VAL
.DW 1 \ .DB %00000000
.DW 2 \ .DB %00000001
.DW 3 \ .DB %00100000
.DW 4 \ .DB %00000010
.DW 6 \ .DB %00100001
.DW 8 \ .DB %00000011
.DW 12 \ .DB %00100010
.DW 16 \ .DB %00000100
.DW 24 \ .DB %00100011
.DW 32 \ .DB %00000101
.DW 48 \ .DB %00100100
.DW 64 \ .DB %00000110
.DW 96 \ .DB %00100101
.DW 128 \ .DB %00001101
.DW 192 \ .DB %00100110
.DW 256 \ .DB %00001110
.DW 384 \ .DB %00101101
.DW 768 \ .DB %00101110
;
XIO_LKUPCNT .EQU ($ - XIO_LKUP) / 3
;
#ENDIF