; ;================================================================================================== ; SIO 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) -- ; ; SIO_NONE .EQU 0 SIO_SIO .EQU 1 ; #IF (SIOMODE == SIOMODE_RC) SIOA_CMD .EQU SIOBASE + $00 ;PS SIOA_DAT .EQU SIOBASE + $01 ;PS SIOB_CMD .EQU SIOBASE + $02 ;PS SIOB_DAT .EQU SIOBASE + $03 ;PS #ENDIF ; #IF (SIOMODE == SIOMODE_SMB) SIOA_CMD .EQU SIOBASE + $02 ;PS SIOA_DAT .EQU SIOBASE + $00 ;PS SIOB_CMD .EQU SIOBASE + $03 ;PS SIOB_WR4 .EQU SIOBASE + $01 ;PS #ENDIF ; #IF (SIOMODE == SIOMODE_ZP) ;PS SIOA_CMD .EQU SIOBASE + $06 ;PS SIOA_DAT .EQU SIOBASE + $04 ;PS SIOB_CMD .EQU SIOBASE + $07 ;PS SIOB_DAT .EQU SIOBASE + $05 ;PS #ENDIF ;PS ; #IF (DEFSIOCLK/DEFSIODIV/1 == 75) SIOBAUD1 .EQU 0 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 150) SIOBAUD1 .EQU 1 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 300) SIOBAUD1 .EQU 2 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 600) SIOBAUD1 .EQU 3 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 1200) SIOBAUD1 .EQU 4 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 2400) SIOBAUD1 .EQU 5 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 4800) SIOBAUD1 .EQU 6 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 9600) SIOBAUD1 .EQU 7 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 19200) SIOBAUD1 .EQU 8 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 38400) SIOBAUD1 .EQU 9 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 76800) SIOBAUD1 .EQU 10 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 153600) SIOBAUD1 .EQU 11 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 307200) SIOBAUD1 .EQU 12 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 614400) SIOBAUD1 .EQU 13 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 =1228800) SIOBAUD1 .EQU 14 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 =2457600) SIOBAUD1 .EQU 15 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 225) SIOBAUD1 .EQU 16 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 450) SIOBAUD1 .EQU 17 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 900) SIOBAUD1 .EQU 18 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 1800) SIOBAUD1 .EQU 19 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 3600) SIOBAUD1 .EQU 20 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 7200) SIOBAUD1 .EQU 21 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 14400) SIOBAUD1 .EQU 22 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 28800) SIOBAUD1 .EQU 23 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 57600) SIOBAUD1 .EQU 24 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 115200) SIOBAUD1 .EQU 25 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 230400) SIOBAUD1 .EQU 26 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 == 921600) SIOBAUD1 .EQU 28 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 =1843200) SIOBAUD1 .EQU 29 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 =3686400) SIOBAUD1 .EQU 30 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/1 =7372800) SIOBAUD1 .EQU 31 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 75) SIOBAUD1 .EQU 0 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 150) SIOBAUD2 .EQU 1 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 300) SIOBAUD2 .EQU 2 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 600) SIOBAUD2 .EQU 3 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 1200) SIOBAUD2 .EQU 4 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 2400) SIOBAUD2 .EQU 5 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 4800) SIOBAUD2 .EQU 6 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 9600) SIOBAUD2 .EQU 7 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 19200) SIOBAUD2 .EQU 8 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 38400) SIOBAUD2 .EQU 9 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 76800) SIOBAUD2 .EQU 10 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 153600) SIOBAUD2 .EQU 11 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 307200) SIOBAUD2 .EQU 12 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 614400) SIOBAUD2 .EQU 13 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 =1228800) SIOBAUD2 .EQU 14 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 =2457600) SIOBAUD2 .EQU 15 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 225) SIOBAUD2 .EQU 16 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 450) SIOBAUD2 .EQU 17 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 900) SIOBAUD2 .EQU 18 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 1800) SIOBAUD2 .EQU 19 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 3600) SIOBAUD2 .EQU 20 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 7200) SIOBAUD2 .EQU 21 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 14400) SIOBAUD2 .EQU 22 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 28800) SIOBAUD2 .EQU 23 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 57600) SIOBAUD2 .EQU 24 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 115200) SIOBAUD2 .EQU 25 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 230400) SIOBAUD2 .EQU 26 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 460800) SIOBAUD2 .EQU 27 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 == 921600) SIOBAUD2 .EQU 28 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 ==1843200) SIOBAUD2 .EQU 29 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 ==3686400) SIOBAUD2 .EQU 30 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/16 ==7372800) SIOBAUD2 .EQU 31 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 75) SIOBAUD3 .EQU 0 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 150) SIOBAUD3 .EQU 1 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 300) SIOBAUD3 .EQU 2 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 600) SIOBAUD3 .EQU 3 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 1200) SIOBAUD3 .EQU 4 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 2400) SIOBAUD3 .EQU 5 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 4800) SIOBAUD3 .EQU 6 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 9600) SIOBAUD3 .EQU 7 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 19200) SIOBAUD3 .EQU 8 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 38400) SIOBAUD3 .EQU 9 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 76800) SIOBAUD3 .EQU 10 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 153600) SIOBAUD3 .EQU 11 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 307200) SIOBAUD3 .EQU 12 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 614400) SIOBAUD3 .EQU 13 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32==1228800) SIOBAUD3 .EQU 14 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32==2457600) SIOBAUD3 .EQU 15 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 225) SIOBAUD3 .EQU 16 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 450) SIOBAUD3 .EQU 17 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 900) SIOBAUD3 .EQU 18 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 1800) SIOBAUD3 .EQU 19 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 3600) SIOBAUD3 .EQU 20 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 7200) SIOBAUD3 .EQU 21 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 14400) SIOBAUD3 .EQU 22 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 28800) SIOBAUD3 .EQU 23 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 57600) SIOBAUD3 .EQU 24 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32= 115200) SIOBAUD3 .EQU 25 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32= 230400) SIOBAUD3 .EQU 26 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 460800) SIOBAUD3 .EQU 27 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32== 921600) SIOBAUD3 .EQU 28 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32==1843200) SIOBAUD3 .EQU 29 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32==3686400) SIOBAUD3 .EQU 30 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/32==7372800) SIOBAUD3 .EQU 31 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 75) SIOBAUD4 .EQU 0 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 150) SIOBAUD4 .EQU 1 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 300) SIOBAUD4 .EQU 2 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 600) SIOBAUD4 .EQU 3 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 1200) SIOBAUD4 .EQU 4 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 2400) SIOBAUD4 .EQU 5 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 4800) SIOBAUD4 .EQU 6 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 9600) SIOBAUD4 .EQU 7 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 19200) SIOBAUD4 .EQU 8 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 38400) SIOBAUD4 .EQU 9 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 76800) SIOBAUD4 .EQU 10 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 153600) SIOBAUD4 .EQU 11 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 307200) SIOBAUD4 .EQU 12 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 614400) SIOBAUD4 .EQU 13 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64==1228800) SIOBAUD4 .EQU 14 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64==2457600) SIOBAUD4 .EQU 15 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 225) SIOBAUD4 .EQU 16 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 450) SIOBAUD4 .EQU 17 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 900) SIOBAUD4 .EQU 18 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 1800) SIOBAUD4 .EQU 19 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 3600) SIOBAUD4 .EQU 20 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 7200) SIOBAUD4 .EQU 21 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 14400) SIOBAUD4 .EQU 22 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 28800) SIOBAUD4 .EQU 23 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 57600) SIOBAUD4 .EQU 24 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 115200) SIOBAUD4 .EQU 25 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 230400) SIOBAUD4 .EQU 26 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 460800) SIOBAUD4 .EQU 27 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64== 921600) SIOBAUD4 .EQU 28 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64==1843200) SIOBAUD4 .EQU 29 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64==3686400) SIOBAUD4 .EQU 30 #ENDIF #IF (DEFSIOCLK/DEFSIODIV/64==7372800) SIOBAUD4 .EQU 31 #ENDIF ; SIO_PREINIT: ; ; SETUP THE DISPATCH TABLE ENTRIES ; LD B,SIO_CNT ; LOOP CONTROL LD C,0 ; PHYSICAL UNIT INDEX XOR A ; ZERO TO ACCUM LD (SIO_DEV),A ; CURRENT DEVICE NUMBER SIO_PREINIT0: PUSH BC ; SAVE LOOP CONTROL LD A,C ; PHYSICAL UNIT TO A RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (8 BYTES) RLCA ; ... RLCA ; ... TO GET OFFSET INTO CFG TABLE LD HL,SIO_CFG ; POINT TO START OF CFG TABLE CALL ADDHLA ; HL := ENTRY ADDRESS PUSH HL ; SAVE IT PUSH HL ; COPY CFG DATA PTR POP IY ; ... TO IY CALL SIO_INITUNIT ; HAND OFF TO GENERIC INIT CODE POP DE ; GET ENTRY ADDRESS BACK, BUT PUT IN DE POP BC ; RESTORE LOOP CONTROL ; LD A,(IY + 1) ; GET THE SIO TYPE DETECTED OR A ; SET FLAGS JR Z,SIO_PREINIT2 ; SKIP IT IF NOTHING FOUND ; PUSH BC ; SAVE LOOP CONTROL LD BC,SIO_FNTBL ; BC := FUNCTION TABLE ADDRESS CALL NZ,CIO_ADDENT ; ADD ENTRY IF SIO FOUND, BC:DE POP BC ; RESTORE LOOP CONTROL ; SIO_PREINIT2: INC C ; NEXT PHYSICAL UNIT DJNZ SIO_PREINIT0 ; LOOP UNTIL DONE ; #IF (INTMODE == 1) ; ADD IM1 INT CALL LIST ENTRY IF APPROPRIATE LD A,(SIO_DEV) ; GET NEXT DEVICE NUM OR A ; SET FLAGS JR Z,SIO_PREINIT3 ; IF ZERO, NO SIO DEVICES LD HL,SIO_INT ; GET INT VECTOR CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST #ENDIF ; #IF (INTMODE == 2) ; SETUP SIO INTERRUPT VECTOR IN IVT LD HL,INT_SIO LD (HBX_IVT + IVT_SER0),HL #ENDIF ; SIO_PREINIT3: XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; ; SIO INITIALIZATION ROUTINE ; SIO_INITUNIT: CALL SIO_DETECT ; DETERMINE SIO TYPE LD (IY + 1),A ; SAVE IN CONFIG TABLE OR A ; SET FLAGS RET Z ; ABORT IF NOTHING THERE ; UPDATE WORKING SIO DEVICE NUM LD HL,SIO_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 ; SET DEFAULT CONFIG LD DE,-1 ; LEAVE CONFIG ALONE JP SIO_INITDEV ; IMPLEMENT IT AND RETURN ; ; ; SIO_INIT: LD B,SIO_CNT ; COUNT OF POSSIBLE SIO UNITS LD C,0 ; INDEX INTO SIO CONFIG TABLE SIO_INIT1: PUSH BC ; SAVE LOOP CONTROL LD A,C ; PHYSICAL UNIT TO A RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (8 BYTES) RLCA ; ... RLCA ; ... TO GET OFFSET INTO CFG TABLE LD HL,SIO_CFG ; POINT TO START OF CFG TABLE CALL ADDHLA ; HL := ENTRY ADDRESS PUSH HL ; COPY CFG DATA PTR POP IY ; ... TO IY LD A,(IY + 1) ; GET SIO TYPE OR A ; SET FLAGS CALL NZ,SIO_PRTCFG ; PRINT IF NOT ZERO POP BC ; RESTORE LOOP CONTROL INC C ; NEXT UNIT DJNZ SIO_INIT1 ; LOOP TILL DONE ; XOR A ; SIGNAL SUCCESS RET ; DONE ; ; INTERRUPT HANDLER ; SIO_INT: SIOA_INT: ; CHECK FOR RECEIVE PENDING ON CHANNEL A XOR A ; A := 0 OUT (SIOA_CMD),A ; ADDRESS RD0 IN A,(SIOA_CMD) ; GET RD0 AND $01 ; ISOLATE RECEIVE READY BIT JR Z,SIOB_INT ; CHECK CHANNEL B ; SIOA_INT00: ; HANDLE CHANNEL A IN A,(SIOA_DAT) ; READ PORT LD E,A ; SAVE BYTE READ LD A,(SIOA_CNT) ; GET CURRENT BUFFER USED COUNT CP SIOA_BUFSZ ; COMPARE TO BUFFER SIZE RET Z ; BAIL OUT IF BUFFER FULL, RCV BYTE DISCARDED INC A ; INCREMENT THE COUNT LD (SIOA_CNT),A ; AND SAVE IT CP SIOA_BUFSZ - 5 ; BUFFER GETTING FULL? JR NZ,SIOA_INT0 ; IF NOT, BYPASS CLEARING RTS LD A,5 ; RTS IS IN WR5 OUT (SIOA_CMD),A ; ADDRESS WR5 LD A,$E8 ; VALUE TO CLEAR RTS OUT (SIOA_CMD),A ; DO IT SIOA_INT0: LD HL,(SIOA_HD) ; GET HEAD POINTER LD A,L ; GET LOW BYTE CP SIOA_BUFEND & $FF ; PAST END? JR NZ,SIOA_INT1 ; IF NOT, BYPASS POINTER RESET LD HL,SIOA_BUF ; ... OTHERWISE, RESET TO START OF BUFFER SIOA_INT1: LD A,E ; RECOVER BYTE READ LD (HL),A ; SAVE RECEIVED BYTE TO HEAD POSITION INC HL ; INCREMENT HEAD POINTER LD (SIOA_HD),HL ; SAVE IT ; ; CHECK FOR MORE PENDING... XOR A ; A := 0 OUT (SIOA_CMD),A ; ADDRESS RD0 IN A,(SIOA_CMD) ; GET RD0 RRA ; READY BIT TO CF JR C,SIOA_INT00 ; IF SET, DO SOME MORE OR $FF ; NZ SET TO INDICATE INT HANDLED RET ; AND RETURN ; SIOB_INT: ; CHECK FOR RECEIVE PENDING ON CHANNEL B XOR A ; A := 0 OUT (SIOB_CMD),A ; ADDRESS RD0 IN A,(SIOB_CMD) ; GET RD0 AND $01 ; ISOLATE RECEIVE READY BIT RET Z ; IF NOT, RETURN WITH Z SET ; SIOB_INT00: ; HANDLE CHANNEL B IN A,(SIOB_DAT) ; READ PORT LD E,A ; SAVE BYTE READ LD A,(SIOB_CNT) ; GET CURRENT BUFFER USED COUNT CP SIOB_BUFSZ ; COMPARE TO BUFFER SIZE RET Z ; BAIL OUT IF BUFFER FULL, RCV BYTE DISCARDED INC A ; INCREMENT THE COUNT LD (SIOB_CNT),A ; AND SAVE IT CP SIOB_BUFSZ - 5 ; BUFFER GETTING FULL? JR NZ,SIOB_INT0 ; IF NOT, BYPASS CLEARING RTS LD A,5 ; RTS IS IN WR5 OUT (SIOB_CMD),A ; ADDRESS WR5 LD A,$E8 ; VALUE TO CLEAR RTS OUT (SIOB_CMD),A ; DO IT SIOB_INT0: LD HL,(SIOB_HD) ; GET HEAD POINTER LD A,L ; GET LOW BYTE CP SIOB_BUFEND & $FF ; PAST END? JR NZ,SIOB_INT1 ; IF NOT, BYPASS POINTER RESET LD HL,SIOB_BUF ; ... OTHERWISE, RESET TO START OF BUFFER SIOB_INT1: LD A,E ; RECOVER BYTE READ LD (HL),A ; SAVE RECEIVED BYTE TO HEAD POSITION INC HL ; INCREMENT HEAD POINTER LD (SIOB_HD),HL ; SAVE IT ; ; CHECK FOR MORE PENDING... XOR A ; A := 0 OUT (SIOB_CMD),A ; ADDRESS RD0 IN A,(SIOB_CMD) ; GET RD0 RRA ; READY BIT TO CF JR C,SIOB_INT00 ; IF SET, DO SOME MORE OR $FF ; NZ SET TO INDICATE INT HANDLED RET ; AND RETURN ; ; DRIVER FUNCTION TABLE ; SIO_FNTBL: .DW SIO_IN .DW SIO_OUT .DW SIO_IST .DW SIO_OST .DW SIO_INITDEV .DW SIO_QUERY .DW SIO_DEVICE #IF (($ - SIO_FNTBL) != (CIO_FNCNT * 2)) .ECHO "*** INVALID SIO FUNCTION TABLE ***\n" #ENDIF ; ; ; SIO_IN: LD A,(IY + 2) ; GET CHANNEL OR A ; SET FLAGS JR Z,SIOA_IN ; HANDLE CHANNEL A DEC A ; TEST FOR NEXT DEVICE JR Z,SIOB_IN ; HANDLE CHANNEL B CALL PANIC ; ELSE FATAL ERROR RET ; ... AND RETURN ; SIOA_IN: CALL SIOA_IST ; RECEIVED CHAR READY? JR Z,SIOA_IN ; LOOP TILL WE HAVE SOMETHING IN BUFFER HB_DI ; AVOID COLLISION WITH INT HANDLER LD A,(SIOA_CNT) ; GET COUNT DEC A ; DECREMENT COUNT LD (SIOA_CNT),A ; SAVE SAVE IT CP 5 ; BUFFER LOW THRESHOLD JR NZ,SIOA_IN0 ; IF NOT, BYPASS SETTING RTS LD A,5 ; RTS IS IN WR5 OUT (SIOA_CMD),A ; ADDRESS WR5 LD A,$EA ; VALUE TO SET RTS OUT (SIOA_CMD),A ; DO IT SIOA_IN0: LD HL,(SIOA_TL) ; GET BUFFER TAIL POINTER LD E,(HL) ; GET BYTE INC HL ; BUMP TAIL POINTER LD A,L ; GET LOW BYTE CP SIOA_BUFEND & $FF ; PAST END? JR NZ,SIOA_IN1 ; IF NOT, BYPASS POINTER RESET LD HL,SIOA_BUF ; ... OTHERWISE, RESET TO START OF BUFFER SIOA_IN1: LD (SIOA_TL),HL ; SAVE UPDATED TAIL POINTER HB_EI ; INTERRUPTS OK AGAIN XOR A ; SIGNAL SUCCESS RET ; AND DONE ; SIOB_IN: CALL SIOB_IST ; RECEIVED CHAR READY? JR Z,SIOB_IN ; LOOP TILL WE HAVE SOMETHING IN BUFFER HB_DI ; AVOID COLLISION WITH INT HANDLER LD A,(SIOB_CNT) ; GET COUNT DEC A ; DECREMENT COUNT LD (SIOB_CNT),A ; SAVE SAVE IT CP 5 ; BUFFER LOW THRESHOLD JR NZ,SIOB_IN0 ; IF NOT, BYPASS SETTING RTS LD A,5 ; RTS IS IN WR5 OUT (SIOB_CMD),A ; ADDRESS WR5 LD A,$EA ; VALUE TO SET RTS OUT (SIOB_CMD),A ; DO IT SIOB_IN0: LD HL,(SIOB_TL) ; GET BUFFER TAIL POINTER LD E,(HL) ; GET BYTE INC HL ; BUMP TAIL POINTER LD A,L ; GET LOW BYTE CP SIOB_BUFEND & $FF ; PAST END? JR NZ,SIOB_IN1 ; IF NOT, BYPASS POINTER RESET LD HL,SIOB_BUF ; ... OTHERWISE, RESET TO START OF BUFFER SIOB_IN1: LD (SIOB_TL),HL ; SAVE UPDATED TAIL POINTER HB_EI ; INTERRUPTS OK AGAIN XOR A ; SIGNAL SUCCESS RET ; AND DONE ; ; ; SIO_OUT: CALL SIO_OST ; READY FOR CHAR? JR Z,SIO_OUT ; LOOP IF NOT LD C,(IY + 3) ; C := SIO CMD PORT #IF (SIOMODE == SIOMODE_RC) INC C ; BUMP TO DATA PORT #ENDIF #IF (SIOMODE == SIOMODE_SMB) DEC C ; DECREMENT CMD PORT TWICE TO GET DATA PORT DEC C #ENDIF #IF (SIOMODE == SIOMODE_ZP) DEC C ; DECREMENT CMD PORT TWICE TO GET DATA PORT DEC C #ENDIF OUT (C),E ; SEND CHAR FROM E XOR A ; SIGNAL SUCCESS RET ; ; ; SIO_IST: LD A,(IY + 2) ; GET CHANNEL OR A ; SET FLAGS JR Z,SIOA_IST ; HANDLE CHANNEL A DEC A ; TEST FOR NEXT DEVICE JR Z,SIOB_IST ; HANDLE CHANNEL B CALL PANIC ; ELSE FATAL ERROR RET ; ... AND RETURN ; SIOA_IST: LD A,(SIOA_CNT) ; GET BUFFER UTILIZATION COUNT OR A ; SET FLAGS JP Z,CIO_IDLE ; NOT READY, RETURN VIA IDLE PROCESSING RET ; AND DONE ; SIOB_IST: LD A,(SIOB_CNT) ; GET BUFFER UTILIZATION COUNT OR A ; SET FLAGS JP Z,CIO_IDLE ; NOT READY, RETURN VIA IDLE PROCESSING RET ; DONE ; ; ; SIO_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 ; ; ; SIO_INITDEV: ; ; TEST FOR -1 WHICH MEANS USE CURRENT CONFIG (JUST REINIT) ; PS LD A,D ; TEST DE FOR ; PS AND E ; ... VALUE OF -1 ; PS INC A ; ... SO Z SET IF -1 ; PS JR NZ,SIO_INITDEV1 ; IF DE == -1, REINIT CURRENT CONFIG ; PS ; ; LOAD EXISTING CONFIG TO REINIT ;PS LD E,(IY + 4) ; LOW BYTE ;PS LD D,(IY + 5) ; HIGH BYTE ;PS ; CHANGE INIT TABLE ; SIO_INITDEV1: PUSH DE ; SAVE CONFIG LD A,D ; GET CONFIG MSB AND $1F ; ISOLATE ENCODED BAUD RATE #IF (SIODEBUG) PUSH AF PRTS(" ENCODE[$") CALL PRTHEXBYTE PRTC(']') POP AF #ENDIF CP SIOBAUD1 ; We set the divider and the lower bit (d2) of the baud rate here LD D,$04 ; /1 N,8,1 JR Z,BROK CP SIOBAUD2 LD D,$44 ; /16 N,8,1 JR Z,BROK CP SIOBAUD3 LD D,$84 ; /32 N,8,1 JR Z,BROK CP SIOBAUD4 LD D,$C4 ; /64 N,8,1 JR Z,BROK ; RET NZ #IF (SIODEBUG) PUSH AF PRTS(" BR FAIL[$") CALL PRTHEXBYTE PRTC(']') POP AF #ENDIF ; EXITINIT: POP DE RET ; NZ status here indicating fail / invalid baud rate. BROK: LD A,E AND $E0 JR NZ,EXITINIT ; NZ status here indicates dtr, xon, parity mark or space so return LD A,E ; set stop bit (d3) and add divider AND $04 RLA OR D ; carry gets reset here LD D,A LD A,E ; get the parity bits SRL A ; move them to bottom two bits SRL A ; we know top bits are zero from previous test SRL A ; add stop bits OR D ; carry = 0 LD BC,SIO_INITVALS+3 LD (BC),A #IF (SIODEBUG) PUSH AF PRTS(" MODE[$") CALL PRTHEXBYTE PRTC(']') POP AF #ENDIF ; THE # DATA BITS NEED TO BE CONVERTED FROM THE ; ROMWBW REPRESENTATION TO THE SIO XILOG CODING ; XOR A ; RR E ; d0 of bits into carry ; RR A ; d0 into msb ; RR E ; d1 of bits into carry ; RR A ; d1 into msb ;; SCF ; 1 into msb ; RR A ; OR $8a LD A,E #IF (SIODEBUG) PUSH AF PRTS(" BITS[$") CALL PRTHEXBYTE PRTC(']') POP AF #ENDIF ; 112233445566d1d0 CC RRA ; CC112233445566d1 d0 RRA ; d0CC112233445566 d1 RRA ; d1d0CC1122334455 66 LD D,A RRA ; 66d1d0CC11223344 55 AND $60 ; 0011110000000000 00 OR $8a ; ; SET TRANSMIT DATA BITS WR5 ; LD BC,SIO_INITVALS+11 LD (BC),A #IF (SIODEBUG) PUSH AF PRTS(" TXDATA[$") CALL PRTHEXBYTE PRTC(']') POP AF #ENDIF ; ; SET RECEIVE DATA BITS WR3 ; LD A,D AND $C0 OR $01 LD BC,SIO_INITVALS+9 LD (BC),A #IF (SIODEBUG) PUSH AF PRTS(" RXDATA[$") CALL PRTHEXBYTE PRTC(']') POP AF #ENDIF POP DE ; RESTORE CONFIG LD (IY + 4),E ; SAVE LOW WORD LD (IY + 5),D ; SAVE HI WORD HB_DI ; AVOID CONFLICTS ; ; PROGRAM THE SIO CHIP CHANNEL LD C,(IY + 3) ; COMMAND PORT LD HL,SIO_INITVALS ; POINT TO INIT VALUES LD B,SIO_INITLEN ; COUNT OF BYTES TO WRITE OTIR ; WRITE ALL VALUES ; ; RESET THE RECEIVE BUFFER LD E,(IY + 6) LD D,(IY + 7) ; 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 ; HB_EI ; READY FOR INTS AGAIN XOR A ; SIGNAL SUCCESS RET ; RETURN ; ; SIO_INITVALS: .DB $00, $18 ; WR0: CHANNEL RESET .DB $04, $00 ; WR4: CLK BAUD PARITY STOP BIT ; PST .DB $01, $18 ; WR1: INTERRUPT ON ALL RECEIVE CHARACTERS .DB $02, IVT_SER0 ; WR2: INTERRUPT VECTOR OFFSET .DB $03, $C1 ; WR3: 8 BIT RCV, RX ENABLE .DB $05, $EA ; WR5: DTR, 8 BITS SEND, TX ENABLE, RTS 1 11 0 1 0 1 0 (1=DTR,11=8bits,0=sendbreak,1=TxEnable,0=sdlc,1=RTS,0=txcrc) SIO_INITLEN .EQU $ - SIO_INITVALS ; ; ; SIO_QUERY: LD E,(IY + 4) ; FIRST CONFIG BYTE TO E LD D,(IY + 5) ; SECOND CONFIG BYTE TO D XOR A ; SIGNAL SUCCESS RET ; DONE ; ; ; SIO_DEVICE: LD D,CIODEV_SIO ; D := DEVICE TYPE LD E,(IY) ; E := PHYSICAL UNIT XOR A ; SIGNAL SUCCESS RET ; ; SIO DETECTION ROUTINE ; SIO_DETECT: LD C,(IY + 3) ; COMMAND PORT XOR A OUT (C),A ; ACCESS RD0 IN A,(C) ; GET RD0 VALUE LD B,A ; SAVE IT LD A,1 OUT (C),A ; ACCESS RD1 IN A,(C) ; GET RD1 VALUE CP B ; COMPARE LD A,SIO_NONE ; ASSUME NOTHING THERE RET Z ; RD0=RD1 MEANS NOTHING THERE LD A,SIO_SIO ; GUESS WE HAVE A VALID SIO HERE RET ; DONE ; ; ; SIO_PRTCFG: ; ANNOUNCE PORT CALL NEWLINE ; FORMATTING PRTS("SIO$") ; 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 SIO TYPE CALL PC_SPACE ; FORMATTING LD A,(IY + 1) ; GET SIO TYPE BYTE RLCA ; MAKE IT A WORD OFFSET LD HL,SIO_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 SIO WAS DETECTED LD A,(IY + 1) ; GET SIO TYPE BYTE OR A ; SET FLAGS RET Z ; IF ZERO, NOT PRESENT ; PRTS(" MODE=$") ; FORMATTING LD E,(IY + 4) ; LOAD CONFIG LD D,(IY + 5) ; ... WORD TO DE CALL PS_PRTSC0 ; PRINT CONFIG ; XOR A RET ; ; ; SIO_TYPE_MAP: .DW SIO_STR_NONE .DW SIO_STR_SIO SIO_STR_NONE .DB "$" SIO_STR_SIO .DB "SIO$" ; ; WORKING VARIABLES ; SIO_DEV .DB 0 ; DEVICE NUM USED DURING INIT ; ; CHANNEL A RECEIVE BUFFER SIOA_RCVBUF: SIOA_CNT .DB 0 ; CHARACTERS IN RING BUFFER SIOA_HD .DW SIOA_BUF ; BUFFER HEAD POINTER SIOA_TL .DW SIOA_BUF ; BUFFER TAIL POINTER SIOA_BUF .FILL 32,0 ; RECEIVE RING BUFFER SIOA_BUFEND .EQU $ ; END OF BUFFER SIOA_BUFSZ .EQU $ - SIOA_BUF ; SIZE OF RING BUFFER ; ; CHANNEL B RECEIVE BUFFER SIOB_RCVBUF: SIOB_CNT .DB 0 ; CHARACTERS IN RING BUFFER SIOB_HD .DW SIOB_BUF ; BUFFER HEAD POINTER SIOB_TL .DW SIOB_BUF ; BUFFER TAIL POINTER SIOB_BUF .FILL 32,0 ; RECEIVE RING BUFFER SIOB_BUFEND .EQU $ ; END OF BUFFER SIOB_BUFSZ .EQU $ - SIOB_BUF ; SIZE OF RING BUFFER ; ; SIO PORT TABLE ; SIO_CFG: ; SIO CHANNEL A .DB 0 ; DEVICE NUMBER (SET DURING INIT) .DB 0 ; SIO TYPE (SET DURING INIT) .DB 0 ; SIO CHANNEL (A) .DB SIOA_CMD ; BASE PORT (CMD PORT) .DW DEFSIOACFG ; LINE CONFIGURATION .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; SIO CHANNEL B .DB 0 ; DEVICE NUMBER (SET DURING INIT) .DB 0 ; SIO TYPE (SET DURING INIT) .DB 1 ; SIO CHANNEL (B) .DB SIOB_CMD ; BASE PORT (CMD PORT) .DW DEFSIOBCFG ; LINE CONFIGURATION .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; SIO_CNT .EQU ($ - SIO_CFG) / 8