Trailing-Edge
-
PDP-10 Archives
-
dec-10-omona-u-mc9
-
msgser.mac
There are 5 other files named msgser.mac in the archive. Click here to see a list.
TITLE MSGSER - SERVICE FOR DEVICE MPX: AND RELATED FUNCTIONS V074
SUBTTL DONALD A. LEWINE 01 MAR 77
SEARCH F,S
$RELOC
$HIGH
;***COPYRIGHT 1973,1974,1975,1976,1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***
XP VMSGSR,074
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
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
XWD R,0 ;DEVIAD.
XWD R,0 ;DEVOAD.
EXP 0 ;DEVSTS. DEVSTS FROM CONTROLED
; 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 ;DEVECE.
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
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: POPJ P,0 ;RELEASE
POPJ P,0 ;CLOSE
POPJ P,0 ;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.
HLRZ T1,M ;WANT TO WIN ONLY FOR
ANDI T1,777000 ; AN OPEN UUO
CAIE T1,(OPEN)
POPJ P,0 ;NOPE. ERROR RETURN
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
BLT T1,MPXLEN-1(F) ; ..
HRLM F,MPXDDB+DEVSER ;SET THE LINKS
IFN FTTRACKS,<
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
> ;END OF FTTRACK
JRST CPOPJ1## ;GOOD RETURN
IFN FTTRACKS,<
$LOW
MPXNUM: EXP 0 ;DDB SERIAL NUMBER
MPX6NM: SIXBIT '000000' ;SAME THING IN SIXBIT
$HIGH
> ;END FTTRACKS
;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,SAVE4## ;SAVE THE P'S
ZAPTST: HRRZ P4,DEVXTR(F) ;ANY DEVICES CONNECTED?
JUMPE P4,ZPMPX1 ;NO--KILL OF 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
MOVEI P1,RELEAC## ;UNCONDITIONAL DISCONNECT
PUSHJ P,DISCON ;REMOVE THE CONNECTION
STOPCD CPOPJ##,JOB,CDD, ;++CAN'T DISCONNECT DEVICE
MOVE F,P2 ;RESTORE F
JRST ZAPTST ;SEE IF ANY DEVICES CONNECTED
ZPMPX1: HLRZ T2,DEVXTR(F) ;ADDRESS OF CDT
HLRZ T1,CDTSIZ(T2) ;SIZE OF CDT
SKIPE T2 ;SKIP IF NO CDT
PUSHJ P,GIVWDS## ;RETURN THE CORE
MOVEI T1,MPXDDB ;ADDRESS OF PROTO
ZPMPX2: 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 ZPMPX2 ;NO--KEEP LOOKING
MOVE T3,DEVSER(F) ;UNLINK THE DDB
HLLM T3,DEVSER(T2) ; ..
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: STOPCD CPOPJ##,JOB,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
CAMG P1,USRHCU## ;SKIP IF TOO BIG
SKIPN P2,USRJDA##(P1) ;SKIP IF OPEN
PJRST ECOD6## ;ELSE GENERATE ERROR
MOVE F,P2 ;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
HLRZ T1,T1 ;COPY FUNCTION
CAILE T1,CNFNMX ;SKIP IF NOT TOO BIG
PJRST ECOD10## ;ERROR 10 -- INVALID FUNCTION
JRST @CNFNTB(T1) ;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
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
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,RELEA9## ;YES--KILL THE DDB
PJRST ECOD12##]; AND GIVE ERROR RETURN
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,RELEA9## ;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,RELEA9## ;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,R ;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
MOVSI T2,DVTTY ;IF THIS IS A TTY
TDNE T2,DEVMOD(P3) ; CLEAR ANY LEFTOVER OUTPUT
SETZM DEVSTS(P3) ; AT CONNECT TIME
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?
CAME 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,RELEAC## ;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 RELEA2##] ;RELEASE AND CLOSE
UDCDEV: MOVEI P1,RELEAC## ;RESET
PUSHJ P,GETWD1## ;PICK UP DEVICE NAME
PUSHJ P,FNDDDB ;FIND DEVICE DATA BLOCK
JRST ECOD2## ;MUST BE VALID DEVICE
;FALL INTO DISCON
;SUBROUTINE TO DISCONNECT A DEVICE
;CALLED WITH:
; F = ADDRESS OF DDB
; P1 = ADDRESS OF ROUTINE TO CALL (RELEAC)
; P2 = ADDRESS OF MPX DDB
; PUSHJ P,DISCON
; RETURN HERE ON ERROR (USER AC UPDATED)
; RETURN HERE IF OK
DISCON:
IFN FTVM,<
HLR M,DEVBUF(P2) ;ADDRESS OF THE RING HEADER
TRNE M,-1 ;GO IF NONE
PUSHJ P,VMCHEK ;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
TLZ F,-1 ;FOR CAIN
DCNDVL: MOVE T4,(T2) ;GET AN ENTRY
CAIN F,(T4) ;IS THIS THE ONE TO ZAP?
AOJA T2,DCNDVL ;YES--GET THE NEXT ENTRY
MOVEM T4,(T3) ;STORE BACK ENTRY
ADDI T2,1 ;UPDATE SOURCE
ADDI T3,1 ;UPDATE DESTINATION
SOJG T1,DCNDVL ;MOVE THE WHOLE CDT DOWN
CAIN T2,(T3) ;DID WE FIND AN ENTRY?
JRST ECOD5## ;NO--DEVICE NOT CONNECTED
CAIN P1,RELEAC## ;UNCONDITIONAL DISCONNECT?
PUSHJ P,RTNOB ;YES, RETURN BUFFERS TO FREE LIST
SETZM -1(T3) ;ZERO ZAPPED ENTRY
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
;PRESERVES ALL ACS
RTNOB: PUSHJ P,SAVT## ;SAVE T ACS
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
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
AOS P1,M ;WHERE TO PUT ERROR COUNT
MOVEI P2,0 ;ERROR COUNT
HLRZ P3,T1 ;NUMBER OF WORDS IN BLOCK
TLZ T1,-1 ;CLEAR JUNK
CAMG T1,USRHCU## ;SKIP IF BOGUS CHAN #
SKIPN F,USRJDA##(T1) ;SKIP IF OPEN
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
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,JOB## ;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 UUOCON ON WAIT UUO FOR DEVICE MPX
MPXWAT::PUSHJ P,SAVE3## ;SAVE P1-P3
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,WAIT1## ;WAIT FOR I/O TO STOP ON THAT DEVICE
PUSHJ P,CALSER ;CALL WAIT1
JRST MPXWA1 ;CHECK NEXT DEVICE
MPXWA2: MOVE F,P3 ;RESTORE ADDRESS OF MPX DDB
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?
POPJ P, ;NO, ALL IS WELL
MOVEI T1,^D10 ;YES, SLEEP A WHILE
MOVE J,.C0JOB## ;CURRENT JOB'S JOB NUMBER
PUSHJ P,SLEEP## ;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 ;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
HRRZ T1,DEVOAD(F) ;ADDRESS OF CURRENT OUTPUT BUFFER
PUSHJ P,UADRCK## ;CHECK THAT THE BUFFER IS OK
IFN FTVM,<
PUSHJ P,BRNGE## ;MAKE SURE THAT THE ENTIRE BUFFER IS IN CORE
>
MOVSI S,IOSTBL ;CLEAR THE TROUBLE BIT
ANDCAB S,DEVIOS(F) ; AND SETUP S
MOVEI T1,CALOUT## ;ROUTINE TO CALL
TRNN S,IOACT ;DON'T CALL SERVICE ROUTINE IF I/O IS ACTIVE
PUSHJ P,CALSER ;CALL THE DEVICE ROUTINE TO START UP THE IO
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
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
LDB P1,PUUOAC## ;SETUP UUO PROGRESS FLAGS
HLL P2,USRJDA##(P1) ; 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
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
IFN FTVM,< ;IF VM MONITOR
HRR M,T1 ;SETUP M FOR VMCHEK
PUSHJ P,VMCHEK ;CHECK ALL BUFFERS ARE IN CORE
> ;END FTVM
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
IFN FTKA10,<
ADDI T1,(R) ;RELOCATE BUFFER HEADER ADDR
ADDI T2,(R) ;AND 1ST BUFFER ADDR
> ;END FTKA10
CONO PI,PIOFF## ;PREVENT RACES
EXCTUX <HRRZ T3,(T2)> ;GET POINTER TO NEXT BUFFER
EXCTXU <MOVEM T3,(T1)> ;AND STORE IT IN HEADER
CONO PI,PION## ;ALLOW IME STOPCDS
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
JUMPE T1,NEWOBF ;JUMP IF DEVICE IDLE
PUSHJ P,UADRCK## ;ADDRESS CHECK LAST BUFFER
IFN FTKA10,<
TLO T1,R ;RELOCATE
>
CONO PI,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
CONO PI,PION##
STOUTP: MOVE F,P3 ;ADDRESS OF TARGET DDB
MOVSI S,IOSTBL ;MAGIC SYNC BIT
ANDCAB S,DEVIOS(F) ;CLEAR (ALSO LOAD UP S)
MOVEI T1,CALOUT## ;CALL CALOUT VIA CALSER
TRNN S,IOACT ;IS DEVICE ACTIVE?
PUSHJ P,CALSER ;NO--CALL SERVICE ROUTINE VIA UUOCON
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
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:
IFN FTVM,<
HLR M,DEVBUF(P2) ;ADDRESS OF RING HEADER
PUSHJ P,VMCHEK ;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
LDB P1,PUUOAC## ;MAKE SURE THAT THE MAGIC
MOVSI T2,OUTBFB ; UUO PROGRESS BIT IS
IORM T2,USRJDA##(P1) ; SET FOR THIS CHANNEL
;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
IFN FTKA10,<
TLO U,R ;SET UP RELOCATION FOR KA
> ;END FTKA10
SOJA J,IOSETC## ;STORE BYTE COUNT AND RETURN
IFN FTVM,<
;SUBROUTINE TO MAKE SURE ALL BUFFERS ARE IN CORE
;CALL WITH:
; M = ADDRESS-OF-FIRST-BUFFER
; PUSHJ P,VMCHEK
; RETURN HERE IF ALL OK
;
VMCHEK: PUSHJ P,SAVE1## ;SAVE P1
PUSH P,T1 ;SAVE T1
MOVEI P1,^D10000 ;DEFEND AGAINST LOOPS
VMCHK1: PUSHJ P,GETWRD## ;GET LINK WORD
JRST ADRERR## ;ADDRESS CHECK
HRR M,T1 ;COPY LINK
TRNE M,-1 ;END OF LIST?
SOJGE P1,VMCHK1 ;NO--KEEP LOOKING
JUMPL P1,ADRERR## ;LIST MESSED UP
;WE HAVE JUST TOUCHED EVERY BUFFER IN THE FREE LIST.
HRR M,DEVOAD(P3) ;START OF ACTIVE LIST
SKIPN DEVEVM(P3) ;SKIP IF ALREADY MAPPED IN EVM
TRNN M,-1 ;SKIP IF LIST EXISTS
JRST TPOPJ## ;RETURN--NO BUFFERS OR ALREADY MAPPED
MOVEI P1,^D10000 ;LOOP COUNT
VMCHK2: PUSHJ P,GETWRD## ;LOOK AT THE BUFFER
JRST ADRERR## ;ADDRESS CHECK
HRR M,T1 ;LINK TO NEXT BUFFER
TRNE M,-1 ;END OF LIST?
SOJGE P1,VMCHK2 ;NO--KEEP LOOKING
JUMPL P1,ADRERR## ;ADDRESS CHECK
JRST TPOPJ## ;ALL OK
>
;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
;
;IF THE DEVICE WANTS THE COUNT IN WORDS NOT BYTES THE BYTE COUNT
; IS CONVERTED TO A WORD COUNT.
STOCNT: PUSHJ P,SAVE1## ;SAVE P1
PUSHJ P,GETWD1## ;PICK UP THE BYTE POINTER
SUBI M,1 ;DO NOT CHANGE M
MOVE P1,T1 ;SAVE POINTER IN P1
MOVE S,DEVIOS(P2) ;PICK UP IOS WORD
TRNE S,IOWC ;DID USER COMPUTE WORD COUNT
JRST STOCT1 ;YES--GO CONVERT TO WORDS
SUBI T1,1(U) ;GET THE WORD COUNT
HRRE T1,T1 ;FILL LH WITH SIGN BITS (0 I HOPE)
PUSH P,M ;SAVE M A MOMENT
HRRI M,1(U) ;STORE COUNT IN BUFFER
PUSHJ P,PUTWDU## ;STORE UPDATED COUNT
PJRST MPOPJ## ;RESTORE M
;AND RETURN
STOCT1: PUSH P,M ;SAVE M
HRRI M,1(U) ;PICK UP ADDRESS OF BUFFER
PUSHJ P,GETWDU## ;GET THE WORD COUNT
PJRST MPOPJ## ;RESTORE M
;AND RETURN
;
;SUBROUTINE CALL WHEN AN OUTPUT BUFFER IS EMPTY
;CALLED WITH:
; 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
IFN FTKI10!FTKL10,<
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
MOVE T3,(T4)
HLRZ T1,DEVBUF(P2) ;POINTER TO THE HEAD OF FREE LIST
MOVEI P4,^D10000
MOVEI P1,-1 ;IF THERE IS NO FREE BUFFER LIST
MSBFE1: PUSHJ P,IADRCK## ;MAKE SURE POINTER IS LEGAL
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: TRNE T3,-1 ;SKIP IF THERE IS NO NEXT BUFFER
JRST MSBFE3 ;MORE EMPTY BUFFERS
HRRZS DEVBUF(P3) ;NO BUFFERS IN OUTPUT LIST
JRST ADVSTP ;ELSE STOP THE I/O
;HERE IF THERE ARE MORE BUFFERS IN THE OUTPUT LIST
MSBFE3: 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
> ;END FTKI10
NOOEVM:
IFN FTKA10,<
MOVEI T4,@DEVOAD(P3) ;EXEC ADDRESS OF BUFFER IF KA10
>
IFN FTKI10!FTKL10,<
HRRZ T4,DEVOAD(P3) ;USER VIRT ADDRESS IF KI10
>
EXCTUU <MOVEM S,-1(T4)>;STORE UPDATED STATUS BITS
HLRZ T1,DEVBUF(P2) ;ADDRESS OF FREE LIST
EXCTUX <MOVE T3,(T4)>
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.
IFN FTKA10,<
ADDI T1,(R) ;RELOCATE IF KA10
> ;END FTKA10
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: TRNE T3,-1 ;MORE BUFFERS
JRST MSBFE6 ;YES--GO ADDRESS CHECK IT
HRRZS DEVBUF(P3) ;NO--MARK LIST AS EMPTY
JRST ADVSTP ;AND STOP I/O
MSBFE6: 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
ADVSTP: PUSHJ P,RTNEVM## ;GIVE BACK EVM
JRST T3POPJ## ;RESTORE T3 AND 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
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 S,DEVIOS(F) ;PICK UP STATUS FLAGS
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
MOVEI T1,CALIN## ;ROUTINE TO CALL
PUSHJ P,CALSER ;CALL SERVICE ROUTINE TO FILL 1 BUFFER
HLRZ T1,1(P3) ;PICK UP THE UDX
IFN FTKA10,<
MOVEI T2,@DEVIAD(P2) ;EXEC ADDRESS OF BUFFER IF KA10
>
IFN FTKI10!FTKL10,<
HRRZ T2,DEVIAD(P2) ;GET UVA OF INPUT BUFFER
>
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,SLEEP## ; ..
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
SKIPLE LDBTOC##(U) ;ANYTHING THERE?
JRST CPOPJ1## ;YES--SKIP RETURN
POPJ P, ;NO--NON SKIP RETURN
IT$TTY: HRRZ U,DDBLDB##(F) ;GET ADDRESS OF LDB
JUMPE U,CPOPJ## ;PUNT IF NO LDB
ITTTY1: HLL U,LDBDCH##(U) ;GET DEVICE BITS
SKIPLE LDBBKC##(U) ;IS THERE A LINE?
JRST CPOPJ1## ;YES--RETURN TO INPUT
PJRST TTLCHK## ;NO--DO BETTER TEST
IT$RDA==:RDA$IN## ;CHECK FOR INPUT.
IT$CDR==:CDR$IN##
SUBTTL CLOCK1 -- SUBROUTINE TO SEE IF AN MPX USER CAN BE SWAPPED
;SUBROUTINE TO KEEP IOACT IN THE MPX DDB CURRENT (SO CAN CALL IOWAIT)
;CALLED WHENEVER A DEVICE CONTROLLED BY MSGSER CALLS STOIOS
;
MPXIOS::PUSH P,F ;SAVE DDB ADDRESS
PUSH P,S ;SAVE DEVIOS FROM TARGET DDB
HRRZ F,DEVXTR(F) ;GET ADDRESS OF MPX DDB
MOVE S,DEVIOS(F) ;IOS FROM MPX DDB
PUSHJ P,MPXACT ;SEE IF STILL ACTIVE
JRST [PUSHJ P,ACTON ;YES--SET IOACT
JRST .+2] ;RESTORE F AND RETURN
PUSHJ P,ACTOFF ;CLEAR IO ACTIVE
POP P,S ;RESTORE S
JRST FPOPJ## ;RETURN
ACTON: TROA S,IOACT ;IOACT ON
ACTOFF: TRZ S,IOACT ;IOACT OFF
HRRM S,DEVIOS(F) ;PRESERVE STATE OF IOW
PJRST SETHNG## ;SET HUNG TIME AND RETURN
;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
;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
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
LDB P1,PUUOAC## ;PICK UP RANDOM NUMBER
PUSH P,USRHCU## ;SAVE THIS
PUSH P,USRJDA##(P1) ;AND THIS
HLL F,DEVXTR(F) ;PICK UP FLAGS
;** DO NOT CHANGE USRJDA SO THERE IS NOT CHANCE FOR ^C TO LEAVE POINTER
;** TO THE WRONG DDB FLOATING AROUND.
;** MOVEM F,USRJDA##(P1) ;INCASE ANYONE SHOULD LOOK HERE
MOVE S,DEVIOS(F) ;ALWAYS NICE TO HAVE S SET UP
PUSHJ P,(T1) ;CALL ROUTINE
SOS -2(P) ;NON-SKIP
LDB P1,PUUOAC## ;I DO NOT TRUST P1 ALL THAT TIME
HLL F,USRJDA##(P1) ;GET UPDATED FLAGS
HLLM F,DEVXTR(F) ;STORE BACK IN DDB
POP P,USRJDA##(P1) ;RESTORE JUNK
POP P,USRHCU## ; ..
MOVE P1,USRJDA##(P1) ;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