1
0
mirror of https://github.com/PDP-10/stacken.git synced 2026-02-15 12:16:07 +00:00
Files
PDP-10.stacken/files/stacken-tape-backup/dskb:10_7/mon/mpxser.mac
Lars Brinkhoff 6e18f5ebef Extract files from tape images.
Some tapes could not be extracted.
2021-01-29 10:47:33 +01:00

1488 lines
49 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
TITLE MPXSER - SERVICE FOR DEVICE MPX: AND RELATED FUNCTIONS V157
SUBTTL DONALD A. LEWINE 21-JUNE-88
SEARCH F,S,DEVPRM
IFN FTNET,<SEARCH NETPRM>
$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==<<CDTQNT+3>/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,<DR.SFT>)
.ORG DEVLEN
MPXLEN:! ;LENGTH OF MPX DDB
.ORG
$LOW
MPXDDB: DDBBEG (MPX,MPXLEN)
SETWRD (DEVCHR,<103>) ;DEVCHR
SETWRD (DEVSER,<MCSEC0+MPXDSP>) ;DEVSER
SETWRD (DEVMOD,<DVIN!DVOUT!DVLNG,,14407>) ;DEVMOD
SETWRD (DEVTYP,<<.TYMPX*.TYEST>,,DEPEVM>) ;DEVTYP
SETWRD (DEVCPU,<707B8>) ;DEVCPU
DDBEND
$HIGH
EQUATE (LOCAL,0,<MPXCKT,MPXKDB,MPXKLN,MPXUDB,MPXULN>)
EQUATE (LOCAL,0,<MPXICD,MPXICL,MPXINT,MPXULB,MPXULP>)
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<DEVTYP> IS = 1
DEFINE TYPBTS(A),<
IRP A,<
ZZ..=ZZ..!1B<.TY'A>
>>
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 ;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,<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 ;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 <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 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 <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+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
MPXEND: END