Trailing-Edge
-
PDP-10 Archives
-
BB-J098B-SB_1980
-
tskser.mac
There are no other files named tskser.mac in the archive.
TITLE TSKSER -TASK TO TASK COMMUNICATION SERVICE ROUTINE - V100
SUBTTL W. E. MATSON/WEM 08 JAN 80
SEARCH F,S,NETPRM
$RELOC
$HIGH
Comment @
End Comment @
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
; COPYRIGHT (C) 1978,1979,1980 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
XP VTSKSER,100 ;PUT VERSION NUMBER IN GLOB AND LOADER MAP
NETTSK::ENTRY NETTSK ;LOADING IF IN LIBRARY SEARCH MODE
;TSK. ERROR CODES
TK%TNL==ECOD1## ; 1 = TSKSER NOT LOADED.
TK%ATS==ECOD2## ; 2 = ARG LIST TOO SHORT
TK%UNP==ECOD3## ; 3 = USER NOT PRIVLEDGED
TK%ILF==ECOD4## ; 4 = ILLEGAL FUNCTION
TK%ILC==ECOD5## ; 5 = ILLEGAL CHANNEL (OR NOT TASK)
TK%ILN==ECOD6## ; 6 = ILLEGAL NPD
TK%NTS==ECOD7## ; 7 = NPD TOO SHORT
TK%ILS==ECOD10## ; 10 = ILLEGAL FUNCTION WHILE IN THIS STATE
TK%NFC==ECOD11## ; 11 = NO MONITOR FREE CORE
TK%NFL==ECOD12## ; 12 = NO FREE LINKS
TK%NXN==ECOD13## ; 13 = ATTEMPT TO CONNECT TO A NONEXISTANT NODE
TK%UDW==ECOD14## ; 14 = UUO (IN OR OUT) DIDN'T SKIP
;TSK. FUNCTION CODES
.TKFRS==1 ; 1 = RETURN STATUS
.TKFEP==2 ; 2 = ENTER PASSIVE STATE
.TKFEA==3 ; 3 = ENTER ACTIVE STATE
.TKFEI==4 ; 4 = ENTER IDLE STATE
.TKFWT==5 ; 5 = WAIT
.TKFOT==6 ; 6 = OUTPUT WITH CONTROL OF TYPE/E-O-R
.TKFIN==7 ; 7 = INPUT WITH NOTIFICATION OF TYPE/E-O-R
;TSK. STATE VALUES
.TKSID==0 ; 0 = LINE IS IDLE
.TKSCI==1 ; 1 = WAITING FOR CONNECT INITIATE
.TKSCC==2 ; 2 = WAITING FOR CONNECT CONFIRM
.TKSOK==3 ; 3 = LINK IS OPERATIONAL
.TKSDC==4 ; 4 = WAITING FOR A DISCONNECT CONFIRM
COMMENT @
The first NPD in the UUO argument list is the Right-hand one (RH(DEVNPD))
The second NPD is the Left-hand one (LH(DEVNPD))
For the passive task.
1) The enter passive state uuo
- NPD1 := Name we wish to be identified as (our process name)
- NPD2 := The "pattern" we wish to match
2) After a successful connection,
- NPD1 := The "actual" that the pattern successfully matched
- NPD2 := The name of the remote process that sent the connect.
For the active task.
1) The enter active state uuo
- NPD1 := The name we want to return as "ours" on the confirm
- NPD2 := The the "actual" we try to connect to.
2) After a successful connection,
- NPD1 := The name the remote thinks we are.
- NPD2 := The name he gave us as "his"
@
TSK.:: PUSHJ P,SAVE4## ;WE USE A LOT OF P'S
HLRZ P4,T1 ;P4 := LENGTH OF ARG LIST
HRRZ P3,T1 ;P3 := ADDRESS OF ARG LIST
CAIGE P4,2 ;MAKE SURE AT LEAST FCN & CHAN ARE THERE
PJRST TK%ATS ;ERROR: ARG LIST TOO SHORT
HRRI M,(P3) ;SET "M" UP TO READ FUNCTION CODE
PUSHJ P,GETWDU## ;READ FUNCTION
SKIPG P2,T1 ;P2 := FUNCTION CODE
PJRST TK%ILF ;ILLEGAL FUNCTION CODE
PUSHJ P,GETWD1## ;GET THE CHANNEL NUMBER
MOVE P1,T1 ;P1 := CHANNEL NUMBER
PUSHJ P,SETUF## ;SET UP F WITH ADDRESS OF DDB
PJRST TK%ILC ;ERROR: ILLEGAL CHANNEL
HRLM P1,.UPMP+.UPCTA ;SET UP THE EXTENDED CHANNEL NUMBER
LDB T1,PDVTYP## ;GET THE DEVICE TYPE
CAIE T1,<.TYTSK/.TYEST> ;MAKE SURE THAT THIS IS A TASK DEVICE
PJRST TK%ILC ;ERROR: ILLEGAL CHANNEL
CAILE P2,TSKMX ;IS THIS A LEGAL FUNCTION CODE
PJRST TK%ILF ;ILLEGAL FUNCTION
JRST @.(P2) ;DISPATCH TO SUBFUNCTION
JRST TSKRS ; 1 = RETURN TASK STATUS
JRST TSKEP ; 2 = ENTER PASSIVE TASK STATE
JRST TSKEA ; 3 = ENTER ACTIVE TASK STATE
JRST TSKEI ; 4 = ENTER IDLE TASK STATE
JRST TSKWT ; 5 = WAIT FOR CONNECT INITIATE/CONFIRM/REJECT
JRST TSKOU ; 6 = OUT WITH CONTROL OF E-O-R.
JRST TSKIN ; 7 = IN WITH NOTIFICATION OF E-O-R.
TSKMX=7 ; 7 = MAXIMUM LEGAL FUNCTION.
;SUB-FUNCTION #1 = RETURN STATUS
TSKRS: PUSHJ P,GETSTA ;GET THE CONNECTION STATE
CAIGE P4,3 ;IF WE CAN'T STORE THE STATUS
JRST TK%ATS ;ERROR: ARG LIST TOO SHORT
HRRI M,2(P3) ;GET THE ADDRESS OF THE RETURN VALUE AREA
PUSHJ P,PUTWDU## ;RETURN THE STATE
CAIN T1,LAT.ID ;SKIP IF WE HAVE TO RETURN NPD'S
JRST [LDB T1,NETRSN##;GET REASON FOR LAST DISCONNECT
PUSHJ P,PUTWD1## ;RETURN THAT AS SECOND ARG
RETSKP] ;GIVE GOOD RETURN
CAIGE P4,4 ;IF THE LIST IS ONLY 3 WDS LONG
JRST CPOPJ1 ; THEN WE'RE DONE
HRRI M,3(P3) ;GET ADDRESS OF THE FIRST NPD POINTER
HRRZ J,DEVNPD(F) ;GET THE POINTER TO THE LOCAL NPD
PUSHJ P,WRTNPD ;STORE THE NPD IN THE USER'S AREA
POPJ P, ;PROPAGATE THE ERROR RETURN
CAIGE P4,5 ;IF THE LIST ISN'T LONG ENOUGH
JRST CPOPJ1 ; THEN RETURN
HRRI M,4(P3) ;GET THE ADDRESS OF THE SECOND NPD POINTER
HLRZ J,DEVNPD(F) ;GET THE POINTER TO THE REMOTE NPD
PUSHJ P,WRTNPD ;STORE THE NPD
POPJ P, ;PROPAGATE THE ERROR RETURN
RETSKP ;ALL DONE, GOOD RETURN
;SUB-FUNCTION #2 = ENTER PASSIVE STATE. (WAITING FOR CONNECT INITIATE)
TSKEP: PUSHJ P,GETSTA ;GET AND RANGE CHECK THE STATE
CAIE T1,LAT.ID ;THIS FUNCTION IS ONLY LEGAL IN IDLE STATE
PJRST TK%ILS ;ERROR: ILLEGAL STATE
PUSHJ P,RD2NPD ;READ THE TWO NPD'S (ARG'S 1 & 2)
POPJ P, ;NPD WAS BAD, PROPAGATE THE ERROR RETURN
NETDBJ ;GET THE NETSER INTERLOCK
PUSHJ P,T.PSIV ;ENTER PASSIVE STATE.
JRST [PUSHJ P,GV2NPD## ;NO FREE LAT'S, FIRST RETURN THE NPD'S
PJRST TK%NFL] ; THEN GIVE "NO FREE LINK ADDRESSES" ERROR
RETSKP ;GIVE GOOD RETURN. STATE = LAT.CI
;SUB;SUB-FUNCTION #3 = ENTER ACTIVE STATE. (SEND CONNECT INITIATE)
TSKEA: PUSHJ P,GETSTA ;GET AND RANGE CHECK THE STATE
CAIE T1,LAT.ID ;THIS FUNCTION IS ONLY LEGAL IN IDLE STATE
PJRST TK%ILS ;ERROR: ILLEGAL STATE
PUSHJ P,RD2NPD ;READ THE TWO NPD'S (ARG'S 1 & 2)
POPJ P, ;NPD WAS BAD, PROPAGATE THE ERROR RETURN
HLRZ J,DEVNPD(F) ;GET THE ADDRESS OF THE REMOTE NPD
SKIPG T1,NPDNOD(J) ;T1 := THE NODE NUMBER TO SEND CONNECT TO
JRST [PUSHJ P,GV2NPD## ;IF IT'S NEGATIVE, RETURN NPD'S
JRST TK%NXN] ; GIVE ILLEGAL NODE ERROR.
NETDBJ ;GET THE NETSER INTERLOCK
PUSHJ P,SRCNDB## ;W := NDB ADDRESS (IF NODE IS UP)
JRST [PUSHJ P,GV2NPD## ;RETURN THE NPD'S
PJRST TK%NXN] ; AND GIVE AN ILLEGAL NODE ERROR
HRRM T1,DEVNET(F) ;MAKE THIS TASK'S NODE BE .T1 (FOR NCSCNT)
PUSHJ P,T.ACTV ;ENTER ACTIVE STATE. SEND CONNECT INITIATE
JRST [PUSHJ P,GV2NPD## ;NO FREE CORE. FIRST RETURN THE NPD'S
PJRST TK%NFC] ; THEN GIVE "NO FREE CORE" ERROR
RETSKP ;GIVE GOOD RETURN. STATE = LAT.CC
;SUB-FUNCTION #4 = ENTER IDLE STATE. SEND DISCONNECT IF NECESSARY.
TSKEI: PUSHJ P,GETSTA ;GET AND RANGE CHECK THE CONNECTION STATE
JRST @[EXP CPOPJ1##,TSKEI1,TK%ILS,TSKEI2,TK%ILS](T1) ;DISPATCH
TSKEI1: NETDBJ ;GET THE NETSER INTERLOCK
PUSHJ P,GV2NPD## ;RETURN THE TWO NPD'S
PUSHJ P,GIVSLA## ;RETURN THE SLA, ENTER STATE LAT.ID
RETSKP ;GIVE GOOD RETURN
TSKEI2: NETDBJ ;GET THE NETSER INTERLOCK
MOVEI T1,RSN.OK ;GET THE "NORMAL" REASON FOR DISCONNECT
PUSHJ P,NTDXDS ;SEND THE DISCONNECT, ENTER LAT.DC STATE
PJRST TK%NFC ;ERROR: NO MONITOR FREE CORE
RETSKP ;GIVE GOOD RETURN
;SUB-FUNCTION #5 = WAIT FOR CONNECT INITIATE/CONFIRM/REJECT
TSKWT: PUSHJ P,T.WAIT ;WAIT FOR TASK TO ENTER "ID" OR "OK" STATE
RETSKP ;GIVE GOOD RETURN
;SUB-FUNCTION #6 = OUTPUT WITH CONTROL OF INTERRUPT/DAP MESSAGE TYPE
TSKOU: PUSHJ P,GETSTA ;GET THE STATE OF THE CONNECTION,
CAIE T1,LAT.OK ; AND IF WE AREN'T CONNECTED, THEN
PJRST TK%ILS ; GIVE "ILLEGAL STATE" ERROR CODE
HRRI M,2(P3) ;GET THE ADDRESS OF TSKOP.'S ARG #1
PUSHJ P,GETWDU## ;READ THE DAP TYPE
PUSH P,T1 ;SAVE THE TYPE FOR A BIT
HLR M,DEVBUF(F) ;GET THE ADDRESS OF THE BUFFER CONTROL BLOCK
PUSHJ P,GETWDU## ;GET THE ADDRESS OF THE BUFFER HEADER
JUMPL T1,TSKOU1 ;RING NOT SET UP. CALL "TOUT" TO SET UP RING
HRRI M,(T1) ;GET THE USE BIT
PUSHJ P,GETWDU## ; TO SEE IF THIS BUFFER HAS HAD AN "OUT"
JUMPL TSKOU1 ; DONE. IF SO, DON'T CHANGE THE DAP TYPE
PUSHJ P,GETWD1## ;GET "XWD 0,WORD-COUNT"
HRL T1,(P) ;T1 := "XWD DAP-TYPE,WORD-COUNT"
PUSHJ P,PUTWDU## ;STORE TYPE AND COUNT IN THE BUFFER HEADER
TSKOU1: POP P,T2 ;CLEAN UP THE STACK
HLLZS M,M ;CLEAR "BUFFER POINTER" BEFORE DOING AN OUT
PUSHJ P,TOUT## ;DO THE OUT. (NTDXMT WILL NOTICE THE DAP TYPE)
RETSKP ;IF UUO SUCCEEDS, RETURN NOW.
JRST TSKIOE ;IF THE UUO DIDN'T WORK, TELL THE USER
;SUB-FUNCTION #7 = INPUT WITH NOTIFICATION OR INTERRUPT/MESSAGE TYPE
TSKIN: HRRZ T1,DEVPCB(F) ;FIRST SEE IF ANY INPUT IS QUEUED
JUMPN T1,TSKIN1 ;IF SO, READ IT. (EVEN IF DISCONNECTED)
PUSHJ P,GETSTA ;GET OUR STATE AND MAKE SURE
CAIE T1,LAT.OK ; THAT WE ARE CONNECTED.
PJRST TK%ILS ;IF NOT CONNECTED, "ILLEGAL STATE"
TSKIN1: HLLZS M,M ;CLEAR THE "BUFFER POINTER"
PUSHJ P,TIN## ;DO THE "IN" UUO
SKIPA ;SKIP IF THE UUO WAS SUCCESSFUL
JRST TSKIOE ;IF UUO DIDN'T GIVE A BUFFER, GO SEE WHY
HRR M,DEVBUF(F) ;TO RETURN E-O-R NOTIFICATION, GET BUFFER
PUSHJ P,GETWDU## ; HEADER, AND FROM THAT TRACK DOWN THE
HRRI M,1(T1) ; ".BTCNT" WORD OF THE BUFFER JUST
PUSHJ P,GETWDU## ; RETURNED.
HLRZ T1,T1 ;TSKSER PUTS THE DAP TYPE IN LH(.BFCNT)
HRRI M,2(P3) ;GET THE ADDRESS OF ARG#1 OF THE TSKOP.
PUSHJ P,PUTWDU## ; BLOCK AND RETURN THE DAP TYPE CODE
RETSKP ;GIVE A GOOD RETURN TO THE ENTIRE UUO.
TSKIOE: HRRZ T1,DEVIOS(F) ;IF UUO FAILS, GET THE DEVICE STATUS
HRRI M,2(P3) ; AND RETURN IT IN ARG #1 OF THE
PUSHJ P,PUTWDU## ; TSK. ARGUMENT BLOCK.
PJRST TK%UDW ;TELL THE USER IT FAILED WITH "UUO DIDN'T WORK"
;T.WAIT ROUTINE TO WAIT FOR A TASK TO ENTER EITHER "LAT.ID" OR "LAT.OK" STATE
;CALL F := DDB POINTER
;RETURN CPOPJ ;ALWAYS
T.WAIT: PUSHJ P,GETSTA ;GET THE CONNECTION STATE
CAIE T1,LAT.ID ;IF IT'S IDLE, OR
CAIN T1,LAT.OK ; IF IT'S "RUNNING"
POPJ P, ; THEN RETURN
PUSHJ P,NETHIB## ;OTHERWISE SLEEP TILL SOMEONE WAKES US.
JRST T.WAIT ;UPON AWAKING, SEE IF THE STATE CHANGED.
;T.PSIV ROUTINE TO PUT A TASK IN THE PASSIVE (LAT.CI) STATE.
;CALL F := DDB POINTER
;RETURN CPOPJ ;IF NO FREE LINK ADDRESSES (LAT FULL)
; CPOPJ1 ;LINK ADDRESS ASSIGNED. WAITING FOR CI
T.PSIV:
IFN PARANOID&P$TSK,< ;IF WE'RE BEING CAUTIOUS,
PUSHJ P,T.CHKC ;MAKE SURE WE'RE NOT CONNECTED
>
MOVEI T1,(F) ;RH(LAT-ENTRY) := DDB ADDRESS
HRLI T1,LAT.CI ;LH(LAT-ENTRY) := NEW LINK STATE
PUSHJ P,GETSLA## ;ASSIGN A SLA, SET NEW STATE
POPJ P, ;NO FREE LINK ADDRESSES
DPB T1,NETSLA## ;REMEMBER THE LINK ADDRESS
RETSKP ;GIVE GOOD RETURN
;T.ACTV ROUTINE TO PUT A TASK IN THE ACTIVE (LAT.CC) STATE. SENDS CONNECT
;CALL F := DDB POINTER (WITH RH(DEVNET) := NODE NUMBER)
;RETURN CPOPJ ;NO CORE, OR NO FREE LINKS, OR NO NODE
; CPOPJ1 ;CONNECT INITIATE SENT. STATE := LAT.CC
T.ACTV:
IFN PARANOID&P$TSK,< ;IF WE'RE BEING CAUTIOUS,
PUSHJ P,T.CHKC ;MAKE SURE WE'RE NOT CONNECTED
>
MOVEI T1,(F) ;RH(LAT-ENTRY) := DDB ADDRESS
HRLI T1,LAT.CC ;LH(LAT-ENTRY) := LAT.CC
PUSHJ P,GETSLA## ;ASSIGN A LINK ADDRESS
POPJ P, ;ERROR: NO FREE LINK ADDRESSES
DPB T1,NETSLA## ;REMEMBER OUR LINK ADDRESS
MOVE T1,[XWD T.XSPN,T.XDPN] ;GET ADDRESS OF ROUTINE TO SEND "DPN"
PUSHJ P,NCSCNT## ;CALL ROUTINE TO ACTUALLY SEND THE CONNECT
PJRST GIVSLA ;ERROR: NO CORE. FREE THE SLA AND RETURN
RETSKP ;GIVE GOOD RETURN
IFN PARANOID&P$TSK,< ;IF CHECKING, STOP IF DDB IS CONNECTED
T.CHKC: PUSHJ P,GETSTA ;GET THE STATE (BETTER BE ZERO)
MOVE S,DEVIOS(F) ;GET THE "CONNECTED" BIT (AND OTHERS...)
CAIN T1,LAT.ID ;DIE IF STATE /= "IDLE"
TLNE S,IOSCON ;DIE IF DEVIOS THINK'S WERE CONNECTED
PUSHJ P,NTDSTP## ;DIE, DIE, DIE...
POPJ P, ;RETURN IF EVERYTHING'S OK
>
SUBTTL 1.0 UUOCON INTERFACE.
;DISPATCH TABLE (FROM UUOCON)
POPJ P, ;(-5) DEVICE OFF LINE
POPJ P, ;(-4) SPECIAL ERROR STATUS
JRST REGSIZ## ;(-3) LENGTH CAN BE GOTTEN FROM DDB
JRST CPOPJ## ;(-2) INITIALIZE
JRST CPOPJ## ;(-1) HUNG DEVICE
NDEVTS::JRST NTDREL## ;(0) RELEASE
JRST T.CLSO ;(1) CLOSE OUTPUT
JRST T.OUT ;(2) OUTPUT
JRST T.IN ;(3) INPUT
JRST T.ENTR ;(4) ENTER
JRST T.LOOK ;(5) LOOKUP
JRST NTDILI## ;(6) DUMP MODE INPUT
JRST NTDILO## ;(7) DUMP MODE OUTPUT
POPJ P, ;(10) USETO
POPJ P, ;(11) USETI
POPJ P, ;(12) GETF UUO
POPJ P, ;(13) RENAME UUO
JRST T.CLSI ;(14) CLOSE INPUT
POPJ P, ;(15) UTPCLR
POPJ P, ;(16) MTAPE UUO
SUBTTL 1.1 DDB SEARCH LOGIC INTERFACE.
;TSTTSK ROUTINE TO SEE IF A TASK DDB SHOULD BE CREATED.
;CALL MOVEI P1,FLAGS ;DD%PHY=1B34, DD%LOG=1B35
; MOVE T1,[SIXBIT /DEVICE/]
; PUSHJ P,TSTTSK
;RETURN CPOPJ ;NOT A TSK
; CPOPJ1 ;WAS A TSK, F := DDB POINTER
;
DD%LOG==1B35 ;I HOPE IT'S THE SAME AS UUOCON.
TSTTSK::TRNE P1,DD%LOG ;IS THIS A LOGICAL SEARCH?
POPJ P, ;IF SO, THEN DON'T MATCH PHYSICAL TASKS
TLC T1,(SIXBIT /TSK/) ;IF T1 := "TSKNNM" THEN THE LH(T1)
TLNE T1,-1 ; IS NOW ZERO.
JRST [TLC T1,(SIXBIT /TSK/) ;IF IT'S NOT, FIXUP T1 AGAIN
POPJ P,] ; AND FAIL RETURN
TLC T1,(SIXBIT /TSK/) ;FIX UP T1 AGAIN...
NETDBJ ;INTERLOCK THIS CODE
PUSHJ P,SAVE4## ;SAVE THE P'S
PUSHJ P,SAVT## ;UUOCON LIKES IT'S TEAS
MOVE P2,T1 ;COPY DEVICE NAME TO A REASONABLE REGISTER
PUSHJ P,DVSCVT## ;CONVERT THE NETWORD DEVICE NAME, GET NODE #
POPJ P, ;ILLEGAL DEVICE NAME
MOVEI T1,(T2) ;COPY THE NODE NUMBER FOR SRCNDB
PUSHJ P,SRCNDB## ;DOES THE NODE EXIST
POPJ P, ;IF NOT, WE CAN'T CONNECT TO IT'S DEVICES
MOVEI P1,(W) ;COPY THE NDB FOR SRCNDT
SETZ P3, ;CLEAR THE LOGICAL NAME WORK
HLRZ T1,P2 ;GET THE GENERIC DEVICE NAME
PUSHJ P,SRCNDT## ;DOES THIS NODE SUPPORT THIS DEVICE?
POPJ P, ;IF NOT. THEN SEARCH FAILS
PUSHJ P,MAKDDB## ;IF NODE DOES SUPPORT THEM, THEN MAKE A DDB
POPJ P, ;IF NO CORE. JUST MAKE SEARCH FAIL
PUSHJ P,LNKDDB## ;LINK IN THIS DDB (EVEN THOUGH NOT CONNECTED)
RETSKP ;RETURN WITH NEWLY CONSTRUCTED DDB.
SUBTTL 1.2 OUTPUT UUO.
;T.OUT ROUTINE TO HANDLE THE OUT UUO FOR THE TSK DEVICE.
;
T.OUT: PUSHJ P,SAVE4## ;THEY GET CLOBBERED NTDXMT AND FRIENDS
MOVSI S,IOSUSO ;CLEAR "UUOCON STOPED OUTPUT" SINCE IT
ANDCAB S,DEVIOS(F) ; APPEARS TO BE TRYING TO START IT AGAIN
TOLOOP: PUSHJ P,NTDSET## ;SET UP S, W ETC
MOVSI S,IO ;SET DIRECTION TO "OUTPUT"
IORB S,DEVIOS(F) ; SO THAT UUOCON WILL BE HAPPY (WAIT1 ETC)
PUSHJ P,NTDONL## ;SEE IF THIS DEVICE IS STILL CONNECTED.
PJRST T.SERR ;NOT CONNECTED. SET IOSERR
;
; AS AN ECONOMY OF CODE, SET P1 := XWD CONVERSION-CODE, BYTE-SIZE. P1
; SHOULD CONTAIN THESE VALUES UNTIL NTDISP IS CALLED.
;
LDB T1,PIOMOD## ;GET THE CURRENT MODE
MOVE P1,[XWD PCV.NC,^D07] ;ASSMUE ASCII MODE. (NO CONVERSION, 7 BIT)
CAILE T1,AL ;IF IT'S NOT ASCII, IT'S IMAGE/BINARY
MOVE P1,[XWD PCV.BN,^D12] ; (BINARY CONVERSION, 12 BITS)
CAIN T1,BYTMOD ;UNLESS IT'S BYTE MODE.
MOVE P1,[XWD PCV.NC,^D08] ; (NO CONVERSION, 8 BIT BYTES)
MOVEI T1,(P1) ;GET THE BYTE SIZE
PUSHJ P,NTDSOB## ;SET UP THE OUTPUT BUFFER
JRST TODONE ;IF NO BUFFER, OUTPUT UUO IS DONE.
;
; NOTE: THIS CODE ALLOWS ZERO LENGTH DATA BUFFERS
;
HRRZ T1,DEVOAD(F) ;GET A POINTER TO THE BUFFER HEADER
EXCTUX <HLRZ P2,1(T1)> ; AND USE IT TO GET THE TYPE/INTERRUPT BIT
PUSHJ P,NTDPRV## ;DOES THIS GUY HAVE NETWORK PRIVS
TRZ P2,(1B0) ;IF NOT, DON'T LET HIM SEND INTERRUPT MSGS
TRZN P2,(1B0) ;IS THIS AN INTERRUPT MESSAGE?
JRST [PUSHJ P,NTDCDQ## ;IF NOT, COUNT DOWN THE DATA REQUEST
JRST TOWAIT ;IF NONE, THEN GO WAIT FOR SOME
JRST .+1] ;WE HAVE DATA-REQUESTS. CONTINUE
HLRZ T1,P1 ;GET THE CONVERSION CODE
SKIPN T2,P2 ;GET THE IDC TYPE FIELD
MOVEI T2,DC.DAR ;IF THE USER DIDN'T SPECIFY ONE. USE THE DEFAULT
PUSHJ P,NTDXMT## ;SEND A PCB'S WORTH OF DATA
JRST T.IMPM ;A NON-DATA MSG DIDN'T FIT. BLOCK TOO LARGE.
SKIPN DEVAXO+1(F) ;IS THE BUFFER FINALLY EMPTY
PUSHJ P,NTDAOB## ;IF SO, ADVANCE THE OUTPUT BUFFER
JRST TOLOOP ;CONTINUE TILL SOMEONE GET'S BORED.
;TOWAIT ROUTINE TO WAIT FOR TASK OUTPUT DATA REQUESTS
;
TOWAIT: PUSHJ P,NTDWTO## ;LET NETSER DO THE WORK.
POPJ P, ;NON-BLOCKING. RETURN TO UUOCON
JRST TOLOOP ;WHEN WE WAKE UP. TRY TO DO MORE OUTPUT
;TODONE HERE WHEN WE HAVE OUTPUT ALL THE USERS BUFFERS
;
TODONE: POPJ P,
SUBTTL 1.3 INPUT UUO.
;T.IN ROUTINE TO HANDLE THE "IN" UUO ENTRY TO THE TSK DEVICE
;
T.IN: PUSHJ P,SAVE4## ;WE CLOBBER MOST OF THEM
MOVSI S,IOSUSI ;CLEAR "UUOCON STOPED INPUT" SINCE IT'S
ANDCAB S,DEVIOS(F) ; OBVIOUSLY TRYING TO START IT AGAIN
TILOOP: PUSHJ P,NTDSET## ;USE COMMON SETUP ROUTINE (S, W, ETC)
MOVE S,DEVIOS(F) ;GET STATUS BITS BACK AFTER A POSSIBLE SLEEP
TLNE S,IOBEG ;IS THIS THE FIRST TIME THROUGH
JRST TIFRST ;IF SO, LOOK FOR PSUEDO NON-BLOCKING CONNECT
MOVSI S,IO ;CLEAR THE DIRECTION BIT SO THAT
ANDCAB S,DEVIOS(F) ; UUOCON WON'T GET CONFUSED.
PUSHJ P,NTDIBA## ;IS THEIR AN INPUT BUFFER AVAILABLE?
POPJ P, ;IF NOT, WE ARE DONE.
HRRZ T1,DEVPCB(F) ;GET A POINTER TO THE LIST OF INPUT PCB'S
JUMPE T1,TIWAIT ;IF NO DATA, WE MUST WAIT
PUSHJ P,NTDDID## ;DO THE DELAYED INPUT DISPATCH
JRST TILOOP ;KEEP IT UP TILL WE RUN OUT OF DATA.
;TIFRST HERE WE CHECK TO SEE IF WE ARE CONNECTED. IF NOT, AND THIS IS NON-
; BLOCKING STYLE I/O. THEN WE DO A DEVERR RETURN TO UUOCON. OTHERWISE WE JUST
; WAIT. WHEN WE FINNALY GET CONNECTED. WE MUST REMEMBER TO TURN OFF "IOSERR"
; WHICH GOT SET BY NTDSET.
;
TIFRST: TLNE S,IOSCON ;ARE WE CONNECTED YET
JRST [MOVSI S,IOBEG!IOSERR!IOSREL ;IF WE ARE CONNECTED, CLEAR
ANDCAB S,DEVIOS(F) ; THESE BITS,
JRST TILOOP] ; AND TRY ONCE AGAIN TO PROCESS DATA.
PUSHJ P,NTDWTI## ;IF NON CONNECTED, THEN WAIT FOR CONNECT/DATA
POPJ P, ;IF NONBLOCKING, RETURN TO UUOCON
JRST TILOOP ;TRY ONCE MORE TO DO INPUT
;TIWAIT HERE IF WE HAVE NO INPUT PCB'S TO PROCESS. FIRST MAKE SURE WE HAVEN'T
; BEEN DISCONNECTED. IF SO, SET EOF. OTHERWISE SEND DATA REQUESTS, AND
; WAIT IT OUT.
;
TIWAIT: PUSHJ P,NTDONL## ;IS THERE ANY PARTICULAR PROBLEM??
JRST T.EOF ; IF SO, GO SEE WHAT IT IS
PUSHJ P,NTDXDQ## ;SEE IF WE ARE BEHIND ON OUR DATA-REQUESTS
PUSHJ P,NTDWTI## ;WAIT FOR DATA
POPJ P, ;RETURN TO UUOCON IF NON-BLOCKING
JRST TILOOP ;AND GO MUNCH IT
;T.EOF ROUTINE TO RETURN END-OF-FILE ON FIRST "IN" AFTER DISCONNECT.
;
T.EOF: MOVSI S,IOEND ;GET THE END-OF-FILE BIT
TDOE S,DEVIOS(F) ;SEE IF IT'S ALREADY SET.
JRST T.SERR ;IF SO, THEN START COMPLAINING
MOVEM S,DEVIOS(F) ;OTHERWISE JUST SET THE BIT
POPJ P, ;AND GO BACK TO UUOCON
;T.IMPM, T.SERR ROUTINES TO SET ERROR BITS AND RETURN
;
T.SERR: MOVE S,[XWD IOSERR,IODERR] ;THE TWO DEVICE ERROR BITS
JRST T.SET ; AND SET THEM IN DEVIOUS
T.IMPM: MOVEI S,IOIMPM ;IMPROPER MODE (NOT LOOKED UP/ENTERED)
T.SET: IORB S,DEVIOS(F) ;SET THE BITS
POPJ P, ;RETURN TO UUOCON.
SUBTTL 1.4 ENTER UUO.
;T.ENTR ROUTINE TO HANDLE THE ENTER VECTORED ENTRY FROM UUOCON
;CALL F := XWD FLAGS,DDB
; M := UUO ;POINTE TO LOOKUP/ENTER BLOCK (LEB)
;RETURN CPOPJ ;NOT ENTERED. ERROR STORED IN LEB
; CPOPJ1 ;ENTERED. TASK IS CONNECTED.
T.ENTR: PUSHJ P,GETSTA ;GET OUR STATE.
MOVEI T2,1 ;GET A "1"
LSH T2,(T1) ;MAKE IT A 1 BIT MASK
TRNN T2,1_LAT.ID!1_LAT.CI!1_LAT.OK ;LEGAL STATES FOR ENTER'ING
PJRST RTNISU ;OTHERWISE RETURN "ILLEGAL SEQUENCE OF UUO'S"
PUSHJ P,SAVJW## ;WE CLOBBER THEM WITH NPD'S AND NDB'S
PUSHJ P,SAVE4## ;SAVE THE P'S
PUSHJ P,GETLEA ;GET THE LOOKUP ENTER ARG'S IN THE P'S
PJRST RTNLEE ; IF LEB ARGS BAD, STORE ERROR IN LEB & RETURN
PUSHJ P,GETSTA ;GET THE STATE AGAIN
CAIN T1,LAT.ID ;IF WE ARE IDLE, THEN
JRST T.ENT1 ; GO STORE ARGS & CONTINUE
;HERE IF TASK HAS BEEN LOOKED-UP (PUT IN PASSIVE STATE, POSSIBLY CONNECTED)
PUSHJ P,CHKLEA ;MAKE SURE THAT THE LEB'S ARE IN AGREEMENT
PJRST RTNAEF ; IF LEB BAD, GIVE AN "AEF" ERROR
PUSHJ P,GETSTA ;GET THE CONNECTION STATE
CAIN T1,LAT.OK ;IF WE'RE ALREADY CONNECTED, THEN
RETSKP ; GIVE A GOOD RETURN TO THE ENTER.
IFN PARANOID&P$TSK,< ;IF WE'RE BEING PARANOID, MAKE SURE
CAIE T1,LAT.CI ; WE'RE IN THE "PASSIVE" STATE
PUSHJ P,NTDSTP## ; IF NOT, THEN WE'VE SCREWED UP.
>
PUSHJ P,GV2NPD ;RETURN THE LOOKUP'S NPDS
PUSHJ P,GIVSLA## ;RETURN THE LAT (T.ACTV ASSIGNS A NEW ONE)
JRST T.ENT2 ;GO SEND THE CONNECT INITIATE AND RETURN
;HERE IF WE HAVEN'T BEEN LOOKED UP YET. (STATE IS "IDLE")
T.ENT1: PUSHJ P,STOLEA ;STORE THE LOOKUP/ENTER ARGS
; PJRST T.ENT2 ;GO SEND THE CONNECT INITIATE
;HERE WE SET UP "W", BUILD TWO NPD'S, SEND THE CONNECT & WAIT FOR A REPLY
T.ENT2: HRRZ T1,DEVNET(F) ;GET THIS DEVICE'S NODE NUMBER
PUSHJ P,SRCNDB## ;SET W := NDB POINTER.
PJRST RTNUNN ; ERROR. RETURN "UNKNOWN NETWORK NODE"
PUSHJ P,LE2NPD ;MAKE 2 NPD'S, REMOTE & LOCAL FOR T.ACTV
PJRST RTNENC ; IF NO CORE "EXCEEDED NETWORK CAPACITY"
HLRZ T1,NDBNNM(W) ;GET THE NODE NUMBER WE'RE TRYING TO CONNECT TO
HLRZ J,DEVNPD(F) ;GET THE "REMOTE" NPD
MOVEM T1,NPDNOD(J) ;SET THE NPD'S NODE NUMBER
PUSHJ P,T.ACTV ;SEND THE CONNECT INITIATE
JRST [PUSHJ P,GV2NPD ;IF NO CORE, OR NO LATS, FREE NPD'S
PJRST RTNENC] ;RETURN EXCEEDED NETWORK CAPACITY
;IF NONBLOCKING, WE MIGHT WANT TO RETURN HERE
PUSHJ P,T.WAIT ;WAIT FOR CONNECT CONFIRM/REJECT
PUSHJ P,GETSTA ;GET OUR STATE (TO SEE IF CONFIRM/REJECT)
CAIE T1,LAT.OK ;IF WE'RE NOT CONNECTED, THEN
JRST [PUSHJ P,GV2NPD ; RETURN BOTH THE NPD'S, AND
PJRST RTNTNA] ; GIVE A "TASK NOT AVAILABLE" ERROR
RETSKP ; OTHERWISE, GIVE A GOOD RETURN
SUBTTL 1.5 LOOKUP UUO.
;T.LOOK ROUTINE TO HANDLE THE LOOKUP VECTORED ENTRY FROM UUOCON
;CALL F := XWD FLAGS,DDB
; M := UUO ;POINTS TO THE USERS LOOKUP/ENTER BLOCK (LEB)
;RETURN CPOPJ ;IF ERROR, CODE RETURNED IN LEB
; CPOPJ1 ;TASK LOOKED-UP. NOW IN "PASSIVE" STATE
T.LOOK: PUSHJ P,GETSTA ;GET OUR CONNECTION STATE
MOVEI T2,1 ;GET A "1"
LSH T2,(T1) ;MAKE IT A 1 BIT MASK
TRNN T2,1_LAT.ID!1_LAT.OK ;LEGAL STATES FOR LOOKING UP
PJRST RTNISU ;OTHERWISE RETURN "ILLEGAL SEQUENCE OF UUO'S"
PUSHJ P,SAVJW## ;J := NPD'S, W := NDB'S
PUSHJ P,SAVE4## ;WE PUT THE LOOKUP/ENTER ARGS HERE
PUSHJ P,GETLEA ;GET THE LEB'S DATA
PJRST RTNLEE ;LEB BAD, RETURN ERROR CODE IN "T1"
PUSHJ P,GETSTA ;GET THE STATE AGAIN
CAIN T1,LAT.ID ;IF NOT IDLE, JUST CHECK THE ARGUMENTS
JRST T.LOO1 ;IF IDLE, GO TO "PASSIVE" STATE
;HERE IF WE'VE BEEN ENTERED, CHECK THE LEB'S ARGS AND RETURN
PUSHJ P,CHKLEA ;MAKE SURE THE LOOKUP AGREES WITH THE ENTER
PJRST RTNAEF ; IF LEB IS BAD, RETURN "AEF"
RETSKP ;GIVE GOOD RETURN TO THE LOOKUP
;HERE IF WE'VE NOT BEEN ENTERED, MAKE 2 NPD'S AND ENTER PASSIVE STATE
T.LOO1: PUSHJ P,STOLEA ;STORE DEVFIL AND FRIENDS FOR LE2NPD.
IFN PARANOID&P$TSK,< ;IF WERE CAUTIOUS, MAKE SURE NOT CONNECTED
SKIPE DEVNPD(F) ;DIE IF WE'VE ALREADY GOT 1 OR MORE NPD'S
PUSHJ P,NTDSTP## ;DIE DIE DIE...
>
HRRZ T1,DEVNET(F) ;GET THE NUMBER OF THIS TASK'S NODE
PUSHJ P,SRCNDB## ;SET W := NDB POINTER.
PJRST RTNUNN ; ERROR. RETURN "UNKNOWN NETWORK NODE"
PUSHJ P,LE2NPD ;MAKE NPD'S BASED ON DEVFIL & FRIENDS
PJRST RTNENC ; NO CORE. RETURN "EXCEEDED NET CAP"
CAIE W,NETNDB## ;IF HE SPECIFIED "ANY" NODE, DON'T SET NPDNOD
JRST [HLRZ J,DEVNPD(F) ;GET ADDRESS OF "REMOTE" NPD.
HLRZ T1,NDBNNM(W) ;GET OUR NODE NUMBER
MOVEM T1,NPDNOD(J) ;SET THE NODE NUMBER
JRST .+1] ;CONTINUE WITH MAIN CODE
PUSHJ P,T.PSIV ;ENTER "PASSIVE" STATE
JRST [PUSHJ P,GV2NPD ;IF NO CORE, OR NO LATS, FREE NPD'S
PJRST RTNENC] ;RETURN EXCEEDED NETWORK CAPACITY
RETSKP ;GIVE GOOD RETURN TO THE LOOKUP
SUBTTL 1.6 CLOSE UUO.
;T.CLS ROUTINE TO HANDLE THE CLOSE ENTRY FROM UUOCON
;CALL MOVEI F,DDB
; PUSHJ P,T.CLS ;FROM CLOSE1 CODE IN UUOCON
;RETURN CPOPJ
;
;THE CLOSE UUO CODE DOES NOTHING IF THE TSK HAS NOT BEEN CLOSED ON BOTH INPUT
; AND OUTPUT. IF IT HAS, IT DOES THE FINAL "OUT" TO FLUSH THE BUFFERS, AND
; SENDS A DISCONNECT INITIATE WAITING FOR THE DISCONNECT CONFIRM.
;
T.CLSO: TLNE F,ENTRB ;DON'T FORCE OUTPUT IF NOT ENTERED
PUSHJ P,NTDCLO## ;FORCE OUT THE LAST BUFFER (AND WAIT)
TLZA F,ENTRB ;SIGNIFY THAT WE ARE NO LONGER "ENTERED"
T.CLSI: TLZ F,LOOKB ;SIGNIFY THAT WE ARE NO LONGER "LOOKED UP"
T.CLS: TLNE F,ICLOSB ;IF WE HAVEN'T CLOSED BOTH INPUT AND
TLNN F,OCLOSB ; OUTPUT, THEN
POPJ P, ; DON'T ATTEMPT TO DISCONNECT THIS TASK
T.CLS1: PUSHJ P,T.WAIT ;WAIT FOR CONNECTS/DISCONNECTS TO FINISH
MOVE S,DEVIOS(F) ;NOW SEE IF WE ARE CONNECTED
TLNN S,IOSCON
JRST T.CLS4 ;DON'T SEND DISCONNECT IF NOT CONNECTED
T.CLS2: MOVEI T1,RSN.OK ;STANDARD REASON
PUSHJ P,NTDXDS## ;SEND THE DISCONNECT
JRST [PUSHJ P,NETSLP## ;IF WE CAN'T SEND THE DISCONNECT, THEN
JRST T.CLS2] ; THEN WAIT FOR A BIT AND TRY AGAIN
T.CLS3: PUSHJ P,NETHIB## ;WAIT FOR THE CONFIRM
LDB T1,NETSLA## ;GET OUR LAT ADDRESS
JUMPE T1,T.CLS5 ;THE DISCONNECT CONFIRM CODE WILL ZERO IT
IFN PARANOID&P$LAT,< ;MAKE SURE LAT ENTRY IS RIGHT
LDB T1,LATSTA## ;GET THE STATE
CAIE T1,LAT.DC ;SHOULD STILL BE DISCONNECT CONFIRM
PUSHJ P,NTDSTP## ;++ WRONG CONNECTION STATE
>
JRST T.CLS3 ;MUST HAVE BEEN A SPURIOUS WAKE
T.CLS4: LDB T1,NETSLA## ;FIRST CHECK TO SEE IF WE HAVE
JUMPE T1,T.CLS5 ;LAT ASSIGNED. IF NOT, DON'T FREE IT.
IFN PARANOID&P$LAT,<
LDB T2,LATSTA## ;GET THE STATE
CAIE T2,LAT.CI ;THE ONLY LEGAL STATE AT THIS POINT IS "CI"
PUSHJ P,NTDSTP## ;++ ILLEGAL STATE FOR TASK LAT
>
PUSHJ P,GIVSLA## ;FREE THE SLA
T.CLS5: PUSH P,J ;NOW FREE THE NPD'S. FIRST SAVE J
PUSHJ P,GV2NPD## ;FREE THE NPD'S
POP P,J
SETZM DEVFIL(F) ;CLEAR THE FILE NAME
HRRZS DEVEXT(F) ; THE EXTENSION
SETZM DEVPPN(F) ; THE PPN
POPJ P, ;ALL DONE.
SUBTTL 2.0 NETSER INTERFACE.
;TSKSER'S NDP DISPATCH VECTOR (HERE ON MESSAGES FROM NETSER)
JRST NTDNWD## ;COMMON CODE FOR CRASHED NODE
JRST NTDDSC## ;COMMON CODE FOR DISCONNECT
JRST T.CONC ;SPECIAL CODE FOR CONNECT CONFIRM
JRST T.CONI ;SPECIAL CODE FOR CONNECT INITIATE
JRST NTDRDQ## ;COMMON CODE FOR DATA-REQUESTS
TSKNDP::JRST NTDQIP## ;QUEUE INCOMING PCB'S TO UUO LEVEL
JRST T.DAPI ;DATA WITH OUT EOR
JRST T.DAPI ;DATA WITH EOR
JRST T.DAPI ;STATUS
JRST T.DAPI ;CONTROL
JRST T.DAPI ;UNIT ID
JRST T.DAPI ;FILE SPEC
SUBTTL 2.1 CONNECT CONFIRM NCL MESSAGE.
;T.CONC ROUTINE TO PROCESS THE CONNECT CONFIRM FOR A TASK
;CALL MOVEI F,DDB
; P1, P4 := POINT TO THE "SLA" FIELD OF THE CONNECT
;RETURN CPOPJ1 ;ALWAYS
;
T.CONC: PUSHJ P,SAVJW## ;WE USE J FOR THE NPD
;SLA
PUSHJ P,EBI2BI## ;READ OUR REMOTE LAT ADDRESS
DPB T1,NETDLA## ;SAVE IT SO WE CAN TALK TO HIM
PUSHJ P,GV2NPD ;RETURN THE TWO STALE NPD'S.
;DPN(OBJ)
PUSHJ P,XSKIP## ;WE'RE NOT INTERESTED
;DPN(PID)
PUSHJ P,GETSPN ;GET WHAT HE THINKS WE ARE
SETZ J, ; IF NO CORE, DON'T WORRY...
HRRM J,DEVNPD(F) ;STORE NEW LOCAL NPD
;SPN(OBJ)
PUSHJ P,XSKIP## ;WE'RE NOT INTERESTED
;SPN(PID)
PUSHJ P,GETSPN ;GET HIS ID
SETZ J, ; IF NO CORE, JUST RETURN ZERO
HRLM J,DEVNPD(F) ;STORE THE NEW REMOTE NPD
;MML,FEA(DCM,RLN,DVT)
PUSHJ P,GETFEA ;READ THE "FEATURES"
PUSHJ P,T.OK ;SET BITS SAYING WE ARE CONNECTED
RETSKP ;GIVE GOOD RETURN
SUBTTL 2.2 CONNECT INITIATE NCL MESSAGE.
;T.CONI ROUTINE TO HANDLE THE CONNECT INITIATE ENTRY FOR THE TSK DEVICE.
;CALL MOVEI F,DDB
; MOVE P3,[XWD SLA,OBJ]
; P1, P4 := POINT TO THE "DPN(PID)" FIELD OF THE CONNECT MESSAGE
;RETURN CPOPJ ;DIDN'T LIKE THE CONNECT
; CPOPJ1 ;OK. CONNECT CONFIRM SENT. LINK IN "OK" STATE
;
T.CONI: HRRZ T1,P3 ;GET THE OBJECT TYPE
CAIE T1,OBJ.TK ; AND MAKE SURE IT'S FOR TYPE "TSK"
POPJ P, ; IF NOT FOR US, EXIT NOW
PUSHJ P,SAVJW## ;WE CLOBBER J
PUSHJ P,SAVE4## ; AND MASSACRE THE P'S
MOVS J,DEVNPD(F) ;GET THE "PATTERN" NPD POINTER
TLNE J,-1 ;MAKE SURE THAT BOTH NPD'S
TRNN J,-1 ; EXIST
POPJ P, ;IF EITHER NPD MISSING, DON'T MATCH
HLRZ T1,NDBNNM(W) ;GET THIS NODE'S NUMBER
SKIPL T2,NPDNOD(J) ;GET THE PATTERN'S NODE NUMBER
CAIN T1,(T2) ;SKIP IF THEY DON'T MATCH
SKIPA ;EITHER WILD CARD, OR MATCH, SUCCEED.
POPJ P, ;NO MATCH. EXIT NOW.
PUSHJ P,T.CON1 ;CALL ROUTINE TO DO PATTERN MATCH
POPJ P, ; IF NO MATCH, GIVE "REJECT" RETURN
HLRZ T1,P3 ;GET THE SLA
DPB T1,NETDLA## ; AND REMEMBER IT.
HLRZ T1,NDBNNM(W) ;GET THE NODE NUMBER
HRRM T1,DEVNET(F) ; AND REMEMBER THAT TO.
;READ NCD'S
;DPN(PID)
PUSHJ P,GETSPN ;SET J := NPD DESCRIBING WHAT WE MATCHED
POPJ P, ; NO CORE, GIVE ERROR RETURN FROM T.CONI
HLRZ T1,NDBNNM+NETNDB## ;GET OUR NODE NUMBER
MOVEM T1,NPDNOD(J) ;AND USE THAT INSTEAD OF HIS.
PUSH P,J ;SAVE NPD FOR A BIT
;SPN(OBJ)
PUSHJ P,XSKIP## ;WE'RE NOT INTERESTED
;SPN(PID)
PUSHJ P,GETSPN ;READ THE SOURCE PID
JRST [POP P,J ;IF NO CORE, GET LAST NPD READ
PJRST GIVNPD] ; RETURN IT, AND ERROR RETURN FROM T.CONI
HRLM J,0(P) ;SAVE THE NEW "REMOTE" NPD
;MML,FEA(DCM,RLN,DVT)
PUSHJ P,GETFEA ;READ THE "FEATURES"
;SEND CONFIRM
HLRZ J,DEVNPD(F) ;GET OLD "REMOTE" NPD AND FREE IT.
PUSHJ P,GIVNPD## ; (THERE MUST BE ONE TO GET THIS FAR...)
HLRZ J,0(P) ;GET THE NEW "REMOTE" NPD
HRLM J,DEVNPD(F) ; AND PUT IT WHERE T.XDPN CAN FIND IT.
MOVE T1,[XWD T.XSPN,T.XDPN] ;ROUTINES TO SEND SPN AND DPN
EMRGCY ;USE EMERGENCY MEMORY IF NECESSARY
PUSHJ P,NCSCNT## ;SEND THE CONNECT CONFIRM
PUSHJ P,NTDSTP## ;WE'VE SCREWED UP... SHOULDN'T HAPPEN
HRRZ J,DEVNPD(F) ;GET OLD "LOCAL" NPD AND FREE IT
PUSHJ P,GIVNPD## ; (THERE MUST BE ONE IF WE GOT THIS FAR)
POP P,J ;GET NEW "LOCAL" NPD
HRRM J,DEVNPD(F) ;AND PUT IT WHERE A ".TKFRS" CAN FIND IT
PUSHJ P,T.OK ;DECLARE THE TSK UP, WAKE ANY WAITING JOBS
RETSKP ;GIVE GOOD RETURN
;T.CON1 SUB-ROUTINE TO SET THINGS UP FOR THE "MATCH" ROUTINE.
; THE ONLY REASON THAT THIS IS A SUBROUTINE IS TO MAKE IT EASY
; TO SKIP/NON-SKIP RETURN.
;CALL J := POINTER TO THE "PATTERN" NPD
; P1, P4 := MESSAGE POINTER,COUNT TO PID (AS USUAL)
;RETURN CPOPJ ;PATTERN DIDN'T MATCH PID
; CPOPJ1 ;PATTERN DID MATCH, P1, P4 UPDATED TO AFTER
; ; PID
T.CON1: PUSH P,P3 ;SAVE THE "XWD SLA,OBJ" INFORMATION
PUSH P,P1 ;SAVE THE BYTE POINTER TO THE MESSAGE
PUSH P,P4 ;SAVE THE LENGTH OF THE MESSAGE
MOVE P3,P4 ;COPY THE LENGTH FOR MATCH
PUSHJ P,XSKIP## ;ADVANCE PAST PID SO WE CAN CALCULATE LENGTH
SUB P3,P4 ;SET P3 := LENGTH(PID)
MOVE P4,-1(P) ;SET P4 := BYTE-POINTER TO PID
MOVE P1,NPDNLN(J) ;SET P1 := LENGTH OF THE "PATTERN"
MOVEI P2,NPDNAM(J) ;GET THE ADDRESS OF THE "PATTERN"
HRLI P2,(POINT 7) ;SET P2 := BYTE-POINTER TO "PATTERN"
SETZ T4, ;GET A ZERO
EXCH T4,TKMTCH ;SEE IF THERE IS ALREADY A PSUEDO-STACK
JUMPE T4,[MOVEI T2,100 ;GET LENGTH OF PSUEDO-STACK
PUSHJ P,GETZWD## ;TRY TO ALLOCATE A NEW PSUEDO-STACK
JRST T.CON2 ;IF NO CORE, CLEAN UP AND ERROR RETURN
MOVEI T4,(T1) ;COPY ADDRESS OF NEW STACK
HRLI T4,-100 ;MAKE IT AN AOBJN POINTER
JRST .+1] ;RETURN TO MAIN CODE WITH T4 := STACK POINTER
PUSHJ P,MATCH ;SEE IF THE PID MATCHES THE PATTERN
JRST T.CON2 ; IF NO MATCH, CLEAN UP AND ERROR RETURN
AOS -3(P) ;IF IT MATCHES. GIVE SKIP RETURN (UGH...)
T.CON2: EXCH T4,TKMTCH ;PUT STACK IN THE PSUEDO-STACK CACHE
JUMPN T4,[MOVEI T1,(T4) ;IF THERE IS ALREADY A P-STACK,
HRLI T2,(T4) ; THEN WE MUST FREE THE EXTRA
MOVN T2,T2 ; ONE.
PUSHJ P,GIVZWD## ;CALL NETSER TO FREE THE CORE.
JRST .+1] ;RETURN TO MAIN LINE CODE.
POP P,P4 ;SET P4 := LENGTH(MESSAGE-PID)
POP P,P1 ;SET P1 := BYTE-POINTER TO PID
POP P,P3 ;SET P3 := "XWD SLA,OBJ"
POPJ P, ;GIVE (POSSIBLY SKIP) RETURN
SUBTTL 2.3 DAP MESSAGES.
;T.DAPI HERE TO PROCESS ALL OF THE INCOMING DAP MESSAGES
;CALL MOVEI T1,IDC MESSAGE TYPE
; MOVEI F,DDB OF DEVICE GETTING MESSAGES
;RETURN CPOPJ ;MESSAGE BAD
; CPOPJ1 ;MESSAGE OK
;
T.DAPI: HRRZ T2,DEVPCB(F) ;GET A POINTER TO THE PCB WE'RE READING
MOVE T2,PCBIAD(T2) ;GET A BYTE POINTER TO THE NCT FIELD OF THE MSG
ILDB T2,T2 ;GET THE NCT BYTE
TLNE T2,NCT.IT ;IF THIS IS AN INTERRUPT MESSAGE,
IORI T1,(1B0) ; REMEMBER, SET "INTERRUPT" BIT IN BUFFER HEAD
MOVE P2,T1 ;COPY THE HALFWORD INTO A SAFER REGISTER.
LDB T1,PIOMOD## ;GET THE MODE WE ARE READING IN.
CAIG T1,AL ;ASCII OR ASCII LINE?
JRST T.ASCI ;IF SO, GO TO ASCII CODE
CAIN T1,BYTMOD ;BYTE MODE?
JRST T.BYTE ;IF SO, SPECIAL CODE
JRST T.IMAG ;ALL THE REST IS IMAGE.
T.ASCI: SKIPA T4,[7] ;SEVEN BIT BYTES IN ASCII
T.BYTE: MOVEI T4,8 ;EIGHT BIT BYTES IN BYTE MODE
PUSHJ P,T.SIB ;USE COMMON SET-UP ROUTINE
T.BYT1: SOJL P4,T.ADVB ;IF DONE. ADVANCE PCB & USER'S BUFFERS
ILDB T1,P1 ;GET THE NEXT DATA BYTE
SOSGE DEVAXI+1(F) ;COUNT OFF NEXT BYTE IN THE BUFFER
JRST T.BKTL ;IF NO ROOM, SET IOBKTL
EXCTUU <IDPB T1,DEVAXI(F)> ;STORE THE BYTE
JRST T.BYT1 ;LOOP UNTIL INPUT MESSAGE IS USED UP.
T.IMAG: MOVEI T4,^D12 ;12 BIT BYTES
PUSHJ P,T.SIB ;USE COMMON SETUP ROUTINE
T.IMG1: SOJL P4,T.ADVB ;IF NO MORE, ADVANCE PCB'S AND USER'S BUFFERS
ILDB T1,P1 ;GET THE TOP 8 BITS OF THE FIRST BYTE
LSH T1,4 ;POSITION THEM IN THE 12 BIT FIELD
SOJL P4,T.IMG2 ;IF NO MORE, STORE THIS WITH ZERO FILL
ILDB T2,P1 ;GET LOW 4 BITS THIS BYTE, HIGH 4 OF THE NEXT
ROT T2,-4 ;POSITION THE LOW 4 BITS
IORI T1,(T2) ;COMBINT BOTH HALVS FOR A 12 BIT BYTE
SOSGE DEVAXI+1(F) ;COUNT OFF THIS BYTE
JRST T.BKTL ;GIVE AN ERROR IF IT WON'T FIT
EXCTUU <IDPB T1,DEVAXI(F)> ;STORE THIS FIRST 12 BIT BYTE
SOJL P4,T.ADVB ;IF NO MORE, LAST 4 BITS ARE GARBAGE.
ILDB T1,P1 ;GET THE LAST 8 BITS OF THE SECOND 12 BIT BYTE
ROT T2,^D12 ;ISOLATE THE LOW 4 BITS AS THE HIGH 4
IORI T1,(T2) ;BUILD THE SECOND 12 BIT BYTE
T.IMG2: SOSGE DEVAXI+1(F) ;COUNT OFF THIS BYTE
JRST T.BKTL ;GIVE AN ERROR IF IT WON'T FIT
EXCTUU <IDPB T1,DEVAXI(F)> ;STORE THE SECOND 12 BIT BYTE
JRST T.IMG1 ;LOOP UNTIL ALL INPUT IS PROCESSED.
;T.SIB ROUTINE TO SET UP AN INPUT BUFFER FOR TSK INPUT
; CALLS NTDSIB, AND STORES THE MESSAGE TYPE AND INTERRUPT BIT IN THE
; USER'S BUFFER HEADER.
;
T.SIB: PUSHJ P,NTDSIB## ;SET UP THE INPUT BUFFER
PUSHJ P,NTDSTP## ;++ NO INPUT BUFFER (BUT WE CHECKED IN T.IN)
HRRZ T1,DEVIAD(F) ;GET THE ADDRESS OF THE BUFFER HEADER
EXCTUU <HRLM P2,1(T1)> ;STORE THE MESSAGE TYPE AND INTERRUPT BIT
POPJ P, ;RETURN TO MAIN-LINE CODE.
;T.ADVB TASK ADVANCE BUFFER AND PCB ROUTINE. THIS ROUTINE ADVANCES
; THE BUFFER IFF THE MESSAGE RECEIVED WAS NOT DATA-WITHOUT-EOR, OR
; IF THE "DISABLE MESSAGE RE-ASSEMBLY" (IOSDMR) BIT WAS SET.
;CALL P2 := IDC TYPE ;LEFT OVER FROM EARLIER
;RETURN CPOPJ1 ;ALWAYS.
T.ADVB: TRZ P2,(1B0) ;MAKE SURE THE "INTERRUPT" BIT IS OFF
CAIN P2,DC.DAT ;IF IT'S NOT DATA-WITHOUT-EOR,
TLNE S,IOSDMR ; OR WE'RE NOT RE-ASSEMBLING BUFFERS
PJRST NTDA1B## ; THEN ADVANCE THE BUFFER
RETSKP ;IF DATA WITHOUT-EOR, THEN DON'T ADVANCE
; THE BUFFER
;T.BKTL ROUTINE TO SET THE "IOBKTL" ERROR BIT IF A USERS BUFFER IS TOO SMALL
; IT ADVANCES THE USERS BUFFER, AND SKIP RETURNS (ADVANCING THE DAP MESSAGE)
;
T.BKTL: MOVEI S,IOBKTL ;GET THE BLOCK TOO LARGE BIT
IORB S,DEVIOS(F) ;SET IT
PJRST NTDA1B## ;ADVANCE THE USERS BUFFER AND THE DAP MESSAGE
SUBTTL X.X ONCE/SECOND TASK CODE
;FREE THE TEMPORARY "PSUEDO-STACK" USED BY TSKSER
TSKSEC::SETZ T2, ;GET A ZERO TO INDICATE NO BLOCK
EXCH T2,TKMTCH ;GET "XWD LENG,ADDR" OF BLOCK
JUMPE T2,CPOPJ## ;IF NONE, RETURN NOW
HLRE T1,T2 ;COPY (MINUS) THE LENGTH
MOVN T1,T1 ;MAKE THE LENGTH POSITIVE
PJRST GIVZWD## ;RETURN THE STORAGE
SUBTTL 3.0 SUBROUTINES.
SUBTTL 3.1 LOOKUP/ENTER BLOCK MANIPULATION
;GETLEA ROUTINE TO GET THE LOOKUP/ENTER ARGUMENTS FOR THE TSK DEVICE.
;CALL MOVE M,THE UUO
; PUSHJ P,GETLEA
;RETURN CPOPJ ;ERROR CODE IN T1
; CPOPJ1 ;P1 := DEVNAM
; ;P2 := DEVEXT
; ;P3 := DEVPPN (THE USERS IF NOT PRVJ)
;
GETLEA: ;HERE TO GET LOOKUP/ENTER ARGS
PUSH P,U ;USE U AS A TEMP TO
MOVE U,M ; THE ADDRESS OF THE ARGUMENT LIST
PUSHJ P,GETWDU## ;GET THE FIRST (DEVNAM OR COUNT)
MOVE P1,T1 ;RETURN FIRST WORD AS DEVNAM
TLNN T1,-1 ;IS IT AN EXTENDED BLOCK
JRST GETLEE ; IF SO. GO TO SPECIAL CODE TO READ IT
HRRI M,UUNEXT(U) ;GET THE EXTENSION
PUSHJ P,GETWDU## ; FROM THE USERS MEMORY, AND
MOVE P2,T1 ; RETURN THAT AS DEVEXT
HRRI M,UUNPPN(U) ;GET THE PPN FROM THE USERS MEMORY
JRST GETLE1 ; AND GO TO COMMON CODE.
GETLEE: MOVEI T1,FNFERR ;IN CASE TOO SHORT
CAIGE P1,UUXEXT ;IS THIS BLOCK LONG ENOUGH
JRST UPOPJ## ; IF TOO SHORT, GIVE AN ERROR RETURN
HRRI M,UUXNAM(U) ;GET THE FILE NAME
PUSHJ P,GETWDU## ; FROM THE USERS MEMORY,
MOVE P1,T1 ; AND RETURN AS DEVNAM
HRRI M,UUXEXT(U) ;GET THE EXTENSION
PUSHJ P,GETWDU## ; FROM THE USER
MOVE P2,T1 ; AND RETURN AS DEVEXT
HRRI M,UUXPPN(U) ;GET THE PPN
GETLE1: PUSHJ P,GETWDU## ;GET THE PPN
MOVE T2,.CPJOB## ;GET THIS GUY'S JOB NUMBER
SKIPN P3,T1 ;GET USER-SPECIFIED PPN
MOVE P3,JBTPPN##(T2) ;HE DIDN'T SPECIFY ONE, USE JOB'S PPN.
CAME P3,JBTPPN##(T2) ;SPECIFYING A PPN OTHER THAN HIS?
CAMN P3,[-1] ;(OR [777777,777777]?)
JRST GETLE2 ;NO, IT IS OK
MOVEI T1,PRTERR ;IN CASE NOT PRIVILEGED
PUSHJ P,NTDPRV## ; HE MUST BE PRIVILEGED
JRST UPOPJ## ; AND HE IS NOT, PROTECTION ERROR
GETLE2: MOVE T1,P3 ;GET THE PPN THAT WE WILL USE
PUSHJ P,PUTWDU## ;TELL THE USER WHAT PPN WE REALLY ARE USING
MOVE M,U ;RESTORE THE UUO
PJRST UPOPJ1## ;GIVE A GOOD RETURN
;CHKLEA ROUTINE TO CHECK TO MAKE SURE THAT THE DDB'S DEVNAM, DEVEXT, AND
; DEVPPN AGREE WITH THE LOOKUP/ENTER BLOCK'S
;CALL MOVEI F,DDB ;WITH DEVNAM ... SET UP
; P1, P2, P3 := THE LOOKUP/ENTER ARGS
;RETURN CPOPJ ;THEY DON'T AGREE (AEF ERROR RETURNED)
; CPOPJ1 ;THEY AGREE
;
CHKLEA: CAMN P1,DEVFIL(F) ;COMPARE THE FILE NAMES
CAME P3,DEVPPN(F) ;COMPARE THE PPN'S
JRST RTNAEF ;GIVE THE "AEF" ERROR (ALREADY EXISTING FILE)
XOR P2,DEVEXT(F) ;COMPARE THE EXTENSIONS
TLNE P2,-1 ; AND ONLY THE EXTENSIONS
JRST RTNAEF ;DIFFERENT. GIVE ERROR
RETSKP ;ALL THE SAME. GIVE GOOD RETURN
;STOLEA ROUTINE TO STORE THE LOOKUP/ENTER ARGS IN P1, P2, P3 INTO A DDB
;CALL MOVEI F,DDB
; P1, P2, P3 := FILE NAME, EXTENSION, PPN
; PUSHJ P,STOLEA
;RETURN CPOPJ ;ALWAYS
;
STOLEA: MOVEM P1,DEVFIL(F) ;STORE THE FILE NAME
HLLM P2,DEVEXT(F) ;STORE JUST THE EXTENSION
MOVEM P3,DEVPPN(F) ;STORE THE PPN
POPJ P, ;ALL DONE
;ERRORS ROUTINES TO RETURN VARIOUS LOOKUP/ENTER ERRORS
;
; RTNFNF ;(00) FILE NOT FOUND
; RTNPRT ;(02) PROTECTION ERROR
; RTNAEF ;(04) ALREADY EXISTING FILE
; RTNENC ;(37) EXCEEDED NETWORK CAPACITY
; RTNTNA ;(40) TASK NOT AVAILABLE
; RTNUNN ;(41) UNKNOWN NETWORK NODE
DEFINE X(CODE),< ;;SIMPLE MACRO TO MAKE DEFINING THESE EASY
RTN'CODE:
MOVEI T1,CODE'ERR ;;S.MAC HAS ALL THESE SYMBOLS DEFINED
PJRST RTNLEE ;;COMMON CODE TO RETURN THE ERROR
>
X FNF ;FILE NOT FOUND
X PRT ;PROTECTION FAILURE (USER NOT PRIVILEGED)
X AEF ;ALREADY EXISTING FILE
X ISU ;ILLEGAL SEQUENCE OF UUO'S
X ENC ;EXCEEDED NTEWORK CAPACITY
X TNA ;TASK NOT AVAILABLE
X UNN ;UNKNOWN NETWORK NODE
;RTNLEE ROUTINE TO RETURN A LOOKUP/ENTER ERROR CODE.
;CALL MOVE U,UUO
; MOVEI T1,ERROR NUMBER
; PUSHJ P,RTNLEE
;RETURN CPOPJ ;ALWAYS
;
RTNLEE: PUSH P,M ;SAVE THE UUO
PUSH P,T1 ;STORE THE ERROR CODE FOR LATER
PUSHJ P,GETWDU## ;GET THE FIRST WORD (TO SEE IF EXTENDED L/E)
MOVEI M,UUNEXT ;ASSUME THAT THIS IS THE OLD NON-EXTENDED FORM
TLNN T1,-1 ; BUT IF IT IS EXTNEDED,
MOVEI M,UUXEXT ; THEN CHANGE OUR MIND
ADD M,-1(P) ;ADD IN OFFSET OF THE BASE OF THE BLOCK
PUSHJ P,GETWDU## ;GET THE "EXTENSION" FIELD
HRR T1,(P) ;PUT THE ERROR CODE IN THE RH
PUSHJ P,PUTWDU## ;STORE THE ERROR CODE IN THE USERS MEMORY
POP P,T1 ;RESTORE THE ERROR CODE
POP P,M ;RESTORE THE UUO
POPJ P, ;ALL DONE
SUBTTL 3.2 NPD MANIPULATION
SUBTTL 3.2.1 USER NPD MANIPULATION
;ADCNPD ROUTINE TO ADDRESS CHECK AN NPD
;CALL M := USER ADDRESS OF NPD POINTER (XWD LENGTH,ADDR)
;RETURN NOT AT ALL -- PAGE FAULT, OR ADDRESS ERROR
; CPOPJ NPD TOO SHORT
; CPOPJ1 ALL'S OK
ADCNPD: PUSHJ P,GETWDU## ;GET XWD LENGTH,ADDRESS
HLRZ T2,T1 ;COPY THE LENGTH
CAIGE T2,3 ;IS IT LONG ENOUGH TO HOLD A VALID NPD
JRST TK%ILN ;IF NOT, SAY "ILLEGAL NPD"
HRRZI T1,(T1) ;CLEAR LH(T1) FOR BRNGE
ADDI T2,-1(T1) ;SET T2 := LAST WORD OF NPD
PUSHJ P,LRNGE## ;MAKE SURE THAT THE NPD IS INCORE
RETSKP ;IF IT IS, GIVE GOOD RETURN
;REDNPD ROUTINE TO READ AN NPD. NPD MUST BE ADDRESSABLE (FAULT = "IME")
;CALL M := USER ADDRESS OF NPD POINTER (XWD LENGTH,ADDR)
;RETURN CPOPJ SOME SORT OF ERROR, ERROR CODE STORED
; CPOPJ1 J := NPD
REDNPD: PUSHJ P,SAVE1## ;USE P1 FOR A TEMP
PUSHJ P,GETWDU## ;GET "XWD LENGTH,ADDRESS" OF NPD
MOVE P1,T1 ;SAVE XWD LENGTH,ADDR
EXCTUX <SKIPL T1,1(T1)>;GET THE LENGTH OF THE NAME-STRING
CAILE T1,^D100 ;ALLOW THIS MANY CHARS FOR THE NPD
PJRST TK%ILN ;GIVE ILLEGAL NPD ERROR IF BAD LENGTH
ADDI T1,<2*5>+4 ;ADD 3 WORDS, ROUND UP
IDIVI T1,5 ;CALCULATE NUMBER OF WORDS TO HOLD NPD
HLRZ T2,P1 ;GET "DECLARED" LENGTH
CAILE T1,(T2) ;MAKE SURE NPD FITS IN RANGE-CHECKED REGION
PJRST TK%ILN ;GIVE ILLEGAL NPD ERROR IF IT DOESN'T FIT
ADDI T1,1 ;ACCOUNT FOR MONITOR'S "NPDBLK" WORD
PUSHJ P,GETNPD## ;ALLOCATE AN NPD, J := ADDRESS
PJRST TK%NFC ;ERROR: NO MONITOR FREE CORE
HRLZ T1,P1 ;MAKE BLT POINTER: FROM = USER ADDRESS
HRRI T1,NPDNOD(J) ; TO = MONITOR NPD ADDRESS
HLRZ T2,NPDBLK(J) ;J := LENGTH OF THE NPD
ADDI T2,-1(J) ;T2 := ADDRESS OF LAST WORD IN THE NPD
EXCTUX <BLT T1,(T2)> ;COPY THE NPD
RETSKP ;GIVE GOOD RETURN
;RD2NPD ROUTINE TO READ BOTH NPD'S FOR .TKFEA OR .TKFEP SUB FUNCTIONS
; FREE'S OLD NPD'S FIRST, THEN READS NEW ONES.
;CALL P1, P2, P3, P4 := CHANNEL, SUB=FUNCTION, ADDRESS, LENGTH
;RETURN CPOPJ SOMETHING'S WRONG, ERROR CODE STORED
; CPOPJ1 NPD'S READ. DEVNPD(F) HAS POINTERS TO BOTH
RD2NPD: SKIPE DEVNPD(F) ;MAKE SURE THAT THERE AREN'T ANY NPD'S ASSIGNED
PUSHJ P,NTDSTP## ;?? NPD'S ALREADY THERE ??
HRRI M,2(P3) ;GET THE ADDRESS OF THE FIRST NPD POINTER
PUSHJ P,ADCNPD ;ADDRESS CHECK IT
POPJ P, ;ERROR? PASS IT BACK
HRRI M,3(P3) ;GET THE ADDRESS OF THE SECOND NPD POINTER
PUSHJ P,ADCNPD ;ADDRESS CHECK THIS ONE TOO
POPJ P, ;ERROR. PASS IT BACK
HRRI M,2(P3) ;GET THE ADDRESS OF THE FIRST NPD POINTER AGAIN
PUSHJ P,REDNPD ;GET J := ADDRESS OF NPD IN MONITOR FREE CORE
POPJ P, ;SOME RANDOM ERROR. CODE ALREADY STORED
HRRM J,DEVNPD(F) ;STORE "LOCAL" NPD
HRRI M,3(P3) ;GET ADDRESS OF SECOND NPD POINTER
PUSHJ P,REDNPD ;GET J := ADDRESS OF COPY
JRST [SETZ J, ;ERROR. FIRST FREE "LOCAL" NPD
EXCH J,DEVNPD(F) ;AND CLEAR DEVNPD
PJRST GIVNPD##];THEN RETURN. (ERROR CODE ALREADY STORED)
HRLM J,DEVNPD(F) ;STORE THE "REMOTE" NPD
RETSKP
;WRTNPD ROUTINE TO COPY A MONITOR NPD BACK INTO USER SPACE.
;CALL M := ADDRESS OF USER'S NPD POINTER (XWD LENGTH,ADDR)
; J := ADDRESS OF MONITOR NPD.
;RETURN CPOPJ ;USER'S NPD DESCRIPTOR IS BAD
; CPOPJ1 ;ALL'S OK. NPD RETURNED.
WRTNPD: JUMPE J,[SETZ T1, ;IF NO NPD, (PROBABLY SHORT OF CORE)
PJRST PUTWDU##] ;WRITE ZERO'S OVER THE USERS NPD POINTER
PUSHJ P,SAVE1## ;WE USE P1 AS A TEMP
PUSH P,J ;SAVE NPD POINTER (???WDU## CLOBBERS J)
PUSHJ P,GETWDU## ;GET THE NPD POINTER (XWD LENGTH,ADDRESS)
POP P,J ;GET NPD POINTER BACK
HLRZ T2,NPDBLK(J) ;GET THE LENGTH OF THE MONITOR NPD
SUBI T2,1 ; LESS ONE (MONITOR'S LENGTH INCLUDES NPDBLK)
HLRZ T3,T1 ;GET THE LENGTH OF THE USER'S AREA
CAIGE T3,(T2) ;SEE IF THE NPD WILL FIT.
PJRST TK%NTS ;ERROR: USER'S NPD IS TOO SHORT
MOVNI T2,1(T2) ;GET NEGATIVE COUNT (+1 FOR AOBJP)
HRLZ P1,T2 ;SET UP THE LH OF THE AOBJN POINTER
HRRI P1,(J) ;SET UP THE RH.
HRRI M,(T1) ;GET THE ADDRESS OF THE USER'S NPD AREA
PUSH P,J ;SAVE NPD POINTER AGAIN. (PUTWRD...)
WRTNP1: AOBJP P1,JPOPJ1## ;COUNT OFF THE NEXT ITEM, EXIT IF DONE
MOVE T1,(P1) ;FETCH THE NEXT WORD OF THE NPD
PUSHJ P,PUTWDU## ;STORE THE WORD
AOJA M,WRTNP1 ;INCREMENT USER'S ADDRESS AND DO NEXT WORD.
SUBTTL 3.2.2 MONITOR NPD MANIPULATION
;GETSPN ROUTINE TO BUILD A REMOTE NPD BASED ON CONNECT MSG DATA
;CALL P1, P4 := POINTER TO THE "PID"
; W := POINTER TO NDB OF REMOTE NODE
; PUSHJ P,GETPID
;RETURN CPOPJ ;NO CORE
; CPOPJ1 ;J := POINTER TO A NEWLY CONS-ED NPD
; ; P1, P4 POINT AFTER THE PID
GETSPN: MOVE T2,P1 ;COPY THE BYTE POINTER
HRREI T1,-1(P4) ;GET THE COUNT -1
GETSP1: ILDB T4,T2 ;GET THE NEXT CHAR FROM THE MESSAGE
TRNE T4,200 ;SKIP OUT OF THE LOOP IF NOT EXTENSIBLE
SOJGE T1,GETSP1 ;LOOP COUNTING ALL CHARS IN THE PID
SUBM P4,T1 ;CALCULATE THE NUMBER OF CHARS IN THE PID
PUSH P,T1 ;SAVE THE PID'S LENGTH (IN CHARACTERS)
ADDI T1,3*5+4 ;ACCOUNT FOR NPDNOD AND NPDNLN, ROUND UP
IDIVI T1,5 ;DIVIDE TO GET WORDS NEEDED TO HOLD PID
PUSHJ P,GETNPD## ;ALLOCATE A NEW NPD
JRST [PUSHJ P,XSKIP##;SKIP OVER THE PID
JRST TPOPJ##] ; FIXUP STACK, RETURN WITH PID NOT COPIED
HLRZ T1,NDBNNM(W) ;GET THE NODE NUMBER OF THE REMOTE
MOVEM T1,NPDNOD(J) ; AND SAVE IT IN THE NPD
POP P,T4 ;GET THE CHARACTER COUNT BACK
MOVEM T4,NPDNLN(J) ; AND SAVE THAT TOO
MOVE T3,[POINT 7,NPDNAM(J)] ;GET A POINTER TO THE "NAME" PART
SUBI P4,(T4) ;MAKE T4 REFLECT THE CHARS WE ARE ABOUT TO READ
GETSP2: ILDB T1,P1 ;READ A CHAR FROM THE MESSAGE
IDPB T1,T3 ;STORE IT IN THE NEW PID STRING
SOJG T4,GETSP2 ;LOOP OVER ALL CHARACTERS
RETSKP ;ALL DONE. GIVE GOOD RETURN
;GETFEA ROUTINE TO COPY THE "FEA" FIELDS FROM A MESSAGE TO A DDB
;CALL P1, P4 := MESSAGE POINTERS
; F := DDB POINTER
; PUSHJ P,GETFEA
;RETURN CPOPJ ;ALWAYS
;
GETFEA: ;HERE TO COPY FEA
;MML
PUSHJ P,XSKIP## ;WE DON'T CARE...
;FEA(DCM)
PUSHJ P,XSKIP## ;WE DON'T CARE ABOUT THIS
;FEA(RLN)
PUSHJ P,EBI2BI## ;GET THE RECORD LENGTH
DPB T1,NETRLN## ;SAVE IT IN THE DDB
;FEA(DVT)
PUSHJ P,EBI2BI## ;GET THE DEVICE ATTRIBUTES
DPB T1,NETDVT## ;SAVE IT IN THT DDB
POPJ P, ;ALL DONE
;GETSTA ROUTINE TO RETURN THE CONNECTION STATE OF A TASK
;CALL F := DDB ADDRESS
;RETURN T1 := CONNECTION STATE
GETSTA: LDB T1,NETSLA## ;GET THE SOURCE LINK ADDRESS
SKIPE T1 ;IF NONE, THEN ZERO IS THE STATE
LDB T1,LATSTA## ;GET THE STATE
CAIG T1,LAT.MX ;MAKE SURE THAT IT'S A LEGAL STATE
SKIPGE T1 ; AND NOT NEGATIVE
PUSHJ P,NTDSTP## ;STATE IS OUT OF RANGE
POPJ P, ;RETURN
;LE2NPD ROUTINE TO DUMMY UP THE NPD'S FOR TASKS OPENED VIA THE
; LOOKUP/ENTER MECHANISM. THIS ROUTINE CREATES 2 NPD'S
; (ONE REMOTE AND ONE LOCAL) BASED ON THE TASK'S FILE-NAME
; AND THE JOB'S NAME
;CALL F := DDB POINTER
;RETURN CPOPJ ;IF NO CORE
; CPOPJ1 ;DEVNPD(F) := XWD RMT,LOCAL NPD'S
LE2NPD: SKIPE DEVNPD(F) ;MAKE SURE THAT THERE AREN'T ANY NPD'S
PUSHJ P,NTDSTP## ;DIE IF THERE ARE...
;FIRST BUILD THE "LOCAL" NPD
MOVEI T1,3+5 ;5 WORDS HOLDS ANY "NAME[P,PN]"
PUSHJ P,GETNPD## ;GET STORAGE FOR A "LOCAL" NPD
POPJ P, ;IF NO CORE, JUST GIVE ERROR RETURN
HLRZ T1,NDBNNM+NETNDB## ;GET OUR NODE NUMBER
MOVEM T1,NPDNOD(J) ;STORE IT IN THE NPD
MOVE P2,[POINT 7,NPDNAM(J)] ;P2 := BYTE POINTER TO STRING AREA
SETZ P3, ;COUNT STARTS AT ZERO
MOVE T1,.CPJOB## ;GET OUR JOB NUMBER
MOVE T1,JBTNAM##(T1) ;GET OUR JOB NAME
PUSHJ P,SX2EAS## ;WRITE THE NAME
MOVE T1,.CPJOB## ;GET OUR JOB NUMBER AGAIN...
MOVE T1,JBTPPN##(T1) ;GET OUR P,PN
PUSHJ P,PP2EAS## ;WRITE THE "[P,PN]"
MOVEM P3,NPDNLN(J) ;STORE THE STRING'S LENGTH
HRRM J,DEVNPD(F) ;STORE THE NPD POINTER IN THE DDB
;NOW BUILD THE "REMOTE" NPD
MOVEI T1,3+5 ;GET THE LENGTH OF THE NPD
PUSHJ P,GETNPD## ;TRY TO ALLOCATE ONE
PJRST GV2NPD ;IF NO CORE, RETURN THE "LOCAL" NPD AND ERR
SETOM NPDNOD(J) ;DEFAULT TO A WILD-CARD NODE.
MOVE P2,[POINT 7,NPDNAM(J)] ;P2 := BYTE POINTER TO STRING AREA
SETZ P3, ;COUNT STARTS AT ZERO
MOVE T1,DEVFIL(F) ;GET THE FILE NAME
PUSHJ P,SX2EAS## ; AND "OUTPUT" THAT
MOVE T1,DEVPPN(F) ;GET THE PPN, AND
CAMN T1,[-1] ; IF IT'S -1, THEN
JRST [XMTI "*" ; OUTPUT A WILDCARD (*)
JRST LE2NP1] ; AND WE'RE DONE WITH THE PPN
XMTI "[" ;OUTPUT THE OPEN BRACKET
HLRZ T1,DEVPPN(F) ;GET THE PROJECT NUMBER
PUSHJ P,OC2EAS## ;OUTPUT THE NUMBER
XMTI "," ;OUTPUT THE COMMA
HRRZ T1,DEVPPN(F) ;GET THE PROGRAMMER NUMBER
PUSHJ P,OC2EAS## ;OUTPUT THAT TOO
XMTI "]" ;CLOSE OFF THE PPN
LE2NP1: MOVEM P3,NPDNLN(J) ;REMEMBER THE LENGTH
HRLM J,DEVNPD(F) ;SAVE THE "REMOTE" NPD
RETSKP ;GIVE A GOOD RETURN
;T.X?PN ROUTINE CALLED BY NCSCNT TO SEND THE "?PN" PART OF A CONNECT MESSAGE
;CALL P2, P3 := POINTERS TO CONNECT MESSAGE SO FAR
; F := POINTER TO TASK DDB
;RETURN CPOPJ ;ALWAYS
T.XSPN: HRRZ J,DEVNPD(F) ;GET NPD FOR LOCAL TASK NAME
PJRST T.XPN ;GO TO COMMON ROUTINE TO SEND "SPN"
T.XDPN: HLRZ J,DEVNPD(F) ;GET NPD FOR REMOTE TASK NAME
; PJRST T.XPN ;GO TO COMMON ROUTINE TO SEND "DPN"
T.XPN: ;ROUTINE TO SEND A "DPN/SPN" J := NPD.
;?PN(OBJ)
XMTI OBJ.TK ;SEND THE TASK OBJECT TYPE
;?PC(PID)
SKIPE J ;IF NO NPD,
SKIPN T3,NPDNLN(J) ; OR IF NAME IS OF LENGTH "ZERO"
JRST J,[XMTI 0 ; SEND A "ZERO" NAME
POPJ P,] ; AND RETURN
MOVE T4,[POINT 7,NPDNAM(J)] ;GET A POINTER TO THE NAME
T.XPN1: ILDB T1,T4 ;GET THE NEXT CHARACTER
IORI T1,200 ;SET THE EXTENSIBLE BIT.
XMT1 T1 ;SEND THE CHAR
SOJG T3,T.XPN1 ;LOOP OVER ALL CHARACTERS
PJRST CLRBT8## ;CLEAR THE BIT ON LAST CHAR & RETURN
;T.OK ROUTINE CALLED WHEN A TASK CONNECTION COMPLETED. SETS THE TASK
; AS ONLINE (CONNECTED, LAT-STATE OK)
;
T.OK: LDB T1,NETSLA## ;GET THE LAT ADDRESS
MOVEI T2,LAT.OK ;THE "OK" STATE
DPB T2,LATSTA## ;SET THE STATE OF THE LAT
MOVSI S,IOSCON
IORB S,DEVIOS(F) ;SET THE "WE ARE CONNECTED" BIT
MOVE S,[XWD IOSERR+IOEND,IODERR]
ANDCAB S,DEVIOS(F) ;CLEAR THESE ERROR BITS.
PUSHJ P,PSIONL## ;GIVE THE USER AN ON-LINE INTERRUPT
PUSHJ P,NTDIAV## ;SAY INPUT IS NOW AVAILABLE
PJRST NETWAK## ; AND WAKE HIM IF SLEEPING OR HIBERING
;MATCH Routine to perform a pattern match.
;Call P1, P2 := Length, Byte pointer to the "Pattern"
; P3, P4 := Length, Byte pointer to the "Source"
; T4 := Aobjn pointer to block of "free" storage. This
; is used as a Psuedo-stack. This routine uses no
; "real" stack.
;Return CPOPJ ;Source did not match Pattern
; CPOPJ1 ;Source did match Pattern
;
;Note Only T1, T2 and T3 are modified. T4, and P1 - P4 are returned
; unchanged.
;
; The algorithm works in the obvious way. Special "pattern"
; characters are:
;
; ? Match any next source character.
; * Match zero or more next source characters.
; ^V (Control "V") Treat the next "pattern" char as a normal
; char even if it is a "?" or a "*".
MATCH: MOVE T3,T4 ;COPY THE PSUEDO-STACK POINTER
HLRE T1,T3 ;GET MINUS(LENGTH) OF STACK LEFT
CAMLE T1,[EXP -4] ;MAKE SURE WE HAVE AT LEAST 4 WORDS LEFT
POPJ P, ;GIVE ERROR RETURN IF NOT ENOUGH STORAGE
;BIG LOOP. ONCE PER STRING
MATCH1: DMOVEM P1,0(T3) ;SAVE THE PATTERN DESCRIPTORS
DMOVEM P3,2(T3) ;SAVE THE SOURCE DESCRIPTORS
;LOOP. ONCE PER CHARACTER
MATCH2: SOJL P1,[SOJL P3,MATCHS ;IF BOTH ARE NULL, RETURN SUCCESS
JRST MATCH3];IF SOURCE STRING TOO LONG, BACK-UP
ILDB T1,P2 ;GET THE NEXT PATTERN CHARACTER
CAIN T1,"*" ;SEE IF IT'S A STAR
JRST MATCH4 ; IF IT'S A STAR, GO RECURSE ON REST.
CAIN T1,"?" ;SEE IF IT'S A WILD CHARACTER
JRST [SOJL P3,MATCHF ; IF SO, COUNT ONE SOURCE CHAR (FAIL IF NONE)
IBP P4 ; SKIP OVER NEXT SOURCE CHAR
JRST MATCH2] ; AND CONTINUE THE MATCH WITH NEXT CHAR
CAIN T1,"V"-100 ;IS IT A ^V?
JRST [SOJL P1,MATCHF ; IF IT'S A ^V, COUNT OFF ON PATTERN CHAR
ILDB T1,P2 ; GET THE NEXT "QUOTED" CHAR
JRST .+1] ; AND CONTINUE WITH THE MATCH
SOJL P3,MATCHF ;COUNT OFF SOURCE CHAR. COMPLETE FAIL IF NONE.
ILDB T2,P4 ;GET THE NEXT SOURCE CHARACTER
XORI T1,(T2) ;COMPARE THE CHARACTERS
TRNN T1,177 ; BUT ONLY LOOK AT LOW 7 BITS
JRST MATCH2 ;IF THEY MATCH, GO COMPARE NEXT CHARS.
;BACKUP. HERE IF CHARS DON'T MATCH
MATCH3: CAMN T3,T4 ;ARE WE AT "LEVEL 0"
JRST MATCHF ;IF AT LEVEL 0 THEN THE MATCH FAILED
DMOVE P1,0(T3) ;GET BACK ORIGIONAL PATTERH
DMOVE P3,2(T3) ;GET BACK SOURCE
SOJL P3,MATCHF ;WE ARE PROCESSING A "*". EAT ONE MORE SOURCE
IBP P4 ; CHARACTER.
DMOVEM P3,2(T3) ;REMEMBER THE UPDATED SOURCE
JRST MATCH2 ;NOW TRY THE COMPARE AGAIN ON SHORTER SOURCE
;STAR. RECURSE
MATCH4: ADD T3,[XWD 4,4] ;BUMP OUR "PSUEDO-STACK" POINTER
HLRE T1,T3 ;GET THE NUMBER OF WORDS LEFT
CAMLE T1,[EXP -4] ;MAKE SURE THERE ARE AT LEAST 4 LEFT.
JRST MATCHF ;IF NO "STACK", RETURN FAILURE
JRST MATCH1 ;GO "RECURSE"
MATCHS: AOS (P) ;IF WE SUCCEED, GIVE SKIP RETURN
MATCHF: DMOVE P1,0(T4) ;LOAD ORIGIONAL P1 & P2
DMOVE P3,2(T4) ; OLD P3 & P4
POPJ P, ;RETURN
SUBTTL 4.0 TSKSER IMPURE STORAGE.
$LOW
TKMTCH: EXP 0 ;THIS TEMP CONTAINS THE "PATTERN" MATCH
; TEMPORARY PSUEDO-STACK.
XLIST ;DON'T LIST LITERALS
$LIT
LIST
TSKEND::END