Trailing-Edge
-
PDP-10 Archives
-
BB-J992D-SB_1984
-
lindrv.p11
There are 5 other files named lindrv.p11 in the archive. Click here to see a list.
.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,<R4,(R4),(R3),2(R3),LB.CCH(R4),LB.CH1(R4),LB.CH2(R4),JIFCLK>
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 <R3,R1,R0>
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,<R4,(R4),R0,2(R3),4(R3),JIFCLK>
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 <R0,R1,R3,R4>
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 <R3,R0,R1>
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,<R4,(R4),(R3),R1,4(R3),JIFCLK> ;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 <R1,R0,R3,R4>
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 <R4,(R4),R0,JIFCLK> ;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,<R4,(R4),R1,JIFCLK>
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,<R4,(R4),R1,JIFCLK> ;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 <R3,R4>
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 <R4,R3>
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 <R0,R1,R2>
15$: CALL GTLCHK ;need a place for the data in the header - privileged call
BCC 17$ ;suc'd ?
SAVE <LB.ALR(R4),TCTIM(R5)> ;since this a kluge anyhow - protect against alarms
CLR LB.ALR(R4)
CLR TCTIM(R5)
DSCHED #EBINTR,#10. ;dally awhile
RESTOR <TCTIM(R5),LB.ALR(R4)>
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 <R2,R1,R0> ;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 <R2,R1,R0>
;*********************************************************
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,<R4,(R4),UP.RSR(R3),UP.XSR(R3),LB.DEW(R4),JIFCLK>
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 <R3,R1,R0>
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,<R4,R0,LB.ALR(R4),JIFCLK> ;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 <R0,R1,R3,R4>
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 <R2,R3,R4,R5>
; 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,<R4,R3,LB.CCD(R4),MDSLPT(R3),LB.ALR(R4),JIFCLK> ;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,<R3,(R3),JIFCLK> ;record silo pointer and its status bits
; here when we are done with this lcb
13$: ADD #2,R5 ;increment line number * 2
CMP #<NLINES*2>,R5 ;done all the lines?
BNE 11$ ;no, do the rest.
; here when all the silos have been emptied.
RESTOR <R5,R4,R3,R2>
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 <R0,R1,R2,R3,R4,R5>
; 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,<R4,(R4),LB.ALR(R4),JIFCLK> ;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 <R4,(R4),UP.RSR(R3),UP.RBF(R3),UP.XSR(R3),UP.XBF(R3),JIFCLK>
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,<R4,(R4),LB.ALR(R4),JIFCLK> ;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 <R5,R4,R3,R2,R1,R0>
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,<R4,(R4),R0,LB.DRP(R4),LB.ALR(R4),JIFCLK>
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,<R4,(R4),R0,LB.DRP(R4),LB.ALR(R4),JIFCLK>
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 <R0,R3,R2>
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,<R4,R0,JIFCLK> ;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 <R2,R3,R0>
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,<R4,JIFCLK> ;trace decision to wait the task.
PION ;restore interrupt level
MOV R0,R4 ;restore r4
RESTOR <R2,R3,R0>
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,<R4,(R4),MDSLFG(R3),LB.ALR(R4),JIFCLK> ;trace silo flag bits
SAVE <R0,R1>
BIT #MDSLFW,MDSLFG(R3) ;reached warning level yet?
BEQ MDSLE1 ;no, dont switch silos
TRACE TRCDQF,<R4,MDSLCC(R3)> ;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,<R4,R0,JIFCLK> ;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,<R4,R0,LB.ALR(R4),JIFCLK> ;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 <R1,R0>
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,<R4,R0,R2,LB.ALR(R4),JIFCLK>
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,<R4,LB.CCH(R4),LB.ALR(R4),JIFCLK> ;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,<R4,(R4),LB.ALR(R4),JIFCLK> ;trace entry to MDACTV
SAVE <R3,R0,R1,R2>
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 <R2,R1,R0,R3>
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,<R4,(R4),R0,LB.DRP(R4),LB.ALR(R4),JIFCLK>
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,<R5,(R4),UP.RSR(R3),LB.CCH(R4),LB.RBF(R4),TCCHKQ(R5),TCCHK2(R5)>
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 <R3,R1>
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 <R1,R3,R4>
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 <R1,R3,R4>
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 <R1,R3>
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 <R3,R1,R4>
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,<R4,R1,JIFCLK> ;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 <R3,R1,R4>
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,<R4,(R4),R0,JIFCLK>
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,<R4,(R4),R0,JIFCLK>
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,<R4,(R4),LB.CCH(R4),LB.CCD(R4),LB.CCR(R4),@LB.CHL(R4),JIFCLK>
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 <R0,R1,R3>
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 <R3,R1,R0>
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