.SBTTL LINDRV - line drivers ;line driver support is invoked via conditional assembly switches in the ; configuration file ;supported driver types are: ; DQ11 - FT.DQ ; KMC11/DUP11 - FT.KDP ; DUP11 - FT.DUP .REPT 0 COPYRIGHT (c) 1982,1981,1980, 1979 DIGITAL EQUIPMENT CORPORATION, maynard, mass. THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED. THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. .ENDR .SBTTL DQ11 - DQ11 synchronous line driver .IF NE,FT.DQ ; this section contains subroutines to drive the DQ11. ; these are: DQENT: DQINI ;initialize the DQ11 DQRED ;read a message DQWRT ;output a data message DQCTL ;output a control message DQKIL ;cease any DQ11 operations DQINQ ;check if any more characters available in current msg DQON ;set DTR on DQOFF ;set DTR off DQSTS ;return DTR,DSR status DQTIK ;once per tick routine DQTRP ;stop code processor ; REVISION HISTORY ; 4(001) BS ADDED VERSION NUMBERS ; 4(002) RLS CHANGE RCVPRI &RCVSEC TO CALL GETCHK INSTEAD OF RIPPING OFF ; THEIR OWN CHUNKS ; 4(003) RLS FIX RCVSEC & RCVPRI TO USE NEW RIPCHK FCN INSTEAD OF GETCHK. ; 4(004) RLS 04-Mar-81 ; Fix XMTPBO to not declare error when it discovers both buffers ; have overflowed. Condition arises when last buffer is very small ; (4 is small enough) and other interrupts keep the processor ; busy til it finishes. Eliminated call to DQERRR at XMTPBO/16$ ; so it stops normally. Let protocol handle any line errors ; which might result. ; 4(005) RLS 07-APR-81 ; Changes to reflect use of message header for data(DQWRIT,XMTPRI) ; 4(006) RLS 17-APR-81 ; Transform static flow control to static/line control VDQ11=006 VEDIT=VEDIT+VDQ11 .SBTTL DQINIT - initialize the DQ11 driver ; r4 = pointer to line control block for dq11 to be initialized DQINI: TRACE TRCDQF,R4 ;trace "dq11 initialization" MOV #DQRI,LVECRA(R4) ;set receiver interrupt process address MOV #DQXI,LVECXA(R4) ;set transmitter interrupt process address MOV #5,LB.TRL(R4) ;set number of trailing pads for data message MOV LB.SLA(R4),R3 ;get dq11 line hardware address DQREGS MSC,(R3) ;select miscellaneous register MOV #DQ.MC,6(R3) ;master clear the dq11 DQREGS MSC,(R3) ;select misc. register again MOV #DQ.MC,6(R3) ;clear it again DQREGS MSC,(R3) ;select misc. register again MOV #10*400,6(R3) ;set '8-bit chars' MOV #DQ.EIE,2(R3) ; and enable error interrupts CALL DQKIL ;kill io to complete database initialization RETURN .SBTTL DQREAD - receive a message ; r4 = pointer to line control block ; ; returns c bit set if error, clear if ok. ; (only error is chunks depleted) DQRED: TRACE TRCDQF,<(SP),R4,JIFCLK> ;trace entry to "dq read" MOV LB.SLA(R4),R3 ;get hardware address DQREGS SYN,(R3) ;select sync register MOV #EBCSYN*401,6(R3) ;store sync value CALL RCVCHK ;get enough chunks to receive a message BCS 16$ ;can't 15$: CALL DQRSTR ;start receiver ; here if out of chunks. 16$: RETURN ;give error return (c already set) ; subroutine to start the receiver. the line block ; points to the first two chunks. DQRSTR: DQREGS PRA,(R3) ;select primary receive address CALL GETRBF ;get primary chunk MOV R0,LB.CH1(R4) ADD #CHDAT,R0 ;point to data part of chunk MOV R0,6(R3) ;store in dq11 ;chunk byte count is zero DQREGS PRC,(R3) ;point to primary receive count MOV #-CHDATL,6(R3) ;store data length of chunk DQREGS SRA,(R3) ;select secondary receive address CALL GETRBF ;get secondary chunk MOV R0,LB.CH2(R4) ADD #CHDAT,R0 ;point to data part of chunk MOV R0,6(R3) ;store in dq11 DQREGS SRC,(R3) ;point to secondary receive count MOV #-CHDATL,6(R3) ;store data length of chunk BIS #LS.RGO,(R4) ;flag receiver to start on carrier PIOFF ;disable cpu interrupts BIT #DQ.SEC,(R3) ;secondary buffer next? BEQ 11$ ;no. MOV LB.CH2(R4),LB.CCH(R4) ;yes, secondary is current MOV #RG.SRC,LB.CCR(R4) ;point to its count field CLR LB.CH2(R4) ;clear this as it will be q'd BR 12$ ;arrange to start receiver ; primary buffer will be first 11$: MOV LB.CH1(R4),LB.CCH(R4) ;primary is current MOV #RG.PRC,LB.CCR(R4) ;point to its count field CLR LB.CH1(R4) ;clear this as it will be q'd ; here when everything is ready. if carrier is already up, ; or this is a zero-turn-around-time modem, start the ; receiver. otherwise let carrier coming up start it. 12$: CLR LB.CRD(R4) ;clear count of characters read MOV LB.TC1(R4),R1 ;get tcb of bsc task MOV LB.CCH(R4),R0 ;get current chunk CALL QUECHK ;send chunk to driver while we fill it BIS #DQ.DIE,2(R3) ;enable dataset interrupts BIC #DQ.RDP!DQ.RDS,(R3) ;kill any "hanging" interrupts TST LB.CSD(R4) ;is this a zero-turn-around- ; time modem? BEQ 13$ ;yes, start the receiver. BIT #DQ.CAR,2(R3) ;no, is carrier already present? BEQ 14$ ;no. 13$: BIS #DQ.RIE!DQ.RGO,(R3) ;yes, start the dq11 now BIC #LS.RGO,(R4) ;not waiting for carrier BIS #LS.RRN,(R4) ;receiver is now running 14$: PION ;restore cpu priority TRACE TRCDQF, DQRCST: CLC ;flag no error RETURN .SBTTL DQWRIT - start transmitting a data message from LB.MSG ; r4 = pointer to line control block ; ; returns with c bit set if error, clear if not. DQWRT: TRACE TRCDQF!TRCLIN,<(SP),R4,(R4),LB.MSG(R4),JIFCLK> ;trace entry to "dq write data" BIT #LS.ACT,(R4) ;is dq11 still active? BEQ 11$ ;no. CALL DQKIL ;yes - kleen up 11$: BIC #LS.CTL,(R4) ;this is a data, not a control message MOV LB.SLA(R4),R3 ;get dq11 hardware address DQREGS SYN,(R3) ;select sync register MOV #EBCSYN*401,6(R3) ;specify the sync character MOV LB.MSG(R4),R0 ;get message ptr CALL FMSGI ;make sure message is inited for output MOV MSGPTR(R0),R1 ;get ptr to 1st full byte BIT #DQ.SEC,2(R3) ;check primary/secondary bit BEQ XMTPRI ;primary is next ; here if the secondary registers will go first. make the ; first data chunk the secondary and the second the ; primary. ;R1/ptr to 1st full byte of message DQREGS STA,(R3) ;select secondary transmitter address MOV R1,6(R3) ;store address in dq11 DQREGS STC,(R3) ;point to secondary transmit count MOV CHLEN(R0),R1 ;get data length NEG R1 ;negate it MOV R1,6(R3) ;give -length to dq11 MOV R0,LB.CH4(R4) ;remember secondary xmit chunk MOV (R0),R0 ;get next chunk BNE 13$ ;branch if there is a second chunk DQREGS PTC,(R3) ;no second chunk CLR 6(R3) ;so clear primary count reg CLR LB.CH3(R4) ;note in lcb, last chunk. CLR LB.CH4(R4) BR 14$ ;and we are done. ; here if there is a primary chunk 13$: DQREGS PTA,(R3) ;select primary transmit address MOV R0,R1 ;compute data address ADD #CHDAT,R1 MOV R1,6(R3) ;store address in dq11 DQREGS PTC,(R3) ;select primary transmit count MOV CHLEN(R0),R1 ;get data length NEG R1 ;negate it for dq11 MOV R1,6(R3) ;store length in cc register MOV R0,LB.CH3(R4) ;remember primary xmit chunk 14$: CALL DQXSTR ;start transmitter RETURN ; here if the primary registers will go first. make the first ; data chunk the primary and the second the secondary. ;r1/ptr to 1st full byte of message XMTPRI: DQREGS PTA,(R3) ;select primary transmitter address MOV R1,6(R3) ;store address in dq11 DQREGS PTC,(R3) ;select primary transmit count MOV CHLEN(R0),R1 ;get data length NEG R1 ;negate it MOV R1,6(R3) ;store negated length in dq11 MOV R0,LB.CH3(R4) ;remember primary xmit chunk MOV (R0),R0 ;get next chunk BNE 11$ ;branch if there is a second chunk DQREGS STC,(R3) ;no second chunk CLR 6(R3) ;so make secondary count zero CLR LB.CH4(R4) ;note in lb, last chunk. CLR LB.CH3(R4) BR 12$ ; and we are done. ; here if there is another chunk. 11$: DQREGS STA,(R3) ;select secondary transmit address MOV R0,R1 ;compute data address ADD #CHDAT,R1 MOV R1,6(R3) ;store address in dq11 DQREGS STC,(R3) ;select secondary transmit count MOV CHLEN(R0),R1 ;get data length NEG R1 ;negate it MOV R1,6(R3) ;store in cc register MOV R0,LB.CH4(R4) ;remember secondary xmit chunk ; here when all done. 12$: CALL DQXSTR ;start transmitter RETURN ; subroutine to arrange to start the transmitter DQXSTR: TRACE TRCDQF,<(SP),R4,LB.CH3(R4),LB.CH4(R4),JIFCLK> BIS #LS.XGO,(R4) ;xmitter waiting for cts ; experience with bell 303 modems may lead to inserting code ; here to avoid setting rts if cts is still up. BIS #DQ.RTS,2(R3) ;raise request to send MOV LB.CSD(R4),LB.DEW(R4) ;wait a while, then check for cts ;note that modem interrupts are ignored ; until time is up. BEQ 13$ ;time is zero, i.e., already up. CLC ;time not up, clear 'c' flag RETURN ; here if clear-to-send delay specified is zero. ; cause a modem interrupt in case cts is already up, and ; enable modem interrupts so that if cts is not up we will ; get an interrupt when it comes up. note that ; a zero clear-to-send delay should be used only with modems ; that have a clear-to-send delay of less than 16 milliseconds, ; since a larger delay can be timed without loss of efficiency ; and too short a delay (less than about 8 milliseconds) ; does not work with some ibm hosts. 13$: BIS #DQ.DSF!DQ.DIE,2(R3) ;enable interrupts and ; cause one. CLC ;clear 'c' flag RETURN .SBTTL DQCNTL - transmit a control message ; r4 = pointer to line control block ; r0 = pointer to message to send ; r1 = length of message to send ; ; on return: ; ; c set if error, clear if not. DQCTL: TRACE TRCLIN!TRCDQF,<(SP),R4,(R4),R0,R1,JIFCLK> ;trace entry to "dq write control" MOV R0,LB.CMA(R4) ;remember control message address MOV R1,LB.CMC(R4) ; and length BIT #LS.ACT,(R4) ;is dq11 still active? BEQ 11$ ;no. CALL DQKIL ;yes - kleen up 11$: BIS #LS.CTL,(R4) ;we are working on a control message MOV LB.SLA(R4),R3 ;get dq11 hardware address DQREGS SYN,(R3) ;select sync register MOV #EBCSYN*401,6(R3) ;specify the sync character BIT #DQ.SEC,2(R3) ;check primary/secondary bit BEQ 14$ ;primary is next ; here if the first register set to go will be the ; secondary registers. 13$: DQREGS STA,(R3) ;select secondary xmit address MOV R0,6(R3) ;store address in dq11 DQREGS STC,(R3) ;select secondary xmit count NEG R1 ;negate count MOV R1,6(R3) ;store count in dq11 DQREGS PTC,(R3) ;select primary xmit count CLR 6(R3) ;no subsequent chunk BR 15$ ;go start dq11 ; here if the first register set to go will be the ; primary registers. 14$: DQREGS PTA,(R3) ; select primary xmit address MOV R0,6(R3) ;store address in dq11 DQREGS PTC,(R3) ;select primary xmit count NEG R1 ;negate count MOV R1,6(R3) ; store count in dq11 DQREGS STC,(R3) ;select secondary xmit count CLR 6(R3) ; no subsequent data ; here to start the dq11 15$: CLR LB.CH3(R4) ;flag no more data to send CLR LB.CH4(R4) ; for interrupt routines CALL DQXSTR ; start the transmitter RETURN .SBTTL DQRI - interrupt routine for DQ11 receivers DQRI: RCVADJ ;R4/line block TRACE TRCINT,<2(SP),6(SP),R4,JIFCLK> ;trace DQ11 interrupt SAVE MOV LB.SLA(R4),R3 ;get hardware address of dq11 INC LB.RCT(R4) ;one more receiver interrupt ; here to check for (another) dq11 receiver interrupt bit 10$: MOV (R3),R0 ;get receiver status register MOV R0,LB.RST(R4) ;store last receiver status ;trace line,line sts,rsts,xsts,errsts,time TRACE TRCDQF, BIT #DQ.RDP!DQ.RDS!DQ.VCH,R0 ;any interrupt bits? BEQ 14$ ;no, check receiver running and exit BIT #DQ.RDS,R0 ;yes, secondary buffer? BEQ 11$ ;no. CALL RCVSEC ;yes, process buffer overflow BCC 10$ ;if all ok, test for more bits BR 15$ ;otherwise just exit. 11$: BIT #DQ.RDP,R0 ;primary buffer overflow? BEQ 12$ ;no. CALL RCVPRI ;yes, process buffer overflow BCC 10$ ;if all ok, test for more bits BR 15$ ;otherwise just exit ; here on special character interrupt - only enabled if task waiting 12$: BIC #DQ.VCH,(R3) ;clear special character flag BIT #DQ.RAC,(R3) ;is receiver active (i.e., seen sync)? BEQ 13$ ;no, don't change sync char BIT #DQ.CIE,(R3) ;interrupts still enabled? BEQ 14$ ;no, dont bother doing this twice BIC #DQ.CIE,(R3) ;yes, disable special char interrupts CALL RCVSCC ;store cc and wake task DQREGS SYN,(R3) ;point to sync register MOV #EBCPAD*401,6(R3) ;get interrupt on trailing pad 13$: BR 10$ ;check for more interrupt bits ; here to verify that the receiver is still running 14$: BIT #LS.RRN,(R4) ;should receiver be running? BEQ 15$ ;no. BIT #DQ.RGO,R0 ;yes, is it? BNE 15$ ;yes, all is ok. INC LB.SE4(R4) ;no, "receiver not fast enough" CALL DQERR ;record dq11 error ; here to restore registers and return. 15$: RESTOR JMP SKDCHK ;exit interrupt .SBTTL DQERR - record a DQ11 error DQERR: MOV (R3),LB.SE2(R4) ;record status reg 1 MOV 2(R3),LB.SE3(R4) ; and status reg 2 ATRACE <(SP),R4,(R4),(R3),2(R3),4(R3),JIFCLK> BIT #LS.ENB,(R4) ;is it because line is disabled BEQ 20$ INC LB.SE1(R4) ;count master error counter BIS #LS.ERR,(R4) ;flag an error .IF NE,DEBUG BIT #TRCLER,TRCHLT ;check for error halts BEQ 20$ STOPCD DBG .ENDC ;.if ne,debug 20$: RETURN ; subroutine to process a secondary receive buffer overflow RCVSEC: BIT #DQ.RDP,R0 ;other buffer interrupted yet? BNE 12$ ;yes, we are too slow. BIC #DQ.RDS,(R3) ;clear the flag bit CALL GETRBF ;get a chunk BCS 10$ ;ran out of receive buffer allotment MOV R0,LB.CH2(R4) ;save ptr to next secondary buffer DQREGS SRA,(R3) ;select secondary receive address MOV R0,R1 ;compute data address ADD #CHDAT,R1 MOV R1,6(R3) ;store address in dq11 DQREGS SRC,(R3) ;select secondary receive count MOV #-CHDATL,6(R3) ;store count 10$: MOV LB.CCH(R4),R0 ;get chunk just filled MOV #CHDATL,CHLEN(R0) ;note chunk is full ; processing of filled chunk is complete MOV LB.CH1(R4),R0 ;get new current chunk BEQ 14$ ;max size message MOV R0,LB.CCH(R4) ;make it current MOV LB.TC1(R4),R1 ;get tcb of task to process received chunks CALL QUECHK ;send him the chunk MOV #RG.PRC,LB.CCR(R4) ;point to its count reg CLR LB.CH1(R4) ;clear this since it has been q'd ADD #CHDATL,LB.CRD(R4) ;count more data read CLC ;no, return flag all ok RETURN ; come here if we are too slow. 12$: INC LB.SE4(R4) ;count "receiver not fast enough" CALL DQERR ;record dq11 error SEC ;flag error RETURN 14$: CALL DQRSTP ;kill the receiver SEC ;flag error RETURN ; subroutine to process a primary buffer overflow. ; ; c set on return if out of chunks. RCVPRI: BIC #DQ.RDP,(R3) ;clear primary overflow flag CALL GETRBF ;get a chunk BCS 10$ ;ran out of receive buffer allotment MOV R0,LB.CH1(R4) ;save ptr to next primary buffer DQREGS PRA,(R3) ;select primary receive address MOV R0,R1 ;compute data address ADD #CHDAT,R1 MOV R1,6(R3) ;store address in dq11 DQREGS PRC,(R3) ;select primary receive count MOV #-CHDATL,6(R3) ;store count 10$: MOV LB.CCH(R4),R0 ;get chunk just filled MOV #CHDATL,CHLEN(R0) ;mark chunk full ; processing of filled chunk is complete. MOV LB.CH2(R4),R0 ;get secondary chunk BEQ 13$ ;max size message MOV R0,LB.CCH(R4) ;it is now current MOV LB.TC1(R4),R1 ;get tcb of receive chunk handler CALL QUECHK ;send him the chunk MOV #RG.SRC,LB.CCR(R4) ;point to its char count reg CLR LB.CH2(R4) ;clear this since it has been q'd ADD #CHDATL,LB.CRD(R4) ;increment count of characters read CLC ;no, clear "c" to flag ok RETURN 13$: CALL DQRSTP ;kill the receiver SEC ;flag error RETURN ; subroutine to stop the receiver ; ; r4 points to lcb, r3 to csr. DQRSTP: ;trace caller,line sts,dq rsts,dq xsts,dq errsts TRACE TRCDQF,<(SP),R4,(R4),(R3),2(R3),4(R3),JIFCLK> RCVKIL: BIC #DQ.RDP!DQ.RDS!DQ.RGO!DQ.CIE!DQ.RIE,(R3) ;kill the dq11 receiver BIC #DQ.DIE,2(R3) ;disable dataset interrupts CALL RCVCLR ;flush any extra receive buffers SAVE R5 MOV LB.TC1(R4),R5 MOV LB.CH1(R4),R0 CALL FRECHK ;release leftover primary chunk MOV LB.CH2(R4),R0 CALL FRECHK ;release leftover secondary chunk RESTOR R5 CLR LB.CCH(R4) ;no current chunk BIC #LS.RGO!LS.RRN,(R4) ;receiver not running SIGNAL LB.TC1(R4),EBINTR ;maybe, unwait it. SETSKD LB.TC1(R4) ;force scheduling pass RETURN ; subroutine to store the current character count in the current ; chunk and restart the driver task if the count has changed. RCVSCC: MOVB LB.CCR(R4),5(R3) ;point to active count reg MOV 6(R3),R1 ;fetch current count register ADD #CHDATL,R1 ;make true count MOV LB.CCH(R4),R0 ;get pointer to current chunk CMP R1,CHLEN(R0) ;has count changed? BEQ 11$ ;no. MOV R1,CHLEN(R0) ;yes, store new count BIC #DQ.CIE,(R3) ;no longer need special char interrupts SIGNAL LB.TC1(R4),EBINTR SETSKD LB.TC1(R4) ;force scheduling pass SEC ;indicate that characters were waiting 11$: RETURN .SBTTL DQXI - DQ11 transmiter and status interrupts DQXI: XMTADJ ;R4/line block TRACE TRCINT,<2(SP),6(SP),R4,JIFCLK> ;trace DQ11 interrupt SAVE MOV LB.SLA(R4),R3 ;get hardware address INC LB.XCT(R4) ;one more transmit interrupt ; here to check for (another) dq11 transmitter or status ; interrupt bit. 10$: MOV 2(R3),R1 ;get transmitter status bits MOV R1,LB.XST(R4) ;record last transmit status TRACE TRCDQF, ;trace line,line sts,rsts,xsts,errsts MOV 4(R3),R0 ;any errors? BMI 30$ ;yes. BIT #DQ.XDP,R1 ;no, primary buffer overflow? BEQ 11$ CALL XMTPBO ;yes. BR 10$ 11$: BIT #DQ.XDS,R1 ;no, secondary? BEQ 12$ CALL XMTSBO ;yes. BR 10$ 12$: BIT #DQ.DSF,R1 ;no, dataset flag? BEQ 15$ ;no. all done. CALL DQDSF ;yes. BR 10$ ;check for more bits ; here when no more flags are found. 15$: BIT #LS.XRN,(R4) ;should transmitter be running? BEQ 20$ ;no. BIT #DQ.XGO,R1 ;yes, is it? BNE 20$ ;yes, all ok. INC LB.SE5(R4) ;no, record error CALL DQERR ;update error counters and store status CALL DQXSTP ;stop the transmitter 20$: RESTOR JMP SKDCHK ;exit the interrupt. 30$: CALL DQXERR BR 10$ ; here on error interrupt DQXERR: MOV R0,LB.ERS(R4) ;save error status BIS #LS.ERR,(R4) ;flag an error ATRACE ;trace dq11 status BIT #DQ.XCL,R0 ;transmit clock loss? BEQ 11$ ;no. INC LB.XCL(R4) ;yes, record it. BIC #DQ.XCL,4(R3) ;clear the flag CALL DQXSTP ;stop the transmitter RETURN ;look for more bits ; here if not transmitter clock loss 11$: BIT #DQ.RCL,R0 ;receiver clock loss? BEQ 12$ ;no. INC LB.RCL(R4) ;yes, record it. BIC #DQ.RCL,4(R3) ;clear the flag CALL DQRSTP ;terminate receiver RETURN ;look for more bits ; here if an error other than clock loss happens 12$: STOPCD QER ;dq11 error ; here when the primary buffer overflows. XMTPBO: BIT #DQ.XDS,R1 ;has other buffer overflowed? BNE 16$ ;yes, we are too slow. MOV LB.CH4(R4),R0 ;get secondary chunk BNE 12$ ;there is one CALL DQXSTP ;none--end of transmission RETURN ;go look for more flags ; here if there is a secondary chunk 12$: MOV (R0),R0 ;get its successor BEQ 15$ ;no more. MOV R0,LB.CH3(R4) ;store new primary chunk DQREGS PTA,(R3) ;select primary transmitter address MOV R0,R1 ;compute data address ADD #CHDAT,R1 MOV R1,6(R3) ;store new data address DQREGS PTC,(R3) ;select primary transmit count MOV CHLEN(R0),R1 ;get length of data NEG R1 ;negate it MOV R1,6(R3) ;store negative of data length BIC #DQ.XDP,2(R3) ;clear flag 14$: RETURN ;look for more flags ; here on primary transmit interrupt with no more data 15$: DQREGS PTC,(R3) ;select count register CLR 6(R3) ;no more data CLR LB.CH3(R4) ;no longer a primary chunk CLR LB.CH4(R4) ; nor a secondary BIC #DQ.XDP,2(R3) ;clear this flag RETURN ; and go look for another. ; here if both buffers have overflowed. 16$: INC LB.SE5(R4) ;count "transmitter too slow" CALL DQERR ;record error information CALL DQXSTP ;stop the transmitter RETURN ;look for more bits ; here if secondary buffer overflows XMTSBO: MOV LB.CH3(R4),R0 ;get primary chunk BNE 12$ ;there is one CALL DQXSTP ;none--stop transmitter RETURN ;and look for more bits ; here if there is a primary chunk 12$: MOV (R0),R0 ;get primary chunk's successor BEQ 14$ ;end of data MOV R0,LB.CH4(R4) ;store new secondary chunk DQREGS STA,(R3) ;select secondary transmit address MOV R0,R1 ;compute data address ADD #CHDAT,R1 MOV R1,6(R3) ;store address of new chunk DQREGS STC,(R3) ;select secondary transmit count MOV CHLEN(R0),R1 ;get length of data in chunk NEG R1 ;negate it for dq11 MOV R1,6(R3) ;store in dq11 cc register BIC #DQ.XDS,2(R3) ;clear this flag RETURN ;check for more flags ; here on secondary transmit interrupt with no more data 14$: DQREGS STC,(R3) ;select count register CLR 6(R3) ;no more data CLR LB.CH4(R4) ;no longer a secondary chunk CLR LB.CH3(R4) ; nor a primary BIC #DQ.XDS,2(R3) ;clear this flag RETURN ; and go look for another. .SBTTL DQDSF - process a data set flag. .ENABL LSB DQDSF: BIC #DQ.DSF,2(R3) ;clear dataset flag INC LB.DIC(R4) ;count dataset interrupts MOV 2(R3),R1 ;get dataset bits again ; in case they changed MOV R1,LB.DIS(R4) ;record last modem interrupt status TST LB.DEW(R4) ;waiting for dataset enable? BNE 14$ ;yes, ignore modem signal. MOV (R4),R0 ;no, get status bits BIT #LS.XGO,R0 ;waiting to start xmitter? BEQ 11$ ;no. CALL 15$ ;yes, check for clear-to-send. 11$: BIT #LS.XRN,R0 ;running the transmitter? BEQ 12$ ;no. CALL 17$ ;yes, be sure cts still up 12$: BIT #LS.RGO,R0 ;waiting to start receiver? BEQ 13$ ;no. CALL 19$ ;yes, see if carrier up yet 13$: BIT #LS.RRN,R0 ;running receiver? BEQ 14$ ;no. CALL 21$ ;yes, set sync reg to pads 14$: RETURN ; four subroutines to process data set flags. they are called ; based on the current state of the dq11. ; ; r1 = modem status flags, from the dq11. ; ; here if we are waiting to start the transmitter 15$: BIT #DQ.CTS,R1 ;have we clear-to-send? BEQ 16$ ;no, wait for it. BIC #LS.XGO,(R4) ;no longer waiting to start transmitter BIS #LS.XRN,(R4) ;now running transmitter BIS #DQ.HD,(R3) ;blind the receiver BIS #DQ.XGO!DQ.XIE,2(R3) ;start the transmitter 16$: RETURN ;all done. ; here if we are running the transmitter 17$: BIT #DQ.CTS,R1 ;is clear-to-send still up? BNE 18$ ;yes, all ok. INC LB.SE6(R4) ;no, note clear-to-send failure CALL DQERR ;note error CALL DQXSTP ;stop the transmitter 18$: RETURN ;all done. ; here if we are waiting to start the receiver 19$: BIT #DQ.CAR,R1 ;is carrier up yet? BEQ 20$ ;no, keep waiting for it. BIS #DQ.RGO!DQ.RIE,(R3) ;yes, start the receiver BIC #LS.RGO,(R4) ;no longer waiting to start receiver 23$: BIS #LS.RRN!LS.CAR,(R4) ;now running receiver TRACE TRCDQF, DQCDT: RETURN 20$: BIC #LS.CAR,(R4) ;haven't seen carrier yet RETURN ;all done. ; here if the receiver is running. 21$: BIT #DQ.RAC,(R3) ;is receiver active? BEQ 22$ ;no. random modem transition. DQREGS SYN,(R3) ;yes, point to sync register MOV #EBCPAD*401,6(R3) ;change sync to trailing pad SAVE R1 CALL RCVSCC ;store char count RESTOR R1 22$: BIT #DQ.CAR,R1 ;check carrier BNE 25$ ;ok BIT #LS.CAR,(R4) ;no - seen carrier before? BEQ 24$ ;no - a non-event TRACE TRCDQF, ;lost it DQCFL: BIC #LS.CAR,(R4) 24$: RETURN 25$: BIT #LS.CAR,(R4) ;seen carrier before? BEQ 23$ ;no - carrier detect event RETURN ;all done. .DSABL LSB ; subroutine to stop the transmitter ; r4 points to the lcb ; r3 points to the csr DQXSTP: ;trace caller,line sts,dq rsts,dq xsts,dq errsts TRACE TRCDQF,<(SP),R4,(R4),(R3),2(R3),4(R3),JIFCLK> XMTKIL: BIC #LS.XGO!LS.XRN,(R4) ;dq11 transmitter not running BIC #DQ.RTS!DQ.XDP!DQ.XDS!DQ.XGO!DQ.XIE,2(R3) ;shut down the transmitter BIC #DQ.HD,(R3) ;unblind the receiver -- this is ; done here because transmit active ; won't clear for a while and we ; want to receive right away for the ; 0 turn-around-time modems. CLR LB.DEW(R4) ;not waiting to enable modem MOV LB.TC1(R4),R1 ;get tcb of bsc task SIGNAL R1,EBINTR ;maybe, restart it. SETSKD R1 ;force scheduling pass 11$: CLC ;mark ok RETURN .SBTTL DQINQ - check the dq11 for recently received characters ; r5/tcb ; r4 and r3 are not set up and must be preserved. ; ; on return: ; ; c set: rcvscc has found characters in the dq11 ; c clear: the dq11 has no characters. it is now ; enabled for special character interrupts. DQINQ: SAVE MOV TCLCB(R5),R4 ;point to lcb MOV LB.SLA(R4),R3 ;point to dq11 csr PIOFF ;disable interrupts CALL RCVSCC ;see if any chars in the dq11 BCS 10$ ;carry set => there characters to process BIS #DQ.CIE,(R3) ;enable special character interrupts BIC #1,(SP) ;set carry clear for return BR 15$ 10$: BIS #1,(SP) ;set carry on for return 15$: PION ;restore interrupt level RESTOR RETURN ;RCVSCC set/cleared cry if characters/none ; also cleared DQ.CIE if characters found .SBTTL DQKIL - kill any DQ11 operations ; r4 = lcb pointer ; r5 = pointer to bsc tcb ; ; destroys r3 DQKIL: TRACE TRCDQF,<(SP),R4,(R4),LB.ALR(R4),JIFCLK> ;trace entry to DQKIL MOV LB.SLA(R4),R3 ;point to csr PIOFF ;disable interrupts BIT #LS.ACT,(R4) ;is the dq11 doing anything? BEQ 12$ ;no. BIT #LS.XGO!LS.XRN,(R4) ;yes, transmitter running? BEQ 11$ ;no. CALL DQXSTP ;yes, stop the transmitter 11$: BIT #LS.RGO!LS.RRN,(R4) ;is receiver running? BEQ 12$ ;no. CALL DQRSTP ;yes, stop the receiver 12$: BIC #DQ.DIE,2(R3) ;clear dataset interrupt enbale PION ;restore interrupts 13$: CALL DEQCHK ;any chunks in reveiver queue? BCS 14$ ;no. CALL FRECHK ; by sending to background task BR 13$ ;be sure we've got them all. ; here when the dq11 has been killed. 14$: RETURN .SBTTL DQOFF,DQON,DQSTS - DSR,DTR functions ; set and clear the modem signals dtr and dsr. ; ; subroutine to clear dtr ; ; r0 = lcb address DQOFF: SAVE R0 MOV LB.SLA(R0),R0 ;point to csr MOV 2(R0),-(SP) ;save current state BIC #DQ.DTR,2(R0) ;clear dtr TRACE TRCDQF,<4(SP),4(SP),2(R0),JIFCLK> ;trace caller,line,dq status BIT #DQ.DTR,(SP)+ ;was it on ? BEQ 10$ ;no - go away DSCHED ,#3*JIFSEC ;yes - allow time for slow modems and phones to hangup 10$: RESTOR R0 RETURN ; subroutine to set dtr DQON: SAVE R0 MOV LB.SLA(R0),R0 ;point to csr BIS #DQ.DTR,2(R0) ;set dtr TRACE TRCDQF,<2(SP),2(SP),2(R0),JIFCLK> ;trace caller,line,dq status RESTOR R0 RETURN ; subroutine to return values of dtr and dsr. ; ; r0 = lcb address ; r1 bits 1 and 2 are 0. ; ; on return: ; ; bit 1 of r1 = dtr ; bit 2 of r1 = dsr ; r1 is otherwise undisturbed. DQSTS: SAVE R0 MOV LB.SLA(R0),R0 ;point to csr BIT #DQ.DTR,2(R0) ;is dtr set? BEQ 11$ ;no. BIS #B1,R1 ;yes, set flag in r1 11$: BIT #DQ.DSR,2(R0) ;is dsr set? BEQ 12$ ;no. BIS #B2,R1 ;yes, set flag in r1 12$: TRACE TRCDQF,<2(SP),2(SP),2(R0),JIFCLK> ;trace caller,line,dq status RESTOR R0 RETURN .SBTTL DQTRP - trap handler stop code processor ; this subroutine is called to store the status of the dq11 ; in the lcb for post-mortum debugging. ; r5 does not point to a tcb, but it must not be destroyed. ; ; r4 = lcb address DQTRP: MOV LB.SLA(R4),R3 ;get hardware address MOV (R3),LB.RG0(R4) ;store reg 0 MOV 2(R3),LB.RG1(R4) ;and the other regs MOV 4(R3),LB.RG2(R4) MOV 6(R3),LB.RG3(R4) CLR R2 ;register pointer MOV R4,R1 ;build pointer into lcb ADD #LB.RGI,R1 MOV #20,R0 ;number of registers to store 11$: MOVB R2,5(R3) ;point to internal register MOV 6(R3),(R1)+ ;store register for debugging INC R2 ;go on to next register SOB R0,11$ ;do all internal registers RETURN .SBTTL DQTIK - DQ11 once per tick functions ; R4/line block DQTIK: BIT #LF.DAC,LB.FGS(R4) ;check for shut down BNE 14$ ;yes - forget it MOV LB.SLA(R4),R3 ;point to csr TST LB.DEW(R4) ;waiting to set modem enable? BEQ 12$ ;no. DEC LB.DEW(R4) ;yes, waited long enough? BNE 12$ ;no, wait a while longer. BIS #DQ.DSF!DQ.DIE,2(R3) ;yes, ; enable interrupt and force one now ; to catch current state 12$: BIT #LS.RRN,(R4) ;is receiver running? BEQ 14$ ;no, done with this line. BIT #DQ.RAC,(R3) ;is receiver active? BEQ 14$ ;no, still searching for sync PIOFF ;disable interrupts BIT #DQ.RAC,(R3) ;is receiver still active? BEQ 13$ ;no. DQREGS SYN,(R3) ;yes, point to sync reg MOV #EBCPAD*401,6(R3) ;change sync char to trailing pad CALL RCVSCC ;significant event if count changed 13$: PION ;enable interrupts 14$: RETURN .ENDC ;.IF NE,FT.DQ .SBTTL KMC11 - KMC11/DUP11 synchronous line driver .IF NE,FT.KDP ; this section contains subroutines to drive the KMC11/DUP11. KDPENT: KDPINI ;initialize the KMC11 and DUP11s KDPRED ;read a message KDPWRT ;output a data message KDPCTL ;output a control message KDPKIL ;cease any KMC/DUP11 operations KDPINQ ;check if any more characters available in current msg KDPON ;set DTR on KDPOFF ;set DTR off KDPSTS ;return DTR,DSR status KDPTIK ;once per tick routine KDPTRP ;stop code processor ; REVISION HISTORY ; 4(001) BS ADDED EDIT NUMBERS ; 4(002) 25-Feb-81 RLS add CIEWAK function and its uses - to make sure BSC task ; is awakened when it needs to be, line faults as well as ; character arrival. ; Make XMTSTP and RCVSTP be carefull and call CIEWAK when done. ; 4(003) 07-Apr-81 RLS Changes to reflect use of message header fordata(DQWRIT) ; DQWRIT has special hack to transform new message format ; into old for benefit of KMC microcode. ; 4(004) 17-Apr-81 RLS ; Transform static flow control to static/line control ; 4(005) 09-JUL-81 RLS Add timer/event counter(LB.DRP) to lcb for kmc's. When ; carrier drops while receiver running, timer is set to ; wait for kmc to possibly finish transferring characters ; to 11 memory. Once/tick code counts down timer and declares ; line error if end of message has not been seen by BSC. ; This fixes a race between dataset interrupts and kmc ; observed at low line speeds(2400 and lower). ; 4(006) 22-JAN-82 RLS Reformat interfaces to driver functions. DQxxxx symbols ; are mapped to kdpyyy symbols...yyy is mnemonical for xxx. ; 4(007) 18-MAR-82 RLS GCO 4.2.1274 - explicitly clear UP.XDL and UP.SND when ; UP.XDL error occurs...KMC cannot always do this for ; some reason. ; 4(010) 21-MAR-82 RLS GCO 4.2.1281 - add time stamps to some trace events. VKMC11=010 VEDIT=VEDIT+VKMC11 .SBTTL KDPINI - initialize a KMC11 and its DUPs ; R4 = pointer to line control block for the KMC11/DUP11 to be initialized KDPINI: TRACE TRCDQF,R4 ;trace KDP initialization MOV #KDPRI,LVECRA(R4) ;set receiver interrupt process address MOV #KDPXI,LVECXA(R4) ;set transmitter interrupt process address MOV #1,LB.TRL(R4) ;set number of trailing pads for data message MOV LB.SLA(R4),R3 ;get dup11 line hardware address MOV #UP.INI,UP.XSR(R3) ;initialize the dup11 1$: BIT #UP.INI,UP.XSR(R3) ;has it finished initialization? BNE 1$ ;no, wait for it. MOV #UP.CCI!UP.DMD!EBCSYN,UP.PAR(R3) ;set up parms for bisync MOV #UP.HDX,UP.XSR(R3) ;blind receiver during transmissions MOV #UP.SSY,UP.RSR(R3) ;strip leading sync from messages ;find this lines's kmc MOV #LINTYP,R0 ;scan LINTYP for 1st kdp driver 5$: CMP #KDPDRV,(R0)+ BNE 5$ ;we won't be here unless there is one SUB #LINTYP+2,R0 ;gen 1st kdp line number ASR R0 SUB LB.LNU(R4),R0 ;calc this line relative to 1st kmc line NEG R0 SAVE R0 ;now find which kmc this line belongs to ASR R0 ASR R0 ;relative line number/4 MOV R0,R2 ;save the kmc number MOV #MDTBL-MDTLN,R1 ;1st kmc 6$: ADD #MDTLN,R1 ;next kmc DEC R0 BGE 6$ RESTOR R0 ;R1/kmc control block for this line BIC #^C3,R0 ;R0/this line number relative to this kmc ASL R0 ADD R1,R0 MOV R4,MDLCB(R0) ;point this kmc11 to this line MOV R1,LB.MD(R4) ;this lines's kmc11 MOV R2,R0 ;get the kmc number back ASL R0 ; make a word offset ; here to initialize the kmc11 which owns this dup11. ; if the kmc11 has already been initialized (by starting one ; of its other lines first, for example) then we need do nothing. ; otherwise we store the kmc11 control block address into sel 2 ; to signal it to start processing and wait for its "run" bit. ; ; R1 = address of kmc11 control block ; R0 = kmc11 number * 2 ; R4 = lcb pointer 13$: BIT #MDFER,MDFGE(R1) ;is pdp-11 already running? BNE 15$ ;yes, don't init again. MOV MDVEC(R0),R2 ;no, point to kmc11 vector BNE 14$ ;there is such a kmc11 STOPCD KMM ;kmc11 is missing 14$: MOV #MDAINT,(R2)+ ;store pointer to int. handler MOV #MD.LVL*40,(R2)+ ;store priority level MOV #MDBINT,(R2)+ ;store other int. handler pointer MOV #MD.LVL*40,(R2)+ ;store priority level MOV #MDFER,MDFGE(R1) ;mark pdp-11 running MOV MDCSR(R0),R3 ;point to kmc11 csr MOV R1,2(R3) ;point microcode to kmc11 table 15$: ; now wait for the kmc11 to start. we wait up to three seconds. MOV R4,-(SP) ;save r4 MOV #JIFSEC*3,-(SP) ;number of jiffies to wait ; here begins the loop that waits for the kmc11 to begin running. 16$: MOV 2(SP),R4 ;point r4 to lcb MOV LB.MD(R4),R3 ;point r3 to kmc11 control block BIT #MDFKR,MDFGK(R3) ;is the kmc11 running now? BNE 17$ ;yes. DSCHED ,#1 ;no, wait one jiffy DEC (SP) ;waited long enough? BNE 16$ ;no, check again. STOPCD KNR ;kmc11 not running (waited 3 sec) ; here when the kmc11 has set its "run" bit. 17$: MOV (SP)+,R4 ;discard depleted counter MOV (SP)+,R4 ;get back lcb pointer ; exercise the kmc11 to be sure it is working MOV #21,R0 ;count of times to exercise 18$: CALL MDACTV ;pull its chain SOB R0,18$ ;do this for a while CALL KDPKIL ;now kill io to complete database initialization RETURN .SBTTL KDPRED - start receiver ; R4 = pointer to line control block ; ; returns C bit set if error, clear if ok. ; (only error is chunks depleted) KDPRED: TRACE TRCDQF,<(SP),R4,JIFCLK> ;trace read entry MOV LB.SLA(R4),R3 ;get hardware address CALL GTLCHK BCS 15$ ;no more chunks CLR LB.CRD(R4) ;clear count of characters read MOV R4,R2 ;point r2 to lcb ADD #LB.SO1,R2 ;build pointer to first silo CALL MDSLOI ;initialize the silo ; here when everything is ready. ; unless we are waiting to start a write, ; we must start the receiver now, since some dup11's ; don't interrupt on carrier, and if we wait up to ; 16 milliseconds before starting the receiver after ; getting carrier, we will frequently lose the first ; character of the message. PIOFF ;disable cpu interrupts BIS #UP.DIE,UP.RSR(R3) ;enable modem interrupts BIS #LS.RGO,(R4) ;waiting to start receiver BIT #LS.XGO,(R4) ;is a write pending? BNE 14$ ;yes, wait for it to start. BIC #LS.RGO!LS.CAR,(R4) ;no, no read pending. BIC #UP.CAR,LB.DIP(R4) ;process carrier next time we see it BIS #LS.RRN,(R4) ;start the read now. CALL MDACTV ;activate the kmc11 BIS #UP.REN,UP.RSR(R3) ;enable the dup11 for reading 14$: PION ;restore cpu priority CLC ;flag no error RETURN ; here if we cannot get a chunk to read into. this is a fatal read error. 15$: INC LB.CHD(R4) ;count times chunks depleted RETURN ;give error return. .SBTTL KDPWRT - start transmitting a data message from LB.MSG ; R4 = pointer to line control block ; ; returns with C bit set if error, clear if not. KDPWRT: TRACE TRCDQF!TRCLIN,<(SP),R4,(R4),LB.MSG(R4),JIFCLK> ;trace entry to "dq write data" BIT #LS.ACT,(R4) ;is dup11 still active? BEQ 11$ ;no. CALL KDPKIL ;yes - kleen it up 11$: BIC #LS.CTL,(R4) ;this is a data, not a control message MOV LB.SLA(R4),R3 ;get dup11 hardware address MOV LB.MSG(R4),R0 ;get the message CALL FMSGI ;maske sure it is inited for output ;LB.MSG points to message header which is already ; initialized for output, namely: ; MSGPTR/ptr to 1st full byte ; MSGLCH/ptr to 1st chunk(=message header) ; CHLEN of 1st chunk/byte count of 1st chunk ;************************************************************** ;this crockery is installed because the KMC microcode knows all about how ;messages ought to be constructed TST CHLEN(R0) ;check if we have faked up old msg format previously BEQ 30$ ;yes(or else the header is empty anyhow) SAVE 15$: CALL GTLCHK ;need a place for the data in the header - privileged call BCC 17$ ;suc'd ? SAVE ;since this a kluge anyhow - protect against alarms CLR LB.ALR(R4) CLR TCTIM(R5) DSCHED #EBINTR,#10. ;dally awhile RESTOR BIT #LS.ENB,(R4) ;check for death BEQ 16$ ;line disabled BIT #TCOAB,TCFG2(R5) ;check output abort also BEQ 15$ ;all seems to be ok - try again 16$: RESTOR ;time to toss in the towel SEC RETURN 17$: MOV LB.MSG(R4),R1 ;get the header MOV MSGPTR(R1),-(SP);get ptr to beg of data MOV (R1),R2 ;link the new chunk in MOV R0,(R1)+ MOV R2,(R0)+ MOV (R1),R2 CLR (R1) ;header is now empty - like so many we know MOV (SP)+,R1 ;R1 -> beg of data MOV R2,(R0)+ ;R2/count ;R0 -> beg of data in new chunk INC R2 ASR R2 ;xfer words 10$: MOV (R1)+,(R0)+ SOB R2,10$ 20$: RESTOR ;********************************************************* 30$: CALL KDXSTR ;arrange to start transmitter RETURN ; subroutine to arrange to start the transmitter KDXSTR: BIS #LS.XGO,(R4) ;xmitter waiting for cts PIOFF ;shut off the world BIS #UP.RTS!UP.DIE,UP.RSR(R3) ;raise request to send ; and enable for cts interrupt MOV LB.CSD(R4),LB.DEW(R4) ;wait a while, then check for cts ; note that modem interrupts are ignored ; until time is up. BNE 11$ ;TIME IS NOT YET UP. ; here if clear-to-send delay specified is zero. ; if cts is up, start the transmitter. note that ; a zero clear-to-send delay should be used only with modems ; that have a clear-to-send delay of less than 16 milliseconds, ; since a larger delay can be timed without loss of efficiency ; and too short a delay (less than about 8 milliseconds) ; does not work with some ibm hosts. BIT #UP.CTS,UP.RSR(R3) ;is cts up? BEQ 11$ ;no, wait for modem interrupt CALL KDPXST ;start the dup BR 12$ ;enable interrupts, clear c and return. ; here if cts delay is non-zero, or if it is zero and cts is not up. 11$: BIC #UP.CTS,LB.DIP(R4) ;process cts raising next time we see it 12$: TRACE TRCDQF, PION ;enable interrupts CLC ;clear 'c' flag RETURN KDPXST: BIS #UP.SND,UP.XSR(R3) ;start dup transmitter MOV #UP.XSM!EBCPAD,UP.XBF(R3) ;start transmission BIC #LS.XGO,(R4) ;not waiting for cts BIS #LS.XRN,(R4) ;now running 10$: BIT #UP.XDN,UP.XSR(R3) ;wait for transmitter done - should be soon BEQ 10$ MOV #EBCPAD,UP.XBF(R3) ;stuff another pad character - clears start bit CALL MDACTV ;activate the kmc11 RETURN .SBTTL KDPCTL - transmit a control message ; R4 = pointer to line control block ; R0 = pointer to message to send ; R1 = length of message to send ; ; on return: ; ; C set if error, clear if not. KDPCTL: TRACE TRCDQF!TRCLIN,<(SP),R4,(R4),R0,R1,JIFCLK> ;trace entry to "dq write control" MOV R0,LB.CMA(R4) ;remember control message address MOV R1,LB.CMC(R4) ; and length BIT #LS.ACT,(R4) ;is dup11 still active? BEQ 11$ ;no. CALL KDPKIL ;yes - kleen it up 11$: BIS #LS.CTL,(R4) ;we are working on a control message MOV LB.SLA(R4),R3 ;get dup11 hardware address CALL KDXSTR ;arrange to start transmitter RETURN .SBTTL KDPRI - KDP receiver interrupt processing ; this is the common interrupt code for dup11 receiver interrupts. ; it is called with ps containing the line number. ; modem interrupts also come here. KDPRI: RCVADJ SAVE MOV LB.SLA(R4),R3 ;GET HARDWARE ADDRESS OF DUP11 ; HERE TO CHECK FOR A DUP11 RECEIVER INTERRUPT BIT RCVTST: MOV UP.RSR(R3),R0 ;GET RECEIVER STATUS REGISTER MOV R0,LB.RST(R4) ;STORE LAST RECEIVER STATUS TRACE TRCDQF, ;TRACE INTERRUPT STATUS ; HERE TO CHECK FOR DATASET INTERRUPT FLAGS, SINCE THE KMC11 TAKES ; CARE OF DATA SIGNALS. 11$: BIT #UP.DCA!UP.DCB,R0 ;ANY DATASET FLAGS? BEQ 12$ ;NO, EXIT THE INTERRUPT. CALL KDPDSF ;YES, PROCESS DATASET FLAGS ; HERE ON NORMAL EXIT. WAKE THE BSC TASK IF REQUESTED. 12$: CALL CIEWAK ; wake BSC on exceptional event ; HERE TO RESTORE REGISTERS AND RETURN. 14$: RESTOR RTI ;EXIT INTERRUPT .ENABL LSB CIEWAK: ; wake BSC if it is waiting for an event ;R4/line block BIT #LS.CIE,(R4) ;DOES BSC TASK WANT TO BE AWAKENED? BEQ 10$ ;NO. KDPBWK: MOV LB.TC1(R4),R0 ;point to bsc task's tcb TRACE TRCDQF,<(SP),R4,(R4),LB.ALR(R4),JIFCLK> SIGNAL R0,EBINTR ;wake the bsc task for a line event BIC #LS.CIE,(R4) ;flush any cie wake flag SETSKD R0 ;force scheduling pass 10$: RETURN .DSABL LSB .SBTTL KDPERR - record a DUP11 error KDPERR: MOV LB.SLA(R4),R3 ;point to dup11 csr MOV UP.RSR(R3),LB.SE2(R4) ;record status reg 1 MOV UP.XSR(R3),LB.SE3(R4) ; and status reg 2 ATRACE <(SP),R4,(R4),UP.RSR(R3),UP.RBF(R3),UP.XSR(R3),UP.XBF(R3),JIFCLK> BIT #LS.ENB,(R4) ;is this all because line is diabled? BEQ 20$ INC LB.SE1(R4) ;count master error counter BIS #LS.ERR,(R4) ;flag an error .IF NE,DEBUG BIT #TRCLER,TRCHLT BEQ 20$ STOPCD DBG .ENDC ;.IF NE,DEBUG 20$: RETURN .SBTTL KDRSTP,KILKMC,KDXSTP - stop io functions ; R4 points to lcb, R3 to csr. .ENABL LSB KDRSTP: TRACE TRCDQF,<(SP),R4,(R4),LB.DRP(R4),LB.ALR(R4),JIFCLK> ;trace dup11 receiver stop CLRB LB.DRP+1(R4) ;clear carrier drop timer BIC #UP.DIE,UP.RSR(R3) ;disable modem interrupts BIT #LS.RGO!LS.RRN,(R4) ;is receiver running? BEQ 15$ ;no - don't bother KMC ;yes - kill the KMC KILKMC: ;kill the KMC - dead BIC #LS.KLC,(R4) ;make sure this is off so KMC won't ignore BIS #LS.KIL,(R4) ;kill current operation CALL MDACTV ;awaken the kmc11 MOV #MDMXTT,R0 ;time to wait for kill 10$: BIT #LS.KLC,(R4) ;wait for the KMC to declare the kill complete BNE 15$ SOB R0,10$ ;but only for awhile 15$: ;flush any event wakeup flag,dup bits CALL KDPBWK ;wake the bsc 20$: CLC ;indicate all is hunkydory...if anyone is interrested RETURN ; subroutine to stop the transmitter ; R4 points to the lcb ; R3 POINTS TO THE DUP11 CSR KDXSTP: TRACE TRCDQF,<(SP),R4,(R4),LB.ALR(R4),JIFCLK> ;trace dup11 transmitter stop BIC #UP.RTS,UP.RSR(R3) ;drop request to send CLR LB.DEW(R4) ;not waiting to enable modem BIT #LS.XGO!LS.XRN,(R4) ;transmitter running? BEQ 15$ ;NO - don't bother KMC BR KILKMC ;yes - mung the KMC .DSABL LSB .SBTTL MDAINT - KMC11 silo interrupt ; here on a silo interrupt from the kmc11. ; drain any non-empty silos which have their "interrupt on ; next character" flag clear, which means that the kmc11 ; might have interrupted because of them. the kmc11 will ; give full and warning interrupts regardless of the ; state of this flag. MDAINT: INTSKD SAVE ; here to check all lcb's for a non-empty silo CLR R5 ;line number * 2 ; here to check the next lcb 11$: MOV LINTBL(R5),R4 ;point to lcb BEQ 13$ ;no lcb for this line BIT #LS.XGO!LS.XRN!LS.KIL!LS.KLC,(R4) ;is this line writing or killed? BNE 13$ ;yes, ignore its silo BIT #LS.RRN,(R4) ;no, is line doing input? BEQ 13$ ;no, ignore its silo. MOV LB.SLO(R4),R3 ;point to silo BEQ 13$ ;not a KDP line TRACE TRCDQF, ;kmc11 input interrupt for this lcb BIT #MDSLFE,MDSLFG(R3) ;will this silo int. on next char? BNE 12$ ;yes, ignore it until it interrupts. MOV MDSLPT(R3),R2 ;no, get current address from silo SUB LB.CCD(R4),R2 ;subtract initial address CMP R2,@LB.CCR(R4) ;has count changed? BEQ 12$ ;no, ignore this empty silo. CALL MDSLEM ;yes, empty the silo BIS #LS.RSE,(R4) ;mark that the receive silo was emptied. .IF NE,DEBUG BR 13$ ;done with this lcb .ENDC ;.if ne,debug (no code between finish and reject unless debug) ; here to reject this lcb (r3 is set up) 12$: TRACE TRCDQF, ;record silo pointer and its status bits ; here when we are done with this lcb 13$: ADD #2,R5 ;increment line number * 2 CMP #,R5 ;done all the lines? BNE 11$ ;no, do the rest. ; here when all the silos have been emptied. RESTOR RTI ;exit the interrupt .SBTTL KDPXI - DUP11 transmit interrupts: an error ; PROCESSES ALL DATA FLAGS. KDPXI: XMTADJ STOPCD UQX ;unknown dup11 transmit interrupt .SBTTL MDBINT - interrupt for KMC11 function done and error MDBINT: INTSKD SAVE ; here to check all lcb's for completion or error. CLR R5 ;line number * 2 ; here to check the next lcb 11$: MOV LINTBL(R5),R4 ;point to lcb BEQ 9$ ;no lcb, do nothing. MOV LB.SLA(R4),R3 ;point to dup11 csr BIT #LS.CMP!LS.KLC,(R4) ;function complete? BNE 10$ 9$: JMP 18$ 10$: TRACE TRCDQF, ;record lcb status on interrupt BIT #LS.KLC,(R4) ;completion of kill request? BEQ 12$ ;no. check for write and read. BIT #LS.MDE,(R4) ;yes, have we had an error? BEQ 16$ ;no. awaken bsc task if req. BIC #LS.MDE,(R4) ;yes, clear kmc11 error flag BIS #LS.ERR,(R4) ;set summary error flag BR 16$ ;awaken bsc task if req. ; here if not completion of a kill request 12$: BIT #LS.XGO!LS.XRN,(R4) ;completion of a write? BEQ 14$ ;no. BIC #UP.DIE,UP.RSR(R3) ;yes, disable modem interrupts BIC #UP.RTS,UP.RSR(R3) ;drop rts CLR LB.DEW(R4) ;not waiting for modem signals BIT #LS.MDE,(R4) ;have we had an error? BEQ 13$ ;no. INC LB.SE5(R4) ;yes, "transmitter not fast enough" CALL KDPERR ;record dup11 registers CALL KDXSTP ;stop the transmitter CALL KDRSTP ;stop the receiver BIC #UP.XDL!UP.SND,UP.XSR(R3) ;flush transmitter and error explicitly BIC #LS.ACT!LS.MDE,(R4) ;dont start a read following write CLR LB.CCH(R4) ;there is no current chunk 13$: BIC #LS.XGO!LS.XRN!LS.CMP,(R4) ;clear completed write flags BIT #LS.ACT,(R4) ;is dup11 still active? BEQ 16$ ;no, leave modem ints disabled. BIS #UP.DIE,UP.RSR(R3) ;yes, enable modem ints BR 16$ ;awaken bsc task if requested. ; here if not completion of kill or write 14$: BIT #LS.RGO!LS.RRN,(R4) ;receiver running? BEQ 15$ ;no. BIC #LS.RGO!LS.RRN!LS.CMP!LS.MDE,(R4) ;yes, clear the flags BIC #UP.DIE,UP.RSR(R3) ;clear modem interrupt enable CLR LB.CCH(R4) ;there is no current chunk MOV LB.SLO(R4),R0 ;point to current silo BIT #MDSLFO,MDSLFG(R0) ;has it overflowed? BEQ 20$ ;no. INC LB.SE7(R4) ;yes, count silo overflows. 20$: INC LB.SE4(R4) ;must be an error... CALL KDPERR ; since that is only reason for stopping BR 16$ ;awaken bsc task if requested ; here if not completion of kill, write or read. 15$: ATRACE STOPCD KCQ ;kmc11 complete on an idle lcb ; here when line has made a transition. 16$: CALL KDPBWK ;wake the bsc 17$: ; here when we are done with this lcb. 18$: .IF NE,DEBUG TST R4 ;have we an lcb? BEQ 19$ ;no, dont trace TRACE TRCDQF, ;yes, trace new state of lcb 19$: .ENDC ;.IF NE,DEBUG ADD #2,R5 ;increment line number * 2 CMP R5,#NLINES*2 ;done last line? BGE 90$ ;no, do the rest. JMP 11$ 90$: ; here when we have done a pass and all lines have no action. RESTOR RTI ;exit the interrupt. .SBTTL KDPDSF - process data set flags ; R0 = dataset flags ; R3 = DUP11 csr ; on return, R3 is destroyed. .ENABL LSB KDPDSF: INC LB.DIC(R4) ;count dataset interrupts MOV R0,LB.DIS(R4) ;record last modem interrupt status TRACE TRCDQF,<(SP),R4,(R4),R0,LB.DEW(R4),LB.ALR(R4),JIFCLK> TST LB.DEW(R4) ;waiting for dataset enable? BNE 13$ ;yes, ignore modem signal. BIT #LS.ACT,(R4) ;is the dup11 active? BEQ 13$ ;no, ignore the modem signals MOV R0,LB.DIP(R4) ;yes, record last modem signals processed BIT #LS.XGO,(R4) ;waiting to start xmitter? BEQ 11$ ;no. CALL 14$ ;yes, check for clear-to-send. 11$: BIT #LS.XRN,(R4) ;running the transmitter? BEQ 12$ ;no. CALL 18$ ;yes, be sure cts still up 12$: BIT #LS.RRN,(R4) ;running receiver? BEQ 13$ ;no. CALL 20$ ;yes, worry about carrier failure. 13$: RETURN ; three subroutines to process data set flags. they are called ; based on the current state of the dup11. ; R0 = modem status flags, from the dup11. ; R3 = pointer to dup11 csr ; HERE if we are waiting to start the transmitter 14$: BIT #UP.CTS,R0 ;have we clear-to-send? BEQ 17$ ;no, wait for it. BIT #LS.RGO,(R4) ;waiting to start receiver? BEQ 15$ ;no. BIC #LS.RGO!LS.CAR,(R4) ;yes, waiting no longer. BIC #UP.CAR,LB.DIP(R4) ;process carrier next time we see it BIS #LS.RRN,(R4) ;start xmit, follow with rcv ; here if the write is not to be followed by a read 15$: CALL KDPXST ;start the dup 17$: RETURN ;all done. ; here if we are running the transmitter 18$: BIT #UP.CTS,R0 ;is clear-to-send still up? BNE 19$ ;yes, all ok. INC LB.SE6(R4) ;no, note clear-to-send failure CALL KDPERR ;note error CALL KDXSTP ;stop the transmitter 19$: RETURN ;all done. ; here if the receiver is running. 20$: BIT #UP.CAR,R0 ;IS CARRIER UP? BNE 24$ ;yes BIT #LS.CAR,(R4) ;no - was it up previously ? BEQ 22$ ;no - worry not BIC #LS.CAR,(R4) ;yes - transition, flush the flag MOVB #10.,LB.DRP+1(R4);set a timer to distinguish kmc/dataset race ;from crufty carrier INCB LB.DRP(R4) ;count these events BNE 23$ DECB LB.DRP(R4) ;hang at max count(255.) 23$: TRACE TRCLIN!TRCDQF, KDPCFL: RETURN ; HERE IF CARRIER IS UP 24$: TSTB LB.DRP+1(R4) ;check if carrier previously went off BEQ 21$ ;no - all is kosher ;yes - this is a hard error .IF NE,DEBUG CALL 23$ ;trace this BIT #TRCLER,TRCHLT ;check if we should halt BEQ 25$ STOPCD DBG 25$: CALL KDRSTP ;definitely a hard error if carrier bobbles RETURN .ENDC ;.IF NE,DEBUG 21$: .IF NE,DEBUG BIT #LS.CAR,(R4) ;check for 1st detect BNE 22$ ;no TRACE TRCLIN!TRCDQF, KDPCDT: .ENDC ;.IF NE,DEBUG 26$: BIS #LS.CAR,(R4) ;mark we have seen carrier 22$: RETURN .DSABL LSB .SBTTL KDPINQ - see if the KMC11 has read any good characters lately ; all characters up to CHLEN have been processed. ; R5 points to the tcb ; R4 points to the current chunk. ; on return: ; ; C set: some characters were found in the silo. ; if R4 undisturbed, they are in current chunk ; (the length field has been updated) ; if R4 clear, get a new chunk to process. ; ; C clear: the silo is empty. it is now ; set to restart the bsc task on the next character. KDPINQ: SAVE MOV R4,R0 ;point r0 to current chunk MOV TCLCB(R5),R4 ;point to lcb 11$: PIOFF BIT #LS.RSE,(R4) ;has the receive silo been emptied since last call? BNE 13$ ;yes, be sure processing is done. CMP R0,LB.CCH(R4) ;no, is this still the current chunk? BNE 12$ ;no. discard it and get another. MOV LB.SLO(R4),R3 ;no, point r3 to silo MOV MDSLPT(R3),R2 ;get current address from silo SUB LB.CCD(R4),R2 ;subtract initial address CMP R2,@LB.CCR(R4) ;has count changed? BNE 14$ ;yes, process characters BR 16$ ;no, tell caller to wait ; here to abandon this chunk because it is no longer being filled. 12$: PION ;enable interrupts TRACE TRCDQF, ;trace decision to abandon old chunk MOV R1,-(SP) ;save r1 CALL FRECHK MOV (SP)+,R1 ;restore r1 BR 15$ ;tell caller to recycle ; here to tell caller to recycle because the silo has been ; drained since the last time we came through here. if we ; do not do this, the silo might have been drained between ; the caller's last test and our tests, so make caller ; do his tests one more time. 13$: BIC #LS.RSE,(R4) ;clear interrupt flag PION ;restore interrupts BR 15$ ;tell caller to recycle ; here to empty the silo and tell caller to process chars 14$: CALL MDSLEM ;empty the silo PION ;enable interrupts ; here to return, telling caller not to wait. 15$: MOV R0,R4 ;restore r4 RESTOR SEC ;flag more processing required RETURN ; here if the silo is still empty. arrange to awaken this task ; when the next character is stored. 16$: BIS #LS.CIE,(R4) ;set wakeup flag BIS #MDSLFE,MDSLFG(R3) ;make this silo interrupt on next character ; come here to wait the task. from above, we will awaken ; on the next character. if the line is running fast, ; we bypass the above code and just require the bsc task ; to wait until either the chunk fills or its timer ; expires. 17$: TRACE TRCDQF, ;trace decision to wait the task. PION ;restore interrupt level MOV R0,R4 ;restore r4 RESTOR CLC ;flag no characters RETURN .SBTTL MDSLEM - empty the KMC11'S silo ; this subroutine is called from input interrupt ; and if the bsc task needs more characters to ; avoid going idle. ; interrupts are masked off by the caller of this subroutine. ; R4 = lcb pointer ; R3 = silo pointer (from LB.SLO(R4)). ; destroys r2 MDSLEM: TRACE TRCDQF, ;trace silo flag bits SAVE BIT #MDSLFW,MDSLFG(R3) ;reached warning level yet? BEQ MDSLE1 ;no, dont switch silos TRACE TRCDQF, ;yes, trace departure of chunk MOV R4,R2 ;build pointer to other silo ADD #LB.SO1,R2 CMP R2,R3 ;is this silo 1? BNE 13$ ;no. ADD #LB.SO2-LB.SO1,R2 ;yes, make r2 point to silo 2 13$: ; get a chunk to hold new silo data CALL GTLCHK ;get a chunk BCS 14$ ;yes, we are out of chunks TRACE TRCDQF, ;trace chunk manipulation CALL MDSLOI ;initialize the new silo BR MDSLE1 ;process data in old silo ; here if we run out of chunks. this is not a fatal error if ; the bsc task sees the end of the bisync message before ; needing the data that was lost. 14$: INC LB.CHD(R4) ;record exhaustion of chunks MOV LB.SLA(R4),R3 ;point to dup11 csr CALL KDRSTP ;stop the receiver BR MDSLEX ;exit the subroutine ; here to give the characters in the silo to the task. ; this is done by updating the length field of the current chunk ; R3 = pointer to silo. LB.SLO(R4) may point to the other silo. MDSLE1: MOV MDSLCC(R3),R2 ;point to this silo's chunk MOV MDSLPT(R3),R0 ;compute new fill level SUB R2,R0 ;copy pointer SUB #CHDAT,R0 ;make pointer to data area MOV R0,CHLEN(R2) ;store new length TRACE TRCDQF, ;trace new length BIT #MDSLFW,MDSLFG(R3) ;are we at warning point? BEQ 12$ ;no, dont record statistic. MOV MDSLPT(R3),R0 ;yes, get current fill point (note that this ; may still be the current silo, but this is unlikely) SUB MDSLPW(R3),R0 ;subtract warning point CMP R0,LB.MDU(R4) ;greater than max needed before? BLO 12$ ;no. MOV R0,LB.MDU(R4) ;yes, store new max depth 12$: CMP R3,LB.SLO(R4) ;are we changing silos? BEQ MDSLEX ;no. ADD CHLEN(R2),LB.CRD(R4) ;yes, accumulate chars read CMP LB.CRD(R4),#DQRLMT ;too many characters in message? BLE MDSLEX ;no, look for another character. MOV LB.SLA(R4),R3 ;yes, point to dup11 csr CALL KDRSTP ;stop the receiver ; here when the silo has been emptied, or on an error. MDSLEX: CALL CIEWAK ; wake the BSC if he is waiting on an event RESTOR RETURN .SBTTL MDSLOI - intiialize a silo ; R0 = pointer to chunk to hold data ; R2 = pointer to silo. ; R4 = lcb pointer MDSLOI: MOV R0,LB.CCH(R4) ;silo chunk is now current MOV LB.TC1(R4),R1 ;get tcb of receive chunk handler TRACE TRCLIN, CALL QUECHK ;send him the chunk ADD #CHLEN,R0 ;point to length field MOV R0,LB.CCR(R4) ;store for next input interrupt ADD #CHDAT-CHLEN,R0 ;point to data field MOV R0,LB.CCD(R4) ;store for next input interrupt MOV R0,MDSLPT(R2) ;store new initial data pointer ADD #CHDATL,R0 ;point to end of data area MOV R0,MDSLPL(R2) ;store for overflow checking SUB LB.MDS(R4),R0 ;back up for latency MOV R0,MDSLPW(R2) ;store as warning level MOV LB.CCH(R4),MDSLCC(R2) ;copy pointer to current chunk CLR MDSLFG(R2) ;clear silo flags MOV R2,LB.SLO(R4) ;we have a new silo TRACE TRCDQF, ;trace new "current chunk" RETURN .SBTTL KDPKIL - kill any KMC11/DUP11 operations ; R4 = lcb pointer ; R5 = pointer to bsc tcb ; destroys r0, r1 and r3 KDPKIL: TRACE TRCDQF,<(SP),R4,(R4),LB.ALR(R4),JIFCLK> ;trace entry to kdpkil MOV LB.SLA(R4),R3 ;point to csr CALL KDXSTP ;flush the tranmitter if on CALL KDRSTP ;flush the receiver if on 14$: CLR LB.CCH(R4) ;there is no current chunk .IF NE,DEBUG MOV #-1,LB.SLO(R4) ;the silo is gone .ENDC ;.IF NE,DEBUG ; here when the line has been killed, or was not running at all. 15$: PIOFF ;disable interrupts BIC #UP.DIE,UP.RSR(R3) ;disable dataset interrupts ; (avoid hardware race condition ; in 11/34 by disabling ints) PION ;restore interrupts 16$: CALL DEQCHK ;any chunks in receiver queue? BCS 17$ ;no. CALL FRECHK ;flush it BR 16$ ;be sure we've got them all. ; here when the kmc11/dup11 has been killed. 17$: BIT #LS.ACT!LS.CMP,(R4) ;was the kmc11 active? BEQ 19$ ;no, this was all for nothing. BIT #LS.KLC,(R4) ;yes, has the kill completed? BNE 18$ ;yes. STOPCD KKF ;no, kmc11 kill failed. ; here when the kill is complete. clear all relevent lcb status bits. 18$: BIC #LS.ACT!LS.CMP!LS.KIL!LS.KLC,(R4) ;the kmc11/dup11 is no longer active 19$: TRACE TRCDQF,R4 ;trace completion of KDPKIL RETURN .SBTTL MDCATV - poke the kmc11 so it will check its line blocks MDACTV: TRACE TRCDQF, ;trace entry to MDACTV SAVE MOV LB.MD(R4),R3 ;point to kmc11 table MOV #MDMXTT,R2 ;wait this long for kmc11 to respond 11$: MOV MDFGE(R3),R0 ;get 11-flags MOV MDFGK(R3),R1 ; and kmc flags XOR R1,R0 ;xor 11-flags with kmc-flags BIT #MDFEA,R0 ;is old active flag still on? BEQ 12$ ;no. SOB R2,11$ ;yes, wait for kmc11 to follow STOPCD KNA ;kmc11 not following active flag 12$: BIT #MDFKR,MDFGK(R3) ;is kmc11 still running? BNE 14$ ;yes. STOPCD KNR ;no, kmc11 not running. ; here when the kmc11 has completed the last operation and is running. 14$: MOV #MDFEA,R0 ;get bit to xor XOR R0,MDFGE(R3) ;complement active flag RESTOR RETURN ;done. .SBTTL KDPOFF,KDPON,KDPSTS - DTR,DSR functions ; set and clear the modem signals dtr and dsr. ; subroutine to clear dtr ; R0 = lcb address KDPOFF: SAVE R0 MOV LB.SLA(R0),R0 ;point to csr MOV UP.RSR(R0),-(SP) ;save current state BIC #UP.DTR,UP.RSR(R0) ;clear dtr TRACE TRCDQF,<4(SP),4(SP),UP.RSR(R0),JIFCLK>;trace caller,line,DUP status BIT #UP.DTR,(SP)+ ;was it on ? BEQ 10$ ;no - go away DSCHED ,#3*JIFSEC ;yes - allow time for slow modems and phones to hangup 10$: RESTOR R0 RETURN ; subroutine to set dtr KDPON: SAVE R0 MOV LB.SLA(R0),R0 ;point to csr BIS #UP.DTR,UP.RSR(R0) ;set dtr TRACE TRCDQF,<2(SP),2(SP),UP.RSR(R0),JIFCLK>;trace caller,line,dq status RESTOR R0 RETURN ; subroutine to return values of dtr and dsr. ; R0 = lcb address ; R1 bits 1 and 2 are 0. ; on return: ; ; bit 1 of R1 = DTR ; bit 2 of R1 = DSR ; R1 is otherwise undisturbed. KDPSTS: SAVE R0 MOV LB.SLA(R0),R0 ;point to csr BIT #UP.DTR,UP.RSR(R0) ;is dtr set? BEQ 11$ ;no. BIS #B1,R1 ;yes, set flag in r1 11$: BIT #UP.DSR,UP.RSR(R0) ;is dsr set? BEQ 12$ ;no. BIS #B2,R1 ;yes, set flag in r1 12$: TRACE TRCDQF,<2(SP),2(SP),UP.RSR(R0),JIFCLK>;trace caller,line,DUP status RESTOR R0 RETURN .SBTTL KDPTRP - stop code processor for the KDP driver ; this subroutine is called to store the status of the dup11 ; in the lcb for post-mortum debugging. ; R5 does not point to a tcb, but it must not be destroyed. ; R4 = lcb address KDPTRP: MOV LB.SLA(R4),R3 ;get hardware address MOV UP.RSR(R3),LB.RG0(R4) ;store receiver status register MOV UP.RBF(R3),LB.RG1(R4) ;store receiver buffer MOV UP.XSR(R3),LB.RG2(R4) ;store transmit status register MOV UP.XBF(R3),LB.RG3(R4) ;store transmit buffer RETURN ; subroutine to stop the kmc11s on a fatal error. TRAPMD: CLR R1 ;kmc11 number MOV #MDTBL,R3 ;pointer to kmc11 table 11$: BIC #MDFER,MDFGE(R3) ;clear "11-running" ADD #MDTLN,R3 ;point to next kmc11 table INC R1 ;increment kmc11 number CMP R1,NKMC11 ;done all kmc11s? BLT 11$ ;no, do the rest. RETURN ;return to trap handler. .SBTTL KDPTIK - check on the DUP11S once a jiffie ; we must count the clear-to-send delay and ; compensate for improper dup11 jumpers which ; will prevent the carrier signal from causing ; an interrupt. ; ; R4/line block KDPTIK: 11$: BIT #LF.DAC,LB.FGS(R4);check for shut down BNE 15$ ;yes - forget it PIOFF ;disable interrupts TST LB.DEW(R4) ;waiting to set modem enable? BEQ 12$ ;no. DEC LB.DEW(R4) ;yes, waited long enough? BNE 14$ ;no, wait until next time 12$: MOV LB.SLA(R4),R3 ;point to csr MOV UP.RSR(R3),R0 ;get modem status bits BIT #UP.DIE,R0 ;are modem interrupts enabled? BEQ 14$ ;no, dont call subroutine. BIT #UP.DCA!UP.DCB,R0 ;are dataset change flags set? BNE 13$ ;yes, process any possible changes MOV LB.DIP(R4),R2 ;get last modem signals processed XOR R0,R2 ;check for any changes in signals BIT #UP.CTS!UP.CAR,R2 ;any important modem signals changed? BEQ 14$ ;no. 13$: CALL KDPDSF ;yes, process any modem signal changes 14$: TSTB LB.DRP+1(R4) ;check for carrier drop timer BEQ 10$ ;no TRACE TRCLIN!TRCDQF, DECB LB.DRP+1(R4) ;yes - count it down BNE 10$ .IF NE,DEBUG BIT #TRCLER,TRCHLT ;check if we should halt BEQ 69$ STOPCD DBG 69$: .ENDC ;.IF NE,DEBUG CALL KDRSTP ;timed out before BSC could call ; KDRSTP(when it sees end of msg), this is ; a hardware error 10$: PION ;restore interrupt level 15$: ; now check this line's KMC11 MOV LB.MD(R4),R3 ;get the kmc control block BEQ 18$ ;amazing - not controlled by a kmc MOV #4,R2 ;find 1st line controlled by this kmc11 MOV R3,R0 ADD #MDLCB,R0 20$: TST (R0)+ ;find 1st nonzero entry BNE 25$ SOB R2,20$ STOPCD DBG ;should't be here 25$: CMP R4,-(R0) ;check if this line is 1st one in kmc's block BNE 18$ ;this way we dthe kmc check only once 16$: BIT #MDFER,MDFGE(R3) ;is pdp-11 running? BEQ 18$ ;no, this kmc11 not in use. BIT #MDFKR,MDFGK(R3) ;yes, is kmc11 running? BEQ 18$ ;no, no timeing yet. ; here when we have a running kmc11. INC MDTIC(R3) ;count towards one second CMP #JIFSEC,MDTIC(R3) ;reached a second yet? BNE 18$ ;no, wait until next time CLR MDTIC(R3) ;yes, reinitialize tick counter INC MDALE(R3) ;count pdp-11 alive counter BIT #7,MDALE(R3) ;has it been eight seconds? [2(755)] BNE 18$ ;no, check next kmc11 MOV MDALK(R3),R0 ;yes, get kmc11 alive counter CMP R0,MDALKS(R3) ;same as last time? BNE 17$ ;no, kmc11 still alive. STOPCD KKS ;kmc11 keep-alive stopped. 17$: MOV R0,MDALKS(R3) ;save old value of keep-alive ; here when we are done with this kmc11 18$: ; here when we are done with this "tick". RETURN .ENDC ;.IF NE,FT.KDP .SBTTL DUP11 - DUP11 synchronous line driver .IF NE,FT.DUP ; this section contains subroutines to drive the dup11. ; these are: DUPENT: DUPINI ;initialize the dup11 DUPRED ;read a message DUPWRT ;output a data message DUPCTL ;output a control message DUPKIL ;cease any dup11 operations DUPINQ ;check if any more characters available in current msg DUPON ;set DTR on DUPOFF ;set DTR off DUPSTS ;return DTR,DSR status DUPTIK ;once per tick routine DUPTRP ;stop code processor ; REVISION HISTORY ; 4(001) BS ADDED EDIT NUMBERS ; 4(002) Remove chunk ownership trace in DUP receiver interrupt code ; 4(003) 07-Apr-81 RLS Changes to reflect use of message header for data(DQWRIT) ; 4(004) 17-Apr-81 RLS ; Transform static flow control to static/line control ; 4(005) 28-DEC-81 RLS ; Rewrite for performance. ; 4(006) 27-AUG-82 RLS GCO 4.2.1504 ; in DUPRED, continuous carrier case, fix wrong sense of branch ; on transmitter active test. VDUP11=006 VEDIT=VEDIT+VDUP11 .SBTTL DUPINI - initialization ; R4 = pointer to line control block for dup11 to be initialized. DUPINI: TRACE TRCDQF,R4 ;trace dup11 initialization MOV #DUPRI,LVECRA(R4) ;set receiver interrupt process address MOV #DUPXI,LVECXA(R4) ;set transmitter interrupt process address MOV #1,LB.TRL(R4) ;set number of trailing pads for data message MOV LB.SLA(R4),R3 ;get dup11 line hardware address MOV #UP.INI,UP.XSR(R3) ;initialize the dup11 11$: BIT #UP.INI,UP.XSR(R3) ;has it finished initialization? BNE 11$ ;no, wait for it. MOV #UP.CCI!UP.DMD!EBCSYN,UP.PAR(R3) ;set up parms for bisync MOV #UP.HDX,UP.XSR(R3) ;blind receiver during transmissions MOV #UP.SSY,UP.RSR(R3) ;strip leading sync from messages CALL DUPKIL ;kill io to complete database initialization RETURN .SBTTL DUPRED - start receiver ; R4 = pointer to line control block ; ; returns C bit set if error, clear if ok. ; (only error is chunks depleted) DUPRED: TRACE TRCDQF,<(SP),R4,JIFCLK> ;trace entry to DUPRED MOV LB.SLA(R4),R3 ;get hardware address CALL RCVCHK ;get enough chunks to receive a message BCS 14$ ;no more chunks ; here when everything is ready. ; we must start the receiver now, since some dup11's ; don't interrupt on carrier, and if we wait up to ; 16 milliseconds before starting the receiver after ; getting carrier, we will frequently lose the first ; character of the message. PIOFF ;disable cpu interrupts CALL DNXRCK ;setup to receive TRACE TRCDQF, BIS #LS.RGO,(R4) ;waiting to start receiver BIT #UP.CAR,UP.RSR(R3) ;check for continous carrier BNE 10$ ;yes - we can't expect a carrier detect interrupt ;switched carrier BIC #LS.CAR,(R4) ;we have not yet seen carrier BIC #UP.CAR,LB.DIP(R4) ;process carrier next time we see it BR 12$ 10$: BIS #LS.CAR,(R4) ;carrier has been seen BIS #UP.CAR,LB.DIP(R4);so we don't need to process it BIT #LS.XGO!LS.XRN,(R4) ;carrier present - check pending transmit BNE 12$ ;yes - wait for transmision end CALL DPRSTR ;start the sucker 12$: BIS #UP.DIE,UP.RSR(R3) ;enable modem interrupts PION ;restore cpu priority CLC ;flag no error 14$: RETURN DPRSTR: BIS #UP.DIE!UP.RIE!UP.REN,UP.RSR(R3) ;start the dup11 now BIS #LS.RRN,(R4) ;receiver is now running BIC #LS.RGO,(R4) ;not waiting to start it anymore RETURN .SBTTL DUPWRT - start transmitting a data message from LB.MSG ; R4 = pointer to line control block ; ; returns with C bit set if error, clear if not. DUPWRT: TRACE TRCDQF!TRCLIN,<(SP),R4,(R4),LB.MSG(R4),JIFCLK> ;trace entry to DUPWRT BIT #LS.ACT,(R4) ; is dup11 still active? BEQ 11$ ;no. CALL DUPKIL ;yes - kleen up 11$: BIC #LS.CTL,(R4) ;this is a data, not a control message MOV LB.SLA(R4),R3 ;get dup11 hardware address MOV LB.MSG(R4),R0 ;get the message CALL FMSGI ;maske sure it is inited for output ;LB.MSG/ptr to message already inited for output ; MSGPTR/ptr to 1st full byte ; MSGLCH/ptr to 1st chunk(=message header) ; CHLEN of 1st chunk/bytes in 1st chunk MOV MSGPTR(R0),LB.CXD(R4) ;set data ptr MOV (R0)+,LB.CCX(R4) ;save ptr to next chunk in message MOV (R0),LB.CXR(R4) ;set byte count CALL DPXSTR ;arrange to start transmitter RETURN ; subroutine to arrange to start the transmitter DPXSTR: BIS #LS.XGO,(R4) ;xmitter waiting for cts MFPS -(SP) ;save interrupt level MTPS #BR7 ;disable interrupts BIS #UP.RTS!UP.DIE,UP.RSR(R3) ;raise request to send ; and enable for cts interrupt MOV LB.CSD(R4),LB.DEW(R4) ;wait a while, then check for cts ; note that modem interrupts are ignored ; until time is up. BNE 11$ ;time is not yet up. ; here if clear-to-send delay specified is zero. ; if cts is up, start the transmitter. note that ; a zero clear-to-send delay should be used only with modems ; that have a clear-to-send delay of less than 16 milliseconds, ; since a larger delay can be timed without loss of efficiency ; and too short a delay (less than about 8 milliseconds) ; does not work with some ibm hosts. BIT #UP.CTS,UP.RSR(R3) ;is cts up? BEQ 11$ ;no, wait for modem interrupt CALL DUPXST ;start dup BR 12$ ;enable interrupts, clear c and return. ; here if cts delay is non-zero, or if it is zero and cts is not up. 11$: BIC #UP.CTS,LB.DIP(R4) ;process cts raising next time we see it 12$: MTPS (SP)+ ;enable interrupts CLC RETURN DUPXST: BIS #UP.SND,UP.XSR(R3) ;start dup transmitter MOV #UP.XSM!EBCPAD,UP.XBF(R3) ;start transmission BIC #LS.XGO,(R4) ;not waiting for cts BIS #LS.XRN,(R4) ;now running CLR R0 BISB @LB.CXD(R4),R0 ;get 1ST data char INC LB.CXD(R4) ;advance data byte ptr ;but don't count it 10$: BIT #UP.XDN,UP.XSR(R3) ;wait for transmitter done - should be soon BEQ 10$ MOV R0,UP.XBF(R3) ;stuff 1st character - clears start bit BIS #UP.XIE,UP.XSR(R3) ;now turn on transmitter interrupts RETURN .SBTTL DUPCTL - start transmitting a control message (e.g., ACK) ; R4 = pointer to line control block ; R0 = pointer to message to send ; R1 = length of message to send ; ; on return: ; ; C set if error, clear if not. DUPCTL: TRACE TRCDQF!TRCLIN,<(SP),R4,(R4),R0,R1,JIFCLK> ;trace entry to DUPCTL MOV R0,LB.CMA(R4) ;remember control message address MOV R1,LB.CMC(R4) ; and length BIT #LS.ACT,(R4) ;is dup11 still active? BEQ 11$ ;no. CALL DUPKIL ;yes - kleen up 11$: BIS #LS.CTL,(R4) ; we are working on a control message MOV LB.SLA(R4),R3 ;get dup11 hardware address MOV LB.CMA(R4),LB.CXD(R4) ;set data ptr MOV LB.CMC(R4),LB.CXR(R4) ;set byte count CALL DPXSTR ; arrange to start transmitter RETURN .SBTTL DUPRI - receiver interrupt processor ; this is the common interrupt code for dup11 receiver interrupts. ; it is called with ps containing the line number. ; modem interrupts also come here. DUPRI: RCVADJ ;dup11 receiver interrupt processor ;R4 -> line block for interrupting dup11 ;old R4 on stack SAVE MOV LB.SLA(R4),R3 ;get device address MOV UP.RSR(R3),LB.RST(R4) ;get receiver status register BMI 10$ ;summary for various conditions: ; cts transition ; ring ; with optional jumper W5 installed: ; carrier detect transition ; dsr transition ; secondary receive data line transition MOV UP.RBF(R3),R1 ;no, get character BMI 12$ ;error. MOVB R1,@LB.CCD(R4) ;store byte in current chunk INC LB.CCD(R4) ;advance pointer DEC LB.CCR(R4) ;count the character BGT 20$ ;chunk not full yet ; we have filled the current chunk. get another one so we can fill it. SAVE R0 MOV LB.CCH(R4),R0 ;set the byte count MOV #CHDATL,CHLEN(R0) CALL DNXRCK ;advance to next chunk BCC 17$ BR 14$ ;msg is already maximum length 10$: SAVE R0 ;error 11$: MOV LB.RST(R4),R0 ;get the status flags CALL DUPDSF ;process dataset flags BR 17$ ; here on error in receiver 12$: SAVE R0 INC LB.SE4(R4) ;receiver overrun CALL DUPERR ;record an error ;terminate the interrupt. ; come here if we have too long a message. if this is actually ; an error and not just reading pads it will be caught by ; the bsc task, as above. 14$: CALL DPRSTP ;kill the receiver RESTOR R0 BR 35$ ;force scheduler pass ; here to restore registers and return. 17$: RESTOR R0 BR 25$ 20$: CMPB #EBCPAD,R1 ;check for possible end of message BEQ 30$ ;maybe 25$: RESTOR RTI ;exit interrupt 30$: MOV #CHDATL,R1 ;update current chunk byte count SUB LB.CCR(R4),R1 ; minus bytes already counted MOV R1,@LB.CHL(R4) ;stuff in chunk byte count word SIGNAL LB.TC1(R4),EBINTR,NOTRACE SETSKD LB.TC1(R4) 35$: RESTOR JMP SKDCHK ;force scheduler pass DUPFUL: BIT #LS.RRN,(R4) ;update curretn chunk's byte count BEQ 10$ ;can't safely update count if receiver not running SAVE R0 MOV #CHDATL,R0 ;max possible SUB LB.CCR(R4),R0 ; minus bytes already counted MOV R0,@LB.CHL(R4) ;stuff in chunk byte count word RESTOR R0 10$: RETURN DNXRCK: MOV LB.RBF(R4),R0 ;advance to next chunk to receive more message BEQ 10$ ;no more - msg a trifle long MOV R0,LB.CCH(R4) ;set as current buffer MOV (R0)+,LB.RBF(R4) ;delink it MOV R0,LB.CHL(R4) ;set ptr to chunk byte count CLR (R0)+ ;clear chunk byte count MOV R0,LB.CCD(R4) ;stash the data ptr MOV #CHDATL,LB.CCR(R4) ;init the receive count MOV LB.CCH(R4),R0 ;get the current chunk MOV LB.TC1(R4),R1 JMP QUEFST ;and queue it to the bsc task 10$: SEC RETURN ; subroutine to record a dup11 error. DUPERR: MOV UP.RSR(R3),LB.SE2(R4) ;record status reg 1 MOV UP.XSR(R3),LB.SE3(R4) ; and status reg 2 ATRACE <(SP),R4,(R4),LB.SE2(R4),LB.SE3(R4),JIFCLK> BIT #LS.ENB,(R4) ;is this because line is disabled BEQ 20$ INC LB.SE1(R4) ;count master error counter BIS #LS.ERR,(R4) ;flag an error .IF NE,DEBUG BIT #TRCLER,TRCHLT BEQ 20$ STOPCD BUG .ENDC ;.IF NE,DEBUG 20$: RETURN ; subroutine to stop the receiver ; ; R4 points to lcb, R3 to csr. DPRSTP: ;stop the receiver CALL DUPFUL ;final update of chunk byte count BIC #UP.REN!UP.RIE!UP.DIE,UP.RSR(R3) ;stop the receiver BIC #LS.RGO!LS.RRN,(R4) ;not running CALL RCVCLR ;flush unused receive buffers CALL DUPBWK ;wake the bsc task RETURN DUPBWK: TRACE TRCDQF,<(SP),R4,(R4),JIFCLK> ;wake the bsc task BIC #LS.CIE,(R4) ;yes, clear flag SAVE R0 MOV LB.TC1(R4),R0 ;point to bsc task's tcb SIGNAL R0,EBINTR SETSKD R0 ;force scheduling pass RESTOR R0 RETURN .SBTTL DUPXI - transmitter interrupt processor DUPXI: XMTADJ ;dup11 transmitter interrupt processor ;R4 -> line block for interrupting dup ;old R4 on stack SAVE MOV LB.SLA(R4),R3 ;get hardware address MOV UP.XSR(R3),R1 ;get transmitter status bits BMI 17$ ;branch if any errors. ; here when we have a real transmit done interrupt. 11$: DEC LB.CXR(R4) ;count the character just completed BLE 12$ ;check if chunk empty 13$: MOVB @LB.CXD(R4),UP.XBF(R3) ;do next character INC LB.CXD(R4) ;advance data ptr 19$: RESTOR RTI 12$: BLT 18$ ;this interrupt for last character completing BIT #LS.CTL,(R4) ;are we sending a control message? BNE 15$ ;yes - end of message by definition MOV LB.CCX(R4),R1 ;get next chunk to go BEQ 15$ ;end of message MOV (R1)+,LB.CCX(R4) ;delink this chunk MOV (R1)+,LB.CXR(R4) ;set number characters in this chunk MOV R1,LB.CXD(R4) ;set data ptr BR 13$ ;output next character from new chunk ;here on end of message 15$: BIS #UP.XEM,UP.XBF(R3) ;tell the dup11 end of message 16$: BIC #UP.SND,UP.XSR(R3) ;next interrupt on end of message state BR 19$ ; here on transmit error interrupt ; (the only error detected here is transmitter data late.) 17$: MOV R1,LB.XST(R4) ;record last transmit status MOV R1,LB.ERS(R4) ;save error status TRACE TRCDQF!TRCLIN, ;trace error interrupt BIS #LS.ERR,(R4) ;flag an error INC LB.SE5(R4) ;count transmitter not fast enough CALL DUPERR ;record the error BIC #UP.SND,UP.XSR(R3) ;kill the transmitter 18$: CALL DPXST1 ;wind up BIT #LS.RGO,(R4) ;check for pending read BEQ 25$ ;no - go away BIT #UP.CAR,UP.RSR(R3) ;yes - check for continuous carrier BEQ 25$ ;no - wait for carrier detect interrupt CALL DPRSTR ;yes - start the receiver now 25$: RESTOR JMP SKDCHK ;and force scheduler pass ; subroutine to stop the transmitter ; ; R4 points to the lcb ; R3 points to the csr DPXSTP: TRACE TRCDQF,<(SP),R4,JIFCLK> ;trace dup11 transmitter stop BIC #UP.SND,UP.XSR(R3) ;tell dup11 we have stopped sending BIT #UP.XIE,UP.XSR(R3) ;are transmit interrupts enabled? BEQ DPXST1 ;no, do second half right away. CLR LB.CXR(R4) ;indicate that next character done is final RETURN ; subroutine called on next transmit done interrupt ; or branched to from above when transmit interrupts not enabled. ; also called directly from transmit error, since in that case ; we do not get another done interrupt. DPXST1: BIC #UP.RTS,UP.RSR(R3) ;drop request to send BIC #UP.XIE,UP.XSR(R3) ;disable transmit done interrupts BIC #LS.XGO!LS.XRN,(R4) ;dup11 transmitter not running CLR LB.DEW(R4) ;not waiting to enable modem CALL DUPBWK ;wake the bsc task RETURN ; subroutine to process a data set flag. .ENABL LSB DUPDSF: INC LB.DIC(R4) ;count dataset interrupts MOV R0,LB.DIS(R4) ;record last modem interrupt status TST LB.DEW(R4) ;waiting for dataset enable? BNE 14$ ;yes, ignore modem signal. BIT #LS.ACT,(R4) ;is the dup11 active? BEQ 14$ ;no, ignore the modem signals MOV R0,LB.DIP(R4) ;yes, record last modem signals processed BIT #LS.XGO,(R4) ;waiting to start xmitter? BEQ 11$ ;no. CALL 15$ ;yes, check for clear-to-send. 11$: BIT #LS.XRN,(R4) ;running the transmitter? BEQ 12$ ;no. CALL 17$ ;yes, be sure cts still up 12$: BIT #LS.RGO,(R4) ;waiting to start receiver? BEQ 13$ ;no. CALL 19$ ;yes, see if carrier up yet 13$: BIT #LS.RRN,(R4) ;running receiver? BEQ 14$ ;no. CALL 21$ ;yes, worry about carrier failure. 14$: RETURN ; four subroutines to process data set flags. they are called ; based on the current state of the dup11. ; ; R0 = modem status flags, from the dup11. ; ; here if we are waiting to start the transmitter 15$: BIT #UP.CTS,R0 ;have we clear-to-send? BEQ 16$ ;no, wait for it. CALL DUPXST ;yes - start the transmitter MOV LB.DIS(R4),R0 ;get the modem status back 16$: RETURN ; here if we are running the transmitter 17$: BIT #UP.CTS,R0 ;is clear-to-send still up? BNE 18$ ;yes, all ok. INC LB.SE6(R4) ;no, note clear-to-send failure CALL DUPERR ;note error CALL DPXSTP ;stop the transmitter 18$: RETURN ; here if we are waiting to start the receiver 19$: BIT #UP.CAR,R0 ;is carrier up yet? BEQ 20$ ;no, keep waiting for it. CALL DPRSTR ;yes - start the receiver now TRACE TRCDQF, DPRCDT: BIS #LS.CAR,(R4) ;mark we have seen carrier 20$: RETURN ; here if the receiver is running. 21$: BIT #UP.CAR,R0 ;is carrier up? BNE 22$ ;yes. BIT #LS.CAR,(R4) ;no, have we seen carrier yet? BEQ 23$ ;no, dont worry about it. TRACE TRCDQF, DPRCFL: CALL DPRSTP ;yes, stop the receiver RETURN ;all done. ; here if carrier is up 22$: 23$: RETURN .DSABL LSB .SBTTL DUPINQ - check if any more characters available ; R5/tcb ; ; on return: ; ; C set: DUPFUL has found characters in the DUP11 ; (not possible in this version) ; C clear: the dup11 has no characters. it is now ; set to restart the bsc task on the next character. DUPINQ: SAVE R4 MOV TCLCB(R5),R4 ;point to lcb PIOFF ;disable interrupts TRACE TRCDQD, MOV @LB.CHL(R4),-(SP) ;save current chunk count CALL DUPFUL ;update character count in current chunk CMP (SP)+,@LB.CHL(R4) ;check if it changed BEQ 20$ ;no PION ;restore interrupt level RESTOR R4 SEC ;claim there characters to be found RETURN 20$: PION RESTOR R4 CLC RETURN ;claim there are no characters to be found .SBTTL DUPKIL - kill any dup11 operations. ; R4 = lcb pointer ; R5 = pointer to bsc tcb DUPKIL: TRACE TRCDQF,<(SP),R4,(R4),LB.ALR(R4),JIFCLK> ;trace entry to dupkil SAVE MOV LB.SLA(R4),R3 ;point to csr PIOFF ;disable interrupts BIT #LS.ACT,(R4) ;is the dup11 doing anything? BEQ 12$ ;no. ; consider stopping the transmitter BIT #LS.XGO!LS.XRN,(R4) ;yes, transmitter running? BEQ 11$ ;no. BIC #UP.XIE,UP.XSR(R3) ;disable transmit done interrupts CALL DPXSTP ;stop the transmitter ; consider stopping the receiver 11$: BIT #LS.RGO!LS.RRN,(R4) ;is receiver running? BEQ 12$ ;no. CALL DPRSTP ;yes, stop the receiver 12$: BIC #UP.DIE,UP.RSR(R3) ;clear dataset interrupt enbale PION ;enable interrupts 13$: CALL DEQCHK ;any chunks in receiver queue? BCS 14$ ;no. CALL FRECHK ;flush it BR 13$ ;be sure we've got them all. ; here when the dup11 has been killed. 14$: RESTOR RETURN .SBTTL DUPON,DUPOFF,DUPSTS - set,clear,check DTR,DSR ; three subroutines to interface to the dl10 task. these sense ; set and clear the modem signals dtr and dsr. ; ; subroutine to clear DTR ; ; R0 = lcb address DUPOFF: SAVE R0 MOV LB.SLA(R0),R0 ;point to csr MOV UP.RSR(R0),-(SP) ;save current state BIC #UP.DTR,UP.RSR(R0) ;clear dtr TRACE TRCDQF,<4(SP),4(SP),UP.RSR(R0),JIFCLK> ;trace caller,line,DUP status BIT #UP.DTR,(SP)+ ;was it on ? BEQ 10$ ;no - go away DSCHED ,#3*JIFSEC ;yes - allow time for slow modems ; and phones to hangup 10$: RESTOR R0 RETURN ; subroutine to set DTR DUPON: SAVE R0 MOV LB.SLA(R0),R0 ;point to csr BIS #UP.DTR,UP.RSR(R0) ;set dtr TRACE TRCDQF,<2(SP),2(SP),UP.RSR(R0),JIFCLK> ;trace caller,line,dq status RESTOR R0 RETURN ; subroutine to return values of DTR and DSR. ; ; R0 = lcb address ; R1 bits 1 and 2 are 0. ; ; on return: ; ; bit 1 of R1 = DTR ; bit 2 of R1 = DSR ; R1 is otherwise undisturbed. DUPSTS: SAVE R0 MOV LB.SLA(R0),R0 ;point to csr BIT #UP.DTR,UP.RSR(R0) ;is dtr set? BEQ 11$ ;no. BIS #B1,R1 ;yes, set flag in r1 11$: BIT #UP.DSR,UP.RSR(R0) ;is dsr set? BEQ 12$ ;no. BIS #B2,R1 ;yes, set flag in r1 12$: TRACE TRCDQF,<2(SP),2(SP),UP.RSR(R0),JIFCLK> ;trace caller,line,dq status RESTOR R0 RETURN .SBTTL DUPTRP - stop code processor for dups ; subroutine to interface with the trap handler. on a stop code ; this subroutine is called to store the status of the dup11 ; in the lcb for post-mortum debugging. ; R5 does not point to a tcb, but it must not be destroyed. ; ; R4 = lcb address DUPTRP: MOV LB.SLA(R4),R3 ;get hardware address MOV UP.RSR(R3),LB.RG0(R4) ;store receiver status register MOV UP.RBF(R3),LB.RG1(R4) ;store receiver buffer MOV UP.XSR(R3),LB.RG2(R4) ;store transmit status register MOV UP.XBF(R3),LB.RG3(R4) ;store transmit buffer RETURN .SBTTL DUPTIK - once per tick routine ; subroutine to check on the dup11s once a jiffie ; we must count the clear-to-send delay and ; compensate for improper dup11 jumpers which ; will prevent the carrier signal from causing ; an interrupt. ; ; R4/line block ptr DUPTIK: CLR R1 ;r1 is dup11 number BIT #LF.DAC,LB.FGS(R4) ;check for shut down BNE 15$ ;yes - forget it PIOFF ;disable interrupts TST LB.DEW(R4) ;waiting to set modem enable? BEQ 12$ ;no. DEC LB.DEW(R4) ;yes, waited long enough? BNE 14$ ;no, wait until next time 12$: MOV LB.SLA(R4),R3 ;point to csr MOV UP.RSR(R3),R0 ;get modem status bits 20$: BIT #UP.DIE,R0 ;are modem interrupts enabled? BEQ 14$ ;no, dont call subroutine. BIT #UP.DCA,R0 ;check for any summary bits(DCB seems to be on always) BNE 13$ ;always process these MOV LB.DIP(R4),R2 ;get last modem signals processed XOR R0,R2 ;check for any changes in signals BIT #UP.DCA!UP.DCB!UP.CTS!UP.CAR,R2 ;any important modem signals changed? BEQ 14$ ;no. 13$: CALL DUPDSF ;yes, process any modem signal changes 14$: PION ;restore interrupt level 15$: RETURN .ENDC ;.IF NE,FT.DUP .SBTTL control messages ; ENQ message, for bidding for the line and asking for a ; repeat of the last response. ENQMSG: .BYTE EBCLPD,EBCSYN,EBCSYN .BYTE EBCSYN,EBCSYN .BYTE EBCSYN,EBCENQ ENQLEN=.-ENQMSG .BYTE EBCPAD .IIF NE,FT.DQ, .BYTE EBCPAD,EBCPAD,EBCPAD,EBCPAD ; ACK-0 message, used for positive acknowledgment to bid and ; for positive acknowledge of even data blocks AK0MSG: .BYTE EBCLPD,EBCSYN,EBCSYN .BYTE EBCSYN,EBCSYN .BYTE EBCSYN,EBCDLE,EBCAK0 AK0LEN=.-AK0MSG .BYTE EBCPAD .IIF NE,FT.DQ, .BYTE EBCPAD,EBCPAD,EBCPAD,EBCPAD ; ACK-1 message, used for positive acknowledgment of odd data ; blocks AK1MSG: .BYTE EBCLPD,EBCSYN,EBCSYN .BYTE EBCSYN,EBCSYN .BYTE EBCSYN,EBCDLE,EBCAK1 AK1LEN=.-AK1MSG .BYTE EBCPAD .IIF NE,FT.DQ, .BYTE EBCPAD,EBCPAD,EBCPAD,EBCPAD ; TTD message, for soliciting a NAK because data is not ; yet ready. TTDMSG: .BYTE EBCLPD,EBCSYN,EBCSYN .BYTE EBCSYN,EBCSYN .BYTE EBCSYN,EBCSTX,EBCENQ TTDLEN=.-TTDMSG .BYTE EBCPAD .IIF NE,FT.DQ, .BYTE EBCPAD,EBCPAD,EBCPAD,EBCPAD ; SOH-ENQ - hasp bid sequence for bidding for a line. BIDMSG: .BYTE EBCLPD,EBCSYN,EBCSYN .BYTE EBCSYN,EBCSYN .BYTE EBCSYN,EBCSOH,EBCENQ BIDLEN=.-BIDMSG .BYTE EBCPAD .IIF NE,FT.DQ, .BYTE EBCPAD,EBCPAD,EBCPAD,EBCPAD ; EOT message, used to terminate a message sequence. EOTMSG: .BYTE EBCLPD,EBCSYN,EBCSYN .BYTE EBCSYN,EBCSYN .BYTE EBCSYN,EBCSYN,EBCEOT EOTLEN=.-EOTMSG .BYTE EBCPAD .IIF NE,FT.DQ, .BYTE EBCPAD,EBCPAD,EBCPAD,EBCPAD ; DLE-EOT message, used to declare line shutdown for leased lines. DISMSG: .BYTE EBCLPD,EBCSYN,EBCSYN .BYTE EBCSYN,EBCSYN .BYTE EBCSYN,EBCSYN,EBCDLE,EBCEOT DISLEN=.-DISMSG .BYTE EBCPAD .IIF NE,FT.DQ, .BYTE EBCPAD,EBCPAD,EBCPAD,EBCPAD ; NAK message, used to request the retransmission of the last ; data message and to refuse a bid. NAKMSG: .BYTE EBCLPD,EBCSYN,EBCSYN .BYTE EBCSYN,EBCSYN .BYTE EBCSYN,EBCNAK NAKLEN=.-NAKMSG .BYTE EBCPAD .IIF NE,FT.DQ, .BYTE EBCPAD,EBCPAD,EBCPAD,EBCPAD ; WACK message, used to acknowledge a data block but force a wait ; before the next data block is sent. WAKMSG: .BYTE EBCLPD,EBCSYN,EBCSYN .BYTE EBCSYN,EBCSYN .BYTE EBCSYN,EBCDLE,EBCWAK WAKLEN=.-WAKMSG .BYTE EBCPAD .IIF NE,FT.DQ, .BYTE EBCPAD,EBCPAD,EBCPAD,EBCPAD .EVEN ;be sure next section starts on a word boundry