TITLE MPXSER - SERVICE FOR DEVICE MPX: AND RELATED FUNCTIONS V157 SUBTTL DONALD A. LEWINE 21-JUNE-88 SEARCH F,S,DEVPRM IFN FTNET, $RELOC $HIGH ;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED ; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION ; 1973,1974,1975,1976,1977,1978,1979,1980,1982,1984,1986,1988. ;ALL RIGHTS RESERVED. .CPYRT<1973,1988> XP VMSGSR,157 MPXSER::ENTRY MPXSER ;AC USAGE WITHIN MPXSER: ; ;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==</4> ;NUMBER OF 4 WORD BLOCKS IN A CDT QUANTUM CDTQNT==CDT4WD*4 ;REDEFINE SO LOW 2 BITS ARE ALWAYS ZERO ;DEVICE DEPENDENT BITS IN DEVIOS MPXVMF==1B0 ;ON IF A DEVICE IS IN TROUBLE AND THE OUTPUT ; BUFFER IS PAGED OUT SUBTTL AUTOCONFIGURE ;DRIVER CHARARCTERISTICS ; MPX = MPXCNF ; MPX = MULTIPLEXED CHANNEL ; 0 = MAXIMUM DEVICES IN SYSTEM ; 0 = KONTROLLER TYPE ; 0 = MAXIMUM DRIVES PER KONTROLLER ; 0 = HIGHEST DRIVE NUMBER ON KONTROLLER ; MDSEC0 = SECTION FOR KDB/UDB ; MDSEC0 = SECTION FOR DDB DRVCHR (MPX,MPX,0,0,0,0,MDSEC0,MDSEC0,) .ORG DEVLEN MPXLEN:! ;LENGTH OF MPX DDB .ORG $LOW MPXDDB: DDBBEG (MPX,MPXLEN) SETWRD (DEVCHR,<103>) ;DEVCHR SETWRD (DEVSER,) ;DEVSER SETWRD (DEVMOD,) ;DEVMOD SETWRD (DEVTYP,<<.TYMPX*.TYEST>,,DEPEVM>) ;DEVTYP SETWRD (DEVCPU,<707B8>) ;DEVCPU DDBEND $HIGH EQUATE (LOCAL,0,) EQUATE (LOCAL,0,) MPDDSP: DRVDSP (MPX,,MPXDDB,MPXLEN,0) $HIGH MPXCFG: SKIPGE MPXNUM ;INITIALIZED YET? SETZM MPXNUM ;INIT DDB SERIAL NUMBER POPJ P, ;FOR NOW ;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: SE1ENT ;ENTER SECTION ONE PUSHJ P,AUTLOK## ;INTERLOCK AUTCON POPJ P, ;BUSY & INTERRUPT LEVEL?? PUSHJ P,SAVT## ;SAVE T2 THRU T4 SETZB T1,T3 ;NO DEVICE CODE, NO CHANNEL DATA BLOCK XMOVEI T2,MPDDSP ;DRIVER DISPATCH PUSHJ P,AUTSET## ;RESET THINGS AOS T1,MPXNUM ;NUMBER OF CALLS TO TSTMPX HRLI T1,'MPX' ;INCLUDE GENERIC DEVICE NAME SETZ T2, ;LOCAL DEVICE PUSHJ P,AUTDDB## ;CREATE A DDB POPJ P, ;NO MORE CORE PUSHJ P,AUTULK## ;RELEASE INTERLOCK JRST CPOPJ1## ;GOOD RETURN $LOW MPXNUM: EXP -1 ;DDB SERIAL NUMBER $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,MPXLEN ;DDB LENGTH MOVEI T2,(F) ;DDB ADDRESS PJRST AUTKIL## ;DELETE THE DDB 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 ;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 JRST [POP P,J ;PHASE STACK JRST ECOD11##] ;DEVICE NOT INITIED OR CONNECTED SKIPGE DEVSPL(F) ;SPOOLED DEVICE? JRST [PUSHJ P,RELEA4## ;YES--KILL THE DDB POP P,J ;RESTORE J JRST ECOD12##] ;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 MPXSER 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 IS = 1 DEFINE TYPBTS(A),< IRP A,< ZZ..=ZZ..!1B<.TY'A> >> ZZ..==0 TYPBTS 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 ;TTY? JRST CPOPJ1## ;YES--ALWAYS GOOD IFN FTNET,< CAIE T2,.TYCDR ;A CDR? JRST LGLMP1 ;NO LDB T3,PDVSTA## ;YES, LOCAL? CAME T3,JBTLOC## 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,SETCPP## ;GET ON CORRECT CPU FOR DEVICE JRST ECOD11## ;CPU DEAD, SAY DEVICE UNAVAILABLE > ;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 MPXSER 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,CDTQNT ;NUMBER OF WORDS TO GET PUSHJ P,GETWDS## ; .. 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 ADDI T2,CDTQNT ;PLUS AMOUNT TO EXPAND PUSHJ P,GETWDS## ;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 ;A TTY? JRST OFEDE2 ;NO PUSHJ P,TTYOFE## ;YES, ASK SCNSER'S OPINION JRST OFEDE5 ;AND FORGET THE DATA REQUEST COUNT OFEDE2: IFE FTNET, ;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 ;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 ; MPXSER, 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 ;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 ;GET POINTER TO NEXT BUFFER EXCTXU ;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 ;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 ;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 ;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 MPXSER'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 JRST [HLL T2,DEVEVM(P3) ;GET THE USER VIRT ADDR OF THIS BUFFER EXCTUU ;STORE THE POINTER IN PREVIOUS BUFFER HLLZS (T4) ;MARK END OF LIST JRST MSBFE2] ;LOOK FOR MORE BUFFERS EXCTUX ;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 ;STORE UPDATED STATUS BITS MOVSI T3,IOUSE ;THE BUFFER-IS-FULL BIT EXCTUX ;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 ;END OF THE BUFFER LIST? JRST [EXCTUU ;ADD TO END OF FREE LIST EXCTUU ;MAKE THIS BUFFER NEW END JRST MSBFE5] ;SEE IF MORE BUFFERS EXCTUX ;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 ;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 ;IF THE SERVICE ROUTINE DON'T PUT ANYTHING JRST MSGIN1 ; IN THE BUFFER, DONT' RETURN IT EMPTY EXCTUU ;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+ITSTAB PJRST IT$'A RELOC >> ITSTAB: ITEST ;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 MPXEND: END