diff --git a/sio.asm b/sio.asm new file mode 100644 index 00000000..75ccdaf3 --- /dev/null +++ b/sio.asm @@ -0,0 +1,921 @@ +; +;================================================================================================== +; 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 +SIO_WR4 .EQU $C4 ;PS CLK/64=115200 BAUD, NO PARITY, 1 STOP BIT ; 11000100 11=*64 00=8bit sync character 01=1 stop bit 0 = parity even/odd 0=parity disabled +#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 +SIO_CFG .EQU $C4 ;PS CLK/64=115200 BAUD, NO PARITY, 1 STOP BIT ; 11000100 11=*64 00=8bit sync character 01=1 stop bit 0 = parity even/odd 0=parity disabled +#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 +SIO_WR4 .EQU $44 ;PS CLK/16=38400 BAUD, NO PARITY, 1 STOP BIT ; PS 01000100 10=*16 00=8bit sync character 01=1 stop bit 0 = parity even/odd 0=parity disabled +#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 ; UDPATE 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: + HB_DI ; AVOID CONFLICTS +; + ; PROGRAM THE SIO/2 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, $SIO_WR4 ; 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 +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/2 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/2 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