diff --git a/Doc/ChangeLog.txt b/Doc/ChangeLog.txt index 2f7c0b98..49e26095 100644 --- a/Doc/ChangeLog.txt +++ b/Doc/ChangeLog.txt @@ -4,6 +4,7 @@ Version 3.1.1 - WBW: Preliminary hard disk partition support (backward compatible) - WBW: Change Propeller VGA signal timings to 60Hz refresh - WBW: Enhanced SYSTEM RESET function to allow a warm start back to boot loader +- C?O: Add DUART driver Version 3.1 ----------- diff --git a/Source/Forth/Build.cmd b/Source/Forth/Build.cmd index 08fb735b..026b4ba5 100644 --- a/Source/Forth/Build.cmd +++ b/Source/Forth/Build.cmd @@ -11,7 +11,7 @@ set ZXBINDIR=%TOOLS%/cpm/bin/ set ZXLIBDIR=%TOOLS%/cpm/lib/ set ZXINCDIR=%TOOLS%/cpm/include/ -zx zsm =camel80.azm +zx zsm =camel80.azm -/l zx link -CAMEL80.BIN=CAMEL80 diff --git a/Source/HBIOS/Config/RCZ80_duart.asm b/Source/HBIOS/Config/RCZ80_duart.asm new file mode 100644 index 00000000..90ba7809 --- /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 .SET TRUE ; DUART: ENABLE 2681/2692 SERIAL DRIVER (DUART.ASM) +DUARTCNT .SET 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_dyno.asm b/Source/HBIOS/cfg_dyno.asm index 52773af2..0c1ad6d8 100644 --- a/Source/HBIOS/cfg_dyno.asm +++ b/Source/HBIOS/cfg_dyno.asm @@ -74,6 +74,8 @@ 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 FALSE ; DUART: ENABLE 2681/2692 SERIAL DRIVER (DUART.ASM) +; UARTENABLE .EQU FALSE ; UART: ENABLE 8250/16550-LIKE SERIAL DRIVER (UART.ASM) ; ASCIENABLE .EQU TRUE ; ASCI: ENABLE Z180 ASCI SERIAL DRIVER (ASCI.ASM) diff --git a/Source/HBIOS/cfg_ezz80.asm b/Source/HBIOS/cfg_ezz80.asm index d604eb3e..0b8cc610 100644 --- a/Source/HBIOS/cfg_ezz80.asm +++ b/Source/HBIOS/cfg_ezz80.asm @@ -76,6 +76,15 @@ 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 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 +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 +; 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/cfg_master.asm b/Source/HBIOS/cfg_master.asm index 2b1baa7c..de7241dd 100644 --- a/Source/HBIOS/cfg_master.asm +++ b/Source/HBIOS/cfg_master.asm @@ -98,6 +98,15 @@ 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 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 +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 +; UARTENABLE .EQU FALSE ; 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/cfg_mk4.asm b/Source/HBIOS/cfg_mk4.asm index 8889fd05..7ca6c871 100644 --- a/Source/HBIOS/cfg_mk4.asm +++ b/Source/HBIOS/cfg_mk4.asm @@ -81,6 +81,8 @@ 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 FALSE ; DUART: ENABLE 2681/2692 SERIAL DRIVER (DUART.ASM) +; 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/cfg_n8.asm b/Source/HBIOS/cfg_n8.asm index 700fc0f7..70c0eec3 100644 --- a/Source/HBIOS/cfg_n8.asm +++ b/Source/HBIOS/cfg_n8.asm @@ -84,6 +84,8 @@ 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 FALSE ; DUART: ENABLE 2681/2692 SERIAL DRIVER (DUART.ASM) +; 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/cfg_rcz180.asm b/Source/HBIOS/cfg_rcz180.asm index 3bc1b090..bc2722e1 100644 --- a/Source/HBIOS/cfg_rcz180.asm +++ b/Source/HBIOS/cfg_rcz180.asm @@ -77,6 +77,15 @@ 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 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 +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 +; 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/cfg_rcz80.asm b/Source/HBIOS/cfg_rcz80.asm index 85b29c30..58d0828b 100644 --- a/Source/HBIOS/cfg_rcz80.asm +++ b/Source/HBIOS/cfg_rcz80.asm @@ -75,6 +75,15 @@ 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 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 +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 +; 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/cfg_sbc.asm b/Source/HBIOS/cfg_sbc.asm index 650d4eae..a04def8f 100644 --- a/Source/HBIOS/cfg_sbc.asm +++ b/Source/HBIOS/cfg_sbc.asm @@ -77,6 +77,8 @@ 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 FALSE ; DUART: ENABLE 2681/2692 SERIAL DRIVER (DUART.ASM) +; 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/cfg_scz180.asm b/Source/HBIOS/cfg_scz180.asm index 5f870219..eac68d87 100644 --- a/Source/HBIOS/cfg_scz180.asm +++ b/Source/HBIOS/cfg_scz180.asm @@ -72,6 +72,15 @@ 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 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 +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 +; 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/cfg_zeta.asm b/Source/HBIOS/cfg_zeta.asm index 14d8770e..94d43677 100644 --- a/Source/HBIOS/cfg_zeta.asm +++ b/Source/HBIOS/cfg_zeta.asm @@ -61,10 +61,12 @@ DSRTCCHG .EQU FALSE ; DSRTC: FORCE BATTERY CHARGE ON (USE WITH CAUTION!!!) BQRTCENABLE .EQU FALSE ; BQRTC: ENABLE BQ4845 CLOCK DRIVER (BQRTC.ASM) BQRTC_BASE .EQU $50 ; BQRTC: I/O BASE ADDRESS ; +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) ; -INTRTCENABLE .EQU FALSE ; ENABLE PERIODIC INTERRUPT CLOCK DRIVER (INTRTC.ASM) +DUARTENABLE .EQU FALSE ; DUART: ENABLE 2681/2692 SERIAL DRIVER (DUART.ASM) ; UARTENABLE .EQU TRUE ; UART: ENABLE 8250/16550-LIKE SERIAL DRIVER (UART.ASM) UARTOSC .EQU 1843200 ; UART: OSC FREQUENCY IN MHZ diff --git a/Source/HBIOS/cfg_zeta2.asm b/Source/HBIOS/cfg_zeta2.asm index 1901511d..a13f0225 100644 --- a/Source/HBIOS/cfg_zeta2.asm +++ b/Source/HBIOS/cfg_zeta2.asm @@ -76,6 +76,8 @@ 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 FALSE ; DUART: ENABLE 2681/2692 SERIAL DRIVER (DUART.ASM) +; 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..af716ece --- /dev/null +++ b/Source/HBIOS/duart.asm @@ -0,0 +1,863 @@ +; +;================================================================================================== +; 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_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 ('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) +; +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 (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) +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 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 +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_DETECT ; DETERMINE DUART TYPE + POP BC ; RESTORE LOOP CONTROL + 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 +; +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: + ; CHECK IF PORT IS PRESENT + LD A,(IY + 1) ; GET TYPE FROM 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 + 8) ; LOW BYTE + LD D,(IY + 9) ; HIGH BYTE +; +DUART_INITDEV1: + ; GET CLOCK SELECT FROM TABLE + 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 + 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 + 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 + 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,(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_INITDEV1B: + CALL DUART_SETBAUD_92 ; CALL '92 BRG SETUP +; +DUART_INITDEV2: +; + ; 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) ; 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 + 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 +; + XOR A ; SIGNAL SUCCESS + RET +; +DUART_INITDEVZ: +; + ; 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 + .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 +; +; 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 + .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) + .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 +; +; +; +DUART_QUERY: + LD E,(IY + 8) ; FIRST CONFIG BYTE TO E + LD D,(IY + 9) ; 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: +; + ; FIRST SEE IF IT LOOKS LIKE A 16X50-STYLE UART + LD A,(IY + 2) ; GET BASE PORT OF CHIP + 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 + 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) + 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 + 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 + 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 PRESENT +; + ; 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 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 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 + 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_26C92 ; 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_26C92: + LD A,DUART_26C92 + 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 + 3) ; 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 + 8) ; LOAD CONFIG + LD D,(IY + 9) ; ... 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 + 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 + 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 + 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 + 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_26C92 + .DW DUART_STR_XR88C681 + +DUART_STR_NONE .DB "$" +DUART_STR_2681 .DB "2681$" +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: +; +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 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 +; +DUART0B_CFG: + ; 1ST DUART MODULE CHANNEL B + .DB 0 ; DEVICE NUMBER (SET DURING INIT) + .DB 0 ; DUART TYPE (SET DURING INIT) + .DB DUART0BASE ; BASE PORT (CHIP) + .DB DUART0BASE + $08 ; BASE PORT (CHANNEL) + .DW DUART0A_CFG ; POINTER TO OTHER CHANNEL + .DW DUART0_ACR ; POINTER TO SHADOW ACR FOR THIS CHIP + .DW DUART0BCFG ; LINE CONFIGURATION + .DB 1 ; MULTIPLIER WRT 3.6864MHZ CLOCK +; +#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 DUART1BASE ; BASE PORT (CHIP) + .DB DUART1BASE + $00 ; BASE PORT (CHANNEL) + .DW DUART1B_CFG ; POINTER TO OTHER CHANNEL + .DW DUART1_ACR ; POINTER TO SHADOW ACR FOR THIS CHIP + .DW DUART1ACFG ; LINE CONFIGURATION + .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 DUART1BASE ; BASE PORT (CHIP) + .DB DUART1BASE + $08 ; BASE PORT (CHANNEL) + .DW DUART1A_CFG ; POINTER TO OTHER CHANNEL + .DW DUART1_ACR ; POINTER TO SHADOW ACR FOR THIS CHIP + .DW DUART1BCFG ; LINE CONFIGURATION + .DB 1 ; MULTIPLIER WRT 3.6864MHZ CLOCK +; +#ENDIF +; +DUART_CFGCNT .EQU ($ - DUART_CFG) / DUART_CFGSIZ diff --git a/Source/HBIOS/hbios.inc b/Source/HBIOS/hbios.inc index 17cbe967..f8e4acc6 100644 --- a/Source/HBIOS/hbios.inc +++ b/Source/HBIOS/hbios.inc @@ -159,6 +159,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 ; diff --git a/Source/HBIOS/uart.asm b/Source/HBIOS/uart.asm index 75466d50..af00cebe 100644 --- a/Source/HBIOS/uart.asm +++ b/Source/HBIOS/uart.asm @@ -230,11 +230,23 @@ UART_INITDEV1: LD A,C UART_OUTP(UART_DLL) ; SET DIVISOR (LS) ; - ; SETUP FCR (DLAB MUST STILL BE ON FOR ACCESS TO BIT 5) - LD A,%00100111 ; FIFO ENABLE & RESET, 64 BYTE FIFO ENABLE ON 750+ + ; FOR 750+, WE ENABLE THE 64-BYTE FIFO + ; DLAB MUST STILL BE ON FOR ACCESS TO BIT 5 + ; WE DO *NOT* ENABLE ANY OTHER FCR BITS HERE + ; BEACAUSE IT WILL SCREW UP THE 2552!!! + LD A,%00100000 UART_OUTP(UART_FCR) ; DO IT ; - ; SETUP LCR FROM SECOND CONFIG BYTE (DLAB IS CLEARED) + XOR A ; DLAB OFF NOW + UART_OUTP(UART_LCR) ; DO IT +; + ; SETUP FCR, BIT 5 IS KEPT ON EVEN THOUGH IT IS PROBABLY + ; IRRELEVANT BECAUSE IT ONLY APPLIES TO 750 AND DLAB IS + ; NOW OFF, BUT DOESN'T HURT. + LD A,%00100111 ; FIFO ENABLE & RESET + UART_OUTP(UART_FCR) ; DO IT +; + ; SETUP LCR FROM SECOND CONFIG BYTE LD A,(IY + 4) ; GET CONFIG BYTE AND ~$C0 ; ISOLATE PARITY, STOP/DATA BITS UART_OUTP(UART_LCR) ; SAVE IT @@ -364,8 +376,9 @@ UART_DETECT: CP $5A ; SPR STILL THERE? JR NZ,UART_DETECT1 ; NOPE, HIDDEN, MUST BE 16650/850 ; - ; RESET LCR TO DEFAULT - LD A,$80 ; DLAB BIT ON + ; RESET LCR TO DEFAULT (DLAB OFF) + ;LD A,$80 ; DLAB BIT ON + XOR A ; DLAB BIT OFF UART_OUTP(UART_LCR) ; RESET LCR ; ; TEST FCR TO ISOLATE 16450/550/550A @@ -381,6 +394,9 @@ UART_DETECT: JR UART_DETECT_16750 ; ONLY THING LEFT IS 16750 ; UART_DETECT1: ; PICK BETWEEN 16650/850 + ; RESET LCR TO DEFAULT (DLAB OFF) + XOR A ; DLAB BIT OFF + UART_OUTP(UART_LCR) ; RESET LCR ; NOT SURE HOW TO DIFFERENTIATE 16650 FROM 16850 YET JR UART_DETECT_16650 ; ASSUME 16650 RET diff --git a/Tools/Makefile.inc b/Tools/Makefile.inc index d410246d..f0018217 100644 --- a/Tools/Makefile.inc +++ b/Tools/Makefile.inc @@ -81,7 +81,7 @@ CPM=$(TOOLS)/cpm/bin $(ZXCC) $(CPM)/SLR180 -$(basename $<)/HF %.rel: %.azm - $(ZXCC) $(CPM)/ZSM =$< + $(ZXCC) $(CPM)/ZSM =$< -/L %.bin: %.rel $(ZXCC) $(CPM)/LINK -$@=$<