Browse Source

DUART: preliminary implementation

assumes XR88C681 for now
pull/133/head
Chris Odorjan 6 years ago
parent
commit
e911e93aaf
  1. 12
      Source/HBIOS/cfg_rcz80.asm
  2. 684
      Source/HBIOS/duart.asm
  3. 15
      Source/HBIOS/hbios.asm
  4. 1
      Source/HBIOS/hbios.inc

12
Source/HBIOS/cfg_rcz80.asm

@ -74,6 +74,18 @@ INTRTCENABLE .EQU FALSE ; ENABLE PERIODIC INTERRUPT CLOCK DRIVER (INTRTC.ASM)
HTIMENABLE .EQU FALSE ; ENABLE SIMH TIMER SUPPORT
SIMRTCENABLE .EQU FALSE ; ENABLE SIMH CLOCK DRIVER (SIMRTC.ASM)
;
DUARTENABLE .EQU TRUE ; DUART: ENABLE 2681/2692 SERIAL DRIVER (DUART.ASM)
DUARTDEBUG .EQU FALSE ; DUART: ENABLE DEBUG OUTPUT
DUARTCNT .EQU 2 ; DUART: NUMBER OF CHIPS TO DETECT (1-2)
DUART0BASE .EQU $A0 ; DUART 0: BASE ADDRESS OF CHIP
DUART0ACFG .EQU DEFSERCFG ; DUART 0A: SERIAL LINE CONFIG
DUART0BCFG .EQU DEFSERCFG ; DUART 0B: SERIAL LINE CONFIG
DUART0CLK .EQU 3686400 ; DUART 0: OSC FREQ IN HZ (STANDARD IS 3686400)
DUART1BASE .EQU $40 ; DUART 1: BASE ADDRESS OF CHIP
DUART1ACFG .EQU DEFSERCFG ; DUART 1A: SERIAL LINE CONFIG
DUART1BCFG .EQU DEFSERCFG ; DUART 1B: SERIAL LINE CONFIG
DUART1CLK .EQU 3686400 ; DUART 1: OSC FREQ IN HZ (STANDARD IS 3686400)
;
UARTENABLE .EQU TRUE ; UART: ENABLE 8250/16550-LIKE SERIAL DRIVER (UART.ASM)
UARTOSC .EQU 1843200 ; UART: OSC FREQUENCY IN MHZ
UARTCFG .EQU DEFSERCFG ; UART: LINE CONFIG FOR UART PORTS

684
Source/HBIOS/duart.asm

