diff --git a/sio.asm b/sio.asm new file mode 100644 index 00000000..c30ab09f --- /dev/null +++ b/sio.asm @@ -0,0 +1,725 @@ +; +;================================================================================================== +; 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) -- +; +; FOR THE ECB-ZILOG-PERIPHERALS BOARD, INFORMATION ON JUMPER SETTINGS +; AND BAUD RATES CAN BE FOUND HERE: +; https://www.retrobrewcomputers.org/doku.php?id=boards:ecb:zilog-peripherals:clock-divider +; +; SIO PORT A (COM1:) and SIO PORT B (COM2:) ARE MAPPED TO DEVICE UC1: AND UL1: IN CP/M. +; +SIO_NONE .EQU 0 +SIO_SIO .EQU 1 +; +#IF (SIOMODE == SIOMODE_RC) +SIOA_CMD .EQU SIOBASE + $00 +SIOA_DAT .EQU SIOBASE + $01 +SIOB_CMD .EQU SIOBASE + $02 +SIOB_DAT .EQU SIOBASE + $03 +#ENDIF +; +#IF (SIOMODE == SIOMODE_SMB) +SIOA_CMD .EQU SIOBASE + $02 +SIOA_DAT .EQU SIOBASE + $00 +SIOB_CMD .EQU SIOBASE + $03 +SIOB_DAT .EQU SIOBASE + $01 +#ENDIF +; +#IF (SIOMODE == SIOMODE_ZP) +SIOA_CMD .EQU SIOBASE + $06 +SIOA_DAT .EQU SIOBASE + $04 +SIOB_CMD .EQU SIOBASE + $07 +SIOB_DAT .EQU SIOBASE + $05 +#ENDIF +; +; CONDITIONALS THAT DETERMINE THE ENCODED VALUE OF THE BAUD RATE +; +#INCLUDE "siobaud.inc" +; +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 +; +; RECEIVE INTERRUPT HANDLER +; +#IF (INTMODE > 0) +; +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 +; +#ENDIF +; +; 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 +; +; +; +#IF (INTMODE == 0) +; +SIO_IN: + CALL SIO_IST ; CHAR WAITING? + JR Z,SIO_IN ; 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) | (SIOMODE == SIOMODE_ZP)) + DEC C ; DECREMENT CMD PORT TWICE TO GET DATA PORT + DEC C +#ENDIF + IN E,(C) ; GET CHAR + XOR A ; SIGNAL SUCCESS + RET +; +#ELSE +; +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 +; +#ENDIF +; +; +; +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) | (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 +; +; +; +#IF (INTMODE == 0) +; +SIO_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 +; +#ELSE +; +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 +; +#ENDIF +; +; +; +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 +; +; AT INITIALIZATION THE SETUP PARAMETER WORD IS TRANSLATED TO THE FORMAT +; REQUIRED BY THE SIO AND STORED IN A PORT/REGISTER INITIALIZATION TABLE, +; WHICH IS THEN LOADED INTO THE SIO. +; +; RTS, DTR AND XON SETTING IS NOT CURRENTLY SUPPORTED. +; MARK & SPACE PARITY AND 1.5 STOP BITS IS NOT SUPPORTED BY THE SIO. +; INITIALIZATION WILL NOT BE COMPLETED IF AN INVALID SETTING IS DETECTED. +; +SIO_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,SIO_INITDEV1 ; IF DE == -1, REINIT CURRENT CONFIG +; + ; LOAD EXISTING CONFIG TO REINIT + LD E,(IY+4) ; LOW BYTE + LD D,(IY+5) ; HIGH BYTE +; +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 +; +; ONLY FOUR BAUD RATES ARE POSSIBLE WITH A FIXED CLOCK. +; THESE ARE PREDETERMINED BY HARDWARE SETTINGS AND MATCHING +; CONFIGURATION SETTINGS. WE PRECALCULATED THE FOUR +; POSSIBLE ENCODED VALUES. +; + CP SIOBAUD1 ; We set the divider and the lower bit (d2) of the stop bits + 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 + +#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 +; +; SET DIVIDER, STOP AND PARITY WR4 +; + LD BC,SIO_INITVALS+3 + LD (BC),A + +#IF (SIODEBUG) + PUSH AF + PRTS(" WR4[$") + CALL PRTHEXBYTE + PRTC(']') + POP AF +#ENDIF + + LD A,E ; 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(" WR5[$") + 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(" WR3[$") + 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 +#IF (INTMODE == 0) + .DB $01, $00 ; WR1: NO INTERRUPTS +#ELSE + .DB $01, $18 ; WR1: INTERRUPT ON ALL RECEIVE CHARACTERS +#ENDIF + .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 +; +#IF (INTMODE == 0) +; +SIOA_RCVBUF .EQU 0 +SIOB_RCVBUF .EQU 0 +; +#ELSE +; +; 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 +; +#ENDIF +; +; 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