diff --git a/Doc/RomWBW Applications.pdf b/Doc/RomWBW Applications.pdf index 99763853..dcc0a294 100644 Binary files a/Doc/RomWBW Applications.pdf and b/Doc/RomWBW Applications.pdf differ diff --git a/Doc/RomWBW Disk Catalog.pdf b/Doc/RomWBW Disk Catalog.pdf index 9cfade05..9bf5e4a5 100644 Binary files a/Doc/RomWBW Disk Catalog.pdf and b/Doc/RomWBW Disk Catalog.pdf differ diff --git a/Doc/RomWBW Hardware.pdf b/Doc/RomWBW Hardware.pdf index 867a73d5..949234ec 100644 Binary files a/Doc/RomWBW Hardware.pdf and b/Doc/RomWBW Hardware.pdf differ diff --git a/Doc/RomWBW Introduction.pdf b/Doc/RomWBW Introduction.pdf index 0fd2b7f3..2ea71c20 100644 Binary files a/Doc/RomWBW Introduction.pdf and b/Doc/RomWBW Introduction.pdf differ diff --git a/Doc/RomWBW System Guide.pdf b/Doc/RomWBW System Guide.pdf index f65cb80f..adbfce6a 100644 Binary files a/Doc/RomWBW System Guide.pdf and b/Doc/RomWBW System Guide.pdf differ diff --git a/Doc/RomWBW User Guide.pdf b/Doc/RomWBW User Guide.pdf index 4ba906e8..8ed3860e 100644 Binary files a/Doc/RomWBW User Guide.pdf and b/Doc/RomWBW User Guide.pdf differ diff --git a/ReadMe.md b/ReadMe.md index d3c3aeeb..013432bb 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -7,7 +7,7 @@ **RomWBW Introduction** \ Version 3.6 \ Wayne Warthen ([wwarthen@gmail.com](mailto:wwarthen@gmail.com)) \ -28 Oct 2025 +29 Oct 2025 # Overview diff --git a/ReadMe.txt b/ReadMe.txt index 424b286f..86d6aba6 100644 --- a/ReadMe.txt +++ b/ReadMe.txt @@ -1,6 +1,6 @@ RomWBW Introduction Wayne Warthen (wwarthen@gmail.com) -28 Oct 2025 +29 Oct 2025 diff --git a/Source/Doc/Hardware.md b/Source/Doc/Hardware.md index bd29abf6..8b3b414d 100644 --- a/Source/Doc/Hardware.md +++ b/Source/Doc/Hardware.md @@ -441,17 +441,19 @@ Z80-based S100 Modular System #### Supported Hardware +- FP: LEDIO=5 +- PLDSER: IO=172 +- SCC MODE=SZ80, IO=160, CHANNEL A +- SCC MODE=SZ80, IO=160, CHANNEL B - SCON: IO=0 - ESPSD: IO=128, PRIMARY - ESPSD: IO=128, SECONDARY - MD: TYPE=RAM -- PPIDE: MODE=STD, IO=48, MASTER -- PPIDE: MODE=STD, IO=48, SLAVE -- PPIDE: MODE=S100A, IO=56, MASTER -- PPIDE: MODE=S100A, IO=56, SLAVE -- PPIDE: MODE=S100B, IO=56, MASTER -- PPIDE: MODE=S100B, IO=56, SLAVE -- SD: MODE=FZ80, IO=108, UNITS=2 +- PPIDE: MODE=S100A, IO=48, MASTER +- PPIDE: MODE=S100A, IO=48, SLAVE +- PPIDE: MODE=S100B, IO=48, MASTER +- PPIDE: MODE=S100B, IO=48, SLAVE + #### Notes: @@ -481,9 +483,13 @@ A T35 FPGA Z80 based S100 SBC #### Supported Hardware +- FP: LEDIO=255 - DS5RTC: RTCIO=104, IO=104 -- SSER: IO=52 -- LPT: MODE=S100, IO=199 +- TSER: IO=53 +- PLDSER: IO=172 +- SCC MODE=SZ80, IO=160, CHANNEL A +- SCC MODE=SZ80, IO=160, CHANNEL B +- LPT: MODE=T35, IO=199 - TVGA: IO=192, KBD MODE=T35, KBD IO=3 - KBD: ENABLED - SCON: IO=0 @@ -2365,8 +2371,11 @@ may be discovered by RomWBW in your system. | PPPCON | ParPortProp Serial Console Interface | | PRPCON | PropIO Serial Console Interface | | SCON | S100 Console | -| SIO | Zilog Serial Port Interface | +| SIO | Zilog Serial Input/Output Controller (SIO) | +| SCC | Zilog Serial Communications Controller (SCC) | | SSER | Simple Serial Interface | +| TSER | Trion FPGA Serial Interface | +| PLDSER | PLD USB Serial Interface | | UART | 16C550 Family Serial Interface | | USB-FIFO | FT232H-based ECB USB FIFO | | Z2U | Zilog Z280 CPU Built-in Serial Ports | @@ -2376,16 +2385,20 @@ discovers for the initial console. The following character devices are scanned in the order shown. The available character devices depend on the active platform and configuration. -#. SSER: Simple Serial Interface #. ASCI: Zilog Z180 CPU Built-in Serial Ports #. Z2U: Zilog Z280 CPU Built-in Serial Ports #. UART: 16C550 Family Serial Interface #. DUART: SCC2681 or compatible Dual UART -#. SIO: Zilog Serial Port Interface +#. SIO: Zilog Serial Port Interface (SIO) +#. SCC: Zilog Serial Port Interface (SCC) #. EZ80UART: eZ80 Serial Port Interface #. ACIA: MC68B50 Asynchronous Communications Interface Adapter +#. SSER: Simple Serial Interface +#. TSER: Trion FPGA Serial Interface +#. PLDSER: PLD USB Serial Interface #. USB-FIFO: FT232H-based ECB USB FIFO + ## Disk | **ID** | **Description** | diff --git a/Source/HBIOS/Config/SZ80_std.asm b/Source/HBIOS/Config/SZ80_std.asm index 9f4f40c3..b63a447d 100644 --- a/Source/HBIOS/Config/SZ80_std.asm +++ b/Source/HBIOS/Config/SZ80_std.asm @@ -43,7 +43,7 @@ ; TO USE ".EQU" BECAUSE IT WON'T LET YOU REDEFINE A SETTING WITH ".EQU". ; #DEFINE AUTO_CMD "" ; AUTO CMD WHEN BOOT_TIMEOUT IS ENABLED -#DEFINE DEFSERCFG SER_9600_8N1 | SER_RTS ; DEFAULT SERIAL CONFIGURATION +#DEFINE DEFSERCFG SER_38400_8N1 | SER_RTS ; DEFAULT SERIAL CONFIGURATION ; #INCLUDE "cfg_SZ80.asm" ; diff --git a/Source/HBIOS/cfg_MASTER.asm b/Source/HBIOS/cfg_MASTER.asm index cc604c16..abcc84f9 100644 --- a/Source/HBIOS/cfg_MASTER.asm +++ b/Source/HBIOS/cfg_MASTER.asm @@ -302,6 +302,28 @@ SIO1BCLK .EQU CPUOSC ; SIO 1B: OSC FREQ IN HZ, ZP=2457600/4915200, RC/SMB=73728 SIO1BCFG .EQU DEFSERCFG ; SIO 1B: SERIAL LINE CONFIG SIO1BCTCC .EQU -1 ; SIO 1B: CTC CHANNEL 0=A, 1=B, 2=C, 3=D, -1 FOR NONE ; +SCCENABLE .EQU FALSE ; SCC: ENABLE ZILOG SCC SERIAL DRIVER (SCC.ASM) +SCCDEBUG .EQU FALSE ; SCC: ENABLE DEBUG OUTPUT +SCCBOOT .EQU 0 ; SCC: REBOOT ON RCV CHAR (0=DISABLED) +SCCCNT .EQU 2 ; SCC: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP +SCCINTS .EQU FALSE ; SCC: INCLUDE SCC INTERRUPT SUPPORT UNDER IM1/2/3 +SCC0MODE .EQU SCCMODE_SZ80 ; SCC 0: CHIP TYPE: SCCMODE_[STD|SZ80] +SCC0BASE .EQU $FF ; SCC 0: REGISTERS BASE ADR +SCC0ACLK .EQU 4915200 ; SCC 0A: OSC FREQ IN HZ, ZP=2457600/4915200, RC/SMB=7372800 +SCC0ACFG .EQU DEFSERCFG ; SCC 0A: SERIAL LINE CONFIG +SCC0ACTCC .EQU -1 ; SCC 0A: CTC CHANNEL 0=A, 1=B, 2=C, 3=D, -1 FOR NONE +SCC0BCLK .EQU 4915200 ; SCC 0B: OSC FREQ IN HZ, ZP=2457600/4915200, RC/SMB=7372800 +SCC0BCFG .EQU DEFSERCFG ; SCC 0B: SERIAL LINE CONFIG +SCC0BCTCC .EQU -1 ; SCC 0B: CTC CHANNEL 0=A, 1=B, 2=C, 3=D, -1 FOR NONE +SCC1MODE .EQU SCCMODE_SZ80 ; SCC 1: CHIP TYPE: SIOMODE_[STD|SZ80] +SCC1BASE .EQU $FF ; SCC 1: REGISTERS BASE ADR +SCC1ACLK .EQU 4915200 ; SCC 1A: OSC FREQ IN HZ, ZP=2457600/4915200, RC/SMB=7372800 +SCC1ACFG .EQU DEFSERCFG ; SCC 1A: SERIAL LINE CONFIG +SCC1ACTCC .EQU -1 ; SCC 1A: CTC CHANNEL 0=A, 1=B, 2=C, 3=D, -1 FOR NONE +SCC1BCLK .EQU 4915200 ; SCC 1B: OSC FREQ IN HZ, ZP=2457600/4915200, RC/SMB=7372800 +SCC1BCFG .EQU DEFSERCFG ; SCC 1B: SERIAL LINE CONFIG +SCC1BCTCC .EQU -1 ; SCC 1B: CTC CHANNEL 0=A, 1=B, 2=C, 3=D, -1 FOR NONE +; XIOCFG .EQU DEFSERCFG ; XIO: SERIAL LINE CONFIG ; VDUENABLE .EQU FALSE ; VDU: ENABLE VDU VIDEO/KBD DRIVER (VDU.ASM) diff --git a/Source/HBIOS/cfg_SZ80.asm b/Source/HBIOS/cfg_SZ80.asm index b94bc4ca..dc6df980 100644 --- a/Source/HBIOS/cfg_SZ80.asm +++ b/Source/HBIOS/cfg_SZ80.asm @@ -45,7 +45,7 @@ #DEFINE PLATFORM_NAME "S100 Z80", " [", CONFIG, "]" ; TEXT LABEL OF THIS CONFIG IN STARTUP MESSAGES #DEFINE BOOT_DEFAULT "H" ; DEFAULT BOOT LOADER CMD FOR EMPTY CMD LINE #DEFINE AUTO_CMD "" ; AUTO CMD WHEN BOOT_TIMEOUT IS ENABLED -#DEFINE DEFSERCFG SER_115200_8N1 | SER_RTS ; DEFAULT SERIAL CONFIGURATION +#DEFINE DEFSERCFG SER_38400_8N1 | SER_RTS ; DEFAULT SERIAL CONFIGURATION ; #INCLUDE "cfg_MASTER.asm" ; @@ -253,6 +253,28 @@ SIO1BCLK .SET CPUOSC ; SIO 1B: OSC FREQ IN HZ, ZP=2457600/4915200, RC/SMB=73728 SIO1BCFG .SET DEFSERCFG ; SIO 1B: SERIAL LINE CONFIG SIO1BCTCC .SET -1 ; SIO 1B: CTC CHANNEL 0=A, 1=B, 2=C, 3=D, -1 FOR NONE ; +SCCENABLE .SET TRUE ; SCC: ENABLE ZILOG SCC SERIAL DRIVER (SCC.ASM) +SCCDEBUG .SET FALSE ; SCC: ENABLE DEBUG OUTPUT +SCCBOOT .SET 0 ; SCC: REBOOT ON RCV CHAR (0=DISABLED) +SCCCNT .SET 1 ; SCC: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP +SCCINTS .SET FALSE ; SCC: INCLUDE SCC INTERRUPT SUPPORT UNDER IM1/2/3 +SCC0MODE .SET SCCMODE_SZ80 ; SCC 0: CHIP TYPE: SCCMODE_[STD|SZ80] +SCC0BASE .SET $A0 ; SCC 0: REGISTERS BASE ADR +SCC0ACLK .SET 4915200 ; SCC 0A: OSC FREQ IN HZ, ZP=2457600/4915200, RC/SMB=7372800 +SCC0ACFG .SET DEFSERCFG ; SCC 0A: SERIAL LINE CONFIG +SCC0ACTCC .SET -1 ; SCC 0A: CTC CHANNEL 0=A, 1=B, 2=C, 3=D, -1 FOR NONE +SCC0BCLK .SET 4915200 ; SCC 0B: OSC FREQ IN HZ, ZP=2457600/4915200, RC/SMB=7372800 +SCC0BCFG .SET DEFSERCFG ; SCC 0B: SERIAL LINE CONFIG +SCC0BCTCC .SET -1 ; SCC 0B: CTC CHANNEL 0=A, 1=B, 2=C, 3=D, -1 FOR NONE +SCC1MODE .SET SCCMODE_SZ80 ; SCC 1: CHIP TYPE: SIOMODE_[STD|SZ80] +SCC1BASE .SET $FF ; SCC 1: REGISTERS BASE ADR +SCC1ACLK .SET 4915200 ; SCC 1A: OSC FREQ IN HZ, ZP=2457600/4915200, RC/SMB=7372800 +SCC1ACFG .SET DEFSERCFG ; SCC 1A: SERIAL LINE CONFIG +SCC1ACTCC .SET -1 ; SCC 1A: CTC CHANNEL 0=A, 1=B, 2=C, 3=D, -1 FOR NONE +SCC1BCLK .SET 4915200 ; SCC 1B: OSC FREQ IN HZ, ZP=2457600/4915200, RC/SMB=7372800 +SCC1BCFG .SET DEFSERCFG ; SCC 1B: SERIAL LINE CONFIG +SCC1BCTCC .SET -1 ; SCC 1B: CTC CHANNEL 0=A, 1=B, 2=C, 3=D, -1 FOR NONE +; XIOCFG .SET DEFSERCFG ; XIO: SERIAL LINE CONFIG ; VDUENABLE .SET FALSE ; VDU: ENABLE VDU VIDEO/KBD DRIVER (VDU.ASM) diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index ff750ad0..4b59c772 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -4102,6 +4102,9 @@ HB_PCINITTBL: #IF (SIOENABLE) .DW SIO_PREINIT #ENDIF +#IF (SCCENABLE) + .DW SCC_PREINIT +#ENDIF #IF (EZ80UARTENABLE) .DW EZUART_PREINIT #ENDIF @@ -4228,6 +4231,9 @@ HB_INITTBL: #IF (SIOENABLE) .DW SIO_INIT #ENDIF +#IF (SCCENABLE) + .DW SCC_INIT +#ENDIF #IF (EZ80UARTENABLE) .DW EZUART_INIT #ENDIF @@ -8953,6 +8959,15 @@ SIZ_SIO .EQU $ - ORG_SIO MEMECHO " bytes.\n" #ENDIF ; +#IF (SCCENABLE) +ORG_SCC .EQU $ + #INCLUDE "scc.asm" +SIZ_SCC .EQU $ - ORG_SCC + MEMECHO "SCC occupies " + MEMECHO SIZ_SCC + MEMECHO " bytes.\n" +#ENDIF +; #IF (ACIAENABLE) ORG_ACIA .EQU $ #INCLUDE "acia.asm" diff --git a/Source/HBIOS/hbios.inc b/Source/HBIOS/hbios.inc index b139e3fd..d5ee7042 100644 --- a/Source/HBIOS/hbios.inc +++ b/Source/HBIOS/hbios.inc @@ -398,6 +398,7 @@ CIODEV_SSER .EQU $0F CIODEV_EZ80UART .EQU $10 CIODEV_PLDSER .EQU $11 CIODEV_TSER .EQU $12 +CIODEV_SCC .EQU $13 ; ; SUB TYPES OF CHAR DEVICES ; diff --git a/Source/HBIOS/invntdev.asm b/Source/HBIOS/invntdev.asm index b45f1f72..781d4893 100644 --- a/Source/HBIOS/invntdev.asm +++ b/Source/HBIOS/invntdev.asm @@ -639,6 +639,7 @@ PS_SDSSER .TEXT "SSER$" PS_SDEZ80 .TEXT "EZ80$" PS_SDPLDSER .TEXT "PLDSER$" PS_SDTSER .TEXT "TSER$" +PS_SDSCC .TEXT "SCC$" ; ; CHARACTER SUB TYPE STRINGS ; diff --git a/Source/HBIOS/scc.asm b/Source/HBIOS/scc.asm new file mode 100644 index 00000000..72770a49 --- /dev/null +++ b/Source/HBIOS/scc.asm @@ -0,0 +1,1076 @@ +; +;================================================================================================== +; ZILOG SCC 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) -- +; +; TODO: +; - IMPLEMENT INTERRUPT DRIVEN BUFFER AND FLOW CONTROL +; +#IF ((SCCINTS) & (INTMODE > 0)) + .ECHO "*** ERROR: SCC DRIVER DOES NOT YET SUPPORT IONTERRUPTS!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR +#ENDIF +; +SCC_BUFSZ .EQU 32 ; RECEIVE RING BUFFER SIZE +; +SCC_NONE .EQU 0 +SCC_SCC .EQU 1 +; +SCC_DEFBAUD .EQU 38400 ; FAILSAFE BAUD RATE +SCC_DEFCLK .EQU 4915200 ; FAILSAVE BAUD CLOCK +SCC_DEFDIV .EQU (SCC_DEFCLK / (2 * 16 * SCC_DEFBAUD)) - 2 +; +SCC_RTSON .EQU $EA +SCC_RTSOFF .EQU $E8 +; +#IF ((SCCINTS) & (INTMODE > 0)) +SCC_WR1VAL .EQU $18 ; WR1 VALUE FOR INT ON RECEIVED CHARS +#ELSE +SCC_WR1VAL .EQU $00 ; WR1 VALUE FOR NO INTS +#ENDIF +; +#IF ((SCCINTS) & (INTMODE >= 2)) +; +SCC0_IVT .EQU IVT(INT_SCC0) +SCC1_IVT .EQU IVT(INT_SCC1) +SCC0_VEC .EQU VEC(INT_SCC0) +SCC1_VEC .EQU VEC(INT_SCC1) +; +#ENDIF +; +#IF (SCC0MODE == SCCMODE_STD) +SCC0A_CMD .EQU SCC0BASE + $01 +SCC0A_DAT .EQU SCC0BASE + $00 +SCC0B_CMD .EQU SCC0BASE + $03 +SCC0B_DAT .EQU SCC0BASE + $02 +#ENDIF +; +#IF (SCC0MODE == SCCMODE_SZ80) +SCC0A_CMD .EQU SCC0BASE + $01 +SCC0A_DAT .EQU SCC0BASE + $03 +SCC0B_CMD .EQU SCC0BASE + $00 +SCC0B_DAT .EQU SCC0BASE + $02 +#ENDIF +; +#IF (SCCCNT >= 2) +; + #IF (SCC1MODE == SCCMODE_STD) +SCC1A_CMD .EQU SCC1BASE + $01 +SCC1A_DAT .EQU SCC1BASE + $00 +SCC1B_CMD .EQU SCC1BASE + $03 +SCC1B_DAT .EQU SCC1BASE + $02 + #ENDIF +; + #IF (SCC0MODE == SCCMODE_SZ80) +SCC1A_CMD .EQU SCC1BASE + $01 +SCC1A_DAT .EQU SCC1BASE + $03 +SCC1B_CMD .EQU SCC1BASE + $00 +SCC1B_DAT .EQU SCC1BASE + $02 + #ENDIF +; +#ENDIF +; +SCC_PREINIT: +; +; SETUP THE DISPATCH TABLE ENTRIES +; NOTE: INTS WILL BE DISABLED WHEN PREINIT IS CALLED AND THEY MUST REMIAIN +; DISABLED. +; + CALL SCC_PROBE ; PROBE FOR CHIPS +; + LD B,SCC_CFGCNT ; LOOP CONTROL + XOR A ; ZERO TO ACCUM + LD (SCC_DEV),A ; CURRENT DEVICE NUMBER + LD IY,SCC_CFG ; POINT TO START OF CFG TABLE +SCC_PREINIT0: + PUSH BC ; SAVE LOOP CONTROL + CALL SCC_INITUNIT ; HAND OFF TO GENERIC INIT CODE + POP BC ; RESTORE LOOP CONTROL +; + LD A,(IY+1) ; GET THE SCC TYPE DETECTED + OR A ; SET FLAGS + JR Z,SCC_PREINIT2 ; SKIP IT IF NOTHING FOUND +; + PUSH BC ; SAVE LOOP CONTROL + PUSH IY ; CFG ENTRY ADDRESS + POP DE ; ... TO DE + LD BC,SCC_FNTBL ; BC := FUNCTION TABLE ADDRESS + CALL NZ,CIO_ADDENT ; ADD ENTRY IF SCC FOUND, BC:DE + POP BC ; RESTORE LOOP CONTROL +; +SCC_PREINIT2: + LD DE,SCC_CFGSIZ ; SIZE OF CFG ENTRY + ADD IY,DE ; BUMP IY TO NEXT ENTRY + DJNZ SCC_PREINIT0 ; LOOP UNTIL DONE +; +#IF ((SCCINTS) & (INTMODE > 0)) + ; SETUP INT VECTORS AS APPROPRIATE + LD A,(SCC_DEV) ; GET DEVICE COUNT + OR A ; SET FLAGS + JR Z,SCC_PREINIT3 ; IF ZERO, NO SCC DEVICES, ABORT +; + #IF (INTMODE == 1) + ; ADD IM1 INT CALL LIST ENTRY + LD HL,SCC_INT ; GET INT VECTOR + CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST + #ENDIF +; + #IF ((INTMODE == 2) | (INTMODE == 3)) + ; SETUP IM2/3 VECTORS + LD HL,SCC_INT0 + LD (SCC0_IVT),HL ; IVT INDEX +; + #IF (SCCCNT >= 2) + LD HL,SCC_INT1 + LD (SCC1_IVT),HL ; IVT INDEX + #ENDIF +; + #ENDIF +; +#ENDIF +; +SCC_PREINIT3: + XOR A ; SIGNAL SUCCESS + RET ; AND RETURN +; +; SCC INITIALIZATION ROUTINE +; +SCC_INITUNIT: + CALL SCC_DETECT ; DETERMINE SCC TYPE + LD (IY+1),A ; SAVE IN CONFIG TABLE + OR A ; SET FLAGS + RET Z ; ABORT IF NOTHING THERE + + ; UPDATE WORKING SCC DEVICE NUM + LD HL,SCC_DEV ; POINT TO CURRENT UART DEVICE NUM + LD A,(HL) ; PUT IN ACCUM + INC (HL) ; INCREMENT IT (FOR NEXT LOOP) + LD (IY),A ; UPDATE UNIT NUM + + ; IT IS EASY TO SPECIFY A SERIAL CONFIG THAT CANNOT BE IMPLEMENTED + ; DUE TO THE CONSTRAINTS OF THE SCC. HERE WE FORCE A GENERIC + ; FAILSAFE CONFIG ONTO THE CHANNEL. IF THE SUBSEQUENT "REAL" + ; CONFIG FAILS, AT LEAST THE CHIP WILL BE ABLE TO SPIT DATA OUT + ; AT A RATIONAL BAUD/DATA/PARITY/STOP CONFIG. + CALL SCC_INITSAFE +; + ; SET DEFAULT CONFIG + LD DE,-1 ; LEAVE CONFIG ALONE + JP SCC_INITDEV ; IMPLEMENT IT AND RETURN +; +; +; +SCC_INIT: + LD B,SCC_CFGCNT ; COUNT OF POSSIBLE SCC UNITS + LD IY,SCC_CFG ; POINT TO START OF CFG TABLE +SCC_INIT1: + PUSH BC ; SAVE LOOP CONTROL + LD A,(IY+1) ; GET SCC TYPE + OR A ; SET FLAGS + CALL NZ,SCC_PRTCFG ; PRINT IF NOT ZERO + POP BC ; RESTORE LOOP CONTROL + LD DE,SCC_CFGSIZ ; SIZE OF CFG ENTRY + ADD IY,DE ; BUMP IY TO NEXT ENTRY + DJNZ SCC_INIT1 ; LOOP TILL DONE +; + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +; RECEIVE INTERRUPT HANDLER +; +#IF ((SCCINTS) & (INTMODE > 0)) +; +; IM1 ENTRY POINT +; +SCC_INT: + ; CHECK/HANDLE FIRST CARD (SCC0) IF IT EXISTS + LD A,(SCC0A_CFG + 1) ; GET SCC TYPE FOR FIRST CHANNEL OF FIRST SCC + OR A ; SET FLAGS + CALL NZ,SCC_INT0 ; CALL IF CARD EXISTS + RET NZ ; DONE IF INT HANDLED +; + #IF (SCCCNT >= 2) + ; CHECK/HANDLE SECOND CARD (SCC1) IF IT EXISTS + LD A,(SCC1A_CFG + 1) ; GET SCC TYPE FOR FIRST CHANNEL OF SECOND SCC + OR A ; SET FLAGS + CALL NZ,SCC_INT1 ; CALL IF CARD EXISTS + #ENDIF +; + RET ; DONE +; +; IM2 ENTRY POINTS +; +SCC_INT0: + ; INTERRUPT HANDLER FOR FIRST SCC (SCC0) + LD IY,SCC0A_CFG ; POINT TO SCC0A CFG + CALL SCC_INTRCV ; TRY TO RECEIVE FROM IT + RET NZ ; DONE IF INT HANDLED + LD IY,SCC0B_CFG ; POINT TO SCC0B CFG + JR SCC_INTRCV ; TRY TO RECEIVE FROM IT AND RETURN +; + #IF (SCCCNT >= 2) +; +SCC_INT1: + ; INTERRUPT HANDLER FOR SECOND SCC (SCC1) + LD IY,SCC1A_CFG ; POINT TO SCC1A CFG + CALL SCC_INTRCV ; TRY TO RECEIVE FROM IT + RET NZ ; DONE IF INT HANDLED + LD IY,SCC1B_CFG ; POINT TO SCC1B CFG + JR SCC_INTRCV ; TRY TO RECEIVE FROM IT AND RETURN +; + #ENDIF +; +; HANDLE INT FOR A SPECIFIC CHANNEL +; BASED ON UNIT CFG POINTED TO BY IY +; +SCC_INTRCV: + ; CHECK TO SEE IF SOMETHING IS ACTUALLY THERE + LD C,(IY+3) ; CMD/STAT PORT TO C + XOR A ; A := 0 + OUT (C),A ; ADDRESS RD0 + IN A,(C) ; GET RD0 + AND $01 ; ISOLATE RECEIVE READY BIT + RET Z ; NOTHING AVAILABLE ON CURRENT CHANNEL +; +SCC_INTRCV1: + ; RECEIVE CHARACTER INTO BUFFER + LD C,(IY+4) ; DATA PORT TO C + IN A,(C) ; READ PORT + #IF (SCCBOOT != 0) + CP SCCBOOT ; REBOOT REQUEST? + JP Z,SYS_RESCOLD ; IF SO, DO IT, NO RETURN + #ENDIF + LD B,A ; SAVE BYTE READ + LD L,(IY+7) ; SET HL TO + LD H,(IY+8) ; ... START OF BUFFER STRUCT + LD A,(HL) ; GET COUNT + CP SCC_BUFSZ ; COMPARE TO BUFFER SIZE + JR Z,SCC_INTRCV4 ; BAIL OUT IF BUFFER FULL, RCV BYTE DISCARDED + INC A ; INCREMENT THE COUNT + LD (HL),A ; AND SAVE IT + CP SCC_BUFSZ / 2 ; BUFFER GETTING FULL? + JR NZ,SCC_INTRCV2 ; IF NOT, BYPASS CLEARING RTS + LD C,(IY+3) ; CMD/STAT PORT TO C + LD A,5 ; RTS IS IN WR5 + OUT (C),A ; ADDRESS WR5 + LD A,SCC_RTSOFF ; VALUE TO CLEAR RTS + OUT (C),A ; DO IT +SCC_INTRCV2: + INC HL ; HL NOW HAS ADR OF HEAD PTR + PUSH HL ; SAVE ADR OF HEAD PTR + LD A,(HL) ; DEREFERENCE HL + INC HL + LD H,(HL) + LD L,A ; HL IS NOW ACTUAL HEAD PTR + LD (HL),B ; SAVE CHARACTER RECEIVED IN BUFFER AT HEAD + INC HL ; BUMP HEAD POINTER + POP DE ; RECOVER ADR OF HEAD PTR + LD A,L ; GET LOW BYTE OF HEAD PTR + SUB SCC_BUFSZ+4 ; SUBTRACT SIZE OF BUFFER AND POINTER + CP E ; IF EQUAL TO START, HEAD PTR IS PAST BUF END + JR NZ,SCC_INTRCV3 ; IF NOT, BYPASS + LD H,D ; SET HL TO + LD L,E ; ... HEAD PTR ADR + INC HL ; BUMP PAST HEAD PTR + INC HL + INC HL + INC HL ; ... SO HL NOW HAS ADR OF ACTUAL BUFFER START +SCC_INTRCV3: + EX DE,HL ; DE := HEAD PTR VAL, HL := ADR OF HEAD PTR + LD (HL),E ; SAVE UPDATED HEAD PTR + INC HL + LD (HL),D + ; CHECK FOR MORE PENDING... + LD C,(IY+3) ; CMD/STAT PORT TO C + XOR A ; A := 0 + OUT (C),A ; ADDRESS RD0 + IN A,(C) ; GET RD0 + RRA ; READY BIT TO CF + JR C,SCC_INTRCV1 ; IF SET, DO SOME MORE +SCC_INTRCV4: + OR $FF ; NZ SET TO INDICATE INT HANDLED + RET ; AND RETURN +; +#ENDIF +; +; DRIVER FUNCTION TABLE +; +SCC_FNTBL: + .DW SCC_IN + .DW SCC_OUT + .DW SCC_IST + .DW SCC_OST + .DW SCC_INITDEV + .DW SCC_QUERY + .DW SCC_DEVICE +#IF (($ - SCC_FNTBL) != (CIO_FNCNT * 2)) + .ECHO "*** INVALID SCC FUNCTION TABLE ***\n" +#ENDIF +; +; +; +#IF ((SCCINTS) & (INTMODE > 0)) +; +SCC_IN: + CALL SCC_IST ; SEE IF CHAR AVAILABLE + JR Z,SCC_IN ; LOOP UNTIL SO + HB_DI ; AVOID COLLISCCN WITH INT HANDLER + LD L,(IY+7) ; SET HL TO + LD H,(IY+8) ; ... START OF BUFFER STRUCT + LD A,(HL) ; GET COUNT + DEC A ; DECREMENT COUNT + LD (HL),A ; SAVE UPDATED COUNT + CP SCC_BUFSZ / 4 ; BUFFER LOW THRESHOLD + JR NZ,SCC_IN1 ; IF NOT, BYPASS SETTING RTS + LD C,(IY+3) ; C IS CMD/STATUS PORT ADR + LD A,5 ; RTS IS IN WR5 + OUT (C),A ; ADDRESS WR5 + LD A,SCC_RTSON ; VALUE TO SET RTS + OUT (C),A ; DO IT +SCC_IN1: + INC HL + INC HL + INC HL ; HL NOW HAS ADR OF TAIL PTR + PUSH HL ; SAVE ADR OF TAIL PTR + LD A,(HL) ; DEREFERENCE HL + INC HL + LD H,(HL) + LD L,A ; HL IS NOW ACTUAL TAIL PTR + LD C,(HL) ; C := CHAR TO BE RETURNED + INC HL ; BUMP TAIL PTR + POP DE ; RECOVER ADR OF TAIL PTR + LD A,L ; GET LOW BYTE OF TAIL PTR + SUB SCC_BUFSZ+2 ; SUBTRACT SIZE OF BUFFER AND POINTER + CP E ; IF EQUAL TO START, TAIL PTR IS PAST BUF END + JR NZ,SCC_IN2 ; IF NOT, BYPASS + LD H,D ; SET HL TO + LD L,E ; ... TAIL PTR ADR + INC HL ; BUMP PAST TAIL PTR + INC HL ; ... SO HL NOW HAS ADR OF ACTUAL BUFFER START +SCC_IN2: + EX DE,HL ; DE := TAIL PTR VAL, HL := ADR OF TAIL PTR + LD (HL),E ; SAVE UPDATED TAIL PTR + INC HL + LD (HL),D + LD E,C ; MOVE CHAR TO RETURN TO E + HB_EI ; INTERRUPTS OK AGAIN + XOR A ; SIGNAL SUCCESS + RET ; AND DONE +; +#ELSE +; +SCC_IN: + CALL SCC_IST ; CHAR WAITING? + JR Z,SCC_IN ; LOOP IF NOT + LD C,(IY+4) ; DATA PORT + IN E,(C) ; GET CHAR + XOR A ; SIGNAL SUCCESS + RET +; +#ENDIF +; +; +; +SCC_OUT: + CALL SCC_OST ; READY FOR CHAR? + JR Z,SCC_OUT ; LOOP IF NOT + LD C,(IY+4) ; DATA PORT + OUT (C),E ; SEND CHAR FROM E + XOR A ; SIGNAL SUCCESS + RET +; +; +; +#IF ((SCCINTS) & (INTMODE > 0)) +; +SCC_IST: + LD L,(IY+7) ; GET ADDRESS + LD H,(IY+8) ; ... OF RECEIVE BUFFER + LD A,(HL) ; BUFFER UTILIZATION COUNT + OR A ; SET FLAGS + JP Z,CIO_IDLE ; NOT READY, RETURN VIA IDLE PROCESSING + RET +; +#ELSE +; +SCC_IST: + LD C,(IY+3) ; CMD PORT + XOR A ; WR0 + OUT (C),A ; DO IT + IN A,(C) ; GET STATUS + AND $01 ; ISOLATE BIT 0 (RX READY) + JP Z,CIO_IDLE ; NOT READY, RETURN VIA IDLE PROCESSING + XOR A ; ZERO ACCUM + INC A ; ASCCUM := 1 TO SIGNAL 1 CHAR WAITING + RET ; DONE +; +#ENDIF +; +; +; +SCC_OST: + LD C,(IY+3) ; CMD PORT + XOR A ; WR0 + OUT (C),A ; DO IT + IN A,(C) ; GET STATUS + AND $04 ; ISOLATE BIT 2 (TX EMPTY) + 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 +; +; AT INITIALIZATION THE SETUP PARAMETER WORD IS TRANSLATED TO THE FORMAT +; REQUIRED BY THE SCC AND STORED IN A PORT/REGISTER INITIALIZATION TABLE, +; WHICH IS THEN LOADED INTO THE SCC. +; +; RTS, DTR AND XON SETTING IS NOT CURRENTLY SUPPORTED. +; MARK & SPACE PARITY AND 1.5 STOP BITS IS NOT SUPPORTED BY THE SCC. +; INITIALIZATION WILL NOT BE COMPLETED IF AN INVALID SETTING IS DETECTED. +; +SCC_INITDEV: + ; INITDEV CAN BE CALLED PRIOR TO INTERRUPTS BEING ENABLED. WE + ; NEED TO LEAVE INTERRUPTS ALONE IN THIS SCENARIO + LD A,(INTSENAB) ; INTS ENABLED? + OR A ; TEST VALUE + JR Z,SCC_INITDEV0 ; BYPASS DI/EI IF NOT ENABLED +; + ; INTERRUPTS DISABLED DURING INIT + HB_DI ; DISABLE INTS + CALL SCC_INITDEV0 ; DO THE WORK + HB_EI ; INTS BACK ON + RET ; DONE +; +SCC_INITDEV0: +; +; THIS ENTRY POINT BYPASSES DISABLING/ENABLING INTS WHICH IS REQUIRED BY +; PREINIT ABOVE. PREINIT IS NOT ALLOWED TO ENABLE INTS! +; +#IF (SCCDEBUG) + CALL NEWLINE + PRTS("SCC$") + LD A,(IY+2) + SRL A + CALL PRTDECB + LD A,(IY+2) + AND $01 + ADD A,'A' + CALL COUT + CALL PC_COLON +#ENDIF +; + ; 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,SCC_INITDEV1 ; IF DE == -1, REINIT CURRENT CONFIG +; + ; LOAD EXISTING CONFIG TO REINIT + LD E,(IY+5) ; LOW BYTE + LD D,(IY+6) ; HIGH BYTE +; +SCC_INITDEV1: +; +#IF (SCCDEBUG) + PUSH DE + POP BC + PRTS(" CFG=$") + CALL PRTHEXWORD +#ENDIF +; + ; SETUP DEFAULT VALUES FOR SCC REGISTERS + PUSH DE + LD HL,SCC_INITDEFS + LD DE,SCC_INITVALS + LD BC,SCC_INITLEN + LDIR + POP DE + +; + ; BUILD WR4 + LD A,(SCC_WR4) + AND %11110000 ; CLEAR BITS WE ARE GOING TO CHG + SET 2,A ; ASSUME 1 STOP BIT + BIT 2,E ; WANT 2 STOP BITS? + JR Z,SCC_INITDEV_WR4A ; SKIP IF NOT + SET 3,A ; SET CONFIG BIT FOR 2 STOP BITS +SCC_INITDEV_WR4A: + BIT 3,E ; PARITY ENABLE? + JR Z,SCC_INITDEV_WR4B ; SKIP IF NOT + SET 0,A ; SET CONFIG BIT FOR PARITY ENABLE +SCC_INITDEV_WR4B: + BIT 4,E ; PARITY EVEN? + JR Z,SCC_INITDEV_WR4C ; SKIP IF NOT + SET 1,A ; SET CONFIG BIT FOR EVEN PARITY +SCC_INITDEV_WR4C: + LD (SCC_WR4),A ; SAVE WR4 VALUE +; + ; CREATE BITS PER CHAR VALUE + ; WARNING: SCC USES NON-SEQUENTIAL VALUES: + ; %00 = 5 BITS + ; %01 = 7 BITS + ; %10 = 6 BITS + ; %11 = 8 BITS + LD B,0 ; INIT B FOR WORKING VALUE + BIT 0,E ; BIT 0 OF E SET? + JR Z,SCC_INITDEV_BPCA ; SKIP IF NOT + SET 1,B ; SET BIT 1 OF B +SCC_INITDEV_BPCA: + BIT 1,E ; BIT 1 OF E SET? + JR Z,SCC_INITDEV_BPCB ; SKIP IF NOT + SET 0,B ; SET BIT 0 OF B +SCC_INITDEV_BPCB: +; + ; BUILD WR3 + LD A,(SCC_WR3) ; GET CUR WR3 VAL + AND %00111111 ; CLEAR BPC BITS + RRC B ; MOVE BPC BITS + RRC B ; ... INTO POSITION + OR B ; APPLY NEW BPC BITS + LD (SCC_WR3),A ; SAVE IT IN WR3 + SET 0,A ; ADD RX ENABLE + LD (SCC_WR3A),A ; AND SAVE IT IN WR3A +; + ; BUILD WR5 + LD A,(SCC_WR5) ; GET CUR WR5 VAL + AND %10011111 ; CLEAR BPC BITS + RRC B ; MOVE BPC BITS INTO POSITION + OR B ; APPLY NEW BPC BITS + LD (SCC_WR5),A ; SAVE IT IN WR5 + SET 3,A ; ADD TX ENABLE + LD (SCC_WR5A),A ; AND SAVE IT IN WR3A +; + ; DETERMINE BAUD DIVISOR + PUSH DE ; SAVE CONFIG + CALL SCC_COMPDIV ; COMPUTE DIVISOR TO BC + POP DE ; RESTORE CONFIG + RET NZ ; ABORT IF COMPDIV FAILS! +; + ; SCC BRG MUST BE PROGRAMMED WITH THE DIVISOR - 2 + DEC BC ; SUBTRACT 2 + DEC BC ; ... FROM DIVISOR + BIT 7,B ; DID WE UNDERFLOW? + JR NZ,SCC_INITERR ; ERROR IF SO +; + ; BUILD WR12/13 + LD A,C ; LSB OF BRG DIVISOR + LD (SCC_WR12),A ; SAVE IT + LD A,B ; MSB OF BRG DIVISOR + LD (SCC_WR13),A ; SAVE IT +; +; SAVE CONFIG PERMANENTLY NOW +; + LD (IY+5),E ; SAVE LOW WORD + LD (IY+6),D ; SAVE HI WORD +; + JR SCC_INITGO ; GO TO SEND INIT +; +SCC_INITERR: + OR $FF ; SIGNAL ERROR + RET +; +; ENTER HERE TO PERFORM A "SAFE" INITIALIZTION. I.E., INIT THE +; CHANNEL USING THE DEFAULT, GENERIC REGISTER VALUES. THIS CAN BE +; USED TO ENSURE INITIALIZATION IF THE FULL CONFIGURATION ABOVE +; FAILS. +; +SCC_INITSAFE: + ; SETUP DEFAULT VALUES FOR SCC REGISTERS + LD HL,SCC_INITDEFS + LD DE,SCC_INITVALS + LD BC,SCC_INITLEN + LDIR +; +SCC_INITGO: +; +; SET INTERRUPT VECTOR OFFSET WR2 +; +#IF ((SCCINTS) & (INTMODE >= 2)) + LD A,(IY+2) ; CHIP / CHANNEL + SRL A ; SHIFT AWAY CHANNEL BIT + LD L,SCC0_VEC ; ASSUME CHIP 0 + JR Z,SCC_INITIVT ; IF SO, DO IT + LD L,SCC1_VEC ; ASSUME CHIP 1 + DEC A ; CHIP 1? + JR Z,SCC_INITIVT ; IF SO, DO IT + SYSCHKERR(ERR_NOUNIT) ; IMPOSSIBLE SITUATION + RET +SCC_INITIVT: + LD A,L ; VALUE TO A + LD (SCC_WR2),A ; SAVE IT +; +#ENDIF +; +#IF (SCCDEBUG) + LD HL,SCC_INITVALS + LD B,SCC_INITLEN/2 +SCC_INITPRT: + PRTS(" WR$") + LD A,(HL) + CALL PRTHEXBYTE + INC HL + LD A,'=' + CALL COUT + LD A,(HL) + CALL PRTHEXBYTE + INC HL + DJNZ SCC_INITPRT + LD DE,65 + CALL VDELAY ; WAIT FOR FINAL CHAR TO SEND +#ENDIF +; + ; RESET THE CHANNEL + LD C,(IY+3) + XOR A + OUT (C),A ; SELECT WR0 + LD A,%10000000 ; CHANNEL A RESET CMD + BIT 0,(IY+2) ; TEST CHANNEL NUM + JR Z,SCC_INITGO1 ; SKIP AHEAD IF CHANNEL 0 + RRCA ; ADJUST FOR CHANNEL 1 +SCC_INITGO1: + OUT (C),A ; SEND IT + NOP ; SMALL DELAY REQUIRED +; + ; PROGRAM THE SCC CHIP CHANNEL + LD C,(IY+3) ; COMMAND PORT + LD HL,SCC_INITVALS ; POINT TO INIT VALUES + LD B,SCC_INITLEN ; COUNT OF BYTES TO WRITE + OTIR ; WRITE ALL VALUES +; +#IF ((SCCINTS) & (INTMODE > 0)) +; + ; RESET THE RECEIVE BUFFER + LD E,(IY+7) + LD D,(IY+8) ; DE := _CNT + XOR A ; A := 0 + LD (DE),A ; _CNT = 0 + INC DE ; DE := ADR OF _HD + PUSH DE ; SAVE IT + INC DE + INC DE + INC DE + INC DE ; DE := ADR OF _BUF + POP HL ; HL := ADR OF _HD + LD (HL),E + INC HL + LD (HL),D ; _HD := _BUF + INC HL + LD (HL),E + INC HL + LD (HL),D ; _TL := _BUF +; +#ENDIF +; + XOR A ; SIGNAL SUCCESS + RET ; RETURN +; +; THE FOLLOWING TABLE IS A GENERIC, STATIC SET OF CONFIG VALUES THAT CAN +; BE USED TO INITIALIZE THE CHIP. THESE ARE THE STARTING VALUES USED FOR +; CHIP CONFIGURATION. +; +; THE SCC IS A LITTLE PRICKLY ABOUT THE ORDER IN WHICH REGISTERS ARE +; WRITTEN DURING CONFIGURATION. THE FOLLOWING TABLE ESTABLISHES THE +; ORDER THE REGISTERS WILL BE PROGRAMMED AND SETS UP THE DEFAULT +; VALUES COPIED TO SCC_INITVALS. INITVALS IS ADJUSTED AS NEEDED, +; THEN INITVALS IS WRITTEN TO THE CHIP. +; +; *** UPDATE SCC_WR... EQUATES BELOW IF TABLE CHANGES!!! +; +SCC_INITDEFS: + .DB 4, $44 ; ASYNC MODE, X16, 1 STOP, NO PARITY ; 0100 0100 + .DB 3, $C0 ; RX 8 BITS PER CHAR ; 1100 0000 + .DB 5, $E2 ; TX 8 BITS PER CHAR ; 1110 0010 + .DB 11, $56 ; RTxC VIA BRG ; 0101 0110 + .DB 12, SCC_DEFDIV & $FF ; BAUD RATE DIVISOR LO BYTE + .DB 13, SCC_DEFDIV >> 8 ; BAUD RATE DIVISOR HI BYTE + .DB 14, $00 ; BRG SOURCE RTxC ; 0000 0000 + .DB 14, $01 ; ENABLE BRG ; 0000 0001 + .DB 3, $C1 ; ENABLE RECEIVER ; 1100 0001 + .DB 5, $EA ; ENABLE TRANSMITTER ; 1110 1010 +; +SCC_INITLEN .EQU $ - SCC_INITDEFS +; +SCC_INITVALS .FILL SCC_INITLEN,0 +; +; BELOW ADDRESSES USED TO ADDRESS CONFIGURATION VALUE REGISTERS +; *** MUST SYNC WITH SCC_INITDEFS !!! +; +SCC_WR4 .EQU SCC_INITVALS + 1 +SCC_WR3 .EQU SCC_WR4 + 2 +SCC_WR5 .EQU SCC_WR3 + 2 +SCC_WR11 .EQU SCC_WR5 + 2 +SCC_WR12 .EQU SCC_WR11 + 2 +SCC_WR13 .EQU SCC_WR12 + 2 +SCC_WR14 .EQU SCC_WR13 + 2 +SCC_WR14A .EQU SCC_WR14 + 2 +SCC_WR3A .EQU SCC_WR14A + 2 +SCC_WR5A .EQU SCC_WR3A + 2 +; +; +; +SCC_QUERY: + LD E,(IY+5) ; FIRST CONFIG BYTE TO E + LD D,(IY+6) ; SECOND CONFIG BYTE TO D + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +; +; +SCC_DEVICE: + LD D,CIODEV_SCC ; D := DEVICE TYPE + LD E,(IY) ; E := PHYSICAL UNIT + LD C,$00 ; C := DEVICE TYPE, 0x00 IS RS-232 + LD H,(IY+14) ; H := MODE + LD L,(IY+3) ; L := BASE I/O ADDRESS + XOR A ; SIGNAL SUCCESS + RET +; +; SCC CHIP PROBE +; CHECK FOR PRESENCE OF SCC CHIPS AND POPULATE THE +; SCC_MAP BITMAP (ONE BIT PER CHIP). THIS DETECTS +; CHIPS, NOT CHANNELS. EACH CHIP HAS 2 CHANNELS. +; MAX OF TWO CHIPS CURRENTLY. INT VEC VALUE IS TRASHED! +; +SCC_PROBE: + ; CLEAR THE PRESENCE BITMAP + LD HL,SCC_MAP ; HL POINTS TO BITMAP + XOR A ; ZERO + LD (SCC_MAP),A ; CLEAR CHIP PRESENT BITMAP + ; INIT THE INT VEC REGISTER OF ALL POSSIBLE CHIPS + ; TO ZERO. A IS STILL ZERO. + LD B,2 ; WR2 REGISTER (INT VEC) + LD C,SCC0B_CMD ; FIRST CHIP + CALL SCC_WR ; WRITE ZERO TO CHIP REG +#IF (SCCCNT >= 2) + LD C,SCC1B_CMD ; SECOND CHIP + CALL SCC_WR ; WRITE ZERO TO CHIP REG +#ENDIF + ; FIRST POSSIBLE CHIP + LD C,SCC0B_CMD ; FIRST CHIP CMD/STAT PORT + CALL SCC_PROBECHIP ; PROBE IT + JR NZ,SCC_PROBE1 ; IF NOT ZERO, NOT FOUND + SET 0,(HL) ; SET BIT FOR FIRST CARD +SCC_PROBE1: +; +#IF (SCCCNT >= 2) + LD C,SCC1B_CMD ; SECOND CHIP CMD/STAT PORT + CALL SCC_PROBECHIP ; PROBE IT + JR NZ,SCC_PROBE2 ; IF NOT ZERO, NOT FOUND + SET 1,(HL) ; SET BIT FOR SECOND CARD +SCC_PROBE2: +#ENDIF +; + RET +; +SCC_PROBECHIP: + ; READ WR2 TO ENSURE IT IS ZERO (AVOID PHANTOM PORTS) + CALL SCC_RD ; GET VALUE + AND $F0 ; ONLY TOP NIBBLE + RET NZ ; ABORT IF NOT ZERO + ; WRITE INT VEC VALUE TO WR2 + LD A,$FF ; TEST VALUE + CALL SCC_WR ; WRITE IT + ; READ WR2 TO CONFIRM VALUE WRITTEN + CALL SCC_RD ; REREAD VALUE + AND $F0 ; ONLY TOP NIBBLE + CP $F0 ; COMPARE + RET ; DONE, Z IF FOUND, NZ IF MISCOMPARE +; +; READ/WRITE CHIP REGISTER. ENTER CHIP CMD/STAT PORT ADR IN C +; AND CHIP REGISTER NUMBER IN B. VALUE TO WRITE IN A OR VALUE +; RETURNED IN A. +; +SCC_WR: + OUT (C),B ; SELECT CHIP REGISTER + OUT (C),A ; WRITE VALUE + RET +; +SCC_RD: + OUT (C),B ; SELECT CHIP REGISTER + IN A,(C) ; GET VALUE + RET +; +; SCC DETECTION ROUTINE +; THERE IS ONLY ONE VARIATION OF SCC CHIP, SO HERE WE JUST CHECK THE +; CHIP PRESENCE BITMAP TO SET THE CHIP TYPE OF EITHER NONE OR SCC. +; +SCC_DETECT: + LD B,(IY+2) ; GET CHIP/CHANNEL + SRL B ; SHIFT AWAY THE CHANNEL BIT + INC B ; NUMBER OF TIMES TO ROTATE BITS + LD A,(SCC_MAP) ; BIT MAP IN A +SCC_DETECT1: + ; ROTATE DESIRED CHIP BIT INTO CF + RRA ; ROTATE NEXT BIT INTO CF + DJNZ SCC_DETECT1 ; DO THIS UNTIL WE HAVE DESIRED BIT + ; RETURN CHIP TYPE + LD A,SCC_NONE ; ASSUME NOTHING HERE + RET NC ; IF CF NOT SET, RETURN + LD A,SCC_SCC ; CHIP TYPE IS SCC + RET ; DONE +; +; COMPUTE DIVISOR TO BC +; +SCC_COMPDIV: + ; WE WANT TO DETERMINE A DIVISOR FOR THE BAUD CLOCK + ; THAT RESULTS IN THE DESIRED BAUD RATE. + ; BAUD RATE = BAUD CLK / DIVISOR, OR TO SOLVE FOR DIVISOR + ; DIVISOR = BAUD CLK / BAUDRATE. + ; THE BAUD CLOCK IS THE SCC OSC PRESCALED BY 32. WE CAN + ; TAKE ADVANTAGE OF ENCODED BAUD RATES ALWAYS BEING A FACTOR OF 75. + ; SO, WE CAN USE (BAUD CLK / 32 / 75) / (BAUDRATE / 75) +; + ; FIRST WE DECODE THE BAUDRATE, BUT WE USE A CONSTANT OF 1 INSTEAD + ; OF THE NORMAL 75. THIS PRODUCES (BAUDRATE / 75). + LD A,D ; GET CONFIG MSB + AND $1F ; ISOLATE ENCODED BAUD RATE + LD L,A ; PUT IN L + LD H,0 ; H IS ALWAYS ZERO + LD DE,1 ; USE 1 FOR ENCODING CONSTANT + CALL DECODE ; DE:HL := BAUD RATE, ERRORS IGNORED + EX DE,HL ; DE := (BAUDRATE / 75), DISCARD HL + PUSH DE ; SAVE FOR NOW +; + ; GET THE BAUD CLOCK FROM CONFIG + LD A,9 + CALL LDHLIYA ; HL = ADR OF BAUD CLOCK DWORD + CALL LD32 ; GET THE BAUD CLOCK SPEED +; + ; DIVIDE BY 32, THEN 75 TO PRODUCE (BAUD CLK / 32 / 75) + LD C,32 ; DIVIDE BY 32 + CALL DIV32X8 ; DO IT + LD C,75 ; DIVIDE BY 75 + CALL DIV32X8 ; DO IT +; + ; RECOVER THE BAUDRATE AND RETURN VIA FINAL DIVISION + POP DE ; RECOVER DE (DECODED BAUD RATE) + JP DIV16 ; BC := HL/DE == DIVISOR AND RETURN +; +; +; +SCC_PRTCFG: + ; ANNOUNCE PORT + CALL NEWLINE ; FORMATTING + PRTS("SCC$") ; FORMATTING + LD A,(IY) ; DEVICE NUM + CALL PRTDECB ; PRINT DEVICE NUM + PRTS(": IO=0x$") ; FORMATTING + LD A,(IY+3) ; GET BASE PORT + CALL PRTHEXBYTE ; PRINT BASE PORT + + ; PRINT THE SCC TYPE + CALL PC_SPACE ; FORMATTING + LD A,(IY+1) ; GET SCC TYPE BYTE + RLCA ; MAKE IT A WORD OFFSET + LD HL,SCC_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 SCC WAS DETECTED + LD A,(IY+1) ; GET SCC TYPE BYTE + OR A ; SET FLAGS + RET Z ; IF ZERO, NOT PRESENT +; + PRTS(" MODE=$") ; FORMATTING + LD E,(IY+5) ; LOAD CONFIG + LD D,(IY+6) ; ... WORD TO DE + CALL PS_PRTSC0 ; PRINT CONFIG +; + XOR A + RET +; +; +; +SCC_TYPE_MAP: + .DW SCC_STR_NONE + .DW SCC_STR_SCC + +SCC_STR_NONE .DB "$" +SCC_STR_SCC .DB "SCC$" +; +; WORKING VARIABLES +; +SCC_DEV .DB 0 ; DEVICE NUM USED DURING INIT +SCC_MAP .DB 0 ; CHIP PRESENCE BITMAP +; +#IF ((SCCINTS) & (INTMODE > 0)) +; +; SCC0 CHANNEL A RECEIVE BUFFER +SCC0A_RCVBUF: +SCC0A_CNT .DB 0 ; CHARACTERS IN RING BUFFER +SCC0A_HD .DW SCC0A_BUF ; BUFFER HEAD POINTER +SCC0A_TL .DW SCC0A_BUF ; BUFFER TAIL POINTER +SCC0A_BUF .FILL SCC_BUFSZ,0 ; RECEIVE RING BUFFER +; +; SCC0 CHANNEL B RECEIVE BUFFER +SCC0B_RCVBUF: +SCC0B_CNT .DB 0 ; CHARACTERS IN RING BUFFER +SCC0B_HD .DW SCC0B_BUF ; BUFFER HEAD POINTER +SCC0B_TL .DW SCC0B_BUF ; BUFFER TAIL POINTER +SCC0B_BUF .FILL SCC_BUFSZ,0 ; RECEIVE RING BUFFER +; + #IF (SCCCNT >= 2) +; +; SCC1 CHANNEL A RECEIVE BUFFER +SCC1A_RCVBUF: +SCC1A_CNT .DB 0 ; CHARACTERS IN RING BUFFER +SCC1A_HD .DW SCC1A_BUF ; BUFFER HEAD POINTER +SCC1A_TL .DW SCC1A_BUF ; BUFFER TAIL POINTER +SCC1A_BUF .FILL SCC_BUFSZ,0 ; RECEIVE RING BUFFER +; +; SCC1 CHANNEL B RECEIVE BUFFER +SCC1B_RCVBUF: +SCC1B_CNT .DB 0 ; CHARACTERS IN RING BUFFER +SCC1B_HD .DW SCC1B_BUF ; BUFFER HEAD POINTER +SCC1B_TL .DW SCC1B_BUF ; BUFFER TAIL POINTER +SCC1B_BUF .FILL SCC_BUFSZ,0 ; RECEIVE RING BUFFER +; + #ENDIF +; +#ELSE +; +SCC0A_RCVBUF .EQU 0 +SCC0B_RCVBUF .EQU 0 +; + #IF (SCCCNT >= 2) +SCC1A_RCVBUF .EQU 0 +SCC1B_RCVBUF .EQU 0 + #ENDIF +; +#ENDIF +; +; SCC PORT TABLE +; +SCC_CFG: + ; SCC0 CHANNEL A +SCC0A_CFG: + .DB 0 ; DEVICE NUMBER (SET DURING INIT) + .DB 0 ; SCC TYPE (SET DURING INIT) + .DB $00 ; CHIP 0 / CHANNEL A (LOW BIT IS CHANNEL) + .DB SCC0A_CMD ; CMD/STATUS PORT + .DB SCC0A_DAT ; DATA PORT + .DW SCC0ACFG ; LINE CONFIGURATION + .DW SCC0A_RCVBUF ; POINTER TO RCV BUFFER STRUCT + .DW SCC0ACLK & $FFFF ; CLOCK FREQ AS + .DW SCC0ACLK >> 16 ; ... DWORD VALUE + .DB SCC0ACTCC ; CTC CHANNEL + .DB SCC0MODE ; MODE +; + DEVECHO "SCC MODE=" +#IF (SCC0MODE == SCCMODE_STD) + DEVECHO "STD" +#ENDIF +#IF (SCC0MODE == SCCMODE_SZ80) + DEVECHO "SZ80" +#ENDIF + DEVECHO ", IO=" + DEVECHO SCC0BASE + DEVECHO ", CHANNEL A" +#IF ((SCCINTS) & (INTMODE > 0)) + DEVECHO ", INTERRUPTS ENABLED" +#ENDIF + DEVECHO "\n" +; +SCC_CFGSIZ .EQU $ - SCC_CFG ; SIZE OF ONE CFG TABLE ENTRY +; + ; SCC0 CHANNEL B +SCC0B_CFG: + .DB 0 ; DEVICE NUMBER (SET DURING INIT) + .DB 0 ; SCC TYPE (SET DURING INIT) + .DB $01 ; CHIP 0 / CHANNEL B (LOW BIT IS CHANNEL) + .DB SCC0B_CMD ; CMD/STATUS PORT + .DB SCC0B_DAT ; DATA PORT + .DW SCC0BCFG ; LINE CONFIGURATION + .DW SCC0B_RCVBUF ; POINTER TO RCV BUFFER STRUCT + .DW SCC0BCLK & $FFFF ; CLOCK FREQ AS + .DW SCC0BCLK >> 16 ; ... DWORD VALUE + .DB SCC0BCTCC ; CTC CHANNEL + .DB SCC0MODE ; MODE +; + DEVECHO "SCC MODE=" +#IF (SCC0MODE == SCCMODE_STD) + DEVECHO "STD" +#ENDIF +#IF (SCC0MODE == SCCMODE_SZ80) + DEVECHO "SZ80" +#ENDIF + DEVECHO ", IO=" + DEVECHO SCC0BASE + DEVECHO ", CHANNEL B" +#IF ((SCCINTS) & (INTMODE > 0)) + DEVECHO ", INTERRUPTS ENABLED" +#ENDIF + DEVECHO "\n" +; +#IF (SCCCNT >= 2) +; + ; SCC1 CHANNEL A +SCC1A_CFG: + .DB 0 ; DEVICE NUMBER (SET DURING INIT) + .DB 0 ; SCC TYPE (SET DURING INIT) + .DB $02 ; CHIP 1 / CHANNEL A (LOW BIT IS CHANNEL) + .DB SCC1A_CMD ; CMD/STATUS PORT + .DB SCC1A_DAT ; DATA PORT + .DW SCC1ACFG ; LINE CONFIGURATION + .DW SCC1A_RCVBUF ; POINTER TO RCV BUFFER STRUCT + .DW SCC1ACLK & $FFFF ; CLOCK FREQ AS + .DW SCC1ACLK >> 16 ; ... DWORD VALUE + .DB SCC1ACTCC ; CTC CHANNEL + .DB SCC1MODE ; MODE +; + DEVECHO "SCC MODE=" + #IF (SCC1MODE == SCCMODE_STD) + DEVECHO "STD" + #ENDIF + #IF (SCC1MODE == SCCMODE_SZ80) + DEVECHO "SZ80" + #ENDIF + DEVECHO ", IO=" + DEVECHO SCC1BASE + DEVECHO ", CHANNEL A" + #IF ((SCCINTS) & (INTMODE > 0)) + DEVECHO ", INTERRUPTS ENABLED" + #ENDIF + DEVECHO "\n" +; + ; SCC1 CHANNEL B +SCC1B_CFG: + .DB 0 ; DEVICE NUMBER (SET DURING INIT) + .DB 0 ; SCC TYPE (SET DURING INIT) + .DB $03 ; CHIP 1 / CHANNEL B (LOW BIT IS CHANNEL) + .DB SCC1B_CMD ; CMD/STATUS PORT + .DB SCC1B_DAT ; DATA PORT + .DW SCC1BCFG ; LINE CONFIGURATION + .DW SCC1B_RCVBUF ; POINTER TO RCV BUFFER STRUCT + .DW SCC1BCLK & $FFFF ; CLOCK FREQ AS + .DW SCC1BCLK >> 16 ; ... DWORD VALUE + .DB SCC1BCTCC ; CTC CHANNEL + .DB SCC1MODE ; MODE +; + DEVECHO "SCC MODE=" + #IF (SCC1MODE == SCCMODE_STD) + DEVECHO "STD" + #ENDIF + #IF (SCC1MODE == SCCMODE_SZ80) + DEVECHO "SZ80" + #ENDIF + DEVECHO ", IO=" + DEVECHO SCC1BASE + DEVECHO ", CHANNEL B" + #IF ((SCCINTS) & (INTMODE > 0)) + DEVECHO ", INTERRUPTS ENABLED" + #ENDIF + DEVECHO "\n" +; +#ENDIF +; +SCC_CFGCNT .EQU ($ - SCC_CFG) / SCC_CFGSIZ diff --git a/Source/HBIOS/std.asm b/Source/HBIOS/std.asm index a06977df..d7c32872 100644 --- a/Source/HBIOS/std.asm +++ b/Source/HBIOS/std.asm @@ -161,6 +161,12 @@ SIOMODE_SMB .EQU 3 ; RCBUS SIO MODULE (SCOTT BAKER) SIOMODE_ZP .EQU 4 ; ECB-ZILOG PERIPHERALS BOARD SIOMODE_Z80R .EQU 5 ; SIO A/B SWAPPED ; +; SIO MODE SELECTIONS +; +SCCMODE_NONE .EQU 0 +SCCMODE_STD .EQU 1 ; STD REG CFG (KIO) +SCCMODE_SZ80 .EQU 2 ; S100 SERIAL I/O +; ; TYPE OF CONSOLE BELL TO USE ; CONBELL_NONE .EQU 0 diff --git a/Source/ver.inc b/Source/ver.inc index ef52cc31..d9fcfede 100644 --- a/Source/ver.inc +++ b/Source/ver.inc @@ -2,7 +2,7 @@ #DEFINE RMN 6 #DEFINE RUP 0 #DEFINE RTP 0 -#DEFINE BIOSVER "3.6.0-dev.37" +#DEFINE BIOSVER "3.6.0-dev.38" #define rmj RMJ #define rmn RMN #define rup RUP diff --git a/Source/ver.lib b/Source/ver.lib index 404271b9..7c14b45e 100644 --- a/Source/ver.lib +++ b/Source/ver.lib @@ -3,5 +3,5 @@ rmn equ 6 rup equ 0 rtp equ 0 biosver macro - db "3.6.0-dev.37" + db "3.6.0-dev.38" endm