@ -0,0 +1,684 @@
;
;==================================================================================================
; DUART DRIVER (SERIAL PORT)
;==================================================================================================
;
; SETUP PARAMETER WORD:
; +-------+---+-------------------+ +---+---+-----------+---+-------+
; | |RTS| ENCODED BAUD RATE | |DTR|XON| PARITY |STP| 8/7/6 |
; +-------+---+---+---------------+ ----+---+-----------+---+-------+
; F E D C B A 9 8 7 6 5 4 3 2 1 0
; -- MSB (D REGISTER) -- -- LSB (E REGISTER) --
;
; MODE REGISTER 1
;
; D7 D6 D5 D4 D3 D2 D1 D0
; +-------+-------+-------+-------+-------+-------+-------+-------+
; | RXRTS | RXINT | EMODE | PARITY MODE | SEL | BITS/CHAR |
; +-------+-------+-------+-------+-------+-------+-------+-------+
;
; RXRTS: AUTOMATIC CONTROL OF /RTS BY RECEIVER
; 0 = NO
; 1 = YES
; RXINT: RECEIVE INTERRUPT SELECT
; 0 = RXRDY
; 1 = FFULL
; EMODE: ERROR MODE
; 0 = BY CHARACTER
; 1 = BY BLOCK
; PARITY MODE:
; 00 = WITH PARITY
; 01 = FORCE PARITY
; 10 = NO PARITY
; 11 = MULTIDROP MODE
; SEL: PARITY TYPE
; 0 = EVEN / SPACE
; 1 = ODD / MARK
; BITS/CHAR:
; 00 = 5
; 01 = 6
; 10 = 7
; 11 = 8
;
; MODE REGISTER 2
;
; D7 D6 D5 D4 D3 D2 D1 D0
; +-------+-------+-------+-------+-------+-------+-------+-------+
; | CHANNEL MODE | TXRTS | TXCTS | STOP BIT LENGTH |
; +-------+-------+-------+-------+-------+-------+-------+-------+
;
; CHANNEL MODE:
; 00 = NORMAL
; 01 = AUTO-ECHO
; 10 = LOCAL LOOP
; 11 = REMOTE LOOP
; TXRTS: AUTOMATIC CONTROL OF /RTS BY TRANSMITTER
; 0 = NO
; 1 = YES
; TXCTS: AUTOMATIC CONTROL OF TRANSMITTER BY /CTS
; 0 = NO
; 1 = YES
; STOP BIT LENGTH:
; 0 = 9/16
; 1 = 10/16 = 5/8
; 2 = 11/16
; 3 = 12/16 = 3/4
; 4 = 13/16
; 5 = 14/16 = 7/8
; 6 = 15/16
; 7 = 16/16 = 1
; 8-F = LENGTHS OF 0-7 PLUS ONE
; IF BITS/CHAR = 5 THEN ADD AN ADDITIONAL HALF BIT
;
DUART_DEBUG .EQU FALSE
;
DUART_NONE .EQU 0 ; UNKNOWN OR NOT PRESETN
DUART_2681 .EQU 1 ; OLD '681 WITHOUT IVR/GPR
DUART_2692 .EQU 2 ; '92 WITH MR0
DUART_XR88C681 .EQU 3 ; EXAR/MAXLINEAR CHIP WITH Z-MODE
;
DUART_BAUD_INV .EQU $FF ; INVALID BAUD RATE
DUART_BAUD_ACR7 .EQU %10000000 ; ACR BIT 7 = 1
DUART_BAUD_X1 .EQU %01000000 ; BRG EXTEND BIT = 1
;
; PER CHANNEL REGISTERS (CHANNEL A AT OFFSET 0, CHANNEL B AT OFFSET 8)
;
DUART_MR .EQU $00 ; MODE REGISTER (R/W)
DUART_SR .EQU $01 ; STATUS REGISTER (READ)
DUART_CSR .EQU $01 ; CLOCK SELECT REGISTER (WRITE)
DUART_CR .EQU $02 ; COMMAND REGISTER (WRITE)
DUART_RX .EQU $03 ; RECEIVER HOLDING REGISTER (READ)
DUART_TX .EQU $03 ; TRANSMITTER HOLDING REGISTER (WRITE)
;
; PER CHIP REGISTERS
;
DUART_IPCR .EQU $04 ; INPUT PORT CHANGE REGISTER (READ)
DUART_ACR .EQU $04 ; AUXILLIARY CONTROL REGISTER (WRITE)
DUART_ISR .EQU $05 ; INTERRUPT STATUS REGISTER (READ)
DUART_IMR .EQU $05 ; INTERRUPT MASK REGISTER (WRITE)
DUART_CTU .EQU $06 ; COUNTER/TIMER UPPER BYTE REGISTER (R/W)
DUART_CTL .EQU $07 ; COUNTER/TIMER LOWER BYTE REGISTER (R/W)
DUART_GPR .EQU $0C ; GENERAL PURPOSE REGISTER (R/W)
DUART_IVR .EQU $0C ; INTERRUPT VECTOR REGISTER (R/W)
DUART_IPR .EQU $0D ; INPUT PORT REGISTER (READ)
DUART_OPCR .EQU $0D ; OUTPUT PORT CONFIGURATION REGISTER (WRITE)
DUART_STCR .EQU $0E ; START COUNTER/TIMER COMMAND (READ)
DUART_SOPR .EQU $0E ; SET OUTPUT PORT REGISTER (WRITE)
DUART_SPCR .EQU $0F ; STOP COUNTER/TIMER COMMAND (READ)
DUART_ROPR .EQU $0F ; RESET OUTPUT PORT REGISTER (WRITE)
;
; COMMAND REGISTER
;
DUART_CR_ENA_RX .EQU %00000100 ; ENABLE RECEIVER
DUART_CR_DIS_RX .EQU %00001000 ; DISABLE RECEIVER
DUART_CR_ENA_TX .EQU %00000001 ; ENABLE TRANSMITTER
DUART_CR_DIS_TX .EQU %00000010 ; DISABLE TRANSMITTER
DUART_CR_NOP .EQU $00 ; NULL COMMAND
DUART_CR_MR1 .EQU $10 ; RESET MR POINTER TO MR1
DUART_CR_RESET_RX .EQU $20 ; RESET RECEIVER
DUART_CR_RESET_TX .EQU $30 ; RESET TRANSMITTER
DUART_CR_RESET_ERR .EQU $40 ; RESET ERROR STATUS
DUART_CR_RESET_BRK .EQU $50 ; RESET BREAK STATUS
DUART_CR_START_BRK .EQU $60 ; START BREAK
DUART_CR_STOP_BRK .EQU $70 ; STOP BREAK
DUART_CR_SET_RX_X .EQU $80 ; SET RECEIVER BRG EXTEND BIT (X=1)
DUART_CR_CLR_RX_X .EQU $90 ; CLEAR RECEIVER BRG EXTEND BIT (X=0)
DUART_CR_SET_TX_X .EQU $A0 ; SET TRANSMITTER BRG EXTEND BIT (X=1)
DUART_CR_CLR_TX_X .EQU $B0 ; CLEAR TRANSMITTER BRG EXTEND BIT (X=0)
DUART_CR_MR0 .EQU $B0 ; RESET MR POINTER TO MR0 (2692 ONLY)
DUART_CR_STANDBY .EQU $C0 ; SET STANDBY MODE (CHANNEL A ONLY)
DUART_CR_RESET_IUS .EQU $C0 ; RESET IUS LATCH (CHANNEL B ONLY)
DUART_CR_ACTIVE .EQU $D0 ; SET ACTIVE MODE (CHANNEL A ONLY)
DUART_CR_ZMODE .EQU $D0 ; SET Z-MODE (CHANNEL B ONLY)
;
; DUART STATUS REGISTER
;
DUART_SR_RXRDY .EQU %00000001 ; RECEIVER READY
DUART_SR_RXFULL .EQU %00000010 ; RECEIVE FIFO FULL
DUART_SR_TXRDY .EQU %00000100 ; TRANSMITTER READY
DUART_SR_TXEMPTY .EQU %00001000 ; TRANSMITTER FIFO EMPTY
DUART_SR_OVERRUN .EQU %00010000 ; OVERRUN ERROR
DUART_SR_PARITY .EQU %00100000 ; PARITY ERROR
DUART_SR_FRAMING .EQU %01000000 ; FRAMING ERROR
DUART_SR_BREAK .EQU %10000000 ; RECEIVED BREAK
;
; DUART MODE REGISTER 1
;
DUART_MR1_RXRTS .EQU %10000000 ; RECEIVER CONTROLS RTS
DUART_MR1_PARNONE .EQU %00010000 ; NO PARITY
DUART_MR1_PARODD .EQU %00000100 ; ODD PARITY
DUART_MR1_PAREVEN .EQU %00000000 ; EVEN PARITY
DUART_MR1_PARMARK .EQU %00001100 ; MARK PARITY
DUART_MR1_PARSPACE .EQU %00001000 ; SPACE PARITY
;
; DUART MODE REGISTER 2
;
DUART_MR2_TXCTS .EQU %00010000 ; CTS CONTROLS TRANSMITTER
DUART_MR2_STOP1 .EQU %00000111 ; 1 STOP BIT (1.5 IF 5 BITS/CHAR)
DUART_MR2_STOP2 .EQU %00001111 ; 2 STOP BITS (2.5 IF 5 BITS/CHAR)
;
;
#DEFINE DUART_INP(RID) CALL DUART_INP_IMP \ .DB RID
#DEFINE DUART_OUTP(RID) CALL DUART_OUTP_IMP \ .DB RID
;
;
;
DUART_PREINIT:
;
; SETUP THE DISPATCH TABLE ENTRIES
;
LD B,DUART_CFGCNT ; LOOP CONTROL
XOR A ; ZERO TO ACCUM
LD (DUART_DEV),A ; CURRENT DEVICE NUMBER
LD IY,DUART_CFG ; POINT TO START OF CFG TABLE
DUART_PREINIT0:
PUSH BC ; SAVE LOOP CONTROL
CALL DUART_INITUNIT ; HAND OFF TO GENERIC INIT CODE
POP BC ; RESTORE LOOP CONTROL
;
LD A,(IY + 1) ; GET THE DUART TYPE DETECTED
OR A ; SET FLAGS
JR Z,DUART_PREINIT1 ; SKIP IT IF NOTHING FOUND
;
PUSH BC ; SAVE LOOP CONTROL
LD BC,DUART_FNTBL ; BC := FUNCTION TABLE ADDRESS
CALL NZ,CIO_ADDENT ; ADD ENTRY IF DUART FOUND, BC:DE
POP BC ; RESTORE LOOP CONTROL
;
DUART_PREINIT1:
LD DE,DUART_CFGSIZ ; SIZE OF CFG ENTRY
ADD IY,DE ; BUMP IY TO NEXT ENTRY
DJNZ DUART_PREINIT0 ; LOOP UNTIL DONE
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
; DUART INITIALIZATION ROUTINE
;
DUART_INITUNIT:
; DETECT THE PRESENCE OF A DUART
CALL DUART_DETECT ; DETERMINE DUART TYPE
LD (IY + 1),A ; ALSO SAVE IN CONFIG TABLE
OR A ; SET FLAGS
RET Z ; ABORT IF NOTHING THERE
; UPDATE WORKING DUART DEVICE NUM
LD HL,DUART_DEV ; POINT TO CURRENT DUART DEVICE NUM
LD A,(HL) ; PUT IN ACCUM
INC (HL) ; INCREMENT IT (FOR NEXT LOOP)
LD (IY),A ; UDPATE UNIT NUM
; SET DEFAULT CONFIG
LD DE,-1 ; LEAVE CONFIG ALONE
JP DUART_INITDEV ; IMPLEMENT IT AND RETURN
;
;
;
DUART_INIT:
LD B,DUART_CFGCNT ; COUNT OF POSSIBLE DUART UNITS
LD IY,DUART_CFG ; POINT TO START OF CFG TABLE
DUART_INIT1:
PUSH BC ; SAVE LOOP CONTROL
LD A,(IY + 1) ; GET DUART TYPE
OR A ; SET FLAGS
CALL NZ,DUART_PRTCFG ; PRINT IF NOT ZERO
POP BC ; RESTORE LOOP CONTROL
LD DE,DUART_CFGSIZ ; SIZE OF CFG ENTRY
ADD IY,DE ; BUMP IY TO NEXT ENTRY
DJNZ DUART_INIT1 ; LOOP TILL DONE
;
XOR A ; SIGNAL SUCCESS
RET ; DONE
;
; DRIVER FUNCTION TABLE
;
DUART_FNTBL:
.DW DUART_IN
.DW DUART_OUT
.DW DUART_IST
.DW DUART_OST
.DW DUART_INITDEV
.DW DUART_QUERY
.DW DUART_DEVICE
#IF (($ - DUART_FNTBL) != (CIO_FNCNT * 2))
.ECHO "*** INVALID DUART FUNCTION TABLE ***\n"
#ENDIF
;
;
;
DUART_IN:
CALL DUART_IST ; RECEIVED CHAR READY?
JR Z,DUART_IN ; LOOP IF NOT
DUART_INP(DUART_RX) ; GET CHAR READ IN A
LD E,A ; CHAR READ TO E
XOR A ; SIGNAL SUCCESS
RET ; AND DONE
;
;
;
DUART_OUT:
CALL DUART_OST ; READY FOR CHAR?
JR Z,DUART_OUT ; LOOP IF NOT
LD A,E ; GET CHAR TO SEND IN A
DUART_OUTP(DUART_TX) ; SEND CHAR FROM A
XOR A ; SIGNAL SUCCESS
RET
;
;
;
DUART_IST:
DUART_INP(DUART_SR) ; GET CHANNEL STATUS REGISTER IN A
AND DUART_SR_RXRDY ; ISOLATE RXRDY BIT
JP Z,CIO_IDLE ; NOT READY, RETURN VIA IDLE PROCESSING
XOR A ; ZERO ACCUM
INC A ; ACCUM := 1 TO SIGNAL 1 CHAR WAITING
RET ; DONE
;
;
;
DUART_OST:
DUART_INP(DUART_SR) ; GET CHANNEL STATUS REGISTER IN A
AND DUART_SR_TXRDY ; ISOLATE TXRDY BIT
JP Z,CIO_IDLE ; NOT READY, RETURN VIA IDLE PROCESSING
XOR A ; ZERO ACCUM
INC A ; ACCUM := 1 TO SIGNAL 1 BUFFER POSITION
RET ; DONE
;
;
;
DUART_INITDEV:
; TEST FOR -1 WHICH MEANS USE CURRENT CONFIG (JUST REINIT)
LD A,D ; TEST DE FOR
AND E ; ... VALUE OF -1
INC A ; ... SO Z SET IF -1
JR NZ,DUART_INITDEV1 ; IF DE == -1, REINIT CURRENT CONFIG
;
; LOAD EXISTING CONFIG TO REINIT
LD E,(IY + 7) ; LOW BYTE
LD D,(IY + 8) ; HIGH BYTE
;
DUART_INITDEV1:
; GET CLOCK SELECT FROM TABLE
LD HL,DUART_BAUDTBL ; GET START OF TABLE IN HL
LD A,D ; GET CONFIG MSB
AND $1F ; ISOLATE ENCODED BAUD RATE
CALL ADDHLA ; HL -> ENTRY
LD A,(HL) ; A = ENTRY
INC A ; A = $FF?
JR Z,DUART_INITDEVZ ; INVALID RATE, ERROR OUT
DEC A ; GET ORIGINAL VALUE BACK
;
; GOT A VALID RATE, COMMIT NEW CONFIG
LD (IY + 7),E ; SAVE LOW WORD
LD (IY + 8),D ; SAVE HI WORD
LD (IY + 5),A ; SAVE BAUD TABLE ENTRY
;
; START OF ACTUAL DUART CHANNEL CONFIGURATION
LD L,A ; SAVE BAUD TABLE ENTRY IN L
LD A,DUART_CR_DIS_RX | DUART_CR_DIS_TX
DUART_OUTP(DUART_CR) ; DISABLE RECEIVER AND TRANSMITTER
LD A,DUART_CR_RESET_RX
DUART_OUTP(DUART_CR) ; RESET RECEIVER
LD A,DUART_CR_RESET_TX
DUART_OUTP(DUART_CR) ; RESET TRANSMITTER
LD A,DUART_CR_RESET_ERR
DUART_OUTP(DUART_CR) ; RESET ERROR STATUS
LD A,L ; GET BAUD TABLE ENTRY IN A
AND DUART_BAUD_X1 ; SEE IF SELECT EXTEND BIT SHOULD BE SET
JR Z,DUART_INITDEV2 ; NO, CLEAR IT
LD A,DUART_CR_SET_RX_X ; YES, SET EXTEND BIT
DUART_OUTP(DUART_CR) ; SET FOR RECEIVER
LD A,DUART_CR_SET_TX_X
DUART_OUTP(DUART_CR) ; SET FOR TRANSMITTER
JR DUART_INITDEV3
;
DUART_INITDEV2:
; CLEAR EXTEND BIT
LD A,DUART_CR_CLR_RX_X
DUART_OUTP(DUART_CR) ; CLEAR FOR RECEIVER
LD A,DUART_CR_CLR_TX_X
DUART_OUTP(DUART_CR) ; CLEAR FOR TRANSMITTER
;
DUART_INITDEV3:
; SET BRG CLOCK SELECT
LD A,L ; GET BAUD TABLE ENTRY IN A
AND $0F ; GET CLOCK SELECT BITS
LD L,A ; SAVE IT IN A
RLA
RLA
RLA
RLA ; MOVE IT INTO THE HIGH NIBBLE
OR L ; AND MERGE BACK IN LOW NIBBLE
DUART_OUTP(DUART_CSR) ; SET CLOCK SELECT
;
; SET PARITY AND WORD SIZE
LD A,DUART_CR_MR1
DUART_OUTP(DUART_CR) ; SET MR POINTER TO MR1
LD A,E ; GET LOW WORD OF CONFIG IN A
AND %00111000 ; KEEP ONLY PARITY BITS
RRA
RRA
RRA ; SHIFT PARITY BITS INTO AN INDEX
LD HL,DUART_PARTBL ; GET START OF TABLE IN HL
CALL ADDHLA ; HL -> ENTRY
LD B,(HL) ; BUILD MR1 IN B
LD A,E ; GET LOW WORD OF CONFIG IN A
AND %00000011 ; WORD LENGTH BITS ARE THE SAME
OR B ; MERGE PARITY BITS
OR DUART_MR1_RXRTS ; ALWAYS ENABLE RECEIVER CONTROL OF RTS
DUART_OUTP(DUART_MR) ; WRITE MR1 (AND SET MR POINTER TO MR2)
;
; SET STOP BITS
LD A,E ; GET LOW WORD OF CONFIG IN A
LD B,DUART_MR2_STOP1 ; BUILD MR2 IN B
AND %00000100 ; KEEP ONLY STOP BITS
JR Z,DUART_INITDEV4 ; 1 STOP BIT
LD B,DUART_MR2_STOP2 ; 2 STOP BITS, REPLACE B
;
DUART_INITDEV4:
LD A,B ; GET MR2 IN A
OR DUART_MR2_TXCTS ; ALWAYS ENABLE CTS CONTROL OF TRANSMITTER
DUART_OUTP(DUART_MR) ; WRITE MR2
;
; RE-ENABLE RECEIVER AND TRANSMITTER
LD A,DUART_CR_ENA_RX | DUART_CR_ENA_TX
DUART_OUTP(DUART_CR) ; ENABLE RECEIVER AND TRANSMITTER
;
; EXPLICITLY ASSERT RTS (SEEMS TO BE REQUIRED FOR SOME CHIPS TO DO AUTO-RTS)
LD L,%00000001 ; RTS FOR CHANNEL A IS IN BIT 0
LD A,(IY + 2) ; GET MODULE IN A
AND L ; MASK ALL BUT CHANNEL
JR Z,DUART_INITDEV5 ; ZERO INDICATES CHANNEL A
SLA L ; MOVE INTO BIT 1, RTS FOR CHANNEL B
;
DUART_INITDEV5:
LD A,(IY + 3) ; GET BASE ADDRESS OF CHIP
ADD A,DUART_SOPR ; SET OUTPUT BITS
LD C,A ; GET PORT IN C
OUT (C),L ; OUTPUT PORT IS INVERTED BUT SO IS RTS
;
XOR A ; SIGNAL SUCCESS
RET
;
DUART_INITDEVZ:
; INVALID BAUD RATE
DEC A ; A WAS $00, GET BACK $FF
RET ; RETURN ERROR STATUS
;
DUART_BAUDTBL:
.DB %0000 | DUART_BAUD_X1 ; 75
.DB %0011 | DUART_BAUD_X1 ; 150
.DB %0100 ; 300
.DB %0101 ; 600
.DB %0110 ; 1200
.DB %1000 ; 2400
.DB %1001 ; 4800
.DB %1011 ; 9600
.DB %1100 | DUART_BAUD_X1 ; 19200
.DB %1100 ; 38400
.DB DUART_BAUD_INV ; 76800
.DB DUART_BAUD_INV ; 153600
.DB DUART_BAUD_INV ; 307200
.DB DUART_BAUD_INV ; 614400
.DB DUART_BAUD_INV ; 1228800
.DB DUART_BAUD_INV ; 2457600
.DB DUART_BAUD_INV ; 225
.DB DUART_BAUD_INV ; 450
.DB DUART_BAUD_INV ; 900
.DB %1010 | DUART_BAUD_X1 ; 1800
.DB %0100 | DUART_BAUD_X1 ; 3600
.DB %1010 ; 7200
.DB %0101 | DUART_BAUD_X1 ; 14400
.DB %0110 | DUART_BAUD_X1 ; 28800
.DB %0111 | DUART_BAUD_X1 ; 57600
.DB %1000 | DUART_BAUD_X1 ; 115200
.DB DUART_BAUD_INV ; 230400
.DB DUART_BAUD_INV ; 460800
.DB DUART_BAUD_INV ; 921600
.DB DUART_BAUD_INV ; 1843200
.DB DUART_BAUD_INV ; 3686400
.DB DUART_BAUD_INV ; 7372800
;
#IF (($ - DUART_BAUDTBL) != 32)
.ECHO "*** ERROR: DUART_BAUDTBL MUST CONTAIN 32 ENTRIES!!!\n"
!!! ; FORCE AN ASSEMBLY ERROR
#ENDIF
;
DUART_PARTBL:
.DB DUART_MR1_PARNONE ; 0 = NO PARITY (ALSO ALL EVEN ENTRIES)
.DB DUART_MR1_PARODD ; 1 = ODD PARITY
.DB DUART_MR1_PARNONE
.DB DUART_MR1_PAREVEN ; 3 = EVEN PARITY
.DB DUART_MR1_PARNONE
.DB DUART_MR1_PARMARK ; 5 = MARK PARITY
.DB DUART_MR1_PARNONE
.DB DUART_MR1_PARSPACE ; 7 = SPACE PARITY
;
#IF (($ - DUART_PARTBL) != 8)
.ECHO "*** ERROR: DUART_PARTBL MUST CONTAIN 8 ENTRIES!!!\n"
!!! ; FORCE AN ASSEMBLY ERROR
#ENDIF
;
;
;
DUART_QUERY:
LD E,(IY + 7) ; FIRST CONFIG BYTE TO E
LD D,(IY + 8) ; SECOND CONFIG BYTE TO D
XOR A ; SIGNAL SUCCESS
RET ; DONE
;
;
;
DUART_DEVICE:
LD D,CIODEV_DUART ; D := DEVICE TYPE
LD E,(IY) ; E := PHYSICAL UNIT
LD C,$00 ; C := DEVICE TYPE, 0x00 IS RS-232
XOR A ; SIGNAL SUCCESS
RET
;
; DUART DETECTION ROUTINE
;
DUART_DETECT:
;
; SEE IF MR1 AND MR2 ARE DISTINCT
LD A,DUART_CR_MR1 ; SET MR POINTER TO MR1
DUART_OUTP(DUART_CR) ; SEND COMMAND
LD A,1 ; WRITE TEST VALUE TO MR1
DUART_OUTP(DUART_MR) ; WRITE MR1 AND SET POINTER TO MR2
XOR A ; WRITE 0 TO MR2
DUART_OUTP(DUART_MR) ; WRITE MR2 AND KEEP POINTER TO MR2
LD A,DUART_CR_MR1 ; SET MR POINTER TO MR1 (AGAIN)
DUART_OUTP(DUART_CR) ; SEND COMMAND
DUART_INP(DUART_MR) ; GET VALUE OF MR1 IN A
CP 1 ; CHECK FOR TEST VALUE
JR NZ,DUART_DETECT_NONE ; NOPE, UNKNOWN DEVICE OR NOT PRESETN
;
; TEST FOR FUNCTIONAL GENERAL PURPOSE REG, IF NOT, WE HAVE A 2681
LD A,$5A ; LOAD TEST VALUE
DUART_OUTP(DUART_GPR) ; PUT IT IN GENERAL PURPOSE REGISTER
DUART_INP(DUART_GPR) ; READ IT BACK
CP $5A ; CHECK IT
JR NZ,DUART_DETECT_2681 ; OLD CHIP
;
; TEST FOR MR0 REGISTER, IN WHICH CASE WE HAVE A 2692 OF SOME SORT
LD A,DUART_CR_MR0 ; SET MR POINTER TO MR0
DUART_OUTP(DUART_CR) ; THIS IS HARMLESS ON OTHER CHIPS
LD A,1 ; WRITE TEST VALUE TO MR0
DUART_OUTP(DUART_MR) ; WRITE TO MR0 ON 2692, MR2 STILL SET ON OTHERS
LD A,DUART_CR_MR1 ; SET MR POINTER TO MR1
DUART_OUTP(DUART_CR) ; THIS WORKS ON ALL CHIPS
XOR A ; WRITE 0 TO MR1
DUART_OUTP(DUART_MR) ; WRITE MR1 AND SET POINTER TO MR2
XOR A ; ALSO WRITE 0 TO MR2
DUART_OUTP(DUART_MR) ; WRITE MR2 AND KEEP POINTER TO MR2
LD A,DUART_CR_MR0 ; SET POINTER TO MR0
DUART_OUTP(DUART_CR) ; POINTER IS STILL MR2 ON OTHER CHIPS
DUART_INP(DUART_MR) ; GET VALUE OF MR0 IN A
CP 1 ; CHECK FOR TEST VALUE
JR Z,DUART_DETECT_2692 ; YES, MUST BE A '92 WITH MR0
JR DUART_DETECT_XR88C681 ; ASSUME WE HAVE A FANCY EXAR CHIP
;
DUART_DETECT_NONE:
LD A,DUART_NONE
RET
;
DUART_DETECT_2681:
LD A,DUART_2681
RET
;
DUART_DETECT_2692:
LD A,DUART_2692
RET
;
DUART_DETECT_XR88C681
LD A,DUART_XR88C681
RET
;
;
;
DUART_PRTCFG:
; ANNOUNCE PORT
CALL NEWLINE ; FORMATTING
PRTS("DUART$") ; FORMATTING
LD A,(IY) ; DEVICE NUM
CALL PRTDECB ; PRINT DEVICE NUM
PRTS(": IO=0x$") ; FORMATTING
LD A,(IY + 4) ; GET CHANNEL BASE PORT
CALL PRTHEXBYTE ; PRINT BASE PORT
; PRINT THE DUART TYPE
CALL PC_SPACE ; FORMATTING
LD A,(IY + 1) ; GET DUART TYPE BYTE
RLCA ; MAKE IT A WORD OFFSET
LD HL,DUART_TYPE_MAP ; POINT HL TO TYPE MAP TABLE
CALL ADDHLA ; HL := ENTRY
LD E,(HL) ; DEREFERENCE
INC HL ; ...
LD D,(HL) ; ... TO GET STRING POINTER
CALL WRITESTR ; PRINT IT
;
; ALL DONE IF NO DUART WAS DETECTED
LD A,(IY + 1) ; GET DUART TYPE BYTE
OR A ; SET FLAGS
RET Z ; IF ZERO, NOT PRESENT
;
PRTS(" MODE=$") ; FORMATTING
LD E,(IY + 7) ; LOAD CONFIG
LD D,(IY + 8) ; ... WORD TO DE
CALL PS_PRTSC0 ; PRINT CONFIG
;
XOR A
RET
;
; ROUTINES TO READ/WRITE PORTS INDIRECTLY
;
; READ VALUE OF DUART PORT ON TOS INTO REGISTER A
;
DUART_INP_IMP:
EX (SP),HL ; SWAP HL AND TOS
PUSH BC ; PRESERVE BC
LD A,(IY + 4) ; GET DUART IO BASE PORT
OR (HL) ; OR IN REGISTER ID BITS
LD C,A ; C := PORT
IN A,(C) ; READ PORT INTO A
POP BC ; RESTORE BC
INC HL ; BUMP HL PAST REG ID PARM
EX (SP),HL ; SWAP BACK HL AND TOS
RET
;
; WRITE VALUE IN REGISTER A TO DUART PORT ON TOS
;
DUART_OUTP_IMP:
EX (SP),HL ; SWAP HL AND TOS
PUSH BC ; PRESERVE BC
LD B,A ; PUT VALUE TO WRITE IN B
LD A,(IY + 4) ; GET DUART IO BASE PORT
OR (HL) ; OR IN REGISTER ID BITS
LD C,A ; C := PORT
OUT (C),B ; WRITE VALUE TO PORT
POP BC ; RESTORE BC
INC HL ; BUMP HL PAST REG ID PARM
EX (SP),HL ; SWAP BACK HL AND TOS
RET
;
;
;
DUART_TYPE_MAP:
.DW DUART_STR_NONE
.DW DUART_STR_2681
.DW DUART_STR_2692
.DW DUART_STR_XR88C681
DUART_STR_NONE .DB "<NOT PRESENT>$"
DUART_STR_2681 .DB "2681$"
DUART_STR_2692 .DB "2692$"
DUART_STR_XR88C681 .DB "XR88C681$"
;
; WORKING VARIABLES
;
DUART_DEV .DB 0 ; DEVICE NUM USED DURING INIT
;
; DUART PORT TABLE
;
DUART_CFG:
;
DUART0A_CFG:
; 1ST DUART MODULE CHANNEL A
.DB 0 ; IY DEVICE NUMBER (SET DURING INIT)
.DB 0 ; IY+1 DUART TYPE (SET DURING INIT)
.DB %00000000 ; IY+2 MODULE 0, CHANNEL A
.DB DUART0BASE ; IY+3 BASE PORT (CHIP)
.DB DUART0BASE + $00 ; IY+4 BASE PORT (CHANNEL)
.DB 0 ; IY+5 BAUD TABLE ENTRY (SET DURING INITDEV)
.DB 0 ; IY+6 SHADOW ACR (SET DURING INITDEV)
.DW DUART0ACFG ; IY+7 LINE CONFIGURATION
.DW DUART0CLK & $FFFF ; IY+9 CLOCK FREQ AS
.DW DUART0CLK >> 16 ; IY+11 ... DWORD VALUE
;
DUART_CFGSIZ .EQU $ - DUART_CFG ; SIZE OF ONE CFG TABLE ENTRY
;
DUART0B_CFG:
; 1ST DUART MODULE CHANNEL B
.DB 0 ; DEVICE NUMBER (SET DURING INIT)
.DB 0 ; DUART TYPE (SET DURING INIT)
.DB %00000001 ; MODULE 0, CHANNEL B
.DB DUART0BASE ; BASE PORT (CHIP)
.DB DUART0BASE + $08 ; BASE PORT (CHANNEL)
.DB 0 ; BAUD TABLE ENTRY (SET DURING INITDEV)
.DB 0 ; SHADOW ACR (SET DURING INITDEV)
.DW DUART0BCFG ; LINE CONFIGURATION
.DW DUART0CLK & $FFFF ; CLOCK FREQ AS
.DW DUART0CLK >> 16 ; ... DWORD VALUE
;
#IF (DUARTCNT >= 2)
;
DUART1A_CFG:
; 2ND DUART MODULE CHANNEL A
.DB 0 ; DEVICE NUMBER (SET DURING INIT)
.DB 0 ; DUART TYPE (SET DURING INIT)
.DB %00000010 ; MODULE 1, CHANNEL A
.DB DUART1BASE ; BASE PORT (CHIP)
.DB DUART1BASE + $00 ; BASE PORT (CHANNEL)
.DB 0 ; BAUD TABLE ENTRY (SET DURING INITDEV)
.DB 0 ; SHADOW ACR (SET DURING INITDEV)
.DW DUART1ACFG ; LINE CONFIGURATION
.DW DUART1CLK & $FFFF ; CLOCK FREQ AS
.DW DUART1CLK >> 16 ; ... DWORD VALUE
;
DUART1B_CFG:
; 2ND DUART MODULE CHANNEL B
.DB 0 ; DEVICE NUMBER (SET DURING INIT)
.DB 0 ; DUART TYPE (SET DURING INIT)
.DB %00000011 ; MODULE 1, CHANNEL B
.DB DUART1BASE ; BASE PORT (CHIP)
.DB DUART1BASE + $80 ; BASE PORT (CHANNEL)
.DB 0 ; BAUD TABLE ENTRY (SET DURING INITDEV)
.DB 0 ; SHADOW ACR (SET DURING INITDEV)
.DW DUART1BCFG ; LINE CONFIGURATION
.DW DUART1CLK & $FFFF ; CLOCK FREQ AS
.DW DUART1CLK >> 16 ; ... DWORD VALUE
;
#ENDIF
;
DUART_CFGCNT .EQU ($ - DUART_CFG) / DUART_CFGSIZ

