Trailing-Edge
-
PDP-10 Archives
-
bb-jr93d-bb
-
7,6/ap017/msgser.x17
There is 1 other file named msgser.x17 in the archive. Click here to see a list.
TITLE MSGSER - SERVICE FOR DEVICE MPX: AND RELATED FUNCTIONS V144
SUBTTL DONALD A. LEWINE 8 APR 86
SEARCH F,S
IFN FTNET,<SEARCH NETPRM>
$RELOC
$HIGH
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
.CPYRT<1973,1986>
;COPYRIGHT (C) 1973,1974,1975,1976,1977,1978,1979,1980,1982,1984,1986
;BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.
;
XP VMSGSR,144
MSGSER::ENTRY MSGSER
;AC USAGE WITHIN MSGSER:
;
;S) DEVICE STATUS. ALWAYS DEVIOS(F)
;P) PUSH DOWN POINTER
;J) USERS JOB NUMBER.
;R) ADDRESS OF USERS JOB IF KA10, 341000 IF KI10
;F) ADDRESS OF A DDB. THIS IS EITHER THE MPX DDB OR
; THE DEVICE CONTROLED BY THE MPX DDB. USE CAUTION.
;U) NOT USED TODAY
;T1-T4) TEMPS. ARGS TO SUBROUTINES PASSED IN
; THESE AC'S.
;M) ADDRESS FOR GETWRD/PUTWRD. USERS UUO.
;W) NOT USED TODAY
;P1) CHANNEL NUMBER
;P2) ADDRESS OF THE MPX DDB.
;P3) ADDRESS OF THE TARGET DDB.
;P4) ADDRESS OF THE CONNECTED DEVICE TABLE
;FORMAT OF THE CONNECTED DEVICE TABLE:
;
; !------------------!------------------!
; ! SIZE OF CDT ! # OF FREE SLOTS !
; !------------------!------------------!
; ! UDX FOR DEV #1 ! ADDRESS OF DDB #1!
; !------------------!------------------!
; ! UDX FOR DEV #2 ! ADDRESS OF DDB #2!
; !------------------!------------------!
; ! UDX FOR DEV #3 ! ADDRESS OF DDB #3!
; !------------------!------------------!
; ! UDX FOR DEV #4 ! ADDRESS OF DDB #4!
; !------------------!------------------!
; / /
; / /
; !------------------!------------------!
; ! UDX FOR DEV #N ! ADDRESS OF DDB #N!
; !------------------!------------------!
;
;NOTE THE CDT IS KEPT SORTED BY UDX SO IT IS EASY (AT LEAST FAST)
; TO CONVERT A UDX FOR A CONNECTED DEVICE TO A DDB ADDRESS.
CDTFRE==0 ;OFFSET FOR THE COUNT OF THE NUMBER OF FREE
; SLOTS IN CDT
CDTSIZ==0 ;OFFSET FOR THE CDT WORD COUNT. THIS INCLUDES
; THIS WORD
CDTQNT==40 ;NUMBER OF WORD TO GET EACH TIME THE CDT FILLS UP
CDT4WD==<<CDTQNT+3>/4> ;NUMBER OF 4 WORD BLOCKS IN A CDT QUANTUM
CDTQNT==CDT4WD*4 ;REDEFINE SO LOW 2 BITS ARE ALWAYS ZERO
;THE PROTOTYPE MPX DDB
$LOW
MPXDDB::EXP 0 ;DEVICE NAME. NOTE: WE DO NOT
; WANT ANYONE TO FIND THE
; PROTOTYPE, HENCE, THE FUNNY NAME.
EXP 103 ;BUFFER SIZE, MPX DEVICES NEVER
; HANG
EXP 0 ;DEVIOS
MPXVMF==1B0 ;ON IF A DEVICE IS IN TROUBLE AND THE OUTPUT
; BUFFER IS PAGED OUT
EXP MPXDSP ;DEVSER
XWD DVIN+DVOUT+DVLNG,<1B<^D35-A>+1B<^D35-AL>+1B<^D35-IB>+1B<^D35-B>+1B<^D35-I>+1B<^D35-PIMMOD>> ;DEVMOD
EXP 0 ;LOGICAL NAME. NOTE: THIS WORD IS
; ALWAYS ZERO.
EXP 0 ;DEVBUF. LH=ADDRESS OF OUTPUT
; RH=ADDRESS OF INPUT
EXP 0 ;DEVIAD.
EXP 0 ;DEVOAD.
EXP 0 ;DEVSTS. DEVSTS FROM CONTROLLED
; DDB.
XWD .TYMPX,DEPEVM ;DEVSTA. MPX DDB (WE DO NOT USE
; EVM)
XWD 0,0 ;DEVXTR. LH = ADDRESS OF THE
; CDT IF ANY. RH = NUMBER OF
; CONNECTED DEVICES.
EXP 0 ;DEVEVM. NOTE: WE NEVER HAVE ANY EVM.
EXP 0 ;DEVPSI. FLAGS FOR PSISER
EXP 0 ;DEVESE.
EXP 0 ;DEVHCW.
EXP 707B8 ;DEVCPU.
EXP 0 ;DEVJOB. JOB NUMBER
EXP 0 ;DEVCID. CURRENT INPUT DEVICE
MPXLEN==.-MPXDDB
MPX4WD==<MPXLEN+3>/4 ;NUMBER OF 4 WORD BLOCKS NEEDED
; TO HOLD DDB
$HIGH
;DISPATCH TABLE FOR MPX
JRST CPOPJ1## ;MPX IS ALWAYS ON-LINE
POPJ P,0 ;SPECIAL ERROR STATUS
JRST REGSIZ## ;SIZE CAN BE GOTTEN FROM DDB
POPJ P,0 ;SYSINI CALL
POPJ P,0 ;HUNG DEVICE
MPXDSP: JRST MSGREL ;RELEASE
POPJ P,0 ;CLOSE
JRST MSGDOU ;OUTPUT
JSP T1,MSGIN ;INPUT
JRST ILLOPR ;ENTER
JRST ILLOPR ;LOOKUP
JRST ILLOPR ;DUMP MODE OUTPUT
JRST ILLOPR ;DUMP MODE INPUT
JRST ILLOPR ;USETO
JRST ILLOPR ;USETI
JRST ILLOPR ;UGETF
JRST ILLOPR ;RENAME
POPJ P,0 ;INPUT CLOSE
JRST ILLOPR ;UTPCLR
JRST ILLOPR ;MTAPE
;HERE ON AN OPERATION WHICH IS ILLEGAL FOR MPX:
ILLOPR: JSP T1,ERRPTU## ;PRINT THE MESSAGE
ASCIZ /Illegal operation for multiplex device/
JRST UUOPCP## ;PRINT PC AND STOP THE JOB
SUBTTL NON-IO INTERFACE WITH UUOCON
;SUBROUTINE TO BUILD THE MPX DDB
;CALL WITH:
; MOVE T1,NAME-OF-DEVICE
; PUSHJ P,TSTMPX
; RETURN HERE IF NOT AN OPEN UUO FOR 'MPX'
; RETURN HERE WITH DDB BUILT AND F SETUP
TSTMPX::CAME T1,[SIXBIT 'MPX'] ;IS THIS MPX:?
POPJ P,0 ;NORMAL CASE.
HRLZ T1,.USMUO ;UUO OP CODE
IOR T1,.USMUE ;EA-CALC
TDZ T1,[777,,UPHNLY] ;ONLY CALLI
CAMN T1,[FILOP.] ;FILOP?
JRST TSTMP1 ;YES, ALLOW THAT
HLRZS T1 ;OR OPEN
CAIE T1,(OPEN)
POPJ P,0 ;NOPE. ERROR RETURN
TSTMP1: PUSHJ P,SAVT## ;SAVE T2 THRU T4
MOVEI T2,MPX4WD ;SIZE OF DDB
PUSHJ P,GET4WD## ;GET SOME CORE
POPJ P,0 ;NO MORE CORE
HRR F,T1 ;COPY THE PROTOTYPE
HRLI T1,MPXDDB ; DDB
DDBSRL ;NO DDB SEARCHING
BLT T1,MPXLEN-1(F) ; ..
HRLM F,MPXDDB+DEVSER ;SET THE LINKS
DDBSRU ;NOW THAT THE LINK IS STORED, ALLOW DDB SEARCHS
AOS T1,MPXNUM ;NUMBER OF CALLS TO TSTMPX
DPB T1,PUNIT## ;STORE SERIAL NUMBER IN DDB
MOVE T1,MPX6NM ;GET SIXBIT NUMBER
AOS T1 ;INCREMENT
TRZE T1,10
ADDI T1,100
TRZE T1,1000
ADDI T1,10000
TRZ T1,100000
HRRZM T1,MPX6NM ;SAVE ANSWER
TRNN T1,70000 ;LEADING ZERO?
LSH T1,6 ;YES--TRIM
TRNN T1,70000 ;ANOTHER
LSH T1,6 ;YES--REMOVE IT
HRLI T1,'MPX' ;PUT IN FIRST PART OF NAME
MOVEM T1,DEVNAM(F) ;STORE IN DDB
JRST CPOPJ1## ;GOOD RETURN
$LOW
MPXNUM: EXP 0 ;DDB SERIAL NUMBER
MPX6NM: SIXBIT '000000' ;SAME THING IN SIXBIT
$HIGH
;HERE TO RELEASE ALL DEVICES CONNECTED TO THE MPX
; CALLED BY ZAPMPX AND THROUGH RELEASE DISPATCH
MSGREL: PUSHJ P,SAVE4## ;SAVE THE P'S
MSGRE1: HRRZ P4,DEVXTR(F) ;ANY DEVICES CONNECTED?
JUMPE P4,CPOPJ## ;NO--KILL OFF MPX DDB
HLRZ P4,DEVXTR(F) ;GET ADDRESS OF CDT
MOVE P2,F ;SAVE F IN P2
HRRZ F,1(P4) ;ADDRESS OF FIRST DDB
HRRZS DEVBUF(F) ; SO DISCONNECT DOESN'T TRY TO RETURN BUFFERS
HRRZS DEVBUF(P2) ;DITTO FOR MPX ITSELF
MOVEI P1,RELEA1## ;UNCONDITIONAL DISCONNECT
PUSHJ P,DISCON ;REMOVE THE CONNECTION
JFCL ;DEVICE NOT CONNECTED
MOVE F,P2 ;RESTORE F
JRST MSGRE1 ;SEE IF ANY DEVICES CONNECTED
;SUBROUTINE TO WIPE OUT THE MPX DDB ON RELEASE
;CALL WITH:
; MOVEI F,ADDRESS-OF-DDB-TO-ZAP
; PUSHJ P,ZAPMPX
; RETURN HERE
ZAPMPX::PUSHJ P,MSGREL ;DISCONNECT ALL DEVICES FIRST
MOVEI T1,MPXDDB ;ADDRESS OF PROTO
DDBSRL ;INTERLOCK DDBS
ZPMPX1: MOVE T2,T1 ;ADDRESS OF LAST DDB
HLRZ T1,DEVSER(T2) ;ADDRESS OF NEXT DDB
JUMPE T1,ZPMPXE ;DDB CHAIN IS MESSED UP IF WE
; CAN NOT FIND THE DDB
CAIE T1,(F) ;IS THIS IT?
JRST ZPMPX1 ;NO--KEEP LOOKING
MOVE T3,DEVSER(F) ;UNLINK THE DDB
HLLM T3,DEVSER(T2) ; ..
DDBSRU ;UNLOCK DDBS
MOVEI T1,MPX4WD ;THROW AWAY THE
HRRZ T2,F ; CORE
PJRST GIV4WD## ; ..
;HERE IF F DID NOT POINT TO AN MPX DDB ON THE DDB CHAIN
ZPMPXE: DDBSRU ;UNLOCK DDBS
STOPCD CPOPJ##,DEBUG,MXM, ;++MPX: DDB MISSING
SUBTTL CONNECT UUO
;UUO TO CONNECT A DEVICE TO AN MPX CHANNEL
;CALL WITH:
; MOVEI AC,E
; CNECT. AC, -OR- CALLI AC,130
; RETURN HERE ERROR CODE IN AC
; RETURN HERE UDX IN AC
;
; E: XWD FUNCTION,CHAN
; SIXBIT /DEVICE/
;
CONECT::PUSHJ P,SAVE4## ;SAVE VOLITILE AC'S
HRR M,T1 ;PICK UP THE
PUSHJ P,GETWDU## ; FIRST ARGUMENT
HRRZ P1,T1 ;COPY CHANEL NUMBER
HLRZ P3,T1 ;GET FUNCTION CODE
PUSHJ P,SETUF##
PJRST ECOD6## ;ELSE GENERATE ERROR
HRLM P1,.USCTA ;STORE MPX CHANNEL #
MOVE P2,F ;SET F=ADDRESS OF MPX DDB
LDB T2,PDVTYP## ;GET THE DEVICE TYPE
CAIE T2,.TYMPX/.TYEST;IS THIS AN MPX DDB?
PJRST ECOD1## ;NO--PUNT
CAILE P3,CNFNMX ;SKIP IF NOT TOO BIG
PJRST ECOD10## ;ERROR 10 -- INVALID FUNCTION
JRST @CNFNTB(P3) ;DISPATCH
;TABLE OF FUNCTIONS
CNFNTB: JRST ECOD10## ;(0)NO FUNCTION 0
JRST CONDEV ;(1)CONNECT
JRST CDCDEV ;(2)CONDITIONAL DISCONNECT
JRST UDCDEV ;(3)UNCONDITIONAL DISCONNECT
JRST OFEDEV ;(4)OUTPUT FEASIBILITY CHECK
CNFNMX==.-CNFNTB-1
;SUBROUTINE TO CONNECT A DEVICE
;CALLED ONLY FROM CONECT
;
CONDEV: PUSHJ P,GETWD1## ;PICK UP DEVICE NAME
MOVEI T3,ASSPRG ;REJECT INITED DEVICES
PUSHJ P,DVASRC## ;LOOK FOR GENERIC DEVICE
SKIPA ;NOT A GENERIC DEVICE
JRST CNDEV4 ;FREE GENERIC DEVICE
PUSHJ P,DVCNSG## ;LOOK UP IN DEVICE CHAIN
JRST ECOD2## ;NO SUCH DEVICE
CNDEV4: PUSHJ P,LGLMPX ;OK TO USE?
PJRST ECOD3## ;CAN NOT USE THAT TYPE OF DEVICE
MOVE P3,F ;SAVE DDB ADDRESS
PUSH P,J ;SAVE J
MOVE J,.CPJCH## ;PICK UP JOB/CONTEXT HANDLE
MOVE T1,DEVNAM(F) ;PICK UP DEVICE NAME
MOVEI T2,ASSPRG ;INIT BIT
TDNN T2,DEVMOD(F) ;ALREADY INITED?
PUSHJ P,ASSASG## ;NO--TRY TO INIT
PJRST ECOD11## ;DEVICE INITED OR CONNECTED
SKIPGE DEVSPL(F) ;SPOOLED DEVICE?
JRST [PUSHJ P,RELEA4## ;YES--KILL THE DDB
PJRST ECOD12##]; AND GIVE ERROR RETURN
POP P,J ;RESTORE J
PUSHJ P,GETCDT ;SET P4 = CDT ADDRESS
JRST CNOCOR ;NO MORE FREE CORE
HRRE T1,CDTFRE(P4) ;GET FREE SLOT COUNT
JUMPG T1,CNDEV1 ;JUMP IF ROOM
PUSHJ P,XPNCDT ;EXPAND THE CDT
PJRST CNOCOR ;NO MORE CORE
CNDEV1: SOS CDTFRE(P4) ;COUNT THE SLOT
MOVE T1,DEVNAM(F) ;PICK UP THE DEVICE NAME
PUSHJ P,UIONDX## ;COMPUTE UDX
PJRST [PUSHJ P,RELEA4## ;YES--KILL THE DDB
PJRST ECOD3##] ; AND GIVE ERROR RETURN
MOVEI T3,1(P4) ;ADDRESS OF FIRST SLOT
CNDEV2: HLRZ T4,(T3) ;COPY UDX FROM CDT
JUMPE T4,CNDEV3 ;JUMP IF TABLE EMPTY
CAIL T1,(T4) ;DOES IT GO HERE
AOJA T3,CNDEV2 ;NO--KEEP LOOKING
HLRZ T2,CDTSIZ(P4) ;SIZE OF CDT
ADDI T2,-1(P4) ;ADDRESS OF LAST WORD
MOVE T4,-1(T2) ;PICK UPNEXT TO LAST WORD
MOVEM T4,(T2) ;STORE AS THE LAST WORD
CAIE T2,(T3) ;SKIP IF WE MOVED ENOUGH
SOJA T2,.-3 ;LOOP OVER ENTIRE CDT
CNDEV3: HRLM T1,(T3) ;STORE UDX
HRRM P3,(T3) ;STORE DDB ADDRESS
AOS DEVXTR(P2) ;INCREMENT NUMBER OF CONNECTED DEVICES
PUSHJ P,CNDDBI ;DO SOME INITIALIZATION
HRRZ T4,DEVSER(F)
PUSHJ P,DSZ(T4)
JRST CPOPJ1## ;GOOD RETURN
CNOCOR: PUSHJ P,RELEA4## ;CLEAR ASSPRG & PJOBN
PJRST ECOD4## ;AND SAY NO FREE CORE
;SUBROUTINE TO CLEAN UP A DDB BEING CONNECTED TO DEVICE MPX
;CALL WITH:
; P2 = ADDRESS OF MPX DDB
; P3 = ADDRESS OF TARGET DDB
; PUSHJ P,CNDDBI
; RETURN HERE
CNDDBI: MOVEI T2,DEPMSG ;FLAG AS CONTROLED VIA MSGSER
IORM T2,DEVMSG(P3) ; ..
HRRM P2,DEVXTR(P3) ;LINK TARGET BACK TO MPX DDB
MOVSI T1,0 ;CLEAR OUT BOTH
MOVE F,P3 ; DEVIAD AND DEVOAD
DPB T1,PDVOAD## ; SO WE DO NOT LOOK
DPB T1,PDVIAD## ; ACTIVE BUFFERS
SETZM DEVBUF(F) ;ALSO ZAP DEVBUF
HRR M,DEVIOS(P2) ;GET STATUS FROM MPX DDB
PUSHJ P,SETIOS## ;SET AS STATUS OF TARGET DDB
MOVSI T1,IOFST!IOBEG
IORM T1,DEVIOS(P3)
MOVEI T1,DEPAIO ;NON BLOCK
TDNE T1,DEVAIO(P2) ;CHECK MPX
IORM T1,DEVAIO(P3) ;SET IN TARGET
MOVEI T1,DEPDEL ;DISABLE ERROR LOGGING (ALSO FULL SCNSER PTY)
ANDCAM T1,DEVSTA(P3) ;CLEAR IT FIRST
TDNE T1,DEVSTA(P2) ;CHECK MPX
IORM T1,DEVSTA(P3) ;PROPAGATE STATE TO TARGET
MOVEI T1,DVDIBP ;BATCH PTY (ALSO DISABLE MESSAGE REASSEMBLY)
ANDCAM T1,DEVCHR(P3) ;CLEAR IT FIRST
TDNE T1,DEVCHR(P2) ;CHECK MPX
IORM T1,DEVCHR(P3) ;PROPAGATE STATE TO TARGET
MOVE F,P3 ;MAKE SURE OF DDB POINTER
MOVSI T2,DVTTY ;IF THIS IS A TTY
TDNE T2,DEVMOD(P3) ; (TEST)
PUSHJ P,TTYMPX## ;LET SCNSER DO SOME INITIALIZATION
POPJ P,0 ;RETURN
;TABLE OF DEVICE TYPES WHICH MAY BE CONNECTED
;DEVICE IS OK IF 1B<DEVTYP> IS = 1
DEFINE TYPBTS(A),<
IRP A,<
ZZ..=ZZ..!1B<<.TY'A/.TYEST>>
>>
ZZ..==0
TYPBTS <LPT,PTP,TTY,PTY,RDA>
TYPMSK: EXP ZZ..
;SUBROUTINE TO SEE IF DEVICE CAN BE USED ON MPX:
;CALL WITH:
; MOVE F,DDB-ADDRESS
; PUSHJ P,MGLMPX
; RETURN HERE IF NO GOOD
; RETURN HERE IF OK
;RESPECTS T1
LGLMPX::LDB T2,PDVTYP## ;GET DEVICE TYPE
CAIN T2,.TYTTY/.TYEST ;TTY?
JRST CPOPJ1## ;YES--ALWAYS GOOD
IFN FTNET,<
CAIE T2,.TYCDR/.TYEST ;A CDR?
JRST LGLMP1 ;NO
LDB T3,PDVSTA## ;YES, LOCAL?
CAIE T3,LOCSTA##
JRST CPOPJ1## ;REMOTE CDR IS OK
LGLMP1:>
MOVSI T3,(1B0) ;SETUP BIT
MOVN T2,T2 ;MAKE COUNT NEGATIVE
LSH T3,(T2) ;SHIFT BIT
TDNN T3,TYPMSK ;VALID TYPE?
POPJ P,0 ;NO--RETURN
JRST CPOPJ1## ;WIN
;SUBROUTINE TO DO A DISCONNECT (CALLED FROM REASSIGN)
;CALLED WITH:
; F=ADDRESS OF DEVICE DDB
; PUSHJ P,MPXDIS
; RETURN HERE IF NOT MPX'ED
; RETURN HERE IF DISCONNECTED
MPXDIS::MOVEI T1,DEPMSG
TDNN T1,DEVMSG(F) ;MPX'ED?
POPJ P, ;NO
PUSHJ P,SAVE4##
MOVEI P1,RELEA1## ;DO RELEASE
HRRZ P2,DEVXTR(F) ;LOCATE MPX DDB
PJRST DISCON ;DO DISCONNECT
;SUBROUTINE TO DO A DISCONNECT (CALLED ONLY FROM CNECT. UUO)
;CALLED WITH:
; P2 = ADDRESS OF MPX DDB
; PUSHJ P,CDCDEV OR UDCDEV
; RETURN HERE IF ERROR
; RETURN HERE IF OK
CDCDEV: SKIPA P1,[EXP URELEA##] ;RELEASE AND CLOSE
UDCDEV: MOVEI P1,RELEA1## ;RESET
PUSHJ P,GETWD1## ;PICK UP DEVICE NAME
PUSHJ P,FNDDDB ;FIND DEVICE DATA BLOCK
JRST ECOD2## ;MUST BE VALID DEVICE
IFN FTMP,<
PUSHJ P,SETCPF## ;GET ON CORRECT CPU FOR DEVICE
>
;FALL INTO DISCON
;SUBROUTINE TO DISCONNECT A DEVICE
;CALLED WITH:
; F = ADDRESS OF DDB
; P1 = ADDRESS OF ROUTINE TO CALL (RELEA1)
; P2 = ADDRESS OF MPX DDB
; PUSHJ P,DISCON
; RETURN HERE ON ERROR (USER AC UPDATED)
; RETURN HERE IF OK
DISCON: HLR M,DEVBUF(P2) ;ADDRESS OF THE RING HEADER
HRRZS P3,F ;ADDRESS OF THE TARGET DDB FOR VMCHEK
; ALSO ZERO LH(F) FOR CAIN BELOW
TRNE M,-1 ;OK IF NO BUFFERS (RELEASE)
PUSHJ P,VMCHKH ;MAKE SURE ALL BUFFERS ARE IN CORE IN
; CASE THEY SHOULD BE RECLAIMED
MOVE S,DEVIOS(F) ;SETUP S
LDB T1,PJOBN## ;GET THE JOB # OF OWNER
MOVEI T2,ASSPRG ; INIT BIT
TDNE T2,DEVMOD(F) ;SKIP IF NOT INITED
CAME T1,J ;SKIP IF INITED BY THIS JOB
JRST ECOD5## ;NO--BOUNCE HIM
HLRZ P4,DEVXTR(P2) ;GET CDT ADDRESS
JUMPE P4,ECOD5## ;IF NONE, THERE ARE NO DEVICES IN CDT
HLRZ T1,CDTSIZ(P4) ;NUMBER OF WORDS IN CDT
SUB T1,CDTFRE(P4) ;LESS NUMBER OF FREE WORDS GIVES # ENTRIES
MOVEI T1,-1(T1) ;CLEAR LH AND SUBTRACT 1
MOVEI T2,1(P4) ;ADDRESS OF FIRST SLOT
MOVE T3,T2 ;2 COPIES
DCNDVL: MOVE T4,(T2) ;GET AN ENTRY
CAIN F,(T4) ;IS THIS THE ONE TO ZAP?
AOJA T2,DCNDV1 ;YES--GET THE NEXT ENTRY
MOVEM T4,(T3) ;STORE BACK ENTRY
ADDI T2,1 ;UPDATE SOURCE
ADDI T3,1 ;UPDATE DESTINATION
DCNDV1: SOJG T1,DCNDVL ;MOVE THE WHOLE CDT DOWN
CAIN T2,(T3) ;DID WE FIND AN ENTRY?
JRST ECOD5## ;NO--DEVICE NOT CONNECTED
SETZM -1(T2) ;ZERO OLD LAST ENTRY IN CDT
CAIN P1,RELEA1## ;UNCONDITIONAL DISCONNECT?
PUSHJ P,RTNOB ;YES, RETURN BUFFERS TO FREE LIST
MOVEI T2,DEPMSG ;NO LONGER CONTROLED
ANDCAM T2,DEVMSG(F) ; BY MSGSER
SOS T2,DEVXTR(P2) ;1 LESS DEVICE CONNECTED
AOS CDTFRE(P4) ; AND 1 MOVE FREE SLOT
TRNE T2,-1 ;SKIP IF CDT NOW EMPTY
JRST DISXIT ;ELSE JUST EXIT
HLRZ T1,CDTSIZ(P4) ;NUMBER OF WORDS IN CDT
MOVEI T2,(P4) ;ADDRESS OF CDT
PUSHJ P,GIVWDS## ;RETURN CDT
SETZB P4,DEVXTR(P2) ;FLAG AS HAVING NO CDT
DISXIT: MOVE T1,P1 ;COPY ROUTINE ADDRESS
AOS (P) ;SKIP RETURN
PJRST CALSER ;CALL SERVICE ROUTINE
;SUBROUTINE TO SETUP CDT
;CALL WITH:
; P2 = ADDRESS OF DDB
; PUSHJ P,GETCDT
; RETURN HERE IF NO CORE
; RETURN HERE P4=ADDRESS OF CDT
GETCDT: HLRZ P4,DEVXTR(P2)
JUMPN P4,CPOPJ1## ;ALL DONE IF NON-ZERO
MOVEI T2,CDT4WD ;NUMBER OF 4 WORD CHUNKS TO GET
PUSHJ P,GET4WD## ; ..
POPJ P,0
MOVE T2,[CDTQNT,,CDTQNT-1] ;SIZE AND FREE COUNT
MOVEM T2,CDTSIZ(T1) ;STORE INFO
MOVEM T1,P4 ;STORE ADDRESS
HRLZM T1,DEVXTR(P2) ;STORE ADDRESS
HRRZM T1,DEVCID(P2) ;STORE NEXT INPUT DEV
SETZM 1(P4) ;ZERO UNUSED WORDS
HRLI T1,1(P4) ;FROM
HRRI T1,2(P4) ;TO
BLT T1,CDTQNT-1(P4) ;ZAP
JRST CPOPJ1## ;GOOD RETURN
;SUBROUTINE TO RETURN FULL BUFFERS WHICH HAVE
; NOT BEEN OUTPUT YET TO THE FREE LIST
;CALL WITH:
; F = ADDRESS OF THE CONNECTED DDB
; PUSHJ P,RTNOB
; ALWAYS RETURN HERE
RTNOB: MOVSI T1,DVTTY ;DEVICE IS A TTY BUT
TDNN T1,DEVMOD(F) ;IF A TTY, DON'T CALL WAIT1 (IOACT GETS LEFT ON)
PUSHJ P,WAIT1## ;MAKE SURE I/O ISN'T GOING ON NOW
HLRZ T1,DEVBUF(F) ;ADDRESS OF THE ACTIVE LIST
JUMPE T1,CPOPJ## ;RETURN IF NO BUFFERS ON LIST
RTNOB1: PUSHJ P,ADVBFE## ;RETURN BUFFER TO THE FREE LIST
POPJ P, ;ALL DONE
JRST RTNOB1 ;RETURN NEXT BUFFER
;SUBROUTINE TO EXPAND A FULL CDT
;CALL WITH:
; MOVE P2,ADDRESS-OF-MPX-DDB
; MOVE P4,ADDRESS-OF-CDT
; PUSHJ P,XPNCDT
; RETURN HERE IF NO MORE CORE
; RETURN HERE DDB AND P4 UPDATED
XPNCDT: HLRZ T2,CDTSIZ(P4) ;CURRENT SIZE
LSH T2,-2 ;IN 4 WORD BLOCKS
ADDI T2,CDT4WD ;PLUS AMOUNT TO EXPAND
PUSHJ P,GET4WD## ;GET THAT MUCH CORE
POPJ P,0 ;NO MORE CORE
AOS (P) ;WE HAVE WON
HRL T1,P4 ;COPY THE OLD ADDRESS
PUSH P,CDTSIZ(P4) ;REMEMBER THE OLD SIZE
HRRM P4,(P) ;AND ADDRESS
MOVE T2,[CDTQNT,,CDTQNT] ;AMOUNT WE ADDED
ADDB T2,CDTSIZ(P4) ;UPDATE THE CDT
HLRZ T2,T2 ;PUT NEW SIZE IN THE RH
ADDI T2,(T1) ;WHERE TO STOP BLT
MOVEI P4,(T1) ;ALSO FIX P4 BEFORE BLT ZAPS AC
SETZM (P4) ;ZERO OUT THE NEW CDT
HRLZ T3,P4 ;BUILT A BLT
HRRI T3,1(P4) ;POINTER
BLT T3,-1(T2) ;ZAP!!
SUBI T2,CDTQNT+1 ;NEW STOP ADDRESS
BLT T1,(T2) ;COPY THE CDT TO IT'S NEW HOME
HRLM P4,DEVXTR(P2) ;REMEMBER ADDRESS OF THE CDT
HRRZM P4,DEVCID(P2) ;UPDATE CURRENT BECAUSE OLD MOVED
POP P,T2 ;RESETORE OLD SIZE AND ADDRESS
HLRZ T1,T2 ;COPY NUMBER OF WORDS
TLZ T2,-1 ;CLEAR LH
PJRST GIVWDS## ;RETURN OLD CORE
;SUBROUTINE TO DETERMINE OUTPUT FEASIBILITY FOR A MPX-CONTROLLED DEVICE
;CALLED ONLY BY CNECT. MONITOR CALL
OFEDEV: PUSHJ P,MPXTBL ;FIRST AND FOREMOST GET I/O GOING
PUSHJ P,GETWD1 ;GET DEVICE UDX FROM CNECT. CALL
PUSHJ P,FNDDDB ;FIND THE DEVICE QUICKLY
; NO GENERAL DEVICE SEARCHES HERE FOR
; SPEED AND EFFICIENCY CONSIDERATIONS
PJRST ECOD2## ;NO SUCH DEVICE, USER LOSES
LDB T1,PDVTYP## ;SEE WHAT SORT OF DEVICE WE CAME UP WITH
CAIE T1,<.TYTTY/.TYEST> ;A TTY?
JRST OFEDE2 ;NO
PUSHJ P,TTYOFE## ;YES, ASK SCNSER'S OPINION
JRST OFEDE5 ;AND FORGET THE DATA REQUEST COUNT
OFEDE2:
IFE FTNET,<TRO T1,-1> ;FLAG LOCAL DEVICE IF NO NETWORKS
IFN FTNET,<
MOVE T1,DEVCHR(F) ;NOT A TTY, GET CHARACTERISTICS
TLNN T1,DVCNET ;A NETWORK (DATA REQUEST) DEVICE?
TROA T1,-1 ;NO, LOCAL, FLAG AS SUCH
HRRZ T1,DEVDRQ(F) ;YES, RETURN OUTPUT DATA REQUEST COUNT
> ;END IFN FTNET
OFEDE5: HLL T1,DEVEVM(F) ;GET ADDRESS OF USER OUTPUT BUFFER
TLNN T1,-1 ;UNLESS NOT EVM MAPPED
HRL T1,DEVOAD(F) ;IN WHICH CASE GET TRUE USER ADDRESS
JRST STOTC1## ;RETURN VALUE TO USER
SUBTTL SENSE. UUO -- RETURN DEVICE INFORMATION
;UUO TO RETURN INFORMATION ABOUT A SPECIFIC DEVICE
;CALL WITH:
; MOVE AC,[LENGTH,,ADDR]
; SENSE. AC,
; RETURN HERE (ERROR CODE IN AC)
;
;ADDR CONTAINS:
;
; !------------------!------------------!
; ! UDX, CHANNEL NUMBER OR SIXBIT DEV !
; !------------------!------------------!
; ! LENGTH OF BLOCK ! ADDR OF BLOCK !
; !------------------!------------------!
; / /
; / /
; !------------------!------------------!
; ! UDX, CHANNEL NUMBER OR SIXBIT DEV !
; !------------------!------------------!
; ! LENGTH OF BLOCK ! ADDR OF BLOCK !
; !------------------!------------------!
;
;
;
;EACH BLOCK GETS:
;
; !------------------!------------------!
; ! SIXBIT DEVICE NAME FOR DEVICE !
; !------------------!------------------!
; ! 0 ! GETSTS INFO !
; !------------------!------------------!
; ! DEVSTS WORD !
; !------------------!------------------!
;
;
;NOTE: THIS UUO IS RESTARTABLE FOR VM
;
SENSE:: PUSHJ P,SAVE2## ;SAVE P1 AND P2
HRRZ P1,T1 ;ADDRESS OF POINTER TABLE
HLRZ P2,T1 ;NUMBER OF ENTRIES
SENSE1: SUBI P2,2 ;TWO MORE WORDS?
JUMPL P2,CPOPJ1## ;NO--ALL DONE
HRR M,P1 ;GET THE FIRST WORD
PUSHJ P,GETWDU## ;GET THE WORD
PUSHJ P,DVCNSG## ;FIND THE DDB
JRST ECOD1## ;(1)ILLEGAL DEVICE
AOS M,P1 ;POINT TO NEXT WORD
PUSHJ P,GETWDU## ;GET THE WORD
PUSHJ P,SNSDEV ;STORE THE SENSE INFO
AOJA P1,SENSE1 ;LOOP OVER ALL THE DEVICES
;SUBROUTINE TO STORE THE SENSE INFO FOR ONE DEVICE
;CALL WITH:
; T1 = COUNT,,ADDR
; F = ADDRESS OF DDB
; PUSHJ P,SNSDEV
; RETURN HERE
;
SNSDEV: HRR M,T1 ;COPY ADDRESS
HLRE T2,T1 ;COPY COUNT
SOJL T2,CPOPJ## ;EXIT IF COUNT .LE. 0
MOVE T1,DEVNAM(F) ;PICK UP DEVICE NAME
PUSHJ P,PUTWDU## ;STORE FOR USER
SOJL T2,CPOPJ## ;EXIT IF COUNT = 1
HRRZ T1,DEVIOS(F) ;PICK UP I/O STATUS WORD
PUSHJ P,PUTWD1## ;STORE FOR USER
SOJL T2,CPOPJ## ;EXIT IF COUNT = 2
MOVE T1,DEVSTS(F) ;GET DEVICE STATUS
PJRST PUTWD1## ;STORE AND RETURN
SUBTTL ERLST. UUO -- RETURN THE STATUS FOR ALL DEVICE WITH ERRORS
;ERLST. UUO
;CALL WITH:
; MOVEI AC,BLOCK
; ERLST. AC,
; RETURN HERE ERROR CODE IN AC
; RETURN HERE BLOCK UPDATED
;
;FORMAT OF BLOCK:
;
; !------------------!------------------!
; ! # OF WORD IN BLK ! CHANNEL NUMBER !
; !------------------!------------------!
; ! NUMBER OF DEVICES WHICH HAVE ERRORS !
; !------------------!------------------!
; ! UDX FOR FIRST DEV! GETSTS FOR DEV !
; !------------------!------------------!
; / /
; / /
; / /
; !------------------!------------------!
; ! UDX FOR LAST DEV ! GETSTS FOR DEV !
; !------------------!------------------!
;
;NOTE: THE NUMBER OF DEVICE WHICH HAVE ERROR WILL BE GREATER THAT THE
; NUMBER OF UDX'S RETURNED IF THERE WAS NOT ENOUGH ROOM IN THE
; BLOCK.
;
ERLST:: PUSHJ P,SAVE4## ;SAVE SOME AC'S
HRR M,T1 ;ADDRESS OF BLOCK
PUSHJ P,GETWDU## ;GET THE WORD
MOVEI P2,0 ;ERROR COUNT
HLRZ P3,T1 ;NUMBER OF WORDS IN BLOCK
HRRZ P1,T1
PUSHJ P,SETUF##
JRST ECOD1## ;(1)NOT AN OPEN CHAN #
LDB T1,PDVTYP## ;GET DEVICE TYPE
CAIE T1,.TYMPX/.TYEST;SKIP IF MPX:
JRST ECOD2## ;NOT MPX: DEVICE
AOS P1,M ;WHERE TO PUT ERROR COUNT
HLRZ P4,DEVXTR(F) ;SET P4 = ADDRESS OF CDT
JUMPE P4,ERLSTX ;JUMP IF NO DEVICES CONNECTED
HLRZ T1,CDTSIZ(P4) ;NUMBER OF WORDS IN CDT
SUB T1,CDTFRE(P4) ;MINUS FREE = # IN USE
MOVNI T4,-1(T1) ;MAKE NEGATIVE
HRLZ T4,T4 ;PUT IN LH
HRRI T4,1(P4) ;POINTER IN RH
ERLSTL: HRRZ F,(T4) ;GET POINTER TO DDB
JUMPE F,ERLSTA ;SHOULD NEVER HAPPEN
MOVE T1,DEVIOS(F) ;GET STATUS
TRNN T1,760000 ;ANY ERRORS?
JRST ERLSTA ;NO--LOOK AT NEXT DEVICE
HLL T1,(T4) ;TOSS IN UDX
ADDI P2,1 ;COUNT ERROR
SOSL P3 ;SKIP IF NO ROOM
PUSHJ P,PUTWD1## ;ELSE STORE
ERLSTA: AOBJN T4,ERLSTL ;LOOP BACK OVER ALL DEVICES
ERLSTX: MOVE T1,P2 ;COUNT OF ERRORS
HRR M,P1 ;WHERE TO PUT IT
PUSHJ P,PUTWDU## ;STORE IT
JRST CPOPJ1## ;GOOD RETURN
SUBTTL CLRST. UUO -- CLEAR DEVICE STATUS
;UUO TO CLEAR DEVICE STATUS
;CALL WITH:
; MOVE AC,[LENGTH,,BLOCK]
; CLRST. AC,
; RETURN HERE ERROR CODE IN AC
; RETURN HERE IF OK
;
;BLOCK CONTAINS:
;
; !------------------!------------------!
; ! UDX, CHAN # OR SIXBIT DEVICE NAME !
; !------------------!------------------!
; ! 0 ! SETSTS VALUE !
; !------------------!------------------!
; ! UDX, CHAN # OR SIXBIT DEVICE NAME !
; !------------------!------------------!
; ! 0 ! SETSTS VALUE !
; !------------------!------------------!
; / /
; / /
; / /
; !------------------!------------------!
; ! UDX, CHAN # OR SIXBIT DEVICE NAME !
; !------------------!------------------!
; ! 0 ! SETSTS VALUE !
; !------------------!------------------!
;
CLRST:: PUSHJ P,SAVE2## ;SAVE P1 AND P2
HRRZ P1,T1 ;SAVE ADDRESS IN P1
HLRZ P2,T1 ;SAVE COUNT IN P2
CLRSTL: SUBI P2,2 ;COUNT ANOTHER TWO WORDS
JUMPL P2,CPOPJ1## ;ALL DONE IF NEGATIVE
HRR M,P1 ;GET ADDRESS OF DEVICE
PUSHJ P,GETWDU## ;GET DEVICE NAME
PUSHJ P,DVCNSG## ;FIND THE DDB
JRST ECOD1## ;(1) ILLEGAL DEVICE NAME
LDB T1,PJOBN## ;GET THE OWNER
CAME T1,.CPJOB## ;IS IT THIS JOB?
JRST ECOD2## ;(2) DEVICE NOT OWNED BY THIS JOB
PUSHJ P,GETWD1## ;GET THE NEW STATUS
TLNE T1,-1 ;ANYTHING IN LH?
PJRST ILLMOD## ;YES--ILLEGAL DATA MODE
HRR M,T1 ;COPY RH BITS
PUSHJ P,SETIOS## ;SET THE STATUS
ADDI P1,2 ;ADVANCE TO NEXT ENTRY
JRST CLRSTL ;LOOP OVER ALL REQUESTS
SUBTTL WAIT UUO
;HERE FROM WAIT1 WHEN CALLED TO WAIT FOR AN MPX CHANNEL
MPXWAI::POP P,T1 ;RESTORE T1
PUSHJ P,SAVT## ;SAVE THE T ACS
PUSHJ P,SAVE3## ;AND THE P ACS TOO
SETZ P2, ;INITIALIZE FOR NXTDV LOOP
MOVE P3,F ;MPX DDB ADDRESS IN P3
MPXWI1: PUSHJ P,NXTDV ;GET NEXT DEVICE ON THIS MPX CHANNEL
JRST MPXWI2 ;DONE THEM ALL, RETURN
MOVEI T1,WAIT1M## ;CALL THE WAIT1 ROUTINE
PUSHJ P,CALSER ;CALL THE CALL CALLER
JFCL ;HO HUM
JRST MPXWI1 ;LOOP FOR REST OF DEVICES
MPXWI2: MOVE F,P3 ;RESTORE F
MOVE S,DEVIOS(F) ;ON G.P.'S
POPJ P, ;RETURN TO WAIT1'S CALLER
;HERE FROM UUOCON ON WAIT UUO FOR DEVICE MPX
MPXWAT::PUSHJ P,SAVE3## ;SAVE P1-P3
MPXWA0: SETZ P2, ;INDICATE FIRST CALL TO NXTDV
MOVE P3,F ;SAVE MPX DDB
MPXWA1: PUSHJ P,NXTDV ;FIND THE NEXT DEVICE CONNECTED TO THE MPX
JRST MPXWA2 ;NO MORE
MOVEI T1,WAIT1M## ;WAIT FOR I/O TO STOP ON THAT DEVICE
PUSHJ P,CALSER ;CALL WAIT1
JFCL ;HO HUM
JRST MPXWA1 ;CHECK NEXT DEVICE
MPXWA2: MOVE F,P3 ;RESTORE ADDRESS OF MPX DDB
MOVE S,DEVIOS(F) ;MPX:'S I/O STATUS
TLNN S,IOSTBL ;TROUBLE SET (DEVICE HAS OUTPUT)?
POPJ P, ;NO, ALL OUTPUT OUT, ALL DEVICES IDLE
MPXWA3: PUSHJ P,MPXTBL ;TRY TO CLEAR UP TROUBLE
MOVE S,DEVIOS(F) ;IO STATUS FOR THE MPX DDB
TLNN S,IOSTBL ;TROUBLE STILL PRESENT?
JRST MPXWA0 ;NO, WAIT FOR I/O COMPLETION
MOVEI T1,^D1 ;YES, SLEEP A WHILE
MOVE J,.CPJOB## ;CURRENT JOB'S JOB NUMBER
PUSHJ P,SLEEPF## ;WAIT FOR TROUBLE TO BE FIXED
JRST MPXWA3 ;AND TRY AGAIN
;SUBROUTINE TO SEE IF ANY DEVICE ON AN MPX CHANNEL IS IN TROUBLE
; AND IF SO, GET THE DEVICE ROUTINE STARTED AGAIN
;CALLING SEQUENCE:
; MOVE F,ADDRESS OF THE MPXDDB
; PUSHJ P,MPXTBL
;ALWAYS RETURN CPOPJ
MPXTBL: MOVSI S,IOSTBL(MPXVMF) ;DEVICE IN TROUBLE BIT
TDNN S,DEVIOS(F) ;SOME DEVICE CONNECTED TO THIS MPX IN TROUBLE?
POPJ P, ;NO, NOTHING TO DO
ANDCAB S,DEVIOS(F) ;CLEAR TROUBLE IN HOPES THAT IT WILL CLEAR UP
PUSHJ P,SAVE3## ;SAVE P1-P3
SETZ P2, ;INDICATE FIRST CALL TO NXTDV
MOVE P3,F ;SAVE ADDRESS OF THE MPX DDB
MPXTB1: PUSHJ P,NXTDV ;FIND THE NEXT DEVICE CONNECTED TO THE MPX DDB
JRST MPXTB2 ;NO MORE
TLNN S,IOSTBL ;IS THIS DDB IN TROUBLE?
JRST MPXTB1 ;NO, LOOK AT THE NEXT DDB
MOVSI T1,(MPXVMF) ;NOTE THE POSSIBILITY OF A PAGE FAULT
IORM T1,DEVIOS(P3) ; IN THE MPX DDB
HRRZ T1,DEVOAD(F) ;ADDRESS OF CURRENT OUTPUT BUFFER
PUSHJ P,UADRCK## ;CHECK THAT THE BUFFER IS OK
PUSHJ P,BRNGE## ;MAKE SURE THAT THE ENTIRE BUFFER IS IN CORE
MOVSI T1,(MPXVMF) ;A PAGE FAULT DIDN'T OCCUR
ANDCAM T1,DEVIOS(P3) ; SO CLEAR THE BIT
MOVSI S,IOSTBL ;CLEAR THE TROUBLE BIT
ANDCAB S,DEVIOS(F) ; AND SETUP S
PUSHJ P,MSGCOU ;DO A CALOUT (START UP OUTPUT)
JRST MPXTB1 ;AND LOOP OVER ALL CONNECTED DEVICES
MPXTB2: MOVE F,P3 ;RESTORE F
POPJ P, ;AND RETURN
;SUBROUTINE TO FIND THE NEXT DEVICE CONNECTED TO AN MPX CHANNEL
;CALLING SEQUENCE
; MOVE F,ADDRESS OF THE MPXDDB FOR THE FIRST CALL
; MOVEI P1,0 (FIRST CALL) OR WHAT WAS RETURNED ON PREVIOUS CALL
; ; ON SUBSEQUENT CALLS
; PUSHJ P,NXTDV
; RETURNS HERE IF NO MORE CONNECTED DEVICES
; RETURNS HERE WITH F POINTING AT THE NEXT CONECTED DEVICE,
; S SETUP FROM DEVIOS FOR THAT DEVICE
NXTDV: JUMPN P2,NXTDV1 ;JUMP IF NOT THE FIRST CALL
HRRZ P1,DEVXTR(F) ;FIRST CALL, P1 = THE NUMBER OF CONNECTED DEVICES
HLRZ P2,DEVXTR(F) ;P2 = ADDRESS OF THE CDT
NXTDV1: SOJL P1,CPOPJ## ;RETURN IF NO MORE CONNECTED DEVICES
HRRZ F,1(P2) ;ADDRESS OF THE DDB FOR THE NEXT CONNECTED DEVICE
MOVE S,DEVIOS(F) ;IO STATUS FOR THAT DDB
IFN FTMP,<
PUSHJ P,SETCPF## ;GET ON CORRECT CPU
>
AOJA P2,CPOPJ1## ;STEP P2 TO NEXT SLOT IN CDT AND SKIP RETURN
;SUBROUTINE TO DETERMINE IF THE CURRENT DEVICE IS AN MPX DDB OR IS
; CONNECTED TO AN MPX DDB
;CALLING SEQUENCE:
; MOVE F,DDB ADDRESS
; PUSHJ P,CHKMPX
;RETURNS CPOPJ IF AN MPX DDB OR A DDB FOR A DEVICE CONTROLLED BY
; MSGSER, CPOPJ1 OTHERWISE
CHKMPX::LDB T1,PDVTYP## ;DEVICE TYPE
MOVE T3,DEVMSG(F) ;WORD WHICH CONTAINS BIT WHICH SAY CONNECTED TO AN MPX
CAIE T1,.TYMPX/.TYEST;AN MPX DDB?
TRNE T3,DEPMSG ;OR CONNECTED TO AN MPX CHANNEL?
POPJ P, ;YES, MULTIPLEXED RETURN
JRST CPOPJ1## ;NO, NORMAL DEVICE RETURN
SUBTTL OUT UUO
;HERE FROM UUOCON ON AN OUT UUO FOR MPX:. UUOCON HAS NOT DONE
; ANYTHING YET
MSGOUT::PUSHJ P,SAVE4## ;EAT SOME PDL
PUSHJ P,MPXTBL ;GET DEVICES GOING AGAIN IF IN TROUBLE
HLRZ P4,DEVXTR(F) ;P4 GETS ADDRESS OF CDT
JUMPLE P4,NDCERR ;BETTER BE ONE
HRRZ P2,F ;P2 IS ADDRESS OF MPX DDB
PUSHJ P,JDAADP##
HLL P2,0(T1) ; IN LEFT HALF OF P2
HLR M,DEVBUF(P2) ;ADDRESS OF OUTPUT BUFFER HDR
ADDI M,3 ;ADDRESS OF 4TH WORD
PUSHJ P,GETWDU## ;GET THE WORD
PUSHJ P,FNDUDX ;FIND THE UDX
PJRST NCDERR ;NO CONNECTED DEVICE
MOVE P3,F ;P3 HOLDS THE ADDRESS OF THE TARGET DDB
IFN FTMP,<
PUSHJ P,SETCPF## ;GET ON CORRECT CPU
>
SUBI M,3 ;FIRST WORD OF HEADER
PUSHJ P,GETWDU## ;PICK UP WORD
TLNN P2,OUTBFB ;OUTBUF DONE?
JRST FIROUT ;NO--SETUP RING
JUMPE T1,STOUT1 ;GO WAIT FOR AN EMPTY BUFFER IF NEEDED
JUMPL T1,FIROUT ;JUMP IF DUMMY OUTPUT
MOVEI T2,DEPOND ;NOTHING PENDING. DO WE KNOW IT?
TDNE T2,DEVAIO(P2) ;IF WE DON'T, WE HAVEN'T CLEANED UP THE BUFFER RING HEADER
JRST STOUT1 ; SO LET'S GO TO NXTOUT IF WE CAN
PUSH P,T1 ;SAVE ADDRESS OF FIRST BUFFER
PUSH P,M ;SAVE ADDRESS OF RING HEADER
HRR M,T1 ;SETUP M FOR VMCHEK
PUSHJ P,VMCHEK ;CHECK ALL BUFFERS ARE IN CORE
MOVEI T1,(T1) ;CLEAR LH OF 1ST BUFFER ADDR
PUSHJ P,UADRCK## ;MAKE SURE IT'S LEGAL
POP P,M ;RESTORE HEADER ADDR
MOVEI T1,(M) ;RH ONLY INTO T1
HRRZ T2,(P) ;GET 1ST BUFFER ADDRESS
PIOFF ;PREVENT RACES
EXCTUX <HRRZ T3,(T2)> ;GET POINTER TO NEXT BUFFER
EXCTXU <MOVEM T3,(T1)> ;AND STORE IT IN HEADER
PION ;ALLOW IME STOPCDS
;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE
MOVSI T1,IOUSE ;GET THE USE BIT
EXCTUU <IORM T1,(T2)> ;AND SET IT FOR THOSE DEVICES THAT CHECK
;***********************************************************************
;
;ALL DEVICES CONTROLLED BY AN MPX CHANNEL MUST EXPLICITLY CHECK THAT
;THE IOUSE BIT IS SET. IF IT IS NOT SET THEN THE DEVICE SERVICE ROUTINE
;MUST SKIP THE OUTPUT AND DIRECTLY CALL ADVBFE IMMEDIATELY. THIS IS BE-
;CAUSE THE LAST CALL TO ADVBFE MARKED THE BUFFER AS OUTPUT BUT WAS UN-
;ABLE TO FREE THE BUFFER (RETURN IT TO THE FREE LIST AND ADVANCE THE
;ACTIVE LIST TO THE NEXT BUFFER TO BE OUTPUT) DUE TO (E.G.,) A PAGE
;FAULT CHAINING DOWN THE MPX FREE LIST. ALTHOUGH THIS SHOULD NOT HAPPEN,
;IF THE DEVICE IS A NETWORK DEVICE (FOR EXAMPLE) AND IT RUNS OUT OF
;DATA REQUESTS THE DEVICE IS SHUT DOWN. AT THIS POINT THE FREE LIST CAN
;BE PAGED OUT WHILE THE DEVICE STILL HAS ACTIVE BUFFERS (DEVOAD POINTS
;TO NEXT BUFFER TO OUTPUT). IF OUTPUT IS STARTED AT THIS POINT THEN
;AT OUTPUT COMPLETION (INTERRUPT LEVEL) THE BUFFER WILL NOT BE FREED UP
;SINCE MSGBFE (ADVBFE) CAN'T CHAIN DOWN THE FREE LIST, BUT IT HAS MARKED
;THE BUFFER AS NO LONGER CONTAINING ACTIVE DATA.
;
;FOR THIS REASON ALL ROUTINES WHICH WANT TO START UP OUTPUT FOR A MPX:
;CONTROLLED DEVICE SHOULD GO THROUGH MSGCOU RATHER THAN CALLING CALOUT
;DIRECTLY.
;
;***********************************************************************
POP P,U ;ADDRESS OF BUFFER TO USE
PUSHJ P,STOCNT ;COMPUTE BYTE OR WORD COUNT AND STORE
; IN BUFFER, RETURN WITH WC IN T1
PUSH P,T1 ;SAVE COMPUTED WORD COUNT
HRRZI T3,(U) ;FIRST WORD OF BUFFER
PUSHJ P,BADRCK## ;ADDRESS CHECK
JRST ADRERR## ;DID NOT PASS
HRRI M,(U) ;ADDRESS OF THE CURRENT BUFFER
PUSHJ P,GETWDU## ;GET THE LINK WORD
HLRZ T2,T1 ;GET USER'S BUFFER SIZE
POP P,T3 ;RECALL WC FROM USER'S BYTE PTR
SKIPL T3 ;NEGATIVE WORD COUNTS ARE ILLEGAL
CAIG T2,(T3) ;DOES WORD COUNT OVERFLOW BUFFER?
JRST ADRERR## ;YES! GO PREVENT HORRIBLE THINGS.
TRZ T1,-1 ;NOT LINKED TO ANYTHING AT ALL
PUSHJ P,PUTWDU## ;STORE UPDATED LINK
HLRZ T1,DEVBUF(P3) ;PICK UP ADDRESS OF LAST FULL OUTPUT BUFFER
SKIPE T1 ;SKIP OVER CHECK IF ZERO (= JUMPE T1,NEWOBF)
PUSHJ P,UADRCK## ;ADDRESS CHECK LAST BUFFER
PIOFF ;AVOID RACES
HLRZ T2,DEVBUF(P3) ;ADDRESS OF LAST BUFFER IN LIST
JUMPE T2,NEWOBF ;JUMP IF BUFFER FREED AT INTERRUPT LEVEL
EXCTUU <HRRM U,@T1> ;STORE NEW LINK
CAIA ;START UP OUTPUT
NEWOBF: HRRM U,DEVOAD(P3) ;REMEMBER ADDRESS OF LIST
HRLM U,DEVBUF(P3) ;SAVE ADDRESS AS LAST BUFFER ON ACTIVE LIST
PION
;CONTINUED FROM PREVIOUS PAGE
STOUTP: MOVE F,P3 ;ADDRESS OF TARGET DDB
MOVSI S,IOSTBL ;MAGIC SYNC BIT
ANDCAB S,DEVIOS(F) ;CLEAR (ALSO LOAD UP S)
PUSHJ P,MSGCOU ;CALL CALOUT (TO START UP OUTPUT)
STOUT1: HLR M,DEVBUF(P2) ;ADDRESS OF NEXT BUFFER
PUSHJ P,GETWDU## ;GET IT
TRNE T1,-1 ;IS IT AVAILABLE
JRST NXTOUT ;YES--START THE NEXT OUTPUT IF WE CAN
MOVEI T1,DEPAIO ;ASYNCHRONOUS OUTPUT
TDNE T1,DEVAIO(P2) ; ..
JRST STOUT2 ;YES--DO NOT WAIT
PUSHJ P,WSYNC## ;NO--WAIT FOR I/O ACTIVE TO CLEAR
HLR M,DEVBUF(P2) ;SEE IF USER WIPED-OUT
PUSHJ P,GETWDU## ;BUFFER HEADER
TRNN T1,-1 ;IS IT 0?
JRST [MOVE F,P2 ;NEED MPXDDB
JRST ADRERR##] ;FOR ADRERR
TLZE S,IOSTBL ;ERROR NEEDING A RETRY
JRST STOUTP ;YES--RETRY
JRST STOUT1 ;NO--LOOK FOR NEXT BUFFER (BETTER BE ONE)
STOUT2: MOVEI T1,DEPOND
HRRZ F,P2
IORM T1,DEVAIO(F) ;TTY BUT NONE PENDING
POPJ P,0
;HERE ON THE FIRST OUTPUT UUO
FIROUT: TRNE T1,-1 ;OUTBUF DONE?
JRST FIROU1 ;YES--DO NOT DO ONE NOW
HRRI M,2 ;TWO BUFFERS
MOVE F,P2 ;POINT TO MPX DDB
PUSHJ P,UOUTBF## ;BUILD THE RING
FIROU1: HLR M,DEVBUF(P2) ;ADDRESS OF RING HEADER
PUSHJ P,VMCHKH ;MAKE SURE ALL BUFFERS ARE IN CORE
HLR M,DEVBUF(P2) ;ADDRESS OF RING HEADER
PUSHJ P,GETWDU## ;GET ADDRESS OF FIRST BUFFER
HRRM T1,DEVOAD(P2) ;STORE IN DDB
HRRZ T1,T1 ;CLEAR VIRGIN RING BIT
PUSHJ P,PUTWDU## ;STORE BACK IN USER SPACE
PUSHJ P,JDAADP##
MOVSI T2,OUTBFB ; UUO PROGRESS BIT IS
IORM T2,0(T1) ; SET FOR THIS CHANNEL
HRRZ T1,DEVOAD(P2) ;RESTORE T1
;HERE WHEN SETUP FOR THE NEXT OUTPUT
NXTOUT: HRRZS T1 ;CLEAR ANY LH JUNK
PUSH P,T1 ;SAVE ADDRESS OF BUFFER
PUSHJ P,BUFCLR## ;CLEAR THE BUFFER
PJRST ADRERR## ;ADDRESS CHECK
MOVEI T2,DEPOND ;CLEAR OUTPUT NOT DONE YET
ANDCAM T2,DEVAIO(P2) ; SINCE THERE IS A BUFFER AVAILABLE NOW
POP P,U ;RESTORE THE ADDRESS
HRR M,U ;PICK UP THE LINK WORD
HLRZ U,DEVBUF(P2) ;ADDRESS OF THE RING HEADER
PUSHJ P,GETWDU## ; ..
MOVEI T2,(M) ;ADDRESS OF THE DATA
LDB J,[POINT 17,T1,17] ;PICK UP BUFFER SIZE
SOJA J,IOSETC## ;STORE BYTE COUNT AND RETURN
;SUBROUTINE TO MAKE SURE ALL BUFFERS ARE IN CORE
;CALL WITH:
; M = ADDRESS-OF-FIRST-BUFFER
; P3 = ADDRESS OF THE TARGET DDB
; PUSHJ P,VMCHEK
; RETURN HERE IF ALL OK
;
VMCHKH: PUSHJ P,GETWDU## ;GET FIRST (MPX: FREE) BUFFER ADDRESS
HRR M,T1 ;TO M FOR VMCHEK
VMCHEK: PUSH P,T1 ;SAVE T1
MOVE T1,DEVIOS(P3) ;DEVICE I/O STATUS
TRNE T1,IOACT ;IF DEVICE IS I/O ACTIVE
JRST TPOPJ## ;THEN BUFFERS WILL BE ASSUMED OK
; (EVEN IF THEY AREN'T (WHICH IS QUITE
; POSSIBLE) THERE IS NOTHING THAT CAN
; BE DONE ABOUT IT IF ANY IOACT IS ON)
TRNE M,-1 ;ANY (MPX FREE LIST) BUFFERS TO CHECK?
PUSHJ P,BCHCK ;MAKE SURE BUFFERS ARE IN CORE
;WE HAVE JUST TOUCHED EVERY BUFFER IN THE FREE LIST.
;NOW CHECK OUT THE DEVICE ACTIVE BUFFER LIST.
HLR M,DEVEVM(P3) ;ASSUME EVM, GET USER VIRTUAL ADDRESS
TRNN M,-1 ;UNLESS OF COURSE NOT EVM MAPPED
HRR M,DEVOAD(P3) ;IN WHICH CASE GET TRUE USER ADDRESS
; NOTE THAT THE ABOVE THREE INSTRUCTIONS
; NEED NOT BE RUN PIOFF'ED SINCE THE WORST
; THAT CAN HAPPEN IS THAT THE DEVICE FREED
; THE BUFFER (FREE LIST KNOWN OK) BUT
; COULD NOT START UP THE NEXT BUFFER DUE
; TO A PAGE FAULT ETC. THE DEVICE WILL BE
; RESTARTED ON NEXT CALL TO MPXTBL.
TRNE M,-1 ;ANY DEVICE ACTIVE LIST BUFFERS TO CHECK?
PUSHJ P,BCHCK ;MAKE SURE BUFFERS ARE IN CORE
JRST TPOPJ## ;ALL OK
;VERIFY A BUFFER CHAIN IS IN MEMORY AND ADDRESSABLE
BCHCK: PUSHJ P,SAVE1## ;SAVE P1
MOVEI P1,^D10000 ;DEFEND AGAINST LOOPS
BCHCK1: PUSHJ P,GETWRD## ;GET LINK WORD
JRST ADRERR## ;ADDRESS CHECK
MOVEI T2,(M) ;ADDRESS OF CURRENT BUFFER
HRR M,T1 ;ADDRESS OF NEXT BUFFER
MOVE T1,T2 ;ADDRESS OF CURRENT BUFFER
PUSHJ P,BRNGE## ;CHECK IT
TRNE M,-1 ;LAST BUFFER?
SOJGE P1,BCHCK1 ;NO
JUMPL P1,ADRERR## ;JUMP IF ADDRESS CHECK
PJRST SCDCHK## ;RETURN WITHOUT HOGGING CPU
;SUBROUTINE TO DO ALL GOOD THINGS FOR BYTE COUNTS AND WORD COUNTS
;CALLED WITH:
; U = ADDRESS OF BUFFER (ACTUALY BUFFER + 1)
; M = ADDRESS OF RING HEADER
; P2 = ADDRESS OF MPX DDB
; P3 = ADDRESS OF TARGET DDB
; PUSHJ P,STOCNT
; RETURN HERE LENGTH OF BUFFER IN T1 (ALWAYS WORDS)
;
;THE COUNT IN THE BUFFER IS COMPUTED FROM THE BYTE POINTER IF IOWC=0
; AND THEN STORED IN THE BUFFER
STOCNT: PUSHJ P,SAVE1## ;SAVE P1
PUSH P,M ;PRESERVE M
PUSHJ P,GETWD1## ;PICK UP THE BYTE POINTER
MOVE P1,T1 ;SAVE POINTER IN P1
HRRI M,1(U) ;POINT TO I/O BUFFER
MOVE S,DEVIOS(P2) ;PICK UP IOS WORD
LDB T2,PIOMOD## ; AND THE ASSOCIATED I/O MODE
TRNE S,IOWC ;DID USER COMPUTE WORD COUNT
JRST STOCN7 ;YES--GO CONVERT TO WORDS
SUBI T1,1(U) ;GET THE WORD COUNT
HRRE T1,T1 ;FILL LH WITH SIGN BITS (0 I HOPE)
CAIE T2,BYTMOD ;IF "BYTE" MODE
CAIN T2,PIMMOD ;OR PACKED IMAGE MODE
JRST STOCN2 ;THEN WE MUST DEAL WITH BYTES NOT WORDS
PUSHJ P,PUTWDU## ;STORE UPDATED WORD COUNT IN BUFFER HEADER
PJRST MPOPJ## ;RESTORE M AND RETURN WITH WORD COUNT IN T1
;HERE TO DEAL WITH BYTE-MODE BUFFERS
STOCN2: LDB T3,[POINT 6,P1,11] ;BITS PER BYTE
MOVEI T2,^D36 ;BITS PER WORD
IDIVI T2,(T3) ;BYTES PER WORD
IMULI T1,(T2) ;BYTES PER CURRENT BUFFER (GENEROUS ESTIMATE)
LDB T2,[POINT 6,P1,5] ;BITS FREE IN LAST WORD OF BUFFER
CAILE T2,^D36 ;LIMIT TO ONE WORD'S WORTH
MOVEI T2,^D36 ;WHAT ABOUT OWGP'S?
LDB T3,[POINT 6,P1,11];BITS PER BYTE
IDIVI T2,(T3) ;BYTES FREE IN LAST WORD OF BUFFER
SUBI T1,(T2) ;TRUE BYTE COUNT FOR BUFFER
PUSHJ P,PUTWDU## ;STORE UPDATED BYTE COUNT IN BUFFER HEADER
SUBI P1,1(U) ;RECALCULATE THE WORD COUNT
HRRE T1,P1 ;AND POSITION IT IN T1
PJRST MPOPJ## ;RETORE M AND RETURN WITH WORD COUNT IN T1
;HERE WHEN USER-SUPPLIED WORD COUNT
STOCN7: PUSHJ P,GETWDU## ;GET THE WORD COUNT FROM USER'S BUFFER HEADER
CAIE T2,BYTMOD ;"BYTE" MODE I/O?
PJRST MPOPJ## ;NO, RETURN WITH WORD COUNT IN T1
LDB T3,[POINT 6,P1,11] ;BITS PER BYTE
MOVEI T2,^D36 ;BITS PER WORD
IDIVI T2,(T3) ;BYTES PER WORD
IDIVI T1,(T2) ;WORDS PER CURRENT BUFFER
CAILE T2,0 ;IF ANY BYTES LEFT OVER,
ADDI T1,1 ;ALLOW FOR TRAILING PARTIAL WORD
PJRST MPOPJ## ;RETURN WORD COUNT IN T1
;SUBROUTINE TO CALL CALOUT FOR AN MPX-CONTROLLED DEVICE
;CALLED WITH F/ADDRESS OF TARGET DDB
;
;HANDLES THE SPECIAL CASE OF SKIPPING THE OUTPUT BUFFER IF THE
;USE BIT IS CLEARED (SEE OUT UUO CODE).
MSGCOU: MOVE S,DEVIOS(F) ;DEVICE I/O STATUS
TRNE S,IOACT ;IS DEVICE ALREADY I/O ACTIVE?
POPJ P, ;YES, DON'T TOUCH IT!
HLRZ T1,DEVEVM(F) ;ADDRESS OF USER BUFFER
TRNN T1,-1 ;UNLESS NOT MAPPED IN EVM
HRRZ T1,DEVOAD(F) ;IN WHICH CASE DEVOAD IS USER ADDRESS
EXCTUU <SKIPG (T1)> ;IS USE BIT SET (DATA TO BE OUTPUT)?
JRST MSGCO5 ;YES, ALL IS WELL
PUSHJ P,MSGBFE ;NO, AH HA! ADVANCE PAST THIS BUFFER
POPJ P, ;CAN'T STARTUP OUTPUT (E.G., PAGE FAULT)
PUSHJ P,SCDCHK## ;BE SURE WE DON'T LOOP TOO LONG
JRST MSGCOU ;JUST TO MAKE SURE . . .
MSGCO5: MOVEI T1,CALOUT## ;BUFFER CONTAINS VALID OUTPUT DATA,
PUSHJ P,CALSER ;CALL CALOUT TO START UP OUTPUT
JFCL ;YAWN
POPJ P, ;RETURN
;SUBROUTINE TO EMULATE CALOUT FOR MPX CHANNELS
;CALLED WITH F/ ADDRESS OF MPX DDB
MSGDOU: PUSHJ P,SAVE3## ;WE USE ACS LEFT AND RIGHT
SETZ P2, ;INITIALIZE FOR NXTDV CALL LOOP
MOVE P3,F ;SAVE MPX DDB (AND SET FOR NXTDV)
MSGDO1: PUSHJ P,NXTDV ;GET NEXT DEVICE OWNED BY MPX CHANNEL
JRST MSGDO2 ;ALL DONE
PUSHJ P,MSGCOU ;CALL CALOUT TO START UP OUTPUT
JRST MSGDO1 ;LOOP FOR REST OF DEVICES
MSGDO2: MOVE F,P3 ;RESTORE F TO MPX DDB
POPJ P, ;RETURN TO CALOUT FOR MPX: DEVICE
SUBTTL MSGBFE MSGSER'S ADVBFE
;SUBROUTINE CALL WHEN AN OUTPUT BUFFER IS EMPTY
;CALLED WITH:
; MOVX F,DDB-ADDRESS (OF TARGET DEVICE)
; PUSHJ P,MSGBFE
; RETURN HERE IN NO MORE FULL BUFFERS
; RETURN HERE IF MORE OUTPUT SHOULD BE DONE
;
MSGBFE::PUSHJ P,SAVE4## ;SAVE ALL THE AC'S IN SIGHT
PUSH P,T3 ; ..
MOVE P3,F ;P3 POINTS TO TARGET DDB
HRRZ P2,DEVXTR(P3) ;P2 POINTS TO MPX DDB
HRRZ T4,DEVEVM(P3) ;DOES THIS DEVICE HAVE EVM?
JUMPE T4,NOOEVM ;NO OUTPUT EVM
MOVE T4,DEVOAD(P3) ;EXEC VIRT ADDR OF CURRENT BUFFER
MOVEM S,-1(T4) ;TODD WILL HAVE FUN FINDING THIS
MOVSI T3,IOUSE ;THE BUFFER-IN-USE BIT
ANDCAB T3,(T4) ;THIS BUFFER IS NOW EMPTY
; (SEE BIG COMMENT IN OUT UUO CODE)
HLRZ T1,DEVBUF(P2) ;POINTER TO THE HEAD OF FREE LIST
MOVEI P4,^D10000 ;MAX BUFFERS LIMIT
MOVEI P1,-1 ;IF THERE IS NO FREE BUFFER LIST
MSBFE1: PUSHJ P,IADRCK## ;MAKE SURE POINTER IS LEGAL
PJRST ADVSTP ;ILLEGAL ADDRESS
PJRST ADVSTP ;CAUGHT IN THE ACT! STOP I/O.
EXCTUU <TDNN P1,(T1)>
JRST [HLL T2,DEVEVM(P3) ;GET THE USER VIRT ADDR OF THIS BUFFER
EXCTUU <HLRM T2,(T1)>;STORE THE POINTER IN PREVIOUS BUFFER
HLLZS (T4) ;MARK END OF LIST
JRST MSBFE2] ;LOOK FOR MORE BUFFERS
EXCTUX <HRRZ T1,(T1)> ;ELSE LINK TO NEXT BUFFER
SOJG P4,MSBFE1 ;SEE IF END OF LIST YET
JRST ADVSTP ;FREE LIST MESSED UP
MSBFE2: TRNN T3,-1 ;SKIP IF THERE IS MORE TO DO
JRST ADVST2 ;NO MORE BUFFERS TO EMPTY, STOP I/O
;HERE IF THERE ARE MORE BUFFERS IN THE OUTPUT LIST
PUSHJ P,BADRCK## ;ADDRESS CHECK
JRST ADVSTP ;OOO EVIL PERSON -- STOP I/O
PUSHJ P,ADVEVM## ;MAP THE NEXT BUFFER
JRST ADVSTP ;NO MORE EVM -- RETRY ON THE NEXT UUO
DPB T1,PDVOAD## ;STORE NEW ADDRESS
PJRST ADVBU1## ;TRY TO CONTINUE
;HERE TO ADVANCE BUFFERS WHEN NOT MAPPED VIA EVM
NOOEVM: HRRZ T4,DEVOAD(P3) ;USER VIRT ADDRESS IF NOT EVM-MAPPED
EXCTUU <MOVEM S,-1(T4)>;STORE UPDATED STATUS BITS
MOVSI T3,IOUSE ;THE BUFFER-IS-FULL BIT
EXCTUX <ANDCAB T3,(T4)>;MARK BUFFER IS NOW EMPTY
; (SEE BIG COMMENT IN OUT UUO CODE)
HLRZ T1,DEVBUF(P2) ;ADDRESS OF FREE LIST
MOVEI P4,^D10000 ;SETUP A LOOP COUNTER
MOVEI P1,-1 ;SETUP AC FOR TDNN BELOW
MSBFE4: PUSHJ P,IADRCK## ;BUFFER POINTERS MESSED UP?
PJRST ADVSTP ;YES..STOP JOB.
PJRST ADVSTP ;ILLEGAL ADDRESS
EXCTUU <TDNN P1,(T1)> ;END OF THE BUFFER LIST?
JRST [EXCTUU <HRRM T4,(T1)> ;ADD TO END OF FREE LIST
EXCTUU <HLLZS (T4)> ;MAKE THIS BUFFER NEW END
JRST MSBFE5] ;SEE IF MORE BUFFERS
EXCTUX <HRRZ T1,(T1)> ;FOLLOW LINK
SOJG P4,MSBFE4 ;LOOK AT NEXT BUFFER
JRST ADVSTP ;TOO MANY BUFFERS...STOP I/O.
MSBFE5: TRNN T3,-1 ;MORE BUFFERS
JRST ADVST5 ;NO MORE BUFFERS, STOP I/O
;HERE IF THERE ARE MORE BUFFERS IN THE OUTPUT LIST
PUSHJ P,BADRCK## ;CHECK THE ADDRESS OF NEXT BUFFER
JRST ADVSTP ;BAD DO NOT USE FOR I/O
HRRM T3,DEVOAD(P3) ;VALID--STORE IN DDB
PJRST ADVBU1## ;TRY TO WRITE NEXT BUFFER
;HERE TO FORCE A DEVICE TO STOP (BUT WITH MORE DATA TO BE OUTPUT)
ADVSTP: PUSHJ P,RTNEVM## ;GIVE BACK EVM
JRST T3POPJ## ;RESTORE T3 AND RETURN
;HERE TO FORCE A DEVICE TO STOP DUE TO LACK OF DATA
ADVST2: PUSHJ P,RTNEVM## ;RETURN ANY EVM WE HAVE
ADVST5: SETZM DEVOAD(P3) ;NO FIRST BUFFER IN OUTPUT LIST
HRRZS DEVBUF(P3) ;NOR LAST BUFFER IN OUTPUT LIST
JRST T3POPJ## ;RESTORE T3, TAKE STOP I/O RETURN
SUBTTL IN UUO
;HERE FROM UUOCON ON INPUT UUO
MSGIN: PUSHJ P,SAVE4## ;SAVE P1-P4 SINCE WE USE THEM
PUSHJ P,MPXTBL ;GET DEVICES GOING AGAIN IF IN TROUBLE
MSGIN0: MOVE P2,F ;ADDRESS OF MPX DDB
HLRZ P4,DEVXTR(P2) ;ADDRESS OF CDT
JUMPE P4,NDCERR ;JUMP IF NO DEVICES CONNECTED
HRRZ P1,DEVXTR(P2) ;NUMBER OF DEVICES
ADD P4,P1 ;END OF THE CDT
AOS P3,DEVCID(P2) ;POINTER TO THE NEXT INPUT DEVICE IN THE CDT
MSGIN1: CAML P3,P4 ;BEYOND THE END OF THE CDT?
HLRZ P3,DEVXTR(P2) ;YES, GET THE ADDRESS OF THE START OF THE CDT
MOVEM P3,DEVCID(P2) ;STORE NEW CURRENT INPUT DEVICE POINTER
SOJL P1,MSGIN3 ;JUMP IF ALL INPUT DEVICES HAVE BEEN POLLED
HRRZ F,1(P3) ;ADDRESS OF THE TARGET DDB
MOVE S,DEVIOS(F) ;PICK UP STATUS FLAG
LDB T1,PDVTYP## ;GET DEVICE TYPE
CAIG T1,TYPMAX ;SKIP IF TOO BIG
PUSHJ P,ITSTAB(T1) ;SEE IF INPUT IS AVAILABLE
MSGIN2: AOJA P3,MSGIN1 ;LOOP IF NO INPUT TO BE HAD
MOVE T1,DEVCHR(F) ;DEVICE CURRENTLY OFF LINE?
TLNN T1,DVOFLN ;IF SO, DON'T CONSIDER IT IN POLLING SEQUENCE
TRNE S,IOACT ;SKIP IF NOT ACTIVE
JRST MSGIN2 ;ACTIVE--IGNORE FOR NOW AND KEEP LOOKING
MOVE T4,DEVIAD(P2) ;COPY ADDRESS OF THIS BUFFER
DPB T4,PDVIAD## ; INTO TARGET DDB
EXCTUU <SETZM 1(T4)> ;CLEAR WORD COUNT IN THE BUFFER HEADER
IFN FTMP,<
PUSHJ P,SETCPF## ;GET ON CORRECT CPU
>
MOVEI T1,CALIN## ;ROUTINE TO CALL
PUSHJ P,CALSER ;CALL SERVICE ROUTINE TO FILL 1 BUFFER
JFCL ;IGNORE SKIP/NONSKIP
HLRZ T1,1(P3) ;PICK UP THE UDX
HRRZ T2,DEVIAD(P2) ;GET UVA OF INPUT BUFFER
EXCTUU <SKIPN 1(T2)> ;IF THE SERVICE ROUTINE DON'T PUT ANYTHING
JRST MSGIN1 ; IN THE BUFFER, DONT' RETURN IT EMPTY
EXCTUU <HRLM T1,1(T2)> ;STORE IN BUFFER
MOVE F,P2 ;SETUP F TO POINT TO MPX DDB
PUSHJ P,ADVBFF## ;ADVANCE BUFFERS
JFCL
POPJ P,0 ;RETURN TO UUOCON
MSGIN3: MOVE F,P2 ;SETUP F
MOVEI T1,DEPAIO ;ASYNCHRONOUS I/O
TDNE T1,DEVAIO(F) ; ..
POPJ P,0 ;YES--RETURN
MOVEI T1,^D1 ;NO--WAIT FOR A BUFFER TO BE READY
PUSHJ P,SLEEPF## ; ..
JRST MSGIN0 ; ..
DEFINE ITEST(A),<
REPEAT TYPMAX+1,<
POPJ P,0
>
IRP A,<
RELOC <.TY'A/.TYEST>+ITSTAB
PJRST IT$'A
RELOC
>>
ITSTAB: ITEST <TTY,PTY,RDA,CDR>
;SUBROUTINE TO DETERMINE IF A TTY OR PTY DDB WILL GO INTO INPUT WAIT
;CALL WITH:
; MOVEI F,ADDRESS-OF-TTY-DDB
; PUSHJ P,IT$TTY
; RETURN HERE IF NOTHING TO READ
; RETURN HERE IF 1 FULL LINE (AT LEAST)
;
IT$PTY: LDB U,PUNIT## ;GET PTY NUMBER
ADDI U,PTYOFS## ;ADD IN MAGIC OFFSET
MOVE U,LINTAB##(U) ;GET LDB ADDRESS
PJRST TOPSOP## ;CHECK IF OUTPUT IS PRESENT
IT$TTY: SE1ENT ;ENTER SECTION 1
MOVE U,DDBLDB##(F) ;GET ADDRESS OF LDB
JUMPE U,CPOPJ## ;PUNT IF NO LDB
SKIPLE LDBBKC##(U) ;IS THERE A LINE?
JRST CPOPJ1## ;YES--RETURN TO INPUT
PJRST TTLCHK## ;NO--DO BETTER TEST
IT$RDA==:NTDIDA## ;CHECK FOR INPUT.
IT$CDR==:NTDIDA##
;SUBROUTINE TO SEE IF IOACT IS ON FOR ANY MPX DEVICE
;CALL WITH:
; F = MPX DDB
; PUSHJ P,MPXACT
; RETURN HERE IF IO ACTIVE
; RETURN HERE IF NOT ACTIVE
MPXACT::PUSHJ P,SAVE4## ;WE MUST RESPECT ALL AC'S
HLRZ P4,DEVXTR(F) ;PICK UP CDT POINTER
JUMPE P4,CPOPJ1## ;JUMP IF NO DEVICES CONNECTED
HLRZ P1,CDTSIZ(P4) ;GET TOTAL SIZE
SUB P1,CDTFRE(P4) ;LESS FREE SLOTS
MOVNI P1,-1(P1) ;MAKE NEGATIVE
JUMPE P1,CPOPJ1## ;DONE NOW IF CDT EMPTY
HRL P1,P1 ;PUT IN LH
HRRI P1,1(P4) ;POINTER TO CDT
MPXAC1: MOVEI P2,IOACT ;SET UP ACTIVE BIT
MOVE P3,(P1) ;GET POINTER TO DDB
TDNN P2,DEVIOS(P3) ;SKIP IF IOACT ON
AOBJN P1,.-2 ;LOOK AT NEXT DEVICE
JUMPGE P1,CPOPJ1## ;NO ACTIVE DEVICES
MOVSI P2,DVTTY ;ACTIVE IS IT A TTY?
TDNN P2,DEVMOD(P3) ; ..
POPJ P,0 ;FAIL--AT LEAST 1 ACTIVE DEVICE
AOBJN P1,MPXAC1 ;NO--KEEP LOOKING
PJRST CPOPJ1## ;NO ACTIVE DEVICES
;SUBROUTINE TO SEE IF IOW IS ON FOR THE MPX DDB
;CALL WITH F = DDB
; PUSHJ P,MPXIOD
; RETURN HERE IF MPX DOESN'T HAVE IOW ON
; RETURN HERE IF IOW WAS ON (CLEAR IT)
MPXIOD::PUSHJ P,SAVE2##
MOVEI P1,DEPMSG ;MPX-CONTROLLED DDB?
TDNN P1,DEVMSG(F)
POPJ P, ;NO, NON-SKIP
HRRZ P1,DEVXTR(F) ;YES, GET MPX ADR
JUMPE P1,CPOPJ##
MOVE P2,DEVIOS(P1) ;IOS
TLZN P2,IOW ;WAITING?
POPJ P, ;NO-RETURN
MOVEM P2,DEVIOS(P1) ;YES, SAVE NEW STATE
PJRST CPOPJ1## ;AND SKIP-RETURN
SUBTTL SUBROUTINES
;SUBROUTINE TO FIND A DDB EITHER IN THE CDT OR BASED ON DEVICE NAME
;CALL WITH:
; T1=UDX OR DEVICE NAME
; P2=ADDRESS OF THE MPX DDB
; PUSHJ P,FNDDDB
; NO SUCH DEVICE
; RETURN HERE DDB ADDRESS IN F
FNDDDB: TLNE T1,-1 ;A UDX?
PJRST DVCNSG## ;NO, SEARCH FOR A DEVICE
PUSHJ P,SAVE4## ;SAVE ACS
HLRZ P4,DEVXTR(P2) ;CDT
JUMPE P4,CPOPJ## ;ERROR IF THERE ISN'T ONE
;FALL INTO FNDUDX
;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE
;SUBROUTINE TO FIND A UDX IN A CDT
;CALL WITH:
; P4 = ADDRESS OF CDT
; T1 = UDX TO LOOK FOR
; PUSHJ P,FNDUDX
; UDX NOT IN CDT
; RETURN HERE DDB ADDRESS IN F
;
;AC USAGE IN FNDUDX:
;P1 = LOWER LIMIT P2 = UPPER LIMIT P3 = INCREMENT
;T2 = TEMP FOR ADDRESS CALCULATION T3 = UDX FROM TABLE FOR COMPARISON
CAIA ;ENTER HERE FROM FNDDDB WITH P?S SAVED
FNDUDX: PUSHJ P,SAVE3## ;SAVE P1 THRU P3
MOVEI P1,1 ;INDEX OF FIRST ENTRY IN CDT
HLRZ P2,CDTSIZ(P4) ;SIZE
SUB P2,CDTFRE(P4) ;MINUS FREE IS INDEX OF LAST ENTRY
FNUDX1: CAILE P1,(P2) ;IS LOWER LIMIT LESS THAN OR
; EQUAL TO UPPER LIMIT?
POPJ P,0 ;NO--UDX IS NOT IN CDT
;COMPUTE MID POINT IN RELEVANT RANGE
MOVEI P3,1(P1) ;LOWER LIMIT (+1 FOR ROUNDING)
ADDI P3,(P2) ;PLUS UPPER LIMIT
LSH P3,-1 ;DIVIDED BY TWO
MOVEI T2,(P4) ;BASE OF TABLE
ADDI T2,(P3) ;PLUS INDEX GIVE ADDRESS OF ENTRY
HLRZ T3,(T2) ;PICK UP THE UDX
JUMPE T3,FNUDX3 ;THE BEST ALGORITHMS NEED A FUDGE
CAMGE T3,T1 ;THE COMPARE
JRST FNUDX2 ;TRY LOWER HALF OF TABLE
CAMN T3,T1 ;IS THIS THE ENTRY?
JRST [HRRZ F,(T2) ;YES--PICK UP DATA
JRST CPOPJ1##] ;GIVE GOOD RETURN
FNUDX3: MOVEI P2,-1(P3) ;SET NEW UPPER LIMIT
JRST FNUDX1 ;TRY AGAIN
;HERE IF ENTRY IS TOO SMALL
FNUDX2: MOVEI P1,1(P3) ;BOOST UP THE LOWER LIMIT
JRST FNUDX1 ;TRY AGAIN
;SUBROUTINE TO CALL A SERVICE ROUTINE VIA UUOCON
;CALL WITH:
; T1 = ADDRESS OF ROUTINE TO CALL
; F = A DDB ADDRESS
; PUSHJ P,CALSER
; RETURN HERE
; OR HERE
CALSER: PUSHJ P,SAVE4## ;SAVE P1 THRU P4
MOVE P1,T1
PUSHJ P,JDAADR##
PUSH P,USRHCU## ;SAVE THIS
PUSH P,0(T1) ;AND THIS
HLL F,DEVXTR(F) ;PICK UP FLAGS
MOVE S,DEVIOS(F) ;ALWAYS NICE TO HAVE S SET UP
PUSHJ P,(P1) ;CALL ROUTINE
SOS -2(P) ;NON-SKIP
PUSHJ P,JDAADR##
HLL F,0(T1) ;GET UPDATED FLAGS
HLLM F,DEVXTR(F) ;STORE BACK IN DDB
POP P,0(T1) ;RESTORE JUNK
POP P,USRHCU## ; ..
HRRZ P1,DEVXTR(F) ;P1 POINTS TO THE MPX DDB
MOVSI P2,IOSTBL ;DEVICE OFF-LINE BIT
TDNE P2,DEVIOS(F) ;TROUBLE ON THE TARGET DEVICE?
IORM P2,DEVIOS(P1) ;YES, SET TROUBLE IN THE MPX DBB
JRST CPOPJ1## ;RETURN (SKIP MAY HAVE BEEN UNDONE)
SUBTTL ERROR ROUTINES
NDCERR: JSP T1,ERRPTU## ;PRINT MESSAGE
ASCIZ \I/O with no devices connected for \
PJRST DEVEXC## ;SAY DEVICE XXX
NCDERR: PUSH P,T1 ;SAVE UDX
PUSHJ P,DVCNSG## ;FIND REAL DDB
SKIPA T2,[SIXBIT .(NONE).] ;NO SUCH DEVICE NAME
MOVE T2,DEVNAM(F) ;REAL DEVICE NAME
PUSH P,T2 ;SAVE NAME
JSP T1,ERRPTU## ;PRINT MESSAGE
ASCIZ /Output to unconnected device [/
MOVE T2,-2(P) ;PICKUP NAME
PUSHJ P,PRNAME## ;PRINT IT
PUSHJ P,INLMES## ;ADD SOME WORDS
ASCIZ \] UDX=\
MOVE T1,-3(P) ;PICKUP UDX
PUSHJ P,PRTDI8## ;PRINT UDX
SUB P,[2,,2] ;REMOVE TWO ITEMS FROM THE STACK
PJRST UUOPCP## ;PRINT PC AND STOP JOB
END