From e911e93aaf59a2b3b7fe8dc647477d4ddda65498 Mon Sep 17 00:00:00 2001 From: Chris Odorjan Date: Sat, 25 Apr 2020 00:50:18 -0400 Subject: [PATCH 1/7] DUART: preliminary implementation assumes XR88C681 for now --- Source/HBIOS/cfg_rcz80.asm | 12 + Source/HBIOS/duart.asm | 684 +++++++++++++++++++++++++++++++++++++ Source/HBIOS/hbios.asm | 15 + Source/HBIOS/hbios.inc | 1 + 4 files changed, 712 insertions(+) create mode 100644 Source/HBIOS/duart.asm diff --git a/Source/HBIOS/cfg_rcz80.asm b/Source/HBIOS/cfg_rcz80.asm index f94c1694..f0b21fa2 100644 --- a/Source/HBIOS/cfg_rcz80.asm +++ b/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 diff --git a/Source/HBIOS/duart.asm b/Source/HBIOS/duart.asm new file mode 100644 index 00000000..b68347f0 --- /dev/null +++ b/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 "$" +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 diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index 55ed757e..da921f2f 100644 --- a/Source/HBIOS/hbios.asm +++ b/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" diff --git a/Source/HBIOS/hbios.inc b/Source/HBIOS/hbios.inc index 6c166307..6c36b826 100644 --- a/Source/HBIOS/hbios.inc +++ b/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 ; From 3bd2eb431a86ff747695722f2878a9b5b3bd9bba Mon Sep 17 00:00:00 2001 From: Chris Odorjan Date: Sat, 25 Apr 2020 23:46:12 -0400 Subject: [PATCH 2/7] spelling + fixes --- Source/HBIOS/duart.asm | 111 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 100 insertions(+), 11 deletions(-) diff --git a/Source/HBIOS/duart.asm b/Source/HBIOS/duart.asm index b68347f0..126c817f 100644 --- a/Source/HBIOS/duart.asm +++ b/Source/HBIOS/duart.asm @@ -173,14 +173,15 @@ DUART_PREINIT: 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 + CALL DUART_DETECT ; DETERMINE DUART TYPE POP BC ; RESTORE LOOP CONTROL -; - LD A,(IY + 1) ; GET THE DUART TYPE DETECTED + LD (IY + 1),A ; SAVE TYPE IN CONFIG TABLE OR A ; SET FLAGS JR Z,DUART_PREINIT1 ; SKIP IT IF NOTHING FOUND ; PUSH BC ; SAVE LOOP CONTROL + PUSH IY + POP DE ; DE := UNIT INSTANCE TABLE ADDRESS LD BC,DUART_FNTBL ; BC := FUNCTION TABLE ADDRESS CALL NZ,CIO_ADDENT ; ADD ENTRY IF DUART FOUND, BC:DE POP BC ; RESTORE LOOP CONTROL @@ -189,15 +190,25 @@ DUART_PREINIT1: LD DE,DUART_CFGSIZ ; SIZE OF CFG ENTRY ADD IY,DE ; BUMP IY TO NEXT ENTRY DJNZ DUART_PREINIT0 ; LOOP UNTIL DONE +; + LD B,DUART_CFGCNT ; LOOP CONTROL + LD IY,DUART_CFG ; POINT TO START OF CFG TABLE +DUART_PREINIT2: + PUSH BC ; SAVE LOOP CONTROL + CALL DUART_INITUNIT ; INITIALIZE UNIT + POP BC ; RESTORE LOOP CONTROL + LD DE,DUART_CFGSIZ ; SIZE OF CFG ENTRY + ADD IY,DE ; BUMP IY TO NEXT ENTRY + DJNZ DUART_PREINIT2 ; 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 + ; CHECK IF PORT IS PRESENT + LD A,(IY + 1) ; GET TYPE FROM CONFIG TABLE OR A ; SET FLAGS RET Z ; ABORT IF NOTHING THERE @@ -298,14 +309,36 @@ DUART_INITDEV: LD D,(IY + 8) ; HIGH BYTE ; DUART_INITDEV1: +#IF (DUART_DEBUG) + PRTS(" [TYPE=$") + + ; DEBUG: DUMP DUART TYPE + LD A,(IY + 1) + CALL PRTHEXBYTE + + ; DEBUG: DUMP PREVIOUS BAUD TABLE ENTRY + PRTS(" OLDBAUDTBL=$") + LD A,(IY + 5) + CALL PRTHEXBYTE +#ENDIF +; ; 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 +; +#IF (DUART_DEBUG) + ; DEBUG: DUMP BAUD TABLE ENTRY + PUSH AF + PRTS(" BAUDTBL=$") + CALL PRTHEXBYTE + POP AF +#ENDIF +; INC A ; A = $FF? - JR Z,DUART_INITDEVZ ; INVALID RATE, ERROR OUT + JP Z,DUART_INITDEVZ ; INVALID RATE, ERROR OUT DEC A ; GET ORIGINAL VALUE BACK ; ; GOT A VALID RATE, COMMIT NEW CONFIG @@ -330,6 +363,12 @@ DUART_INITDEV1: DUART_OUTP(DUART_CR) ; SET FOR RECEIVER LD A,DUART_CR_SET_TX_X DUART_OUTP(DUART_CR) ; SET FOR TRANSMITTER +; +#IF (DUART_DEBUG) + ; DEBUG: DUMP BRG SELECT EXTEND BIT + PRTS(" X=1$") +#ENDIF +; JR DUART_INITDEV3 ; DUART_INITDEV2: @@ -339,16 +378,30 @@ DUART_INITDEV2: LD A,DUART_CR_CLR_TX_X DUART_OUTP(DUART_CR) ; CLEAR FOR TRANSMITTER ; +#IF (DUART_DEBUG) + ; DEBUG: DUMP BRG SELECT EXTEND BIT + PRTS(" X=0$") +#ENDIF +; 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 + LD L,A ; SAVE IT IN L RLA RLA RLA RLA ; MOVE IT INTO THE HIGH NIBBLE OR L ; AND MERGE BACK IN LOW NIBBLE +; +#IF (DUART_DEBUG) + ; DEBUG: DUMP CLOCK SELECT REGISTER + PUSH AF + PRTS(" CSR=$") + CALL PRTHEXBYTE + POP AF +#ENDIF +; DUART_OUTP(DUART_CSR) ; SET CLOCK SELECT ; ; SET PARITY AND WORD SIZE @@ -366,6 +419,15 @@ DUART_INITDEV3: AND %00000011 ; WORD LENGTH BITS ARE THE SAME OR B ; MERGE PARITY BITS OR DUART_MR1_RXRTS ; ALWAYS ENABLE RECEIVER CONTROL OF RTS +; +#IF (DUART_DEBUG) + ; DEBUG: DUMP MODE REGISTER 1 + PUSH AF + PRTS(" MR1=$") + CALL PRTHEXBYTE + POP AF +#ENDIF +; DUART_OUTP(DUART_MR) ; WRITE MR1 (AND SET MR POINTER TO MR2) ; ; SET STOP BITS @@ -377,7 +439,16 @@ DUART_INITDEV3: ; DUART_INITDEV4: LD A,B ; GET MR2 IN A - OR DUART_MR2_TXCTS ; ALWAYS ENABLE CTS CONTROL OF TRANSMITTER + ;OR DUART_MR2_TXCTS ; ALWAYS ENABLE CTS CONTROL OF TRANSMITTER +; +#IF (DUART_DEBUG) + ; DEBUG: DUMP MODE REGISTER 2 + PUSH AF + PRTS(" MR2=$") + CALL PRTHEXBYTE + POP AF +#ENDIF +; DUART_OUTP(DUART_MR) ; WRITE MR2 ; ; RE-ENABLE RECEIVER AND TRANSMITTER @@ -396,11 +467,22 @@ DUART_INITDEV5: 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 +; +#IF (DUART_DEBUG) + PRTS(" SOPR=$") + LD A,L + CALL PRTHEXBYTE + PRTC(']') +#ENDIF ; XOR A ; SIGNAL SUCCESS RET ; DUART_INITDEVZ: +; +#IF (DUART_DEBUG) + PRTC(']') +#ENDIF ; INVALID BAUD RATE DEC A ; A WAS $00, GET BACK $FF RET ; RETURN ERROR STATUS @@ -491,7 +573,7 @@ DUART_DETECT: 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 + JR NZ,DUART_DETECT_NONE ; NOPE, UNKNOWN DEVICE OR NOT PRESENT ; ; TEST FOR FUNCTIONAL GENERAL PURPOSE REG, IF NOT, WE HAVE A 2681 LD A,$5A ; LOAD TEST VALUE @@ -567,6 +649,13 @@ DUART_PRTCFG: LD E,(IY + 7) ; LOAD CONFIG LD D,(IY + 8) ; ... WORD TO DE CALL PS_PRTSC0 ; PRINT CONFIG +; +#IF (DUART_DEBUG) + ; DEBUG: DUMP BAUD TABLE ENTRY + PRTS(" BAUDTBL=$") + LD A,(IY + 5) + CALL PRTHEXBYTE +#ENDIF ; XOR A RET @@ -672,7 +761,7 @@ DUART1B_CFG: .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 DUART1BASE + $08 ; BASE PORT (CHANNEL) .DB 0 ; BAUD TABLE ENTRY (SET DURING INITDEV) .DB 0 ; SHADOW ACR (SET DURING INITDEV) .DW DUART1BCFG ; LINE CONFIGURATION From db24d6e4351dee5e69de235056053397e3996885 Mon Sep 17 00:00:00 2001 From: Chris Odorjan Date: Sat, 25 Apr 2020 23:46:37 -0400 Subject: [PATCH 3/7] detect/initialize DUART _after_ 16550 prevents 16550 detection from stomping on DUART registers (untested: does the DUART detection stomp on the 16550?) add DUART to serial device strings list --- Source/HBIOS/hbios.asm | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index da921f2f..c586badc 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -1625,12 +1625,12 @@ HB_PCINITTBL: #IF (ASCIENABLE) .DW ASCI_PREINIT #ENDIF -#IF (DUARTENABLE) - .DW DUART_PREINIT -#ENDIF #IF (UARTENABLE) .DW UART_PREINIT #ENDIF +#IF (DUARTENABLE) + .DW DUART_PREINIT +#ENDIF #IF (SIOENABLE) .DW SIO_PREINIT #ENDIF @@ -1662,12 +1662,12 @@ HB_INITTBL: #IF (ASCIENABLE) .DW ASCI_INIT #ENDIF -#IF (DUARTENABLE) - .DW DUART_INIT -#ENDIF #IF (UARTENABLE) .DW UART_INIT #ENDIF +#IF (DUARTENABLE) + .DW DUART_INIT +#ENDIF #IF (SIOENABLE) .DW SIO_INIT #ENDIF @@ -2991,15 +2991,6 @@ 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" @@ -3009,6 +3000,15 @@ SIZ_UART .EQU $ - ORG_UART .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 (SIOENABLE) ORG_SIO .EQU $ #INCLUDE "sio.asm" @@ -3913,7 +3913,7 @@ PS_FLP_DSTR: .TEXT "SD$" ; PS_FLPSD ; PS_SDSTRREF: .DW PS_SDUART, PS_SDASCI, PS_SDTERM - .DW PS_SDPRPCON, PS_SDPPPCON, PS_SDSIO, PS_SDACIA, PS_SDPIO,PS_SDUF + .DW PS_SDPRPCON, PS_SDPPPCON, PS_SDSIO, PS_SDACIA, PS_SDPIO,PS_SDUF,PS_SDDUART ; PS_SDUART .TEXT "UART$" PS_SDASCI .TEXT "ASCI$" @@ -3924,6 +3924,7 @@ PS_SDSIO .TEXT "SIO$" PS_SDACIA .TEXT "ACIA$" PS_SDPIO .TEXT "PORT$" PS_SDUF .TEXT "UF$" +PS_SDDUART .TEXT "DUART$" ; ; CHARACTER SUB TYPE STRINGS ; From ceb1826bedd0bbdc66b645bd03ce8e085a56007e Mon Sep 17 00:00:00 2001 From: Chris Odorjan Date: Wed, 29 Apr 2020 13:45:39 -0400 Subject: [PATCH 4/7] DUART: try not to step on 16x50 UART configuration --- Source/HBIOS/duart.asm | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Source/HBIOS/duart.asm b/Source/HBIOS/duart.asm index 126c817f..5bbda846 100644 --- a/Source/HBIOS/duart.asm +++ b/Source/HBIOS/duart.asm @@ -562,6 +562,29 @@ DUART_DEVICE: ; DUART_DETECT: ; + ; FIRST SEE IF IT LOOKS LIKE A 16X50-STYLE UART + LD A,(IY + 3) ; GET BASE PORT OF CHIP + ADD A,6 ; BASE + 6 = CTU (DUART), MSR (1ST 16X50) + LD B,A ; B := CTU/MSR PORT ADDRESS + INC A ; BASE + 7 = CTL (DUART), SCR (1ST 16X50) + LD D,A ; D := CTL/SCR PORT ADDRESS + ADD A,7 ; BASE + 14 = STCR (DUART), MSR (2ND 16X50) + LD E,A ; E := STCR/MSR PORT ADDRESS + LD A,$A5 ; TEST VALUE + LD C,B ; CTU + OUT (C),A ; WRITE TEST VALUE TO CTU + LD A,$FF ; LARGE VALUE TO PREVENT CTL FROM ROLLING OVER WHILE WE TEST + LD C,D ; CTL + OUT (C),A ; WRITE LARGE VALUE TO CTL + LD C,E ; STCR + IN A,(C) ; START COUNTER/TIMER (LATCH CTU, CTL) + LD C,B ; CTU + IN A,(C) ; READ BACK TEST VALUE + CP $A5 ; CHECK FOR TEST VALUE + JR NZ,DUART_DETECT_NONE ; NO, PROBABLY NOT A DUART + IN A,(C) ; CHECK TEST VALUE AGAIN, + CP $A5 ; ... IN RARE CASE DELTAS IN MSR WERE SET TO OUR TEST + JR NZ,DUART_DETECT_NONE ; ALMOST CERTAINLY NOT A DUART ; SEE IF MR1 AND MR2 ARE DISTINCT LD A,DUART_CR_MR1 ; SET MR POINTER TO MR1 DUART_OUTP(DUART_CR) ; SEND COMMAND From 0f0eae6bd7c57cdcbc3d02d5d68c5f5a7100e8e2 Mon Sep 17 00:00:00 2001 From: Chris Odorjan Date: Mon, 11 May 2020 21:54:33 -0400 Subject: [PATCH 5/7] 26C92 support (untested) cleanup remove debugging (it didn't work when the DUART was the primary device anyways) simplify configuration tables --- Source/HBIOS/duart.asm | 227 +++++++++++++++++------------------------ 1 file changed, 94 insertions(+), 133 deletions(-) diff --git a/Source/HBIOS/duart.asm b/Source/HBIOS/duart.asm index 5bbda846..ef1da758 100644 --- a/Source/HBIOS/duart.asm +++ b/Source/HBIOS/duart.asm @@ -74,12 +74,14 @@ 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_26C92 .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 +DUART_BAUD_X1 .EQU %01000000 ; BRG EXTEND BIT = 1 ('681) +DUART_BAUD_EXT1 .EQU %00100000 ; EXTENDED TABLE 1 ('92) +DUART_BAUD_EXT2 .EQU %00010000 ; EXTENDED TABLE 2 ('92) ; ; PER CHANNEL REGISTERS (CHANNEL A AT OFFSET 0, CHANNEL B AT OFFSET 8) ; @@ -125,7 +127,7 @@ 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_MR0 .EQU $B0 ; RESET MR POINTER TO MR0 (26C92 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) @@ -305,46 +307,29 @@ DUART_INITDEV: 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 + LD E,(IY + 8) ; LOW BYTE + LD D,(IY + 9) ; HIGH BYTE ; DUART_INITDEV1: -#IF (DUART_DEBUG) - PRTS(" [TYPE=$") - - ; DEBUG: DUMP DUART TYPE - LD A,(IY + 1) - CALL PRTHEXBYTE - - ; DEBUG: DUMP PREVIOUS BAUD TABLE ENTRY - PRTS(" OLDBAUDTBL=$") - LD A,(IY + 5) - CALL PRTHEXBYTE -#ENDIF -; ; GET CLOCK SELECT FROM TABLE - LD HL,DUART_BAUDTBL ; GET START OF TABLE IN HL + LD HL,DUART_BAUDTBL_681 ; GET START OF XR88C681 TABLE IN HL + LD A,(IY + 1) ; GET DUART TYPE + CP DUART_26C92 ; IS IT A 26C92? + JR NZ,DUART_INITDEV1A ; NO, SKIP NEXT INSTRUCTION + LD HL,DUART_BAUDTBL_92 ; GET START OF SC26C92 TABLE IN HL +; +DUART_INITDEV1A: LD A,D ; GET CONFIG MSB AND $1F ; ISOLATE ENCODED BAUD RATE CALL ADDHLA ; HL -> ENTRY LD A,(HL) ; A = ENTRY -; -#IF (DUART_DEBUG) - ; DEBUG: DUMP BAUD TABLE ENTRY - PUSH AF - PRTS(" BAUDTBL=$") - CALL PRTHEXBYTE - POP AF -#ENDIF -; INC A ; A = $FF? JP 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 + LD (IY + 8),E ; SAVE LOW WORD + LD (IY + 9),D ; SAVE HI WORD ; ; START OF ACTUAL DUART CHANNEL CONFIGURATION LD L,A ; SAVE BAUD TABLE ENTRY IN L @@ -363,12 +348,6 @@ DUART_INITDEV1: DUART_OUTP(DUART_CR) ; SET FOR RECEIVER LD A,DUART_CR_SET_TX_X DUART_OUTP(DUART_CR) ; SET FOR TRANSMITTER -; -#IF (DUART_DEBUG) - ; DEBUG: DUMP BRG SELECT EXTEND BIT - PRTS(" X=1$") -#ENDIF -; JR DUART_INITDEV3 ; DUART_INITDEV2: @@ -378,11 +357,6 @@ DUART_INITDEV2: LD A,DUART_CR_CLR_TX_X DUART_OUTP(DUART_CR) ; CLEAR FOR TRANSMITTER ; -#IF (DUART_DEBUG) - ; DEBUG: DUMP BRG SELECT EXTEND BIT - PRTS(" X=0$") -#ENDIF -; DUART_INITDEV3: ; SET BRG CLOCK SELECT LD A,L ; GET BAUD TABLE ENTRY IN A @@ -393,15 +367,6 @@ DUART_INITDEV3: RLA RLA ; MOVE IT INTO THE HIGH NIBBLE OR L ; AND MERGE BACK IN LOW NIBBLE -; -#IF (DUART_DEBUG) - ; DEBUG: DUMP CLOCK SELECT REGISTER - PUSH AF - PRTS(" CSR=$") - CALL PRTHEXBYTE - POP AF -#ENDIF -; DUART_OUTP(DUART_CSR) ; SET CLOCK SELECT ; ; SET PARITY AND WORD SIZE @@ -419,15 +384,6 @@ DUART_INITDEV3: AND %00000011 ; WORD LENGTH BITS ARE THE SAME OR B ; MERGE PARITY BITS OR DUART_MR1_RXRTS ; ALWAYS ENABLE RECEIVER CONTROL OF RTS -; -#IF (DUART_DEBUG) - ; DEBUG: DUMP MODE REGISTER 1 - PUSH AF - PRTS(" MR1=$") - CALL PRTHEXBYTE - POP AF -#ENDIF -; DUART_OUTP(DUART_MR) ; WRITE MR1 (AND SET MR POINTER TO MR2) ; ; SET STOP BITS @@ -440,15 +396,6 @@ DUART_INITDEV3: DUART_INITDEV4: LD A,B ; GET MR2 IN A ;OR DUART_MR2_TXCTS ; ALWAYS ENABLE CTS CONTROL OF TRANSMITTER -; -#IF (DUART_DEBUG) - ; DEBUG: DUMP MODE REGISTER 2 - PUSH AF - PRTS(" MR2=$") - CALL PRTHEXBYTE - POP AF -#ENDIF -; DUART_OUTP(DUART_MR) ; WRITE MR2 ; ; RE-ENABLE RECEIVER AND TRANSMITTER @@ -457,23 +404,16 @@ DUART_INITDEV4: ; ; 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 + LD A,(IY) ; GET UNIT NUMBER 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 + LD A,(IY + 2) ; 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 -; -#IF (DUART_DEBUG) - PRTS(" SOPR=$") - LD A,L - CALL PRTHEXBYTE - PRTC(']') -#ENDIF ; XOR A ; SIGNAL SUCCESS RET @@ -487,7 +427,8 @@ DUART_INITDEVZ: DEC A ; A WAS $00, GET BACK $FF RET ; RETURN ERROR STATUS ; -DUART_BAUDTBL: +DUART_BAUDTBL_681: + ; ASSUME XR88C681 RUNS AT 3.6864MHZ .DB %0000 | DUART_BAUD_X1 ; 75 .DB %0011 | DUART_BAUD_X1 ; 150 .DB %0100 ; 300 @@ -521,10 +462,40 @@ DUART_BAUDTBL: .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_BAUDTBL_92: + ; ASSUME SC26C92 RUNS AT 7.3728MHZ + .DB DUART_BAUD_INV ; 75 + .DB DUART_BAUD_INV ; 150 + .DB DUART_BAUD_INV ; 300 + .DB DUART_BAUD_INV ; 600 + .DB DUART_BAUD_INV ; 1200 + .DB DUART_BAUD_INV ; 2400 + .DB DUART_BAUD_INV ; 4800 + .DB %1001 | DUART_BAUD_EXT2 | DUART_BAUD_ACR7 ; 9600 + .DB %1011 | DUART_BAUD_EXT2 | DUART_BAUD_ACR7 ; 19200 + .DB %1100 | DUART_BAUD_EXT2 | DUART_BAUD_ACR7 ; 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 DUART_BAUD_INV ; 1800 + .DB DUART_BAUD_INV ; 3600 + .DB DUART_BAUD_INV ; 7200 + .DB %0000 | DUART_BAUD_EXT2 | DUART_BAUD_ACR7 ; 14400 + .DB %0011 | DUART_BAUD_EXT2 | DUART_BAUD_ACR7 ; 28800 + .DB %0100 | DUART_BAUD_EXT2 | DUART_BAUD_ACR7 ; 57600 + .DB %0101 | DUART_BAUD_EXT2 | DUART_BAUD_ACR7 ; 115200 + .DB %0110 | DUART_BAUD_EXT2 | DUART_BAUD_ACR7 ; 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 ; DUART_PARTBL: .DB DUART_MR1_PARNONE ; 0 = NO PARITY (ALSO ALL EVEN ENTRIES) @@ -536,16 +507,11 @@ DUART_PARTBL: .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 + LD E,(IY + 8) ; FIRST CONFIG BYTE TO E + LD D,(IY + 9) ; SECOND CONFIG BYTE TO D XOR A ; SIGNAL SUCCESS RET ; DONE ; @@ -563,7 +529,7 @@ DUART_DEVICE: DUART_DETECT: ; ; FIRST SEE IF IT LOOKS LIKE A 16X50-STYLE UART - LD A,(IY + 3) ; GET BASE PORT OF CHIP + LD A,(IY + 2) ; GET BASE PORT OF CHIP ADD A,6 ; BASE + 6 = CTU (DUART), MSR (1ST 16X50) LD B,A ; B := CTU/MSR PORT ADDRESS INC A ; BASE + 7 = CTL (DUART), SCR (1ST 16X50) @@ -605,11 +571,11 @@ DUART_DETECT: 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 + ; TEST FOR MR0 REGISTER, IN WHICH CASE WE HAVE A 26C92 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 + DUART_OUTP(DUART_MR) ; WRITE TO MR0 ON 26C92, 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 @@ -620,7 +586,7 @@ DUART_DETECT: 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 Z,DUART_DETECT_26C92 ; YES, MUST BE A '92 WITH MR0 JR DUART_DETECT_XR88C681 ; ASSUME WE HAVE A FANCY EXAR CHIP ; @@ -632,8 +598,8 @@ DUART_DETECT_2681: LD A,DUART_2681 RET ; -DUART_DETECT_2692: - LD A,DUART_2692 +DUART_DETECT_26C92: + LD A,DUART_26C92 RET ; DUART_DETECT_XR88C681 @@ -649,7 +615,7 @@ DUART_PRTCFG: LD A,(IY) ; DEVICE NUM CALL PRTDECB ; PRINT DEVICE NUM PRTS(": IO=0x$") ; FORMATTING - LD A,(IY + 4) ; GET CHANNEL BASE PORT + LD A,(IY + 3) ; GET CHANNEL BASE PORT CALL PRTHEXBYTE ; PRINT BASE PORT ; PRINT THE DUART TYPE @@ -669,16 +635,9 @@ DUART_PRTCFG: RET Z ; IF ZERO, NOT PRESENT ; PRTS(" MODE=$") ; FORMATTING - LD E,(IY + 7) ; LOAD CONFIG - LD D,(IY + 8) ; ... WORD TO DE + LD E,(IY + 8) ; LOAD CONFIG + LD D,(IY + 9) ; ... WORD TO DE CALL PS_PRTSC0 ; PRINT CONFIG -; -#IF (DUART_DEBUG) - ; DEBUG: DUMP BAUD TABLE ENTRY - PRTS(" BAUDTBL=$") - LD A,(IY + 5) - CALL PRTHEXBYTE -#ENDIF ; XOR A RET @@ -690,7 +649,7 @@ DUART_PRTCFG: DUART_INP_IMP: EX (SP),HL ; SWAP HL AND TOS PUSH BC ; PRESERVE BC - LD A,(IY + 4) ; GET DUART IO BASE PORT + LD A,(IY + 3) ; GET DUART IO BASE PORT OR (HL) ; OR IN REGISTER ID BITS LD C,A ; C := PORT IN A,(C) ; READ PORT INTO A @@ -705,7 +664,7 @@ 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 + LD A,(IY + 3) ; GET DUART IO BASE PORT OR (HL) ; OR IN REGISTER ID BITS LD C,A ; C := PORT OUT (C),B ; WRITE VALUE TO PORT @@ -719,18 +678,28 @@ DUART_OUTP_IMP: DUART_TYPE_MAP: .DW DUART_STR_NONE .DW DUART_STR_2681 - .DW DUART_STR_2692 + .DW DUART_STR_26C92 .DW DUART_STR_XR88C681 DUART_STR_NONE .DB "$" DUART_STR_2681 .DB "2681$" -DUART_STR_2692 .DB "2692$" +DUART_STR_26C92 .DB "26C92$" DUART_STR_XR88C681 .DB "XR88C681$" ; ; WORKING VARIABLES ; DUART_DEV .DB 0 ; DEVICE NUM USED DURING INIT ; +; PER-CHIP VARIABLES +; +DUART0_ACR .DB 0 ; SHADOW ACR (DUART 0) +; +#IF (DUARTCNT >= 2) +; +DUART1_ACR .DB 0 ; SHADOW ACR (DUART 1) +; +#ENDIF +; ; DUART PORT TABLE ; DUART_CFG: @@ -739,14 +708,12 @@ 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 + .DB DUART0BASE ; IY+2 BASE PORT (CHIP) + .DB DUART0BASE + $00 ; IY+3 BASE PORT (CHANNEL) + .DW DUART0B_CFG ; IY+4 POINTER TO OTHER CHANNEL + .DW DUART0_ACR ; IY+6 POINTER TO SHADOW ACR FOR THIS CHIP + .DW DUART0ACFG ; IY+8 LINE CONFIGURATION + .DB 1 ; IY+10 MULTIPLIER WRT 3.6864MHZ CLOCK ; DUART_CFGSIZ .EQU $ - DUART_CFG ; SIZE OF ONE CFG TABLE ENTRY ; @@ -754,14 +721,12 @@ 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 DUART0A_CFG ; POINTER TO OTHER CHANNEL + .DW DUART0_ACR ; POINTER TO SHADOW ACR FOR THIS CHIP .DW DUART0BCFG ; LINE CONFIGURATION - .DW DUART0CLK & $FFFF ; CLOCK FREQ AS - .DW DUART0CLK >> 16 ; ... DWORD VALUE + .DB 1 ; MULTIPLIER WRT 3.6864MHZ CLOCK ; #IF (DUARTCNT >= 2) ; @@ -769,27 +734,23 @@ 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 DUART1B_CFG ; POINTER TO OTHER CHANNEL + .DW DUART1_ACR ; POINTER TO SHADOW ACR FOR THIS CHIP .DW DUART1ACFG ; LINE CONFIGURATION - .DW DUART1CLK & $FFFF ; CLOCK FREQ AS - .DW DUART1CLK >> 16 ; ... DWORD VALUE + .DB 1 ; MULTIPLIER WRT 3.6864MHZ CLOCK ; 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 + $08 ; BASE PORT (CHANNEL) - .DB 0 ; BAUD TABLE ENTRY (SET DURING INITDEV) - .DB 0 ; SHADOW ACR (SET DURING INITDEV) + .DW DUART1A_CFG ; POINTER TO OTHER CHANNEL + .DW DUART1_ACR ; POINTER TO SHADOW ACR FOR THIS CHIP .DW DUART1BCFG ; LINE CONFIGURATION - .DW DUART1CLK & $FFFF ; CLOCK FREQ AS - .DW DUART1CLK >> 16 ; ... DWORD VALUE + .DB 1 ; MULTIPLIER WRT 3.6864MHZ CLOCK ; #ENDIF ; From 74d357ed4b8f6c1f4fee6ab1b60b971d3c569245 Mon Sep 17 00:00:00 2001 From: Chris Odorjan Date: Fri, 15 May 2020 16:42:41 -0400 Subject: [PATCH 6/7] DUART: actually support 26C92 baud rate generator also improve detection --- Source/HBIOS/duart.asm | 164 +++++++++++++++++++++++++++++++++-------- 1 file changed, 135 insertions(+), 29 deletions(-) diff --git a/Source/HBIOS/duart.asm b/Source/HBIOS/duart.asm index ef1da758..af716ece 100644 --- a/Source/HBIOS/duart.asm +++ b/Source/HBIOS/duart.asm @@ -144,6 +144,12 @@ DUART_SR_PARITY .EQU %00100000 ; PARITY ERROR DUART_SR_FRAMING .EQU %01000000 ; FRAMING ERROR DUART_SR_BREAK .EQU %10000000 ; RECEIVED BREAK ; +; DUART MODE REGISTER 0 +; +DUART_MR0_NORMAL .EQU %00000000 ; NORMAL BAUD RATE TABLE +DUART_MR0_EXT1 .EQU %00000001 ; EXTENDED BAUD RATE TABLE 1 +DUART_MR0_EXT2 .EQU %00000100 ; EXTENDED BAUD RATE TABLE 2 +; ; DUART MODE REGISTER 1 ; DUART_MR1_RXRTS .EQU %10000000 ; RECEIVER CONTROLS RTS @@ -341,33 +347,16 @@ DUART_INITDEV1A: 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 + LD A,(IY + 1) ; GET DUART TYPE + CP DUART_26C92 ; IS IT A 26C92? + JR Z,DUART_INITDEV1B ; YES + CALL DUART_SETBAUD_681 ; NO, CALL '681 BRG SETUP + JR DUART_INITDEV2 ; -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_INITDEV1B: + CALL DUART_SETBAUD_92 ; CALL '92 BRG SETUP ; -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 L - 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 +DUART_INITDEV2: ; ; SET PARITY AND WORD SIZE LD A,DUART_CR_MR1 @@ -420,13 +409,59 @@ DUART_INITDEV5: ; DUART_INITDEVZ: ; -#IF (DUART_DEBUG) - PRTC(']') -#ENDIF ; INVALID BAUD RATE DEC A ; A WAS $00, GET BACK $FF RET ; RETURN ERROR STATUS ; +; INITIALIZE BRG FOR '681 DUART +; +DUART_SETBAUD_681: + ; SET ACR + LD C,(IY + 6) ; GET SHADOW ACR FOR THIS CHIP + LD B,(IY + 7) ; BC IS POINTER + LD A,(BC) ; GET SHADOW ACR IN A + AND %01111111 ; MASK OUT BIT 7 + LD H,A ; SAVE IT IN H + LD A,L ; TABLE ENTRY IS IN L, GET IT IN A + AND DUART_BAUD_ACR7 ; SEE IF ACR[7] SHOULD BE SET (BIT MASK SHOULD ACTUALLY _BE_ BIT 7) + OR H ; MERGE IN REST OF ACR + LD H,A ; SAVE IT IN H + LD A,(IY + 2) ; GET CHIP BASE IN A + ADD A,DUART_ACR ; ADD OFFSET OF ACR + LD C,A ; C = ACR PORT + ; YES, THIS OVERWRITES ACR[7] REGARDLESS OF THE OTHER CHANNEL, + ; BUT CURRENTLY THE TABLE IS SET SO EVERY VALID RATE HAS ACR[7] SET + OUT (C),H ; WRITE VALUE + ; SELECT PER-CHANNEL EXTENDED TABLE + LD A,L ; CALLED WITH TABLE ENTRY IN L, MOVE IT TO A + AND DUART_BAUD_X1 ; SEE IF SELECT EXTEND BIT SHOULD BE SET + JR Z,DUART_SETBAUD_681A ; 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_SETBAUD_681B +; +DUART_SETBAUD_681A: + ; 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_SETBAUD_681B: + ; 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 L + 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 + RET +; DUART_BAUDTBL_681: ; ASSUME XR88C681 RUNS AT 3.6864MHZ .DB %0000 | DUART_BAUD_X1 ; 75 @@ -462,6 +497,64 @@ DUART_BAUDTBL_681: .DB DUART_BAUD_INV ; 3686400 .DB DUART_BAUD_INV ; 7372800 ; +; INITIALIZE BRG FOR '92 DUART +; +DUART_SETBAUD_92: + ; SET ACR + LD C,(IY + 6) ; GET SHADOW ACR FOR THIS CHIP + LD B,(IY + 7) ; BC IS POINTER + LD A,(BC) ; GET SHADOW ACR IN A + AND %01111111 ; MASK OUT BIT 7 + LD H,A ; SAVE IT IN H + LD A,L ; TABLE ENTRY IS IN L, GET IT IN A + AND DUART_BAUD_ACR7 ; SEE IF ACR[7] SHOULD BE SET (BIT MASK SHOULD ACTUALLY _BE_ BIT 7) + OR H ; MERGE IN REST OF ACR + LD H,A ; SAVE IT IN H + LD A,(IY + 2) ; GET CHIP BASE IN A + ADD A,DUART_ACR ; ADD OFFSET OF ACR + LD C,A ; C = ACR PORT + ; YES, THIS OVERWRITES ACR[7] REGARDLESS OF THE OTHER CHANNEL, + ; BUT CURRENTLY THE TABLE IS SET SO EVERY VALID RATE HAS ACR[7] SET + OUT (C),H ; WRITE VALUE + ; SELECT NORMAL OR EXTENDED BAUD RATE TABLES + LD H,DUART_MR0_NORMAL ; ASSUME NORMAL + LD A,L ; GET TABLE ENTRY IN A AGAIN + AND DUART_BAUD_EXT1 ; SHOULD EXT1 BE SET? + JR Z,DUART_SETBAUD_92A ; NO, CHECK NEXT VALUE + LD H,DUART_MR0_EXT1 ; YES, SET IT + JR DUART_SETBAUD_92C +; +DUART_SETBAUD_92A: + LD A,L ; GET TABLE ENTRY IN A ONCE MORE + AND DUART_BAUD_EXT2 ; SHOULD EXT2 BE SET? + JR Z,DUART_SETBAUD_92C ; NO, CONTINUE + LD H,DUART_MR0_EXT2 ; YES, SET IT +; +DUART_SETBAUD_92C: + ; H NOW CONTAINS MR0 + LD A,(IY + 2) ; GET CHIP BASE IN A + ADD A,DUART_CR ; WE WANT TO WRITE THE COMMAND REGISTER OF CHANNEL A, EVEN IF WE'RE CHANNEL B + LD C,A ; C = CRA + LD A,DUART_CR_MR0 ; RESET MR POINTER TO MR0 + OUT (C),A ; WRITE COMMAND + LD A,(IY + 2) ; GET CHIP BASE IN A + ADD A,DUART_MR ; NOW WE WANT TO WRITE TO MR0 OF CHANNEL A + LD C,A ; C = MRA + ; AS WITH ACR[7] THE TABLE IS SET SO EVERY VALID RATE IS FROM + ; THE SAME TABLE + OUT (C),H + ; SET BRG CLOCK SELECT + LD A,L ; GET BAUD TABLE ENTRY IN A YET AGAIN + AND $0F ; GET CLOCK SELECT BITS + LD L,A ; SAVE IT IN L + 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 OF CURRENT CHANNEL + RET +; DUART_BAUDTBL_92: ; ASSUME SC26C92 RUNS AT 7.3728MHZ .DB DUART_BAUD_INV ; 75 @@ -530,12 +623,21 @@ DUART_DETECT: ; ; FIRST SEE IF IT LOOKS LIKE A 16X50-STYLE UART LD A,(IY + 2) ; GET BASE PORT OF CHIP - ADD A,6 ; BASE + 6 = CTU (DUART), MSR (1ST 16X50) + ADD A,4 ; BASE + 4 = ACR (DUART), MCR (1ST 16X50) + LD H,A ; H := ACR/MCR PORT ADDRESS + ADD A,2 ; BASE + 6 = CTU (DUART), MSR (1ST 16X50) LD B,A ; B := CTU/MSR PORT ADDRESS INC A ; BASE + 7 = CTL (DUART), SCR (1ST 16X50) LD D,A ; D := CTL/SCR PORT ADDRESS ADD A,7 ; BASE + 14 = STCR (DUART), MSR (2ND 16X50) LD E,A ; E := STCR/MSR PORT ADDRESS + INC A ; BASE + 15 = SPCR (DUART), SCR (2ND 16X50) + LD C,A ; SPCR + IN A,(C) ; STOP COUNTER/TIMER, JUST IN CASE + LD C,H ; ACR/MCR + IN L,(C) ; GET ORIGINAL VALUE (ACTUALLY IPCR ON DUART) IN L + LD A,$30 ; ENABLE A SOURCE FOR THE COUNTER/TIMER + OUT (C),A ; WRITE TO ACR/MCR LD A,$A5 ; TEST VALUE LD C,B ; CTU OUT (C),A ; WRITE TEST VALUE TO CTU @@ -544,6 +646,10 @@ DUART_DETECT: OUT (C),A ; WRITE LARGE VALUE TO CTL LD C,E ; STCR IN A,(C) ; START COUNTER/TIMER (LATCH CTU, CTL) + INC C ; C := SPCR + IN A,(C) ; STOP COUNTER/TIMER + LD C,H ; ACR/MCR + OUT (C),L ; WRITE ORIGINAL VALUE OF MCR (ACR GETS SET ON DUART LATER) LD C,B ; CTU IN A,(C) ; READ BACK TEST VALUE CP $A5 ; CHECK FOR TEST VALUE From c57de185931f4a8cd29ff20766abc8804446a1b2 Mon Sep 17 00:00:00 2001 From: Chris Odorjan Date: Thu, 21 May 2020 20:30:28 -0400 Subject: [PATCH 7/7] DUART: don't build in the standard configuration add a separate RCZ80_duart configuration, at least until it gets more testing --- Source/HBIOS/Config/RCZ80_duart.asm | 32 +++++++++++++++++++++++++++++ Source/HBIOS/Makefile | 1 + Source/HBIOS/cfg_rcz80.asm | 5 +---- 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 Source/HBIOS/Config/RCZ80_duart.asm diff --git a/Source/HBIOS/Config/RCZ80_duart.asm b/Source/HBIOS/Config/RCZ80_duart.asm new file mode 100644 index 00000000..b539bdb7 --- /dev/null +++ b/Source/HBIOS/Config/RCZ80_duart.asm @@ -0,0 +1,32 @@ +; +;================================================================================================== +; RC2014 Z80 CONFIGURATION W/ DUART +;================================================================================================== +; +; THE COMPLETE SET OF DEFAULT CONFIGURATION SETTINGS FOR THIS PLATFORM ARE FOUND IN THE +; CFG_.ASM INCLUDED FILE WHICH IS FOUND IN THE PARENT DIRECTORY. THIS FILE CONTAINS +; COMMON CONFIGURATION SETTINGS THAT OVERRIDE THE DEFAULTS. IT IS INTENDED THAT YOU MAKE +; YOUR CUSTOMIZATIONS IN THIS FILE AND JUST INHERIT ALL OTHER SETTINGS FROM THE DEFAULTS. +; EVEN BETTER, YOU CAN MAKE A COPY OF THIS FILE WITH A NAME LIKE _XXX.ASM AND SPECIFY +; YOUR FILE IN THE BUILD PROCESS. +; +; THE SETTINGS BELOW ARE THE SETTINGS THAT ARE MOST COMMONLY MODIFIED FOR THIS PLATFORM. +; MANY OF THEM ARE EQUAL TO THE SETTINGS IN THE INCLUDED FILE, SO THEY DON'T REALLY DO +; ANYTHING AS IS. THEY ARE LISTED HERE TO MAKE IT EASY FOR YOU TO ADJUST THE MOST COMMON +; SETTINGS. +; +; N.B., SINCE THE SETTINGS BELOW ARE REDEFINING VALUES ALREADY SET IN THE INCLUDED FILE, +; TASM INSISTS THAT YOU USE THE .SET OPERATOR AND NOT THE .EQU OPERATOR BELOW. ATTEMPTING +; TO REDEFINE A VALUE WITH .EQU BELOW WILL CAUSE TASM ERRORS! +; +; PLEASE REFER TO THE CUSTOM BUILD INSTRUCTIONS (README.TXT) IN THE SOURCE DIRECTORY (TWO +; DIRECTORIES ABOVE THIS ONE). +; +#define BOOT_DEFAULT "H" ; DEFAULT BOOT LOADER CMD ON OR AUTO BOOT +; +#define PLATFORM_NAME "RC2014 (DUART)" +; +#include "Config/RCZ80_std.asm" +; +DUARTENABLE .EQU TRUE ; DUART: ENABLE 2681/2692 SERIAL DRIVER (DUART.ASM) +DUARTCNT .EQU 1 ; DUART: NUMBER OF CHIPS TO DETECT (1-2) diff --git a/Source/HBIOS/Makefile b/Source/HBIOS/Makefile index 316fb027..c8f7c8fb 100644 --- a/Source/HBIOS/Makefile +++ b/Source/HBIOS/Makefile @@ -13,6 +13,7 @@ else OBJECTS += RCZ180_nat.rom RCZ180_nat.com OBJECTS += RCZ80_kio.rom RCZ80_kio.com OBJECTS += RCZ80_mt.rom RCZ80_mt.com + OBJECTS += RCZ80_duart.rom RCZ80_duart.com OBJECTS += RCZ80_std.rom RCZ80_std.com OBJECTS += SBC_simh.rom SBC_simh.com OBJECTS += SBC_std.rom SBC_std.com diff --git a/Source/HBIOS/cfg_rcz80.asm b/Source/HBIOS/cfg_rcz80.asm index ca5b6bb5..4efdd960 100644 --- a/Source/HBIOS/cfg_rcz80.asm +++ b/Source/HBIOS/cfg_rcz80.asm @@ -75,17 +75,14 @@ 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 +DUARTENABLE .EQU FALSE ; DUART: ENABLE 2681/2692 SERIAL DRIVER (DUART.ASM) 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