15
Source/HBIOS/hbios.asm

@ -1625,6 +1625,9 @@ HB_PCINITTBL:
#IF (ASCIENABLE)
.DW ASCI_PREINIT
#ENDIF
#IF (DUARTENABLE)
.DW DUART_PREINIT
#ENDIF
#IF (UARTENABLE)
.DW UART_PREINIT
#ENDIF
@ -1659,6 +1662,9 @@ HB_INITTBL:
#IF (ASCIENABLE)
.DW ASCI_INIT
#ENDIF
#IF (DUARTENABLE)
.DW DUART_INIT
#ENDIF
#IF (UARTENABLE)
.DW UART_INIT
#ENDIF
@ -2985,6 +2991,15 @@ SIZ_ASCI .EQU $ - ORG_ASCI
.ECHO " bytes.\n"
#ENDIF
;
#IF (DUARTENABLE)
ORG_DUART .EQU $
#INCLUDE "duart.asm"
SIZ_DUART .EQU $ - ORG_DUART
.ECHO "DUART occupies "
.ECHO SIZ_DUART
.ECHO " bytes.\n"
#ENDIF
;
#IF (UARTENABLE)
ORG_UART .EQU $
#INCLUDE "uart.asm"

1
Source/HBIOS/hbios.inc

@ -98,6 +98,7 @@ CIODEV_SIO .EQU $50
CIODEV_ACIA .EQU $60
CIODEV_PIO .EQU $70
CIODEV_UF .EQU $80
CIODEV_DUART .EQU $90
;
; SUB TYPES OF CHAR DEVICES
;

Loading…
Cancel
Save