mirror of
https://github.com/PDP-10/stacken.git
synced 2026-02-15 12:16:07 +00:00
7494 lines
276 KiB
Plaintext
7494 lines
276 KiB
Plaintext
TITLE NETSER - DEVICE INDEPENDENT NETWORK SERVICE ROUTINES - V1200
|
||
SUBTTL D. TODD/DRT/EJW/JBS/DRL 27-JUN-88
|
||
SEARCH F,S,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
|
||
; 1974,1975,1976,1977,1978,1979,1980,1982,1984,1986,1988.
|
||
;ALL RIGHTS RESERVED.
|
||
|
||
.CPYRT<1974,1988>
|
||
|
||
|
||
XP VNETSER,1200 ;PUT VERSION NUMBER IN GLOB AND LOADER MAP
|
||
|
||
NETSER::ENTRY NETSER ;LOADING IF IN LIBRARY SEARCH MODE
|
||
Comment @
|
||
|
||
Loose ends.
|
||
|
||
NETSER problems.
|
||
|
||
o The interface to PSISER with respect to PSINTC (Topology
|
||
change) is poor. Probably should have a bit in the NDB
|
||
that indicates whether or not the interrupt has been
|
||
given.
|
||
|
||
Network device (rdx, cdr, lpt, tsk etc) problems
|
||
|
||
|
||
Monitor problems (in routines other than NETSER)
|
||
|
||
o Make COMMON generate the right amount of free core.
|
||
|
||
DN87 problems (-11 code)
|
||
|
||
o LB.IBF gets filled up too easily. Make it use a chunk?
|
||
|
||
|
||
Loose ends in general (Programs to write etc...)
|
||
|
||
|
||
|
||
@
|
||
SUBTTL SYSINI INITIALIZATION
|
||
|
||
|
||
$INIT
|
||
|
||
NETINI::MOVE T1,ANFNUM## ;ANF-10 STATION NUMBER
|
||
HRLM T1,NETNDB##+NDBNNM ;STUFF INTO OUR NDB
|
||
MOVEI T2,NETNDB## ;GET NDB ADDRESS FOR CENTRAL STATION
|
||
HRRM T2,.GTNDA##(T1) ;SAVE FOR NETSER
|
||
MOVEM T1,JBTLOC## ;AND FOR THE REST OF THE MONITOR
|
||
MOVE T1,ANFNAM## ;STATION NAME
|
||
MOVEM T1,NETNDB##+NDBSN2 ;SAVE IN NDB
|
||
POPJ P, ;RETURN
|
||
|
||
$HIGH
|
||
SUBTTL INTERFACE TO AUTCON
|
||
|
||
|
||
;ROUTINE TO SET THE COUNT OF VARIOUS DEVICES IN THE HOST'S NDB.
|
||
;CALL: PUSHJ P,NETDEV
|
||
;
|
||
; AC USAGE: T1 - T4
|
||
|
||
NETDEV::PUSH P,W ;SAVE W
|
||
XMOVEI W,NETNDB## ;POINT TO OUR NDB
|
||
MOVEI T1,M.RMCR## ;SEE IF WE HAVE AN MCR
|
||
MOVEM T1,DDBCNT##+.TYMCR ;FAKE OUT OUR LOOP BELOW
|
||
HRRZ T1,NETRTY## ;GET NUMBER OF LOCAL TERMINAL LINES
|
||
MOVEM T1,DDBCNT##+.TYTTY ;WE DON'T CARE ABOUT SCNN
|
||
MOVSI T1,-TYPMAX-1 ;AOBJN POINTER TO DDB COUNT TABLE
|
||
NETDE1: SKIPN DDBTAB##(T1) ;IS THERE A PROTOTYPE DDB?
|
||
JRST NETDE3 ;TRY THE NEXT ENTRY
|
||
HRRZ T2,T1 ;GET .TY???
|
||
MOVSI T3,-<OBJ.MX+1> ;AOBJN POINTER
|
||
NETDE2: HLRZ T4,OBJTAB##(T3) ;GET A DEVICE TYPE
|
||
CAME T2,T4 ;MATCH?
|
||
AOBJN T3,NETDE2 ;TRY ANOTHER
|
||
JUMPGE T3,NETDE3 ;FOUND ONE?
|
||
MOVE T2,DDBCNT##(T1) ;GET DEVICE COUNT
|
||
DPB T2,NETCNF##(T3) ;UPDATE DEVICE COUNT IN THE NDB
|
||
NETDE3: AOBJN T1,NETDE1 ;LOOP FOR ALL DEVICES
|
||
JRST WPOPJ## ;RESTORE W AND RETURN
|
||
SUBTTL INTERFACE TO COMCON
|
||
;ENTRY FROM COMCON WITH A NETWORK ASSIGN COMMAND
|
||
;
|
||
; ASSIGN NODENAME_DEV:LOGICAL
|
||
;
|
||
;COMCON HAS ALREADY SCANNED OF THE NODE NAME
|
||
; T2=NODE NAME
|
||
; T3=DELIMETER
|
||
;RETURN
|
||
; CPOPJ ;NOT A NETWORK DEVICE. ERROR MESSAGE PRINTED
|
||
; CPOPJ1 ;IT IS A NETWORK DEVICE. T2 := THE "TRANSLATED"
|
||
; ; NAME OF THE FORM GGGNNU
|
||
NETASG:: ;ENTRY
|
||
MOVE P1,T2 ;SAVE THE STATION NAME
|
||
CAIE T3,"_" ;TERMINATED BY A _
|
||
JRST CPOPJ1## ;IF NOT, DON'T CONVERT THE NAME
|
||
PUSHJ P,COMTYS## ;YES, SKIP THE "_"
|
||
NETDBJ ;INTERLOCK THIS CODE
|
||
PUSHJ P,CTXDEV## ;GET THE DEVICE NAME
|
||
JUMPE T2,NOTENF## ;ILLEGAL ARG LIST
|
||
MOVE P2,T2 ;SAVE THE DEVICE NAME
|
||
TRNE T2,505050 ;MUST BE NUMERIC GGGU
|
||
JRST NOTDEV## ;ERROR RETURN
|
||
|
||
TLNE P2,505050 ;IS LH A NUMBER?
|
||
JRST NETAS1 ;NO, CONTINUE NORMALLY
|
||
MOVSS P2,P2 ;FLIP HALVES OF ARGUMENT
|
||
NETAS0: TRNE P2,77 ;IS RIGHTMOST DIGIT ZERO?
|
||
JRST NETAS2 ;NO, DONE
|
||
LSH P2,-6 ;SHIFT RIGHT ONE DIGIT
|
||
JRST NETAS0 ; AND TRY AGAIN
|
||
NETAS2: TRO P2,202020 ;MAKE IT ALL DIGITS
|
||
HRLI P2,(SIXBIT/TTY/); AND MAKE LH SAY TTY
|
||
;HERE TO VALIDATE THE STATION NAME
|
||
NETAS1: MOVE T1,P1 ;COPY THE STATION NAME
|
||
PUSHJ P,SRCNDB ;DOES THE STATION EXIST
|
||
JRST [HRRZ T1,NRTUNN ;TYPE AN ERROR
|
||
PJRST ERRMES##] ;ERROR MESSAGE
|
||
MOVE T2,P2 ;RESTORE DEVICE NAME
|
||
HLRZ P1,NDBNNM##(W) ;GET NODE #
|
||
CAMN P1,JBTLOC## ;LOCAL NODE?
|
||
JRST CPOPJ1## ;YES, JUST RETURN
|
||
MOVEI P1,(W) ;SAVE THE NDB POINTER
|
||
|
||
;HERE TO VALIDATE THE REMOTE DEVICE NAME
|
||
HLRZ T1,P2 ;GENERIC NAME ONLY FROM THE LEFT HALF
|
||
CAIN T1,(SIXBIT /TTY/) ;IS IT TERMINAL?
|
||
JRST NETAST ;YES, ASSIGN IT
|
||
TRNN P2,505050 ;MUST BE LEFT HALF NUMERIC OR ZEROS
|
||
PUSHJ P,SRCNDT ;SEARCH THE NDT
|
||
PJRST NOTDEV## ;NOT A LEGAL DEVICE
|
||
HLL P2,NDTNAM(W) ;COPY THE GENERIC -10 DEVICE NAME
|
||
MOVEI W,(P1) ;GET THE NODE POINER BACK
|
||
HLRZ P1,NDBNNM(W) ;PUT THE NODE NUMBER IN P1
|
||
|
||
;HERE TO CONVERT THE DEVICE NAME INTO A NETWORK NAME
|
||
;DEVICE MUST BE OF THE FORM(S) GGGU,OR GGG
|
||
|
||
MOVEI T1,(P1) ;CONVERT THE NODE NUMBER TO SIXBIT
|
||
TRO T1,77700 ;FORCE CONVERSION TO LINE UP
|
||
S0PSHJ CVTSBT## ;IN UUOCON
|
||
MOVEI T2,(P2) ;COPY THE UNIT NUMBER IF ANY
|
||
LSH T2,-14 ;SHIFT THE UNIT NUMBER IF ANY TO LOW ORDER
|
||
IORI T2,(T1) ;COMBINE THE RIGHT HALF
|
||
HLL T2,P2 ;AND INSERT THE GENERIC NAME
|
||
JRST CPOPJ1## ;RETURN WITH T2 := GGGNNU
|
||
|
||
NETAST: ;HERE IF NETWORK TERMINAL BEING ASSIGNED
|
||
HRLZ T1,P2 ;GET THE REMOTE LINE NUMBER
|
||
PUSHJ P,CVTOCT## ;CONVERT IT TO OCTAL
|
||
JRST NOTDEV## ;NON NUMERIC LINE NUMBER
|
||
HLL T1,NDBNNM(W) ;GET THE NODE NUMBER
|
||
PUSHJ P,ASGTTY## ;AND TRY TO CONVERT THE PAIR TO "TTYNNN"
|
||
JRST NOTDEV## ;COULDN'T CONNECT. DEVICE NOT AVAILABLE
|
||
MOVE T2,T1 ;COPY THE DEVICE NAME
|
||
JRST CPOPJ1## ;WE SUCCEDED. T2 := DEVICE NAME
|
||
SUBTTL INTERFACE TO COMCON FOR THE "NODE" COMMAND
|
||
|
||
NODE.A::NETDBJ ;INTERLOCK THIS CODE
|
||
SKIPN T1,T2 ;CHECK FOR AN ARG
|
||
JRST [PUSHJ P,FNDSTA## ;IF NO ARG, GET THE STATION OUR TTY
|
||
JRST NODEC1] ; IS AT, AND USE THAT ONE
|
||
PUSHJ P,CVTOCT## ;TRY TO CONVERT THE NUMBER
|
||
MOVE T1,T2 ; IF WE CAN'T, USE THE NAME
|
||
|
||
;TYPE OUT A PARTICULAR NODE NAME
|
||
NODEC1: PUSHJ P,SRCNDB ;FIND THE NODE BLOCK
|
||
POPJ P, ;NO SUCH NODE, GIVE FAIL RETURN (IF MORE
|
||
; NETWORKS, LET THEM TRY).
|
||
; PJRST NODEC2 ;TYPE THE INFO
|
||
|
||
NODEC2: PUSHJ P,TYPNDB ;TYPE IT
|
||
PUSHJ P,INLMES## ;TYPE CR-LF-TAB
|
||
ASCIZ /
|
||
/
|
||
MOVSI P1,-<OBJ.MX+1> ;GET THE DEVICE TABLE SIZE
|
||
NODEC4: LDB T1,NETCNF##(P1) ;GET THE NUMBER OF DEVICES
|
||
JUMPE T1,NODEC5 ;NONE DON'T PRINT
|
||
HRLZ T2,OBJTAB##(P1) ;GET THE DEVICE NAME
|
||
PUSHJ P,PRNAME## ;PRINT IT OUT
|
||
MOVEI T3,"[" ;BRACKET
|
||
PUSHJ P,COMTYO## ;TYPE
|
||
LDB T1,NETCNF##(P1) ;GET THE NUMBER OF ENTRIES
|
||
PUSHJ P,RADX10## ;PRINT
|
||
PUSHJ P,INLMES## ;BRACKET SPACE
|
||
ASCIZ /] /
|
||
NODEC5: AOBJN P1,NODEC4 ;CONTINUE TO THE END
|
||
PUSHJ P,PCRLF## ;END OF LINE
|
||
JRST CPOPJ1## ;AND RETURN SUCCESS
|
||
SUBTTL INTERFACE TO COMCON
|
||
|
||
|
||
;WHERE COMMAND
|
||
|
||
CWHANF::MOVE U,0(P) ;COMMAND TTY LDB
|
||
PUSHJ P,SRCNDB ;SEARCH FOR THE NDB
|
||
MOVEI W,NETNDB## ;USE THE LOCAL MODE
|
||
PUSHJ P,TYPNDB ;TYPE THE NODE INFO
|
||
PUSHJ P,PRSPC##
|
||
MOVE T2,DEVNAM(F)
|
||
PUSHJ P,PRNAME##
|
||
MOVSI T1,DVTTY ;CHECK FOR A TTY
|
||
TDNN T1,DEVMOD(F) ;IS DEVICE A TTY?
|
||
JRST [PUSHJ P,ZAPNET ;NO, FREE DDB IF APPROPRIATE
|
||
POP P,U ;RESTORE U
|
||
PJRST CRLF##] ;TYPE CRLF AND EXIT
|
||
MOVE U,DDBLDB##(F) ;YES, GET THE LDB
|
||
LDB T1,LDPLNO## ;GET THE LOCAL LINE NUMBER
|
||
MOVSI T2,LTLANF## ;ANF NETWORK VIRTUAL TERMINAL FLAG
|
||
TDNE T2,LDBTTW##(U) ;CHECK A BIT
|
||
LDB T1,LDPRLN## ;GET REMOTE LINE NUMBER
|
||
POP P,U ;RESTORE THE LDB
|
||
PUSH P,T1 ;SAVE LINE NUMBER
|
||
PUSHJ P,INLMES## ;TYPE OUT
|
||
ASCIZ / line # /
|
||
POP P,T1 ;RESTORE LINE NUMBER
|
||
PUSHJ P,PRTDI8## ;TYPE IT
|
||
PJRST PCRLF## ;AND CRLF
|
||
SUBTTL INTERFACE TO CPNSER
|
||
|
||
|
||
COMMENT @
|
||
|
||
PCBMRK and PCBCHK
|
||
|
||
These routines are used to manage the transfer of PCB's to and from
|
||
Front End Kontrollers in a Multi-Cpu, or Cached environment. The protocol
|
||
for using these two routines is as follows.
|
||
|
||
PCBMRK This routine should be called after the PCB is altered by
|
||
the -10. In a cached environment, it stores the Cache Sweep
|
||
Serial number so that PCBCHK can tell if cache needs to be
|
||
swept at a later date. On a non-cached, or multi-cpu machine
|
||
(free core is not cached on a SMP system) this routine is a
|
||
no-op.
|
||
|
||
PCBCHK This routine should be called with J := FEK address, and
|
||
U := PCB address. It should be immediatly before either
|
||
"FEKRDD" or "FEKWRT" is executed. If it skips, then that
|
||
implies that the FEK may access the data. If it does not
|
||
skip, then either the FEK is on the wrong CPU, or the data
|
||
is still in cache, and may not be accessed by the FEK.
|
||
|
||
@
|
||
IFN FTKL10,< ;THINGS ARE MESSY FOR KL'S
|
||
PCBMRK::CONSO APR,LP.CSB+LP.CSD ;IF THE CACHE IS ALREADY SWEEPING (BUSY)
|
||
TDZA T1,T1 ; THEN IT MAY HAVE MISSED SOME OF THE PCB
|
||
MOVEI T1,1 ; IF SO, ADD ONE TO THE SWEEP SERIAL NUMBER
|
||
ADD T1,.CPCSN## ;GET SWEEP SERIAL NUMBER (MAYBE PLUS ONE)
|
||
MOVEM T1,PCBCSN(U) ;SAVE IT FOR PCBCHK TO LOOK AT
|
||
POPJ P, ;EXIT WITH THE PCB MARKED
|
||
|
||
PCBCHK::
|
||
IFN FTMP,<
|
||
PUSHJ P,MLSCSH## ;SEE IF FRECOR IS CACHED
|
||
POPJ P, ; RETURN NOW. (NO SWEEP PROBLEMS)
|
||
>;END FTMP
|
||
MOVE T1,.CPCSN## ;GET THE CURRENT CSSN
|
||
CAMG T1,PCBCSN(U) ; SEE IF WE'VE SWEPT SINCE LAST ACCESS TO PCB
|
||
PUSHJ P,CSDMP## ;IF NOT, SWEEP NOW. (TOO SLOW TO WAIT)
|
||
POPJ P, ;WE'VE SWEPT, GIVE GOOD RETURN
|
||
|
||
>;END FTKL10
|
||
;ROUTINE CALLED FROM CPNSER WHEN A CPU HAS CRASHED. THIS ROUTINE
|
||
;TELLS NETSER WHICH FRONT ENDS HAVE BECOME INACCESSABLE DUE TO THE
|
||
;CPU GOING DOWN, AND CRASHES THE APPROPRIATE FEKS.
|
||
;CALL: MOVE T1, ADDRESS OF THE CRASHED CPU'S CDB
|
||
; PUSHJ P,BRKFEK
|
||
;
|
||
;PRESERVES ALL ACS
|
||
|
||
IFE FTMP,<BRKFEK==:CPOPJ##>
|
||
IFN FTMP,<
|
||
BRKFEK::SKIPN [M.CPU##-1] ;MULTI-CPU?
|
||
POPJ P, ;NO
|
||
PUSHJ P,SAVT## ;PRESERVE THE T'S
|
||
MOVSI T2,FK.CPD ;FLAG THAT SAYS "THIS FEK'S CPU DIED"
|
||
SKIPA T3,[FEKFST##] ;GET ADDRESS OF THE FIRST FEK.
|
||
BRKFE1: HRRZ T3,FEKBLK(T3) ;GET THE ADDRESS OF THE NEXT FEK.
|
||
JUMPE T3,CPOPJ## ;ZERO ADDRESS MEANS WEVE DONE THEM ALL
|
||
HLRE T4,FEKUNI(T3) ;GET THE CPU NUMBER OF THIS FEKS CPU
|
||
CAME T4,.CPCPN##-.CPCDB##(T1) ;SEE IF THIS IS THE CPU THAT DIED
|
||
JRST BRKFE1 ;NO
|
||
AOS .CPNBI##-.CPCDB##(T1) ;COUNT THE BROKEN INTERLOCK
|
||
IORM T2,FEKBLK(T3) ;IF ON JUST-DEAD CPU, SET BIT FOR 1/SECOND
|
||
JRST BRKFE1 ;GO CHECK THE NEXT FEK.
|
||
> ;END IFN FTMP
|
||
SUBTTL INTERFACE TO UUOCON FOR DDB DISPATCH
|
||
|
||
|
||
SUBTTL NETDDB DISPATCH TABLE
|
||
|
||
JSP T4,DSPOBJ ;(-5) ON LINE CHECK
|
||
JSP T4,DSPOBJ ;(-4) DEVOP. UUO
|
||
JSP T4,DSPOBJ ;(-3) RETURN BUFFER SIZE
|
||
POPJ P, ;(-2) DEVICE INITIALIZATION
|
||
JSP T4,DSPOBJ ;(-1) HUNG DEVICE
|
||
NETDSP::JSP T4,DSPOBJ ;(0) RELEASE DEVICE
|
||
JSP T4,DSPOBJ ;(1) CLOSE
|
||
JSP T4,DSPOBJ ;(2) OUTPUT
|
||
JSP T4,DSPOBJ ;(3) INPUT
|
||
JSP T4,DSPOBJ ;(4) ENTER
|
||
JSP T4,DSPOBJ ;(5) LOOKUP
|
||
JSP T4,DSPOBJ ;(6) DUMP MODE OUTPUT
|
||
JSP T4,DSPOBJ ;(7) DUMP MODE INPUT
|
||
JSP T4,DSPOBJ ;(10) USETO
|
||
JSP T4,DSPOBJ ;(11) USETI
|
||
JSP T4,DSPOBJ ;(12) UGETF UUO
|
||
JSP T4,DSPOBJ ;(13) RENAME UUO
|
||
JSP T4,DSPOBJ ;(14) CLOSE INPUT
|
||
JSP T4,DSPOBJ ;(15) UTPCLR UUO
|
||
JSP T4,DSPOBJ ;(16) MTAPE UUO
|
||
|
||
;DISPATCH ON THE OBJECT TYPE
|
||
DSPOBJ: SUBI T4,NETDSP+1 ;RELOCATE THE ENTRY
|
||
HRRES T4 ;MAKE IT A FULL WORD NUMBER
|
||
MOVSI W,DVCNET ;GET THE NETWORK DEVICE BIT
|
||
TDNN W,DEVCHR(F) ;IS THIS A NETWORK DEVICE?
|
||
STOPCD CPOPJ##,DEBUG,DFU,;++DEVICE UNRECOGNIZED
|
||
|
||
IFN PARANOID&P$DDB,< ;SOME CONSISTENCY CHECKING
|
||
MOVSI W,DVLNG ;THE LONG-DISPATCH FLAG
|
||
TDNN W,DEVMOD(F) ;CAN DEVICE HANDLE WHIZZY FUNCTIONS?
|
||
CAIG T4,DIN ;NO, WAS WHIZZY ACTION REQUESTED?
|
||
CAIA ;REASONABLE FUNCTION
|
||
PUSHJ P,NTDSTP ;++ BAD DEVSER DISPATCH
|
||
IFN FTXMON,<
|
||
XMOVEI W,. ;GET CURRENT PC
|
||
TLNE W,-1 ;NETSER/NETDEV/ET AL REALLY WANT SECTION 0
|
||
PUSHJ P,NTDSTP ;CALLED FROM NON-ZERO SECTION!
|
||
> ;IFN FTXMON
|
||
> ;IFN PARANOID&P$DDB
|
||
CAME T4,[DDVO] ;EXCEPT FOR DEVOP. UUO
|
||
JUMPL T4,DSPOB1 ;DON'T INTERLOCK HUNG DEVICE CHECK ETC.
|
||
; (THEY COME IN AT LEVEL #7)
|
||
NETDBJ ;NETSER INTERLOCK FROM HERE ON..
|
||
|
||
DSPOB1: HLRZ W,DEVNET(F) ;GET THE NDT POINTER
|
||
PJRST @NDTDSP(W) ;GO TO DEVICE DEPENDENT SERVICE ROUTINE
|
||
; (NDTDSP IS @N---DP(T4))
|
||
SUBTTL INTERFACE TO UUOCON FOR THE NODE UUO
|
||
|
||
;NODE. UUO SUB-FUNCTIONS
|
||
; .NDALN==1 ;ASSIGN LOGICAL NAME
|
||
; .NDRNN==2 ;RETURN NODE NUMBER
|
||
; .NDSSM==3 ;SEND STATION CONTROL MESSAGE
|
||
; .NDRBM==4 ;RECEIVE BOOT REQUEST MESSAGE
|
||
; .NDRCI==5 ;RETURN CONFIGURATION INFORMATION
|
||
; .NDOUT==6 ;DO DOUTPU WITH E-O-R (NOT IMPLEMENTED)
|
||
; .NDIN==7 ;DO INPUT WITH E-O-R (NOT IMPLEMENTED)
|
||
; .NDTCN==10 ;TERMINAL CONNECT
|
||
; .NDTDS==11 ;TERMINAL DIS-CONNECT
|
||
; .NDLND==12 ;LIST KNOWN NODES
|
||
; .NDNDB==13 ;RETURN VARIOUS NDB FIELDS
|
||
; .NDGNF==14 ;GET NEXT UN-GREETED NODE, CLEAR UN-GREETED FLG
|
||
|
||
|
||
;NODE. UUO ERROR CODES
|
||
|
||
ND%IAL==ECOD1## ;ILLEGAL ARGUMENT LIST
|
||
ND%INN==ECOD2## ;ILLEGAL NODE NAME/NUMBER
|
||
ND%PRV==ECOD3## ;CALLER NOT PRIVILEGED
|
||
ND%NNA==ECOD4## ;NODE NOT AVAILABLE
|
||
ND%NLC==ECOD5## ;NOT LOCKED IN CORE
|
||
ND%TOE==ECOD6## ;TIME OUT ERROR
|
||
ND%RNZ==ECOD7## ;RESERVED WORD NOT ZERO
|
||
ND%NND==ECOD10## ;NOT NETWORK DEVICE
|
||
ND%IOE==ECOD11## ;IO ERROR
|
||
ND%NFC==ECOD12## ;NO FREE CORE
|
||
ND%IAJ==ECOD13## ;IN USE BY ANOTHER JOB (TERMINAL)
|
||
ND%NMA==ECOD14## ;NO MESSAGE AVAILABLE
|
||
ND%TNA==ECOD15## ;TERMINAL NOT AVAILABLE
|
||
ND%NLT==ECOD16## ;NOT A LEGAL TERMINAL
|
||
ND%ISF==ECOD17## ;ILLEGAL SUB-FUNCTION
|
||
ND%RBS==ECOD20## ;RECEIVE BUFFER TOO SMALL
|
||
ND%NUG==ECOD21## ;NO UNGREETED NODES
|
||
ND%ILN==ECOD22## ;ILLEGAL LINE NUMBER (IN STC MESSAGE)
|
||
ND%ADC==ECOD23## ;ADDRESS CHECK
|
||
NODE.U:: ;ENTRY POINT
|
||
HLRZ T4,T1 ;GET THE FUNCTION IN T4
|
||
SKIPE T4 ;NOT ZERO
|
||
CAILE T4,NUULEN ;CHECK THE LENGTH
|
||
JRST ND%IAL ;ILLEGAL RETURN 1
|
||
HRRI M,(T1) ;GET THE ARG LIST IN M
|
||
NETDBJ ;INTERLOCK THIS CODE
|
||
JRST UUOTAB-1(T4) ;JUMP ON THE FUNCTION TYPE
|
||
|
||
UUOTAB: ;NODE UUO FUNCTIONS
|
||
JRST NODE.1 ;ASSIGN A DEVICE
|
||
JRST NODE.2 ;RETURN A NODE NUMBER
|
||
JRST NODE.3 ;STATION CONTOL MESSAGE
|
||
JRST NODE.4 ;AUTO RELOAD OF DAS 80 SERIES
|
||
JRST NODE.5 ;RETURN CONFIG INFO FOR NODE
|
||
JRST CPOPJ## ;OUTPUT DATA TO NETWORK
|
||
JRST CPOPJ## ;INPUT DATA FROM NETWORK
|
||
JRST NODE10 ;CONNECT A TERMINAL
|
||
JRST NODE11 ;DISCONNECT A TERMINAL
|
||
JRST NODE12 ;GET COUNT AND NUMBERS OF ALL NODES
|
||
JRST NODE13 ;GET SELECTED INFORMATION ABOUT A NODE
|
||
JRST NODE14 ;RETURN/CLEAR UN-GREETED NODE FLAG
|
||
NUULEN==.-UUOTAB ;LENGTH OF THE TABLE
|
||
SUBTTL NODE.1 - ASSIGN A REMOTE DEVICE
|
||
NODE.1: POPJ P, ;RESERVED (UNTIL IT WORKS)
|
||
PUSHJ P,SAVE4## ;SAVE THE P'S
|
||
PUSHJ P,GETWRD## ;GET THE ARGUMENT LIST SIZE
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
CAIE T1,4 ;MUST HAVE FOUR ARGS
|
||
JRST ECOD1## ;ILLEGAL ARG LIST
|
||
PUSHJ P,GETWR1## ;GET THE NODE NAME
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
PUSHJ P,SRCNDB ;CHECK IF DEFINED
|
||
JRST ECOD2## ;NO, ILLEGAL NODE NAME
|
||
HLRZ T1,NDBNNM(W) ;GET NODE NUMBER
|
||
CAMN T1,JBTLOC## ;IS IT LOCAL SITE?
|
||
JRST ECOD2## ;YES, CAN'T ASSIGN LOCAL DEVICE
|
||
MOVEI P1,(W) ;SAVE THE NODE DATA BLOCK
|
||
PUSHJ P,GETWR1## ;GET THE PHYSICAL DEVICE NAME
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
SKIPN P2,T1 ;COPY THE NAME
|
||
JRST ECOD3## ;ZERO IS ILLEGAL
|
||
HLRZS T1 ;GENERIC NAME ONLY FOR SEARCH
|
||
PUSHJ P,SRCNDT ;SEARCH THE DEFINED NAME TABLE
|
||
JRST ECOD3## ;ILLEGAL DEVICE NAME
|
||
PUSHJ P,GETWR1## ;GET THE LOGICAL NAME
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
MOVE P3,T1 ;COPY THE NAME
|
||
PUSHJ P,MAKDDB ;MAKE A REMOTE NETWORK DDB
|
||
JRST ECOD4## ;NO CORE AVAILABLE
|
||
PUSHJ P,NCSCNT ;CONNECT THE DEVICE
|
||
JRST [MOVEI T1,10(T1);STEP UP THE ERROR NUMBER
|
||
PUSHJ P,STOTAC## ;TELL CALLER WHY IT FAILED
|
||
PJRST RMVNET] ;REMOVE DDB FROM SYSTEM
|
||
PUSHJ P,LNKDDB ;LINK NEWLY CONNECTED DDB
|
||
MOVEI T1,ASSCON ;NOW THAT WE'VE ASSIGNED THE DEVICE, WE
|
||
IORM T1,DEVMOD(F) ; BETTER MARK IT. (OR ELSE UUOCON WILL ZAP IT)
|
||
MOVE T1,DEVNAM(F) ;GET NAME OF DEVICE WE CREATED
|
||
PJRST STOTC1## ;TELL USER AND SUCCEED
|
||
SUBTTL NODE.2 RETURN A NODE NUMBER IN THE AC
|
||
NODE.2: ;ENTRY
|
||
PUSHJ P,GETWRD## ;GET THE ARG COUNT
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
CAIE T1,2 ;MUST BE A 2
|
||
JRST ND%IAL ;NO ILLEGAL FUNCTION
|
||
PUSHJ P,GETWR1## ;GET THE NODE NAME
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
PUSHJ P,NODE.S ;FIND CORRECT NDB
|
||
PJRST ND%INN ;ILLEGAL NODE
|
||
MOVE T2,T1 ;COPY ARGUMENT
|
||
HLRZ T1,NDBSNM(W) ;GET THE NAME POINTER
|
||
MOVE T1,(T1) ;GET THE NAME
|
||
TLNE T2,-1 ;WANTS A NAME?
|
||
HLRZ T1,NDBNNM(W) ;NO, GET THE NODE NUMBER
|
||
PJRST STOTC1## ;RETURN NODE NUMBER IN AC
|
||
|
||
;SUBROUTINE TO FIND NDB FOR NODE.UUO FUNCTIONS
|
||
;CALL T1 = ARGUMENT TO NODE.UUO
|
||
;RETURNS CPOPJ IF NOT FOUND
|
||
; CPOPJ1 WITH W SET TO NDB, RESPECTS T1
|
||
|
||
NODE.S::PUSH P,T1 ;SAVE ARGUMENT
|
||
PUSHJ P,SRCNDB ;SCAN NDB'S
|
||
PJRST TPOPJ## ;NOPE, GIVE ERROR
|
||
MOVSI T1,NDB.UP ;DON'T DO THE TRANSLATION
|
||
TDNN T1,NDBFLG(W) ; UNLESS THE NODE IS UP.
|
||
JRST TPOPJ## ; IF WE DO, WE GET GARBAGE NAMES
|
||
PJRST TPOPJ1## ;RETURN WITH W SET UP
|
||
SUBTTL NODE.3 STATION CONTROL MESSAGES
|
||
;FORMAT OF THE UUO ARGS
|
||
; XWD TIME,ARG-LIST-LENGTH
|
||
; SIXBIT /NODE NAME/ OR NUMBER
|
||
; XWD COUNT,ADR OF OUTPUT BUFFER
|
||
; XWD COUNT,ADR OF RESPONSE BUFFER
|
||
|
||
NODE.3: PUSHJ P,NTDPRV ; SURE THAT THIS GUY IS PRIVILEDGED
|
||
PJRST ND%PRV ;USER HAS INSUFFICIENT PRIVILEDGES
|
||
PUSHJ P,SAVJW## ;WE WILL CLOBBER THESE
|
||
PUSHJ P,SAVE4## ;WE COPY THE UUO ARGS IN P1 - P4
|
||
PUSHJ P,N34SET ;GO READ THE UUO ARGS
|
||
POPJ P, ; IF BAD ARGLIST, PROPAGATE THE ERROR
|
||
MOVE T1,P2 ;GET THE SECOND ARG (NODE ID)
|
||
PUSHJ P,SRCNDB ;GO SET W := NDB POINTER
|
||
JRST ND%INN ;IF NO NDB, GIVE ILLEGAL NODE ERROR
|
||
CAIN W,NETNDB## ;IF HE SPECIFIED THE LOCAL NODE,
|
||
JRST NODE3L ; GO TRY TO SEND MSG TO A FEK
|
||
HRRZ J,NDBSTC(W) ;SEE IF ANYONE IS USING STATION CONTROL
|
||
CAMN J,.CPJOB## ;IF WE ARE USING IT, THEN ASSUME A PAGE
|
||
JRST N34NRD ; FAULT WHILE READING STC AND TRY AGAIN
|
||
JUMPN J,ND%NNA ;IF SOMEONE ELSE HAS IT, NOT AVAILABLE
|
||
|
||
HRRZ J,NDBICT(W) ;GET MESSAGE ADDR
|
||
SKIPE J ;IS THERE ONE?
|
||
PUSHJ P,GIVSTC ; FREE IT, SINCE LOOKING FOR A RESPONSE
|
||
SETZM NDBICT(W) ;CLEAR THE INCOMING MESSAGE POINTER.
|
||
;NOW SEND THE STATION CONTROL MESSAGE
|
||
|
||
MOVEI T1,(P3) ;GET THE ADDRESS OF THE OUTPUT MESSAGE
|
||
HLRE T2,P3 ;GET ITS LENGTH IN BYTES
|
||
JUMPLE T2,ND%IAL ;IF GARBAGE LENGTH, GIVE ILLEGAL ARG ERROR
|
||
ADDI T2,3 ;ROUND UP AND GET THE LENGTH OF THE
|
||
LSH T2,-2 ;MESSAGE IN WORDS
|
||
PUSH P,T2 ;SAVE LENGTH IN WORDS FOR LATER
|
||
HRLI T1,(IFIW) ;SECTION LOCAL ADDRESSING
|
||
PUSHJ P,ARNGE## ;MAKE SURE ALL THE DATA IS IN CORE.
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
JFCL ;ADDR OK BUT ILLEGAL FOR I/O (IGNORED HERE)
|
||
|
||
HRRZ T1,(P) ;GET THE WORD COUNT BACK
|
||
ADDI T1,5 ;ACCOUNT FOR A HEADER AND WORD ALIGNMENT
|
||
PUSHJ P,MKNPCB ;MAKE A "NUMBERED" PCB
|
||
JRST [POP P,T1 ;IF NO CORE, CLEAN UP THE STACK
|
||
JRST ND%NFC] ; AND GIVE THE "NO FREE CORE" ERROR
|
||
PUSH P,P2 ;SAVE THE NODE'S NAME/NUMBER
|
||
PUSH P,P3 ;SAVE THE OUTPUT BUFFER POINTER
|
||
MOVE P2,PCBPTR(U) ;GET BYTE POINTER TO THE PCB
|
||
SETZ T1, ;WE WANT AN NCT OF 0 (NUMBERED MSG)
|
||
PUSHJ P,NCSWHD ;WRITE THE NCL HEADER
|
||
;DLA
|
||
XMTI 0 ;DLA = 0 MEANS NOT DEVICE CONTROL
|
||
;CNT
|
||
HLRZ T1,(P) ;GET MESSAGE'S BYTE COUNT
|
||
ADDI T1,1 ; +1 FOR "NC.CTL" TYPE FIELD
|
||
XMT T1 ;WRITE THE COUNT
|
||
;TYP
|
||
XMTI NC.CTL ;THIS IS A STATION CONTROL MESSAGE
|
||
ADDM P3,PCBCTR(U) ;THAT'S ALL OF THE "HEADER" UPDATE ITS LENGTH
|
||
POP P,P3 ;GET THE OUTPUT MESSAGE POINTER BACK
|
||
;NOW BLT THE DATA INTO THE PCB
|
||
|
||
MOVEI T1,1(P2) ;GET THE ADDRESS OF FIRST "FULL" FREE WORD
|
||
HRLI T1,(POINT 8,0) ;MAKE ADDRESS A BYTE POINTER
|
||
MOVEM T1,PCBPT2(U) ; STORE IT AS "SECONDARY" BUFFER POINTER
|
||
|
||
HLRZM P3,PCBCT2(U) ;SET NUMBER OF BYTES TO WRITE AS SECONDARY SIZE
|
||
|
||
HRLI T1,(P3) ;GET THE USER ADDRESS OF THE DATA IN SRC(BLT)
|
||
POP P,P2 ;GET THE NODE NUMBER BACK
|
||
IFE FTXMON,<
|
||
POP P,T2 ;GET THE LENGTH OF THE DATA IN WORDS
|
||
ADDI T2,-1(T1) ;GET ADDRESS OF LAST WORD TO FILL WITH DATA
|
||
EXCTUX <BLT T1,(T2)> ;COPY THE DATA TO THE PCB
|
||
>
|
||
IFN FTXMON,<
|
||
XSFM T2 ;GET PCS
|
||
HRLZS T2 ;IN LH WHERE IT BELONGS
|
||
HLR T2,T1 ;FORM USER SOURCE ADDRESS
|
||
HRRZ T3,T1 ;FORM MONITOR DESTINATION ADDRESS
|
||
POP P,T1 ;GET THE LENGTH OF THE DATA IN WORDS
|
||
XBLTUX T1 ;COPY THE DATA TO THE PCB
|
||
>
|
||
|
||
MOVEI T1,PCV.NC ;SAY THAT DATA IS 8 BIT BYTES (NO CONVERSION)
|
||
PUSHJ P,NTDWRT ;GIVE THE MESSAGE TO THE NETWORK
|
||
|
||
;NOW CLAIM OWNERSHIP OF STATION CONTROL AND WAIT FOR A RESPONSE
|
||
|
||
JUMPE P4,CPOPJ1## ;IF NO RESPONSE BUFFER, UUO IS DONE.
|
||
HLLZ T1,P1 ;LH OF NDBSTC := SECONDS TO WAIT FOR ANSWER
|
||
SKIPN T1 ;IF USER SPECIFIED A TIME, THEN USE HIS
|
||
MOVSI T1,10 ; OTHERWISE DEFAULT TO 8 SECONDS
|
||
MOVE J,.CPJOB## ;GET OUR JOB NUMBER
|
||
HRRI T1,(J) ;RH OF NDBSTC := JOB TO WAKE UPON ANSWER
|
||
MOVEM T1,NDBSTC(W) ;STORE NDBSTC SO ICMCTL CAN WAKE US
|
||
|
||
NODE31: MOVEI T1,EV.STC ;GET THE "STATION CONTROL" EVENT WAIT CODE
|
||
PUSHJ P,[NTSAVE ; RETURN THE "NT" RESOURCE
|
||
JRST ESLEEP##] ; AND SLEEP UNTIL MSG COMES OR WE TIME OUT
|
||
|
||
MOVE T1,P2 ;WE'VE BEEN AWAKENED. TRACK THE NDB DOWN AGAIN
|
||
PUSHJ P,SRCNDB ; AS IT MAY HAVE CRASHED.
|
||
PJRST ND%INN ;IF NDB GONE, GIVE ILLEGAL NODE ERROR
|
||
SKIPE T1,NDBICT(W) ;SEE IF THERE IS AN INCOMING MESSAGE
|
||
PJRST N34NRD ;IF RESPONSE, GO READ IT
|
||
SKIPN T1,NDBSTC(W) ;SEE IF STATION CONTROL STILL ASSIGNED
|
||
PJRST ND%TOE ;IF NOT, WE MUST HAVE TIMED OUT.
|
||
MOVEI T1,(T1) ;GET JUST THE JOB NUMBER
|
||
CAME T1,.CPJOB## ;MAKE SURE WE STILL OWN STATION CONTROL
|
||
PJRST ND%TOE ;IF NOT, THEN TIME OUT ERROR
|
||
JRST NODE31 ;IF SO, THEN SPURIOUS WAKE, SLEEP SOME MORE
|
||
IFE FTKS10,<NODE3L==ND%INN> ;THE KS-10 IS CURRENTLY THE ONLY SYSTEM
|
||
; THAT CAN DOWN-LINE LOAD ITS FEKS.
|
||
|
||
IFN FTKS10,< ;IF ON A KS-10, ASSEMBLE STC-FEK STUFF
|
||
|
||
;HERE WHEN A STC MESSAGE FOR THE "LOCAL" NODE IS SEEN. SEE IF IT'S FOR
|
||
; ONE OF OUR LINES. IF IT IS, SEND THE STC MESSAGE TO THE FEK.
|
||
|
||
NODE3L: MOVEI T1,(P3) ;GET THE ADDRESS OF THE STC MESSAGE
|
||
MOVE J,.CPJOB## ;SET UP OUR JOB (SO WE DON'T GET AN LN1)
|
||
PUSHJ P,UADRCK## ;MAKE SURE IT'S LEGAL AND IN CORE
|
||
EXCTUX <LDB T1,[POINT 8,(P3),7]> ;GET THE "LINE NUMBER FIELD"
|
||
JUMPE T1,ND%INN ;DON'T LET STC TO THIS NODE DO ANYTHING
|
||
PUSHJ P,LN2FEK ;CONVERT LINE NUMBER TO FEK ADDRESS (IN "J")
|
||
JRST ND%ILN ;GIVE "ILLEGAL LINE NUMBER" IF NO SUCH FEK
|
||
HRRZ T1,FEKBJN(J) ;GET THE NUMBER OF JOB OWNING STC ON FEK
|
||
CAMN T1,.CPJOB## ;IF WE OWN THE STC OF THIS FEK,
|
||
JRST NODFRD ; ASSUME PAGE FAULT WHILE STORING RESPONSE
|
||
JUMPN T1,ND%NNA ;IF SOMEONE ELSE HAS STC, SAY "NOT AVAIL"
|
||
|
||
;HERE STC FOR THIS FEK IS FREE. COPY THE MESSAGE AND SEND IT
|
||
|
||
MOVE W,J ;USE "W" AS A FEK POINTER FOR A BIT
|
||
SKIPE J,FEKICT(W) ;SEE IF THERE ARE ANY STALE INPUT MSGS
|
||
PUSHJ P,GIVSTC ;IF STALE MSGS, FREE THEM
|
||
SETZM FEKICT(W) ;CLEAR INCOMING MESSAGE POINTER
|
||
|
||
MOVEI T1,(P3) ;GET USER ADDRESS OF MESSAGE TO SEND
|
||
HLRE T2,P3 ;GET LENGTH OF THE MESSAGE (BYTES)
|
||
JUMPLE T2,ND%IAL ;SAY ILLEGAL ARG LIST IF GARBAGE LENGTH
|
||
ADDI T2,3 ;WE WANT LENGTH IN WORDS. ROUND BYTES UP
|
||
LSH T2,-2 ; AND DIVIDE BY 4 BYTES PER WORD
|
||
PUSH P,T2 ;SAVE THE WORD COUNT FOR BLT COMING UP
|
||
HRLI T1,(IFIW) ;SECTION LOCAL ADDRESSING
|
||
PUSHJ P,ARNGE## ;MAKE SURE WE DON'T IME.
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
JFCL ;ADDR OK BUT ILLEGAL FOR I/O (IGNORED HERE)
|
||
|
||
HLRE T1,P3 ;GET THE BYTE COUNT AGAIN
|
||
PUSHJ P,GETSTC ;GET A STC BLOCK TO HOLD THE DATA
|
||
JRST [POP P,T1 ;IF NO CORE, FIXUP THE STACK
|
||
JRST ND%NFC] ; AND TELL THE USER
|
||
|
||
IFE FTXMON,<
|
||
MOVSI T1,(P3) ;SOURCE(BLT) := USER ADDRESS
|
||
HRRI T1,STCDAT(J) ;DEST(BLT) := STC BLOCK
|
||
POP P,T2 ;GET THE LENGTH (IN WORDS) BACK
|
||
ADDI T2,-1(T1) ;GET LAST MONITOR ADDRESS TO FILL
|
||
EXCTUX <BLT T1,(T2)> ;COPY THE DATA INTO THE STC BLOCK
|
||
>
|
||
IFN FTXMON,<
|
||
XSFM T2 ;GET PCS
|
||
HRLZS T2 ;IN LH WHERE IT BELONGS
|
||
HRRI T2,(P3) ;FORM USER SOURCE ADDRESS
|
||
HRRZI T3,STCDAT(J) ;FORM MONITOR DESTINATION ADDRESS
|
||
POP P,T1 ;GET THE LENGTH (IN WORDS) BACK
|
||
XBLTUX T1 ;COPY DATA TO STC BLOCK
|
||
>
|
||
;NOW PUT OUR NODE NUMBER IN THE FIRST BYTE, AND GIVE MSG TO THE FEK
|
||
|
||
HLRZ T1,NETNDB##+NDBNNM ;GET OUR NODE NAME
|
||
DPB T1,[POINT 8,STCDAT(J),7] ; AND STORE IT AS THE "SNA"
|
||
|
||
MOVE U,J ;SET UP U := STC MESSAGE
|
||
MOVE J,W ; AND J := FEK -- FOR CALL TO FEK
|
||
|
||
HLRE T1,P1 ;GET THE USERS TIMER VALUE
|
||
SKIPG T1 ;IF HE DIDN'T SPECIFY A VALUE
|
||
MOVEI T1,10 ; THEN USE 8 SECONDS
|
||
MOVSI T1,(T1) ;PUT TIMER IN THE LH
|
||
HRR T1,.CPJOB## ;GET OUR JOB NUMBER
|
||
MOVEM T1,FEKBJN(J) ;CLAIM OWNERSHIP OF THE FEK'S STC
|
||
|
||
MOVEI T1,FF.STC ;GET THE "STC" FUNCTION CODE
|
||
XCT FEKDSP(J) ;CALL THE FEK
|
||
JRST [SETZM FEKBJN(J);IF THE FEK DOESN'T ACCEPT THE STC,
|
||
MOVEI J,(U) ; CLEAR STC OWNERSHIP, GET STC IN "J"
|
||
PUSHJ P,GIVSTC ; FREE THE STC BLOCK
|
||
JRST ND%ILN] ; AND GIVE ILLEGAL LINE ERROR
|
||
JUMPE P4,[SETZM FEKBJN(J) ;IF NO RESPONSE WANTED, CLEAR OWNER
|
||
RETSKP] ; AND GIVE GOOD RETURN
|
||
|
||
;NOW WE'VE SENT THE MESSAGE. CHECK FOR A RESPONSE. IF NONE, WAIT.
|
||
|
||
NOD3L1: HRRZ T1,FEKBJN(J) ;GET THE OWNER OF THE FEK'S STC
|
||
CAME T1,.CPJOB## ;MAKE SURE IT'S US.
|
||
JRST ND%TOE ;IF NOT US, THEN GIVE "TIME OUT ERROR"
|
||
|
||
SKIPE FEKICT(J) ;SEE IF ANY INCOMING MSGS.
|
||
JRST NODFRD ;IF INCOMING MESSAGE. RETURN IT TO THE USER
|
||
|
||
MOVEI T1,EV.STC ;GET THE "STATION CONTROL" EVENT WAIT CODE
|
||
PUSH P,J ;SAVE OUR FEK FOR A BIT
|
||
MOVE J,.CPJOB## ;SET J := JOB NUMBER (FOR ESLEEP)
|
||
PUSHJ P,[NTSAVE ;RETURN THE "NT" INTERLOCK
|
||
JRST ESLEEP##] ; AND SLEEP WAITING FOR A RESPONSE
|
||
POP P,J ;GET OUR FEK ADDRESS BACK
|
||
JRST NOD3L1 ;UPON AWAKING, SEE IF WE HAVE A MSG.
|
||
|
||
>;END IFN FTKS10
|
||
SUBTTL NODE.4 RECEIVE STATION CONTROL BOOT MESSAGES
|
||
;FORMAT OF THE UUO ARGS
|
||
; EXP 0
|
||
; EXP 0
|
||
; EXP 0
|
||
; XWD COUNT,ADR OR RESPONSE BUFFER
|
||
|
||
NODE.4: PUSHJ P,NTDPRV ; SURE THAT THIS GUY IS PRIVILEDGED
|
||
PJRST ND%PRV ;USER HAS INSUFFICIENT PRIVILEDGES
|
||
PUSHJ P,SAVJW## ;WE WILL CLOBBER THESE
|
||
PUSHJ P,SAVE4## ;WE COPY THE UUO ARGS IN P1 - P4
|
||
PUSHJ P,N34SET ;GO READ THE UUO ARGS
|
||
POPJ P, ; IF BAD ARGLIST, PROPAGATE THE ERROR
|
||
|
||
;NOW SEARCH FOR AN NDB WITH AN UNCLAIMED INCOMING CONTROL MESSAGE
|
||
|
||
SKIPA W,[EXP NETNDB##];START WITH OUR NDB
|
||
NODE41: HRRZ W,NDBNNM(W) ;STEP TO THE NEXT NDB
|
||
JUMPE W,NODE42 ;IF NO MSGS ON NDB'S, CHECK FEKS
|
||
SKIPN NDBSTC(W) ;IF SOME JOB IS WAITING, OR
|
||
SKIPN NDBICT(W) ; IF NO STC MESSAGE HAS COME,
|
||
JRST NODE41 ; THEN GO TRY NEXT NDB
|
||
|
||
N34NRD: HRRZ J,NDBICT(W) ;GET THE ADDRESS OF THE STC MESSAGE
|
||
JUMPE J,ND%TOE ;IF NONE, THEN PROBABLY A TIME OUT
|
||
HLL T1,STCBLK(J) ;THE NUMBER OF BYTES IS THE LH(STCBLK)
|
||
HLLZM T1,STCLNN(J) ; SAVE THE COUNT FOR N34RED
|
||
PUSHJ P,N34RED ;STORE THE MESSAGE IN THE USERS BUFFER
|
||
SOS (P) ;PROPAGATE THE ERROR (IF ANY)
|
||
SETZM NDBSTC(W) ;CLEAR STC OWNERSHIP
|
||
SETZM NDBICT(W) ;CLEAR (NOW FREED) INCOMING STC MSG
|
||
RETSKP ;GIVE (POSSIBLY BAD) RETURN
|
||
IFE FTKS10,<NODE42==ND%NMA> ;IF NO MESSAGES FROM FEKS, SAY NO MSG AVAIL
|
||
IFN FTKS10,< ;THE KS-10 GETS STC MSGS FROM ITS D8K FEKS
|
||
|
||
NODE42: MOVEI J,FEKFST## ;GET THE ADDRESS OF THE FIRST FEK.
|
||
CAIA ;SKIP INTO THE LOOP
|
||
NODE43: HRRZ J,FEKBLK(J) ;ADVANCE TO THE NEXT FEK
|
||
JUMPE J,ND%NMA ;IF NO MORE, SAY "NO MESSAGE AVAILABLE"
|
||
SKIPN FEKBJN(J) ;IF SOMEONE IS WAITING, OR
|
||
SKIPN FEKICT(J) ; THERE ISN'T A MESSAGE
|
||
JRST NODE43 ;GO TRY THE NEXT FEK.
|
||
|
||
;NODFRD ROUTINE TO RETURN THE STC MESSAGE QUEUED ON FEK
|
||
;CALL J := FEK
|
||
;RETURN CPOPJ ;ERROR (BUT STC FREED)
|
||
; CPOPJ1 ;OK (STC FREED)
|
||
|
||
NODFRD: SKIPN U,FEKICT(J) ;GET U := INCOMING MESSAGE
|
||
JRST ND%TOE ;IF NONE, ASSUME A TIME OUT ERROR (?)
|
||
EXCH J,U ;REMEMBER THE FEK, SET J := STC MSG
|
||
|
||
;NOW REMOVE ANY NODE NUMBER ON THE MESSAGE AND INSERT THE LINE NUMBER
|
||
; THIS MEANS COPYING THE MESSAGE DOWN IF THE NODE NUMBER IS EXTENSIBLE
|
||
|
||
HLRZ T1,STCBLK(J) ;GET THE INITIAL LENGTH OF THE MESSAGE
|
||
MOVE T2,[POINT 8,STCDAT(J)] ;A POINTER TO THE MESSAGE
|
||
MOVEI T3,1 ;FINAL VALUE OF MESSAGE (START WITH LINE #)
|
||
MOVE T4,T2 ;"PUTTER" BYTE POINTER FOR COPYING
|
||
|
||
SOJGE T1,[ILDB W,T2 ;GET NEXT BYTE
|
||
TRNE W,200 ;AND SEE IF IT'S STILL THE NODE NUMBER
|
||
JRST . ;STILL EXTENSIBLE, KEEP LOOKING
|
||
JRST .+1] ; END OF NODE NUMBER
|
||
|
||
HRRZ W,STCLNN(J) ;GET THE LINE NUMBER
|
||
IDPB W,T4 ;STORE AS THE FIRST BYTE
|
||
; AOS T3 ;COUNT THE BYTE (DONE ABOVE...)
|
||
|
||
SOJGE T1,[ILDB W,T2 ;FOR ALL THE REST OF THE BYTES, LOAD
|
||
IDPB W,T4 ; AND STORE IN THE NEW MESSAGE
|
||
AOJA T3,.] ; COUNT THE BYTE AND LOOP
|
||
|
||
HRLM T3,STCLNN(J) ;STORE THE LENGTH FOR N34RED
|
||
|
||
MOVEI W,NETNDB## ;SET UP "W" := NETNDB TO RETURN OUR NODE #
|
||
PUSHJ P,N34RED ;STUFF THE MESSAGE IN THE USERS BUFFER
|
||
SOS (P) ;IF FAIL RETURN, MAKE SURE WE DON'T SKIP
|
||
SETZM FEKBJN(U) ;CLEAR THE STC OWNER
|
||
SETZM FEKICT(U) ;CLEAR ANY INCOMING MSG (N34RED FREED IT)
|
||
RETSKP
|
||
|
||
>; END OF IFN FTKS10
|
||
;N34RED ROUTINE TO COPY STC MESSAGES BACK INTO THE USERS BUFFER
|
||
;CALL P1 - P4 := AS SET UP BY N34SET
|
||
; J := ADDR OF STC MESSAGE TO COPY
|
||
; W := NDB OF NODE WHOS NUMBER WE RETURN AS THE BOOT NODE
|
||
;RETURN NOT AT ALL IF ADDRESS CHECK OR PAGE FAULT
|
||
; CPOPJ ;IF ERROR, WITH STC BLOCK FREED
|
||
; CPOPJ1 ;IF OK, WITH STC BLOCK FREED
|
||
|
||
N34RED: MOVEI T1,(P4) ;GET THE ADDRESS OF THE USER'S INPUT BUFFER
|
||
HLRZ T2,STCLNN(J) ;GET THE LENGTH OF THE STC MESSAGE (BYTES)
|
||
HLRZ T3,P4 ;GET THE LENGTH OF THE USER'S BUFFER (BYTES)
|
||
CAIGE T3,(T2) ;IF THE MESSAGE IS LONGER THAN THE USER'S
|
||
JRST [PUSHJ P,GIVSTC ;IF STC WON'T FIT, FREE THE MESSAGE
|
||
PJRST ND%RBS] ; AND GIVE A "RECEIVE BUFFER 2 SMALL" ERROR
|
||
ADDI T2,3 ;ROUND BYTES UP TO NEXT EVEN WORD
|
||
LSH T2,-2 ;CONVERT BYTES TO WORDS
|
||
PUSH P,T2 ;SAVE LENGTH IN WORDS
|
||
HRLI T1,(IFIW) ;SECTION LOCAL ADDRESSING
|
||
PUSHJ P,ARNGE## ;RANGE CHECK THE USER'S INPUT BUFFER AREA
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
JRST ND%ADC ;ILLEGAL FOR I/O
|
||
|
||
IFE FTXMON,<
|
||
POP P,T2 ;GET LENGTH BACK
|
||
ADDI T2,-1(T1) ;COMPUTE LAST ADDRESS
|
||
MOVEI T1,(P4) ;GET THE ADDRESS OF THE USER'S BUFFER BACK
|
||
HRLI T1,STCDAT(J) ;GET THE ADDRESS OF THE STC MESSAGE
|
||
EXCTXU <BLT T1,(T2)> ;COPY THE STC MESSAGE
|
||
>
|
||
IFN FTXMON,<
|
||
XSFM T3 ;GET PCS
|
||
HRLZS T3 ;IN LH WHERE IT BELONGS
|
||
HRRI T3,(P4) ;FORM USER DESTINATION ADDRESS
|
||
HRRZI T2,STCDAT(J) ;FORM MONITOR SOURCE ADDRESS
|
||
POP P,T1 ;GET LENGTH IN WORDS BACK
|
||
XBLTXU T1 ;COPY THE STC MESSAGE
|
||
>
|
||
|
||
PUSH P,J ;PROTECT STC POINTER FROM DEATH BY PUTWRD
|
||
HRRI M,1(M) ;SET RH(M) TO THE ADDRESS TO RETURN NODE NUMBER
|
||
HLRZ T1,NDBNNM(W) ;GET THE NODE NUMBER
|
||
PUSHJ P,PUTWRD## ;RETURN THE NODE NUMBER
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
|
||
MOVEI T1,(P4) ;GET THE ADDRESS OF THE USERS INPUT BUFFER
|
||
HRRZ J,(P) ;RECOVER STC POINTER AGAIN
|
||
HLL T1,STCLNN(J) ;GET THE NUMBER OF VALID BYTES IN IT
|
||
HRRI M,2(M) ;SET RH(M) TO ADDRESS OF USERS INPUT BUFFER
|
||
PUSHJ P,PUTWRD## ;STORE UPDATED "XWD LENGTH,ADDR" FOR THE USER
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
|
||
POP P,J ;GET STC POINTER ONCE AGAIN
|
||
PUSHJ P,GIVSTC ;RETURN THE STC BLOCK
|
||
RETSKP ;GIVE GOOD RETURN
|
||
;N34SET ROUTINE TO SET P1 - P4 TO THE NODE. UUO ARGUMENTS
|
||
;CALL M := UUO
|
||
N34SET: PUSHJ P,GETWRD## ;P1 GETS THE "XWD TIME,ARG-LIST-LENGTH"
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
MOVE P1,T1
|
||
HRRZ T1,T1 ;GET JUST THE ARG LIST LENGTH
|
||
CAIGE T1,4 ;MAKE SURE IT'S LONG ENOUGH
|
||
PJRST ND%IAL ; IF TOO SHORT, GIVE ILLEGAL ARG LIST
|
||
PUSHJ P,GETWR1## ;P2 GETS THE NODE NAME
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
MOVE P2,T1
|
||
PUSHJ P,GETWR1## ;P3 GETS THE OUTPUT BUFFER POINTER
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
MOVE P3,T1
|
||
PUSHJ P,GETWR1## ;P4 GETS THE INPUT BUFFER POINTER
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
MOVE P4,T1
|
||
SUBI M,3 ;SET THE UUO POINTER BACK
|
||
RETSKP ;SKIP RETURN WITH P1 - P4 SET UP
|
||
SUBTTL NODE.5 RETURN CONFIG INFO FOR NODE
|
||
;FORMAT OF THE UUO ARGS
|
||
; XWD 0,,COUNT
|
||
; SIXBIT /NODE NAME/ OR NUMBER
|
||
; 0 RESERVED FOR DATE AND NAME
|
||
; BLOCK <COUNT-3> INFO RETURNED HERE
|
||
|
||
NODE.5: PUSHJ P,SAVE1## ;SAVE P1 FIRST
|
||
PUSHJ P,GETWRD## ;GET ARGUMENT LIST SIZE
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
SUBI T1,3 ;DEDUCT OVERHEAD
|
||
CAIG T1,^D1000 ;RIDICULOUS SIZE
|
||
SKIPG P1,T1 ;ANY ROOM LEFT FOR ANSWER
|
||
PJRST ND%IAL ;NO, ILLEGAL ARG LIST
|
||
PUSHJ P,GETWR1## ;GET NODE NAME
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
PUSHJ P,NODE.S ;FIND CORRECT NDB
|
||
PJRST ND%INN ;ILLEGAL NODE
|
||
PUSHJ P,GETWR1## ;GET RESERVED WORD
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
JUMPN T1,ND%RNZ ;MUST BE ZERO
|
||
NODE51: PUSHJ P,GETWR1## ;GET DEVICE TYPE REQUEST
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
MOVSI T2,-<OBJ.MX+1> ;NUMBER OF KNOWN DEVICES
|
||
NODE52: LDB T3,[EXP OB%TYP##+OBJTAB##+(T2)] ;GET A TYPE
|
||
CAIE T3,(T1) ;FOUND REQUEST
|
||
AOBJN T2,NODE52 ;NO, TRY ANOTHER TYPE
|
||
SKIPL T2 ;FIND ANY
|
||
TDZA T2,T2 ;NONE OF REQUESTED TYPE
|
||
LDB T2,NETCNF##(T2) ;GET NUMBER OF THAT TYPE
|
||
HRL T1,T2 ;INSERT COUNT FOR USER
|
||
PUSHJ P,PUTWRD## ;STORE BACK
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
SOJG P1,NODE51 ;DO FOR ALL ARGS
|
||
PJRST CPOPJ1## ;GIVE GOOD RETURN
|
||
SUBTTL NODE.6 NETWORK OUTPUT WITH USER CONTROL OF EOR
|
||
|
||
REPEAT 0,< ;SUPERSEDED BY TSK. UUO
|
||
;FORMAT OF THE UUO ARGS
|
||
; XWD 0,NUMBER OF ARGS
|
||
; XWD FLAGS,IO CHANNEL
|
||
|
||
NODE.6: PUSHJ P,SAVE1## ;HAVE TO SAVE FLAGS SOMEWHERE
|
||
PUSHJ P,N67SET ;SETUP F, T1
|
||
MOVE P1,T1 ;SAVE PARAMETER WORD FOR EOR CHECK BELOW
|
||
HLR M,DEVBUF(F) ;GET ADDRESS OF OUTPUT BUFFER HEADER
|
||
PUSHJ P,GETWRD## ;GET ADDRESS OF CURRENT BUFFER
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
JUMPL T1,NODE61 ;IF BUFFER NEVER SET UP, JUST DO THE OUTPUT
|
||
HRR M,T1 ;TO READ LINKAGE WORD OF BUFFER
|
||
PUSHJ P,GETWRD## ;GET IT
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
JUMPL P1,NODE60 ;SKIP IF USER WANTS EOR
|
||
TLOA T1,IONER ;DOESN'T, FLAG BUFFER
|
||
NODE60: TLZ T1,IONER ;DOES, MAKE SURE THIS IS OFF
|
||
PUSHJ P,PUTWRD## ;PUT BACK IN BUFFER
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
NODE61: PUSHJ P,TOUT## ;DO THE OUTPUT
|
||
PJRST CPOPJ1## ;SUCCESS, GIVE USER A SKIP RETURN
|
||
JRST N67IOE ;FAILED, RETURN ERROR STATUS
|
||
>;REPEAT 0
|
||
SUBTTL NODE.7 NETWORK INPUT WITH NOTIFICATION OF END OF RECORD
|
||
REPEAT 0,< ;SUPERSEDED BY TSK. UUO
|
||
;FORMAT OF UUO ARGS
|
||
; XWD 0,NUMBER OF ARGS
|
||
; XWD 0,IO CHANNEL
|
||
NODE.7: PUSHJ P,N67SET ;VERIFY IO CHANNEL, SETUP F, T1
|
||
PUSHJ P,TIN## ;DO THE INPUT
|
||
JRST NODE70 ;SUCCESS, CHECK EOR
|
||
N67IOE: MOVEI T1,11 ;ERROR CODE 11 IS IO ERROR
|
||
HRL T1,DEVIOS(F) ;AND WE RETURN THE GETSTS INFO TO THE
|
||
PJRST STOTAC## ; SO THE USER DOESN'T NEED ANOTHER UUO
|
||
|
||
NODE70: HRR M,DEVBUF(F) ;GET ADDRESS OF INPUT BUFFER HEADER
|
||
PUSHJ P,GETWRD## ;GET IT
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
HRR M,T1 ;GET ADDRESS OF BUFFER LINKAGE WORD
|
||
PUSHJ P,GETWRD## ;GET THAT
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
TLNE T1,IONER ;NOW, DOES THIS BUFFER NOT MARK THE END OF RECORD?
|
||
TDZA T1,T1 ;RIGHT, MAKE BIT 0 0
|
||
MOVSI T1,400000 ;END OF RECORD, SET BIT 0
|
||
PJRST STOTC1## ;RETURN THAT TO USER
|
||
|
||
;ROUTINE FOR NODE. UUO FUNCTIONS 6 AND 7 TO DO COMMON SETUP.
|
||
; M/RH: ADDR OF ARG LIST (SETUP BY UUOCON)
|
||
; PUSHJ P,N67SET
|
||
; NORMAL RETURN,
|
||
; F/ DDB ADDRESS, T1/ FLAGS,,IO CHANNEL
|
||
;THIS ROUTINE ABORTS THE UUO IF THE IO CHANNEL IS NOT OPEN OR THE DEVICE
|
||
;IS NOT A NETWORK DEVICE.
|
||
|
||
N67SET: PUSHJ P,GETWRD## ;GET ARG LIST LENGTH
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
CAIGE T1,2 ;NEED AT LEAST 2 WORDS
|
||
PJRST ND%IAL ;TOO SHORT, RETURN LIST LENGTH ERROR
|
||
PUSHJ P,GETWR1## ;GET FLAGS,,IOCHAN WORD
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
PUSH P,T1
|
||
PUSHJ P,SETUF##
|
||
JRST [POP P,(P)
|
||
PJRST ND%IAL]
|
||
POP P,T1
|
||
MOVSI T2,DVCNET ;MAKE SURE DEVICE IS A NETWORK DEVICE
|
||
TDNN T2,DEVCHR(F) ; FOR PARANOIA'S SAKE
|
||
PJRST ND%NND ;IT ISN'T, ABORT UUO
|
||
POPJ P, ;RETURN TO DO IO
|
||
>;REPEAT 0
|
||
;NODE10 (.NDTCN) UUO TO ATTEMPT TO CONNECT REMOTE TERMINAL'S TO THE SYSTEM.
|
||
;ARGUMENT BLOCK FORMAT.
|
||
;
|
||
; 1) XWD 0,LENGTH ;LENGTH ALWAYS = 2
|
||
; 2) XWD NODE,LINE ;NODE AND LINE TO TRY TO CONNECT
|
||
;
|
||
;RETURNS
|
||
; SIXBIT /TTYNNN/ ;THE NAME THE TERMINAL WAS ASSIGNED.
|
||
;
|
||
;ERRORS
|
||
; NDIAL%==1 ;ILLEGAL ARGUMENT LIST
|
||
; NDTNA%==2 ;TERMINAL NOT AVAILABLE.
|
||
;
|
||
NODE10: PUSHJ P,GETWRD## ;GET THE ARG-LIST LENGTH
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
CAIE T1,2 ;WE ONLY WANT 1 DATA ARGUMNET
|
||
JRST ND%IAL ;ILLEGAL ARG LIST (NDIAL%)
|
||
PUSHJ P,GETWR1## ;GET THE "XWD NODE,LINE" TO CONNECT TO
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
PUSHJ P,ASGTTY## ;ATTEMPT THE CONNECT.
|
||
PJRST ND%TNA ;TERMINAL NOT AVAILABLE (NDTNA%)
|
||
PJRST STOTC1## ;RETURN TERMINAL NUMBER IN AC
|
||
;NODE11 (.NDTDS) DISCONNECT A REMOTE TERMINAL FROM THE SYSTEM (WITH OPTIONAL
|
||
; RECONNECT TO ANOTHER SYSTEM).
|
||
;
|
||
;NODE. UUO ARGUMENT BLOCK.
|
||
; 1) XWD 0,LENGTH ;EITHER 2 OR 3 (3 IMPLIES AUTO RECONNECT)
|
||
; 2) SIXBIT /TTYNNN/ ;NAME OF TERMINAL DO DIS/RE-CONNECT
|
||
; 3) EXP NODE-NUMBER ;OPTIONAL NODE NUMBER TO RECONNECT TO.
|
||
;
|
||
;RETURNS
|
||
; NOTHING. ON A SUCCESSFUL RETURN, THE AC IS UNCHANGED
|
||
;
|
||
;ERRORS
|
||
; NDIAL%==1 ;ILLEGAL ARGUMENT LIST (LENGTH WRONG)
|
||
; NDINN%==2 ;ILLEGAL NODE NUMBER/NAME (CAN'T HAPPEN...)
|
||
; NDIAJ%==3 ;THE TERMINAL IS IN USE BY ANOTHER JOB.
|
||
; NDNLT%==4 ;USER DID NOT GIVE A LEGAL TERMINAL NAME AS
|
||
; ; THE SECOND ARGUMENT.
|
||
;
|
||
NODE11: PUSHJ P,SAVE4## ;WE USE THE P'S FOR TEMPS
|
||
PUSHJ P,GETWRD## ;GET THE LENGTH OF THE ARG-LIST
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
CAIL T1,2 ;RANGE CHECK THE LENGTH. MUST
|
||
CAILE T1,3 ; BE BETWEEN 2 AND 3
|
||
JRST ND%IAL ;ILLEGAL ARG LIST (NDIAL%)
|
||
MOVE P2,T1 ;SAVE THE LENGTH FOR A BIT
|
||
PUSHJ P,GETWR1## ;GET THE TERMINAL NAME
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
MOVE P3,T1 ;SAVE THE NAME
|
||
MOVEI P4,RSN.OK ;ASSUME THAT THIS IS SIMPLE DISCONNECT.
|
||
CAIN P2,3 ;BUT IF THIS IS A RE-CONNECT,
|
||
JRST [PUSHJ P,GETWR1## ;THEN GET NODE NUMBER TO RECONNECT TO.
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
HRLZ P4,T1 ;AND PUT NODE NUMBER IN LH
|
||
HRRI P4,RSN.RC ;REASON IS "RE-CONNECT"
|
||
JRST .+1] ;REJOIN MAIN FLOW WITH ALL ARGS READ
|
||
NOD11A: MOVE T1,P3 ;GET THE TERMINAL NAME BACK
|
||
PUSHJ P,TTYPHY## ;SET U := LDB, F := DDB(IF ANY)
|
||
PJRST ND%NLT ;GIVE "NDNLT%" ERROR IF TERMINAL NAME IS BAD
|
||
JUMPN F,[LDB T1,PJOBN## ;IF WE FOUND A LDB, SEE IF WE GOT A DDB.
|
||
SKIPE T1 ;IF NO-ONE OWNS IT, WE'RE OK
|
||
CAMN T1,.CPJOB## ; IF WE OWN IT WE'RE OK
|
||
CAIA ; WE'RE OK
|
||
JRST ND%IAJ ; IF WE DON'T OWN IT, GIVE "NDIAJ%" ERROR
|
||
PUSHJ P,TTYDTC## ; DETACH THE TERMINAL
|
||
JRST .+1] ; IF WE DO OWN IT, THEN ALL'S OK
|
||
PUSHJ P,MCRCHK## ;SEE IF IT'S A LEGAL REMOTE TERMINAL.
|
||
JRST ND%NLT ;IF NOT, THEN RETURN "NDNLT%"
|
||
LDB T1,LDPRNN## ;GET THE NODE NUMBER THAT IT'S CONNECTED TO
|
||
PUSHJ P,SRCNDB ;FIND THE NDB
|
||
STOPCD .,STOP,ANFNNT, ;++ NO NBD FOR TERMINAL
|
||
MOVE T1,P4 ;GET "XWD NODE,REASON"
|
||
PUSHJ P,TRMXDC## ;SEND THE DISCONNECT
|
||
JRST [PUSHJ P,NETSLP ;IF NO CORE, SLEEP FOR A BIT
|
||
JRST NOD11A] ; AND TRY AGAIN
|
||
JRST CPOPJ1## ;ALL DONE. GIVE GOOD RETURN
|
||
;NODE12 (.NDLND) RETURNS THE NUMBER OF NODES IN THE NETWORK, AND A LIST
|
||
; OF THE NODE NUMBERS.
|
||
;
|
||
;NODE. UUO ARGUMENT BLOCK
|
||
; 1) XWD 0,LENGTH ;LENGTH OF ARG BLOCK (INCLUDES THIS WORD)
|
||
; 2) EXP RTN-VAL-1 ;FILLED IN WITH NODE NUMBER OF FIRST NODE
|
||
; 3) EXP RTN-VAL-2 ;FILLED WITH SECOND NODE NUMBER
|
||
; .
|
||
; .
|
||
; .
|
||
; N+1) EXP RTN-VAL-N ;FILLED WITH NUMBER OF N'TH NODE
|
||
;
|
||
;RETURNS
|
||
; IN THE AC, THE NUMBER OF NODES IN THE NETWORK
|
||
; IN ARG-LIST(2 THRU N+1) THE NUMBERS OF THE NODES IN THE NETWORK
|
||
;
|
||
;ERRORS
|
||
; NDIAL%==1 ;ARG-LIST LENGTH LESS THAN 1
|
||
;
|
||
;NOTE! NO ERROR IS RETURNED IF THE ARGUMENT LIST IS TOO SHORT TO HOLD
|
||
; ALL THE NODES. THE EXTRA ARGUMENTS ARE SIMPLY NOT RETURNED.
|
||
|
||
NODE12: PUSHJ P,GETWRD## ;GET THE LENGTH OF THE ARG LIST
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
CAIGE T1,1 ;MAKE SURE IT'S LEGAL
|
||
JRST ND%IAL ;NDIAL% ILLEGAL ARG LIST
|
||
MOVE T3,T1 ;SAVE THE ARG-LIST LENGTH FOR A WHILE
|
||
MOVEI T2,NETNDB## ;GET THE ADDRESS OF THE FIRST DDB
|
||
SETZ T4, ;WE'VE COUNTED NO NODES YET.
|
||
NOD12A: JUMPE T2,[MOVE T1,T4 ;IF WE'VE COUNTED ALL THE NODES,
|
||
JRST STOTC1##] ;COPY THE COUNT AND RETURN IT
|
||
HLRZ T1,NDBNNM(T2) ;GET THE NUMBER OF THE NODE
|
||
SOJLE T3,NOD12B ;COUNT DOWN ANOTHER RETURN-VALUE
|
||
PUSHJ P,PUTWR1## ;RETURN THE NODE NUMBER
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
NOD12B: HRRZ T2,NDBNNM(T2) ;STEP TO THE NEXT NODE
|
||
AOJA T4,NOD12A ;COUNT THIS ONE AND LOOP OVER ALL NODES
|
||
;NODE13 (.NDNDB) RETURN INFORMATION ABOUT AN NDB.
|
||
;
|
||
;NODE. UUO ARGUMENT LIST
|
||
; 1) XWD 0,LENGTH ;LENGTH OF ARG LIST. (INCLUDES THIS WORD)
|
||
; 2) EXP NODE NUMBER/NAME;NUMBER OR NAME OF THE NODE IN QUESTION
|
||
; 3) EXP SUB-FCN NUMBER ;DESCRIBES WHICH FIELD TO RETURN
|
||
; 4) RTN-VALUE-1 ;FIRST RETURN VALUE
|
||
; 5) RTN-VALUE-2 ;SECOND RETURN VALUE
|
||
; .
|
||
; .
|
||
; .
|
||
; 3+N) N'TH-RETURN-VALUE ;LAST RETURN VALUE
|
||
;
|
||
;ERRORS
|
||
; NDIAL%==1 ;ARG LIST TOO SHORT
|
||
; NDINN%==2 ;ILLEGAL NODE NUMBER/NAME
|
||
; NDISF%==3 ;ILLEGAL SUB-FUNCTION
|
||
;
|
||
;VALID FIELDS (ARG #3)
|
||
; ND.NNM==1 ;THE NUMBER OF THE SPECIFIED NODE
|
||
; ND.SNM==2 ;THE NAME IN 6 OR LESS SIXBIT CHARACTERS
|
||
; ND.SID==3 ;THE SOFTWARE ID IN "ASCIZ"
|
||
; ND.DAT==4 ;THE SOFTWARE DATE IN "ASCIZ"
|
||
; ND.LMA==5 ;THE NCL LAST MESSAGE ASSIGNED
|
||
; ND.LMS==6 ;THE NCL LAST MESSAGE SENT
|
||
; ND.LAR==7 ;THE NCL LAST ACK RECEIVED
|
||
; ND.LAP==10 ;THE NCL LAST ACK PROCESSED
|
||
; ND.LMR==11 ;THE NCL LAST MESSAGE RECEIVED
|
||
; ND.LMP==12 ;THE NCL LAST MESSAGE PROCESSED
|
||
; ND.LAS==13 ;THE NCL LAST ACK SENT
|
||
; ND.MOM==14 ;THE MAXIMUM OUTSTANDING MESSAGE COUNTER
|
||
; ND.TOP==15 ;THE TOPOLOGY TABLE. THIS IS "NGHMAX" WORDS
|
||
; ; OF THE FORM "XWD LEVEL,NODE"
|
||
; ND.CNF==16 ;THE CONFIGURATION TABLE. THIS IS VARIABLE
|
||
; ; LENGTH OF THE FORM "XWD OBJ,NUMBER"
|
||
; ND.CTL==17 ;RETURN STATION CONTROL JOB
|
||
; ND.OPR==20 ;RETURN OPR TTY NUMBER
|
||
; ND.NVR==21 ;RETURN NCL VERSION NUMBER
|
||
;
|
||
NODE13: PUSHJ P,SAVE4## ;WE USE THE P'S AS TEMPS
|
||
PUSHJ P,GETWRD## ;GET THE LENGTH OF THE ARG LIST
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
CAIGE T1,4 ;MAKE SURE THAT IT'S AT LEAST 4 WORDS LONG
|
||
JRST ND%IAL ;RETURN NDIAL% -- ILLEGAL ARG LIST
|
||
MOVE P4,T1 ;SAVE THE LENGTH FOR A WHILE
|
||
SUBI P4,3 ;ADJUST SO P4 = RETURN LOCATIONS FREE
|
||
PUSHJ P,GETWR1## ;GET THE NODE NUMBER/NAME
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
PUSHJ P,SRCNDB ;SET UP W FROM THE NUMBER/NAME
|
||
JRST ND%INN ;RETURN NDINN% -- ILLEGAL NODE NUMBER
|
||
PUSHJ P,GETWR1## ;GET THE SUB-SUB-FUNCTION CODE.
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
CAIL T1,1 ;RANGE CHECK IT
|
||
CAILE T1,N13LEN ; TO MAKE SURE IT'S VALID
|
||
JRST ND%ISF ;RETURN NDISF% -- INVALID SUB-FUNCTION
|
||
XCT N13TBL-1(T1) ;CALL ROUTINE TO GET FIELD
|
||
SKIPA ;MUST STORE
|
||
JRST CPOPJ1## ;DON'T
|
||
N13WD1: PUSHJ P,PUTWR1## ;NON-SKIP MEANS WE SHOULD STORE ARG HERE
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
JRST CPOPJ1## ;ALL DONE.
|
||
|
||
|
||
;N13TBL TABLE OF INSTRUCTIONS TO EXECUTE TO RETURN VARIOUS FIELDS OF AN NDB
|
||
|
||
N13TBL: HLRZ T1,NDBNNM(W) ;(01) GET THE NODE NUMBER FIELD
|
||
MOVE T1,NDBSN2(W) ;(02) GET NODE NAME
|
||
JRST N13SID ;(03) CALL SUBROUTINE TO GET SOFTWARE-ID
|
||
JRST N13DAT ;(04) CALL SUBROUTINE TO GET SOFTWARE-DATE
|
||
LDB T1,NDBLMA ;(05) GET LAST MESSAGE ASSIGNED
|
||
LDB T1,NDBLMS ;(06) GET LAST MESSAGE SENT
|
||
LDB T1,NDBLAR ;(07) GET LAST ACK RECEIVED
|
||
LDB T1,NDBLAP ;(10) GET LAST ACK PROCESSED
|
||
LDB T1,NDBLMR ;(11) GET LAST MESSAGE RECEIVED
|
||
LDB T1,NDBLMP ;(12) GET LAST MESSAGE PROCESSED
|
||
LDB T1,NDBLAS ;(13) GET LAST ACK SENT
|
||
MOVE T1,NDBMOM(W) ;(14) GET MAXIMUM OUTSTANDING MESSAGE COUNTER
|
||
JRST N13TOP ;(15) RETURN TOPOLOGY TABLE
|
||
JRST N13CNF ;(16) RETURN CONFIGURATION TABLE
|
||
HRRZ T1,NDBSTC(W) ;(17) GET STATION CONTROL JOB NUMBER
|
||
PUSHJ P,N13OPR ;(20) GET OPR TTY NUMBER
|
||
HRRZ T1,NDBNVR(W) ;(21) GET NCL VERSION NUMBER
|
||
|
||
N13LEN==.-N13TBL ;DEFINE LENGTH FOR RANGE CHECK
|
||
;N13SID (03) RETURN THE SOFTWARE ID (VERSION INFO) FOR THE NODE.
|
||
|
||
N13SID: HRRZ P1,NDBSID(W) ;GET A POINTER TO THE SID
|
||
PJRST N13ASZ ;AND GO USE ASCIZ COPY ROUTINE
|
||
|
||
|
||
;N13DAT (04) RETURN THE SOFTWARE DATE FOR THE NODE
|
||
|
||
N13DAT: HLRZ P1,NDBSID(W) ;GET A POINTER TO THE DATE
|
||
; PJRST N13ASZ ;AND GO USE THE ASCIZ COPY ROUTINE
|
||
|
||
N13ASZ: SOSGE P4 ;COUNT DOWN NEXT WORD TO RETURN
|
||
JRST ND%IAL ;IF WE COUNT OUT, THEN LIST WAS TO SHORT
|
||
SKIPE T1,P1 ;UNLESS POINTER NOT PRESENT,
|
||
MOVE T1,(P1) ;GET THE NEXT WORD TO RETURN
|
||
PUSHJ P,PUTWR1## ;STORE THE WORD IN THE ARG LIST
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
MOVEI T2,5 ;COUNT TO SEE ANY CHAR WAS A NULL
|
||
N13AS1: TLNN T1,774000 ;WAS THIS CHAR A NUL
|
||
JRST CPOPJ1## ;IF SO, GIVE SKIP RETURN
|
||
LSH T1,7 ;SHIFT TO NEXT CHAR POSITION
|
||
SOJG T2,N13AS1 ;LOOP OVER ALL 5 CHARACTERS
|
||
AOJA P1,N13ASZ ;LOOP OVER ALL WORDS IN NAME
|
||
;N13TOP (15) RETURN THE TOPOLOGY TABLE FOR THE PARTICULAR NODE.
|
||
;
|
||
;THE TABLE IS RETURNED IN THE FORM OF UP TO 16 WORDS OF
|
||
; XWD LEVEL,NODE
|
||
; WHERE NODE IS THE NEIGHBOR OF THE NODE IN QUESTION, AND LEVEL IS THE
|
||
; "COST" OF THE LINK TO GET THERE
|
||
|
||
N13TOP: MOVE P3,[POINT 9,NDBTOP(W)] ;POINTER TO THE TOPOLOGY TABLE
|
||
MOVEI P2,NGHMAX ;MAX LENGTH OF THE TOPOLOGY TABLE
|
||
N13TP1: SOSGE P2 ;COUNT DOWN ANOTHER ENTRY
|
||
JRST N13RZR ;ALL DONE. WRITE TERMINATING ZERO AND RETURN
|
||
ILDB T1,P3 ;GET THE NEXT ENTRY
|
||
ILDB T2,P3 ;GET ITS COST
|
||
JUMPE T1,N13TP1 ;IF NULL, KEEP TRYING
|
||
SOSGE P4 ;COUNT DOWN THE LENGTH OF THE ARGLIST
|
||
JRST ND%IAL ;ILLEGAL ARGLIST (TOO SHORT)
|
||
HRLI T1,(T2) ;PUT COST IN LH OF RETURN VALUE
|
||
PUSHJ P,PUTWR1## ;STORE THE "XWD LEVEL,NODE"
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
JRST N13TP1 ;LOOP OVER ALL TABLE ENTRIES
|
||
|
||
;N13CNF (16) RETURN THE CONFIGURATION INFORMATION FOR A NODE.
|
||
;
|
||
; CONFIGURATION INFORMATION RETURNED AS UP TO "OBJ.MX" WORDS OF THE FORM
|
||
; XWD OBJECT-TYPE,NUMBER
|
||
; WHERE OBJECT-TYPE IS THE NCL TYPE OF THE DEVICE, AND NUMBER IS THE
|
||
; NUMBER OF SAID DEVICES THAT THE NODE POSSESSES.
|
||
|
||
N13CNF: MOVEI P1,OBJ.MX+1 ;MAXIMUM OBJECT TYPE +1
|
||
N13CN1: SOJL P1,N13RZR ;COUNT DOWN THROUGH ALL OBJECT TYPES
|
||
LDB T1,NETCNF##(P1) ;GET THE NUMBER OF THIS TYPE
|
||
JUMPE T1,N13CN1 ;IF NONE, KEEP TRYING
|
||
HRLI T1,(P1) ;PUT OBJECT TYPE IN THE LH
|
||
SOSGE P4 ;COUNT DOWN ANOTHER RETURN VALUE
|
||
JRST ND%IAL ;ARG LIST TOO SHORT
|
||
PUSHJ P,PUTWR1## ;RETURN THE VALUE
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
JRST N13CN1 ;LOOP OVER ALL OBJECT TYPES
|
||
|
||
;N13RZR ROUTINE TO WRITE THE TERMINATING ZERO FOR N13TOP AND N13CNF
|
||
|
||
N13RZR: SOSGE P4 ;COUNT DOWN THE ARGLIST
|
||
JRST ND%IAL ;ERROR IF LIST TOO SHORT
|
||
SETZ T1, ;ZERO TO STORE
|
||
JRST N13WD1 ;AND LET NODE13 STORE IT FOR US.
|
||
|
||
|
||
;N13OPR (20) RETURNS OPR TTY NUMBER OR -1 IF NOT CONNECTED
|
||
|
||
N13OPR: HRRZ T1,NDBOPR(W) ;GET LDB OF OPR LINE FOR THIS NODE
|
||
SKIPN T1 ;HAVE ONE?
|
||
SOJA T1,CPOPJ## ;NO--RETURN -1
|
||
EXCH U,T1 ;SAVE U, GET LDB ADDRESS
|
||
SSX U,MS.SCN ;USE SCNSER SECTION
|
||
LDB U,LDPLNO## ;GET THE LOCAL LINE NUMBER
|
||
EXCH T1,U ;RESTORE U
|
||
POPJ P, ;AND RETURN
|
||
;NODE14 (.NDGNF) READ/SET THE GREETED NODE FLAG
|
||
;NODE. UUO ARGUMENT BLOCK
|
||
; 1) XWD 0,LENGTH ;LENGTH MUST BE "2"
|
||
; 2) EXP 0!NODE # ;EITHER 0 (RETURN FIRST UN-GREETED NODE)
|
||
; ; OR NODE # (SET "GREETED BIT")
|
||
;RETURNS
|
||
; IN ARG 2 THE NODE # OF THE FIRST "UN-GREETED" NODE)
|
||
;
|
||
;ERRORS:
|
||
; ND%IAL ;ILLEGAL ARG LIST
|
||
; ND%NUG ;NO UNGREETED NODES
|
||
; ND%INN ;ILLEGAL NODE NUMBER (SET GREETED BIT FCN)
|
||
; ND%PRV ;USER NOT PRIVLEGDED
|
||
;
|
||
NODE14: PUSHJ P,NTDPRV ;CHECK PRVS RIGHT AWAY
|
||
PJRST ND%PRV ;USER DOESN'T HAVE PRVS TO DO THIS
|
||
PUSHJ P,GETWRD## ;GET ARG LIST LENGTH
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
CAIGE T1,2 ;MAKE SURE ITS LONG ENOUGH
|
||
PJRST ND%IAL ;IF TO SHORT, GIVE "ILLEGAL ARG LIST" ERROR
|
||
PUSHJ P,GETWR1## ;GET 0 (RETURN) OR NODE # (SET)
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
JUMPE T1,NOD14A ;IF 0 (RETURN) GO SEARCH NDB'S
|
||
PUSHJ P,SRCNDB ;GO SEE IF WE CAN FIND AN NDB FOR HIM
|
||
PJRST ND%INN ;IF NO NDB, GIVE ILLEGAL NODE NUMBER ERROR
|
||
MOVSI T1,NDB.GF ;GET THE "GREETED FLAG"
|
||
IORM T1,NDBFLG(W) ; AND SET IT
|
||
RETSKP ;GIVE GOOD RETURN TO THE UUO.
|
||
|
||
NOD14A: HRRZI W,NETNDB ;GET THE ROOT OF ALL NODES
|
||
NOD14B: HRRZ W,NDBNNM(W) ;GO TO NEXT NODE (SKIP NETNDB)
|
||
JUMPE W,ND%NUG ;IF AT END OF LIST, GIVE NO UN-GREETED NODE ERR
|
||
MOVE T1,NDBFLG(W) ;GET THE FLAGS
|
||
TLNE T1,NDB.UP ;IF THE NODE IS NOT UP,
|
||
TLNE T1,NDB.GF ; OR IT'S ALREADY BEEN GREETED
|
||
JRST NOD14B ;THEN GO TRY THE NEXT NODE
|
||
HLRZ T1,NDBNNM(W) ;THIS IS OUR NODE, GET THE NUMBER
|
||
PUSHJ P,PUTWRD## ;STORE IT FOR THE USER
|
||
JRST ND%ADC ;ADDRESS CHECK
|
||
RETSKP ;GIVE GOOD RETURN TO UUO
|
||
SUBTTL INTERFACE TO UUOCON (RECON. UUO)
|
||
|
||
|
||
;SYSTEM SLEEP ROUTINES
|
||
|
||
;ROUTINE TO CALL ALL FEKS ON THIS CPU WHEN SYSTEM GOES TO SLEEP
|
||
;CALL PUSHJ P,FEKCPS
|
||
;RETURN CPOPJ ;CLOBBERS NO REGISTERS
|
||
|
||
FEKCPS::PUSHJ P,SAVE1## ;SAVE P1
|
||
MOVEI P1,FF.CPS ;GET THE "CPU SLEEP" BIT
|
||
JRST FEKCPC ; AND GO TO COMMON CODE TO CALL THE FEKS
|
||
|
||
|
||
;ROUTINE TO CALL ALL FEKS ON THIS CPU WHEN SYSTEM WAKES UP
|
||
;CALL PUSHJ P,FEKCPW
|
||
;RETURN CPOPJ ;CLOBBERS NO REGISTERS
|
||
|
||
FEKCPW::PUSHJ P,SAVE1## ;SAVE P1
|
||
MOVEI P1,FF.CPW ;GET THE "CPU WAKING UP" FUNCTION CODE
|
||
; PJRST FEKCPC ;GO TO COMMON CODE
|
||
|
||
|
||
;CODE TO CALL ALL FEKS ON THIS CPU WITH THE FUNCTION CODE IN "P1"
|
||
FEKCPC: PUSHJ P,SAVT## ;SAVE ALL THE TEMPS (FOR SPRINI)
|
||
PUSH P,U ; AS WELL AS
|
||
PUSH P,F ; SUNDRY OTHER
|
||
PUSH P,W ; REGISTERS
|
||
PUSH P,J ; ..
|
||
MOVEI J,FEKFST## ;START WITH THE FIRST FEK
|
||
JUMPE J,FEKCP2 ; IF NONE AT ALL, WE'RE DONE
|
||
FEKCP1: MOVE T1,P1 ;GET THE FUNCTION CODE
|
||
IFN FTMP,<
|
||
HLRZ T2,FEKUNI(J) ;GET THE CPU THIS FEK IS ON
|
||
CAMN T2,.CPCPN## ; AND IF WE ARE ON THE RIGHT ONE.
|
||
>
|
||
XCT FEKDSP(J) ;CALL THE FEK
|
||
HRRZ J,FEKBLK(J) ;GET THE NEXT FEK
|
||
JUMPN J,FEKCP1 ; AND CALL HIM TOO.
|
||
FEKCP2: POP P,J ;RESTORE ALL
|
||
POP P,W ; THESE REGISTERS
|
||
JRST FUPOPJ## ;AND WE'RE DONE
|
||
SUBTTL NDB INTERFACE ROUTINES
|
||
;SUBROUTINE NETOPR -- KEEP NETNDB(NDBOPR) UP TO DATE WITH OPRLDB
|
||
;CALL MOVE U,NEW OPR LDB
|
||
;RETURN CPOPJ1
|
||
|
||
NETOPR::HRRM U,NETNDB##+NDBOPR ; STORE THE LDB ADDRESS
|
||
JRST CPOPJ1## ; SKIP RETURN FOR SCNSER
|
||
|
||
|
||
|
||
;SUBROUTINE TO LOAD INTO T1 THE TERMINAL NUMBER OF THE OPR'S
|
||
; TERMINAL FOR THE STATION WHOSE NUMBER IS IN T1.
|
||
|
||
STBOPR::
|
||
SE1ENT
|
||
PUSH P,U ;SAVE U
|
||
HRRZS T1 ;STATION NUMBER IN T1
|
||
NETOFF ;PROTECT OURSELF WHEN SCANNING THE NDB'S
|
||
; (SEE FOOTNOTE AFTER ROUTINE "SRCNDB")
|
||
PUSHJ P,SRCND0 ;FIND THE NODE BLOCK (BYPASS 'NT' CHECK)
|
||
JRST LCLOPR ;NO, USE LOCAL OPR
|
||
HRRZ U,NDBOPR(W) ;GET THE OPR LDB
|
||
SKIPN U ;ANY ASSIGNED
|
||
LCLOPR: MOVE U,OPRLDB## ;NO, USE LOCAL OPR
|
||
SSX U,MS.SCN ;USE SCNSER SECTION
|
||
LDB T1,LDPLNO## ;GET NUMBER OF TERMINAL IN U
|
||
NETON ;INT'S ON AGAIN
|
||
JRST UPOPJ## ;RESTORE U AND EXIT.
|
||
|
||
;SUBROUTINE STBSCA - RETURN THE STATION NUMBER
|
||
;CALL MOVEI T1,NNM
|
||
; PUSHJ P,STBSCA
|
||
;RETURN CPOPJ ;NO SUCH STATION
|
||
; CPOPJ1 ;STATION VALID T1=NNM
|
||
|
||
STBSCA:: ;ENTRY
|
||
PUSHJ P,SAVJW## ;SAVE J AND W
|
||
NETOFF ;PROTECT WHILE LOOKING AT THE NDB'S
|
||
; (SEE FOOTNOTE AFTER ROUTINE "SRCNDB")
|
||
PUSHJ P,SRCND0 ;SEARCH NDB'S (BYPASS THE 'NT' CHECK)
|
||
JRST NTONPJ ;RETURN INVALID STATION
|
||
HLRZ T1,NDBNNM(W) ;GET THE STATION NUMBER
|
||
NETON ;ALL'S CLEAR
|
||
PJRST CPOPJ1## ;EXIT
|
||
SUBTTL ERROR MESSAGES.
|
||
|
||
NODERT: XWD [ASCIZ / Assigned/]
|
||
NRTDNA: XWD [ASCIZ /Device Not Available/]
|
||
NRTNCE::XWD [ASCIZ /Network Capacity Exceeded/]
|
||
NRTTNA: XWD [ASCIZ /Task Not Available/]
|
||
NRTUNT: XWD [ASCIZ /Undefined Network Task/]
|
||
NRTUNN::XWD [ASCIZ /Undefined Network Node/]
|
||
NRTUND: XWD [ASCIZ /Undefined Network Device/]
|
||
SUBTTL TSTNET - FIND OUT IF A DEVICE EXISTS ON THE NETWORK
|
||
;SUBROUTINE TSTNET - ASSIGN A DDB FOR THE DEVICE IF IT EXISTS
|
||
;CALL MOVE T1,DEVICE NAME
|
||
; PUSHJ P,TSTNET
|
||
;RETURN CPOPJ ;DEVICE DOES NOT EXIST/NOT AVAILABLE
|
||
; CPOPJ1 ;DEVICE EXISTS AND IS AVAILABLE
|
||
|
||
TSTNET:: ;ENTRY FROM UUOCON
|
||
HLRZ T2,M ;GET THE UUO
|
||
ANDI T2,777000 ;ONLY THE UUO OP CODE
|
||
CAIE T2,(OPEN) ;IS IT
|
||
POPJ P, ;NO, GET THE ASSIGN LATER
|
||
HLRZ T2,T1 ;GET GENERIC PORTION OF NAME
|
||
CAIN T2,'TTY' ;IS IT A TTY?
|
||
POPJ P, ;YES, TTY'S DON'T HAVE STATION NUMBERS IN DDBS
|
||
TRNE T1,7700 ;IS THERE A STATION NUMBER
|
||
PUSHJ P,DVSCVT## ;GET THE STATION NUMBER
|
||
POPJ P, ;NOT A STATION NUMBER
|
||
PUSH P,T1 ;SAVE THE NAME
|
||
DPB T1,[POINT 6,T1,23] ;MOVE THE UNIT NUMBER OVER
|
||
TRZ T1,7777 ;CLEAR THE JUNK
|
||
PUSHJ P,GENNET ;GO ASSIGN THE DEVICE
|
||
PJRST TPOPJ## ;NO SUCH DEVICE
|
||
PJRST TPOPJ1## ;DEVICE ASSIGNED F=DDB
|
||
;SUBROUTINE GENNET - TEST FOR A GENERIC NETWORK DEVICE
|
||
;CALL MOVE T1,[SIXBIT /DEVNAME/]
|
||
; MOVE T2,STATION NUMBER
|
||
; PUSHJ P,GENNET
|
||
;RETURN POPJ ;NO ON THE NETWORK OR AVAILABLE
|
||
; CPOPJ1 ;F=DDB ADDRESS
|
||
|
||
GENNET:: ;ENTRY FROM UUOCON
|
||
NETDBJ ;INTERLOCK THIS CODE
|
||
CAMN T2,JBTLOC## ;LOCAL STATION
|
||
POPJ P, ;YES, RETURN
|
||
PUSHJ P,SAVT## ;NO, SAVE THE T'S
|
||
MOVEI T4,(P) ;GET THE STACK ADDRESS
|
||
CAMG T4,LOCORE## ;RUNNING AT CLOCK LEVEL
|
||
POPJ P, ;YES, DON'T TRY THE NETWORK
|
||
PUSHJ P,SAVJW## ;SAVE J AND W
|
||
PUSHJ P,SAVE3## ; AND THE P'S
|
||
MOVE P2,T1 ;COPY THE DEVICE NAME
|
||
MOVEI T1,(T2) ;PUT THE STATION NUMBER IN T1
|
||
PUSHJ P,SRCNDB ;DOES THE STATION EXIST
|
||
POPJ P, ;NO EXIT
|
||
MOVEI P1,(W) ;SAVE THE NDB POINTER
|
||
SETZ P3, ;CLEAR THE LOCAL NAME
|
||
HLRZ T1,P2 ;GET THE GENERIC DEVICE NAME
|
||
PUSHJ P,SRCNDT ;SEE IF IT EXISTS AT THE STATION
|
||
POPJ P, ;NO, EXIT
|
||
PUSHJ P,MAKDDB ;YES, MAKE A DDB
|
||
POPJ P, ;CAN'T
|
||
PUSHJ P,NTDCNT ;USE THE "NORMAL" DEVICE CONNECT ROUTINE (WAITS)
|
||
PJRST RMVNET ;FAILED DISCARD DDB
|
||
PUSHJ P,LNKDDB ;LINK CONNECTED DDB
|
||
PJRST CPOPJ1## ;WE WON
|
||
SUBTTL DDB -- ROUTINES TO MANAGE NETWORK DEVICE DATA BLOCKS
|
||
|
||
;MAKDDB ROUTINE TO CREATE A NETWORK DDB
|
||
;CALL MOVE P1,NDB POINTER
|
||
; MOVE P2,DEVICE NAME
|
||
; MOVE P3,LOGICAL NAME
|
||
; MOVE W,NDT POINTER
|
||
; MOVE T2,LENGTH ;MAKDDC ONLY
|
||
; PUSHJ P,MAKDDB/MAKDDC
|
||
;RETURN CPOPJ ;NO SPACE AVAILABLE
|
||
; CPOPJ1 ;F=DDB POINTER,U=PCB
|
||
;
|
||
;NOTE! THIS ROUTINE DOES NOT ASSIGN AN SLA
|
||
|
||
MAKDDB::MOVEI T2,NETLEN ;GET THE LENGTH OF THE PROTOTYPE DDB
|
||
MAKDDC::NTDBUG ;VERIFY THE INTERLOCK
|
||
IFN PARANOID&P$DDB,< ;SOME CONSISTENCY CHECKING
|
||
CAIL T2,NETLEN ;CAN'T BE SMALLER THAN MINIMUM NETWORK LENGTH
|
||
CAILE T2,NETLEN+10 ;AND NONE ARE MUCH BIGGER
|
||
STOPCD .,STOP,ANFUND, ;++ UNREASONABLE NETWORK DDB LENGTH
|
||
> ;END IFN PARANOID&P$DDB
|
||
PUSH P,T2 ;SAVE ALLOCATED LENGTH
|
||
PUSHJ P,GETZWD ;ALLOCATE THE SPACE
|
||
JRST T2POPJ## ;SPACE NOT AVAILABLE
|
||
MOVEI F,(T1) ;COPY THE DDB POINTER
|
||
HRLI T1,NETDDB## ;BLT POINTER TO COPY THE PROTOTYPE DDB
|
||
BLT T1,NETLEN-1(F) ;COPY IT
|
||
POP P,T2 ;RETRIEVE LENGTH OF NEW DDB
|
||
DPB T2,NETZWD ;SET LENGTH OF DDB FOR RMVNET
|
||
CAIG T2,NETLEN ;IS THIS AN EXTENDED DDB?
|
||
JRST MAKDD2 ;NO
|
||
SETZM NETLEN(F) ;YES, CLEAR OUT REMAINDER
|
||
MOVSI T1,NETLEN(F) ;CONCOCT A
|
||
HRRI T1,NETLEN+1(F) ; BLT POINTER
|
||
ADDI T2,(F) ;AND A BLT TERMINATOR
|
||
BLT T1,-1(T2) ;TO CLEAR DDB EXTENSIONS
|
||
|
||
;CONTINUED ON NEXT PAGE
|
||
;CONTINUED FROM PREVIOUS PAGE
|
||
|
||
MAKDD2: MOVEM P2,DEVNAM(F) ;STORE THE DEVICE NAME
|
||
MOVEM P3,DEVLOG(F) ;STORE THE LOGICAL NAME
|
||
HLRZ T1,NDBNNM(P1) ;GET THE NODE NUMBER
|
||
HRRZM T1,DEVNET(F) ;STORE THE NODE NUMBER
|
||
DPB T1,PDVSTA## ;STORE AS THE STATION NUMBER
|
||
TRO T1,77700 ;FORCE A STATION NUMBER ALIGNMENT
|
||
S0PSHJ CVTSBT## ;CONVERT TO SIXBIT
|
||
MOVE T2,P2 ;COPY THE DEVICE NAME
|
||
TRNN T2,7777 ;CHECK FOR GGGU
|
||
LSH T2,-14 ;YES, SHIFT FOR THE UNIT NUMBER
|
||
ANDI T2,77 ;ONLY ONE DIGIT
|
||
IORI T1,(T2) ;INSERT THE DIGIT
|
||
HRRM T1,DEVNAM(F) ;STORE IN THE DEVNAME
|
||
ANDI T1,77 ;SAVE LAST DIGIT
|
||
SKIPN T1 ;IS IT A BLANK IE GENERIC
|
||
TROA T1,177 ;YES, USE 177 FOR GENERIC SEARCH
|
||
ANDI T1,7 ;ONLY THREE BITS WORTH (FOR GGGNNU)
|
||
DPB T1,PUNIT## ;STORE THE UNIT NUMBER
|
||
MOVSI T1,DVCNET ;GET THE NETWORK OWNERSHIP BIT
|
||
IORM T1,DEVCHR(F) ;STORE WE OWN IT
|
||
DPB J,PJOBN## ;STORE THE JOB NUMBER
|
||
LDB T1,NDTBFZ ;GET THE DEFAULT BUFFER SIZE
|
||
DPB T1,PBUFSZ## ;STORE THE BUFFER SIZE
|
||
LDB T1,NDTTYP ;GET THE DEVICE TYPE
|
||
DPB T1,DEYTYP## ;STORE THE DEVICE TYPE
|
||
LDB T1,NDTSPL ;GET THE DEFAULT SPOOL BITS
|
||
DPB T1,DEYSPL## ; AND STORE THEM IN THE NEW DDB
|
||
MOVE T1,NDTMOD(W) ;GET THE DEVMOD BITS
|
||
MOVEM T1,DEVMOD(F) ;STORE DEVMOD
|
||
HRLM W,DEVNET(F) ;LINK THE NDT TO THE DDB
|
||
JRST CPOPJ1## ;EXIT WITH F=NETDDB, U=PCB, W=NDT
|
||
;SUBROUTINE LNKDDB - ADD THE DDB(F) INTO THE DDB CHAIN
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,LNKDDB
|
||
;RETURN CPOPJ
|
||
|
||
LNKDDB::PUSHJ P,SAVE1## ;SAVE P1
|
||
PUSH P,F ;SAVE THE DDB POINTER
|
||
MOVE T1,DEVLOG(F) ;GET THE LOGICAL NAME
|
||
PUSHJ P,DEVLG## ;CHECK FOR IN USE
|
||
JRST LNKDD1 ;NO,
|
||
SETZM DEVLOG(F) ;YES, CLEAR THE LOGICAL NAME
|
||
MOVE T2,DEVMOD(F) ;GET THE DEV MODE BITS
|
||
TLNE T2,DVDSK ;IS IT A DSK
|
||
TRNE T2,ASSPRG ; AND INIT'ED
|
||
JRST LNKDD1 ;NO IGNORE
|
||
PUSHJ P,CLRDVL## ;CLEAR JOB NUMBER IN DDB
|
||
PUSHJ P,CLRDDB## ;YES, CLEAR THE DDB
|
||
LNKDD1: POP P,F ;RESTORE THE DDB POINTER
|
||
DPB J,PJCHN## ;SET JCH IN DDB
|
||
SKIPN DEVLOG(F) ;WAS IT BEING CLEARED
|
||
PUSHJ P,ASSCK1## ;YES, RECLAIM SPACE
|
||
PJRST AUTLNK## ;PUT IT IN THE DEVICE CHAIN AND RETURN
|
||
;SUBROUTINE UNLDDB -- ROUTINE TO UNLOAD A NETWORK DDB. THIS ROUTINE
|
||
; UNLINKS AND DELETES THE DDB.
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,UNLDDB
|
||
;RETURN CPOPJ
|
||
|
||
UNLDDB:: ;GLOBAL ENTRY POINT
|
||
NTDBUG ;VERIFY THE INTERLOCK
|
||
PUSHJ P,UNLKDB ;UNLINK DDB (ALSO WORKS OK IF NOT LINKED!!)
|
||
PJRST RMVNET ;NO GIVE THE STORAGE BACK TO THE MONITOR
|
||
|
||
|
||
;SUBROUTINE UNLKDB - UNLINK A DDB FROM THE SYSTEM'S LIST
|
||
;CALL MOVE F,DDB
|
||
;RETURN CPOPJ
|
||
|
||
UNLKDB: MOVEI T2,(F) ;COPY DDB ADDRESS
|
||
SETZ T1, ;ZERO LENGTH ARG MEANS DON'T DELETE
|
||
PJRST AUTKIL## ;HALF-KILL THIS DDB
|
||
|
||
|
||
;RMVNET ROUTINE TO FREE THE STORAGE ASSOCIATED WITH A DDB.
|
||
;CALL MOVEI F,DDB ;NOT LINKED OR CONNECTED
|
||
; PUSHJ P,RMVNET
|
||
;RETURN CPOPJ ;DDB FREED
|
||
;
|
||
RMVNET:: ;HERE TO DELETE A DDB
|
||
PUSHJ P,CLNNET ;CLEAN OUT THE DDB (FREE RANDOM STUFF)
|
||
LDB T1,NETZWD ;GET LENGTH OF THIS PARTICULAR DDB
|
||
MOVEI T2,(F) ;GET ADDR OF THE DDB
|
||
PUSHJ P,GIVZWD ;FREE THE DDB
|
||
SETZ F, ;MAKE SURE F DOESN'T POINT ANYWHERE
|
||
POPJ P, ;ALL DONE
|
||
;CLNNET ROUTINE TO INITIALIZE A DDB.
|
||
;CALL MOVEI F,DDB ;MUST NOT BE CONNECTED
|
||
; PUSHJ P,CLNNET
|
||
;RETURN CPOPJ ;DDB INITIALIZED
|
||
|
||
CLNNET::NTDBUG ;JUST CHECKING...
|
||
|
||
IFN PARANOID&P$DDB,< ;MAKE SURE THAT THIS DDB IS TRULY FREE.
|
||
|
||
SKIPN F ;IS THERE A DDB THERE
|
||
STOPCD .,STOP,ANFCND ;++ CLNNDB HAS NO DDB
|
||
LDB T1,NETSLA ;SHOULDN'T HAVE A LAT ASSIGNED
|
||
SKIPE T1 ; ALL THE DISCONNECT ROUTINES CLEAR THIS
|
||
STOPCD .,STOP,ANFCLA ;++ LAT STILL ASSIGNED IN CLNNDB
|
||
>
|
||
PUSHJ P,GV2NPD ;WE MUST FREE THE NPD'S
|
||
|
||
PUSH P,U ;SAVE "U" FOR A BIT
|
||
HRRZ U,DEVPCB(F) ;GET THE POINTER TO QUEUED PCB'S (IF ANY)
|
||
PUSHJ P,RMVALP ;FREE THEM ALL
|
||
POP P,U ;RESTORE "U"
|
||
|
||
SETZM DEVDRQ(F) ;CLEAR ANY STALE DATA-REQUESTS
|
||
SETZB T1,DEVPCB(F) ;CLEAR POINTER TO JUST FREED PCB'S
|
||
SETZB T2,DEVPBP(F) ; AND CLEAR AUX POINTER TO SUB MSG
|
||
DMOVEM T1,DEVAXI(F) ;CLEAR INPUT BUFFER POINTERS
|
||
DMOVEM T1,DEVAXO(F) ; AND OUTPUT TOO.
|
||
HLLZS DEVNET(F) ;CLEAR NODE NUMBER
|
||
DPB T1,NETSLA ;CLEAR SOURCE LINK ADDR
|
||
DPB T1,NETDLA ; DESTINATION LINK
|
||
DPB T1,NETRLN ; RECORD LENGTH
|
||
DPB T1,NETDVT ; AND ATTRIBUTES
|
||
POPJ P, ;ALL DONE. RESTORE A CLEAN DDB
|
||
;ZAPNET ROUTINE TO TAKE CARE OF USELESS NETWORK DDB'S
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,ZAPNET
|
||
;RETURN CPOPJ, F/0 IF DDB ZAPPED, OTHERWISE UNCHANGED
|
||
;
|
||
;ZAPNET IS CALLABLE FOR ANY NON-TTY DDB IN F, WILL RETURN HARMLESSLY IF
|
||
;THE DDB IS NOT NETWORK-ZAPPABLE (I.E., IS NOT A ANF DEVICE, IS UNDER MDA
|
||
;CONTROL, IS RESTRICTED, OR IS ASSIGNED/INITED BY A JOB/PROGRAM)
|
||
|
||
ZAPNET::MOVE T1,DEVMOD(F) ;A COLLECTION OF DEVICE FLAGS
|
||
TRNE T1,ASSCON!ASSPRG;NEVER DISCONNECT A DDB WHICH IS IN USE
|
||
POPJ P, ;DON'T DISCONNECT THIS DEVICE
|
||
ZAPNE0: MOVE T1,DEVCHR(F) ;SOME DIFFERENT DEVICE FLAGS
|
||
IFN FTMDA,<TLNN T1,DVCMDA> ;NEVER DISCONNECT ONE OF QUASAR'S PLAYTHINGS
|
||
TLNN T1,DVCNET ;NEVER DISCONNECT A NON-ANF-NETWORK DEVICE
|
||
POPJ P, ;DON'T DISCONNECT THIS DEVICE
|
||
MOVE T1,DEVSTA(F) ;OTHER ASSORTED DEVICE FLAGS
|
||
TLNE T1,DEPRAS ;NEVER DISCONNECT A RESTRICTED DEVICE
|
||
POPJ P, ;DON'T DISCONNECT THIS DEVICE
|
||
LDB T1,PDVTYP## ;GET THE DEVICE TYPE
|
||
CAIE T1,.TYDDP ;IS THIS A DDP DEVICE?
|
||
JRST ZAPNE1 ;NO
|
||
SKIPE [M.RDDP##] ;DDCMP DEVICE SERVICE LOADED?
|
||
PJRST ZAPDDP## ;YES, FIRST CHECK WITH DDPSER ON ZAPABILITY
|
||
|
||
ZAPNE1::NETDBJ ;GET THE NETSER INTERLOCK
|
||
SETCM T1,NETZAP## ;GET CATASTROPHIC ERROR FLAG
|
||
JUMPN T1,ZAPNE2 ;NORMAL RELEASE
|
||
DPB T1,NETSLA ;PITCH SLA
|
||
DPB T1,NETDLA ;AND DLA
|
||
ZAPNE2: MOVE S,DEVIOS(F) ;GET THE IO STATUS
|
||
TLNE S,IOSZAP ;HAVE WE FREED THIS DDB ONCE ALREADY??
|
||
STOPCD .,STOP,ANFRDT, ;++ RELEASING DDB TWICE
|
||
TLNN S,IOSCON ;IS THIS DEVICE CONNECTED?
|
||
PJRST UNLDDB ;IF NOT CONNECTED, JUST DELETE THE DDB.
|
||
MOVEI T1,RSN.OK ;NORMAL DISCONNECT REASON
|
||
PUSHJ P,NTDXDS ;SEND THE DISCONNECT.
|
||
JRST [PUSHJ P,NETSLP ;IF WE CAN'T, WAIT FOR CORE TO SHOW UP
|
||
JRST ZAPNET] ;AND TRY AGAIN.
|
||
MOVSI S,IOSZAP ;SINCE NO-ONE WANTS THIS DEVICE ANY MORE,
|
||
IORB S,DEVIOS(F) ;INDICATE THAT IT IS FREE TO BE DELETED.
|
||
PUSHJ P,UNLKDB ;UNLINK THE DDB SO NO-ONE ELSE GETS IT
|
||
SETZ F, ;INDICATE THAT THE DDB IS GONE, AND
|
||
POPJ P, ;RETURN. (NTDDSC WILL EVENTUALLY FREE THE DDB)
|
||
SUBTTL PCB -- ROUTINES TO HANDLE PROTOCOL CONTROL BLOCKS
|
||
|
||
;SUBROUTINE MK?PCB - BUILD A PROTOCOL DATA BLOCK
|
||
;CALL MOVEI F,DDB OR 0 IF AN NCL MESSAGE
|
||
; MOVEI W,NDB
|
||
; MOVEI T1,BUFFERSIZE ;SIZE OF ASSOCIATED MESSAGE BUFFER
|
||
; PUSHJ P,MK?PCB
|
||
;RETURN CPOPJ ;NO SPACE AVAILABLE, OR TOO MANY PENDING MSGS
|
||
; CPOPJ1 ;U=PCB POINTER
|
||
;
|
||
;MKUPCB THIS SUBROUTINE IS USED TO GET A PCB FOR AN UNNUMBERED MESSAGE.
|
||
; IT DOES NOT DECREMENT, OR CHECK NDBMOM(W)
|
||
;MKNPCB THIS SUBROUTINE IS USED TO ALLOCATE A PCB FOR A NUMBERED MESSAGE.
|
||
; IT CHECKS TO MAKE SURE THAT NDBMOM(W) IS GREATER THAN ZERO. THIS
|
||
; CHECK IS NECESSARY TO ENSURE THAT WE DO NOT SEND MORE THAN 128 MSGS
|
||
; TO ANY GIVEN NODE. (IF WE DID THE MSG NUMBERS WOULD WRAP AROUND!)
|
||
|
||
MKNPCB:: ;MAKE NUMBERED PCB
|
||
SKIPE NTUEFC ;IS THIS AN EMERGENCY?
|
||
JRST MKNPC1 ;YES - SKIP THIS CHECK
|
||
PUSH P,T1 ;NO
|
||
MOVE T1,NDBMOM(W) ;GET NUMBER OF MESSAGES AVAILABLE
|
||
CAIG T1,5 ;ARE THERE A FEW FREE?
|
||
JRST TPOPJ## ;NO - SAY WE CAN'T DO IT
|
||
POP P,T1 ;DO IT
|
||
MKNPC1:
|
||
SOSLE NDBMOM(W) ;CHECK ON THE NUMBER OF OUTSTANDING MSGS
|
||
PUSHJ P,MKUPCB ; IF WE CAN, TRY TO MAKE ANOTHER PCB
|
||
AOSA NDBMOM(W) ;HERE IF WE CAN'T SEND ANOTHER PCB NOW.
|
||
JRST [SETZM NTUEFC ;IF WE GOT ONE, CLEAR "EMERGENCY FLAG"
|
||
RETSKP] ; AND GIVE GOOD RETURN
|
||
SKIPN NTUEFC ;IF WE CAN'T USE EMERGENCY FREE CORE,
|
||
POPJ P, ; THEN GIVE BAD RETURN
|
||
SETZM NTUEFC ;OTHERWIZE CLEAR THE "EMERGENCY" FLAG
|
||
PJRST PCBEGT ; AND GO GET "EMERGENCY" MEMORY
|
||
MKUPCB:: ;MAKE UN-NUMBERED PCB
|
||
IFN PARANOID&P$COR,< ;IF WE'RE BEING CAUTIOUS,
|
||
SKIPLE T1 ; THEN MAKE SURE THAT THE CALLER
|
||
CAILE T1,MSGMAW## ; ASKED FOR A POSITIVE, NOT-TOO-LARGE BUFFER
|
||
STOPCD .,STOP,ANFMRL, ;++ MESSAGE REQUEST TOO LARGE
|
||
> ;END IFN PARANOID&P$COR
|
||
|
||
ADDI T1,MSGAGW##-1 ;ROUND UP AND
|
||
ANDCMI T1,MSGAGW##-1 ; TRUNCATE MODULO ALLOCATION GRANULARITY
|
||
MOVE T2,T1 ;COPY OF REQUESTED SIZE (WORDS)
|
||
LSH T2,-MSGAGN## ;REDUCE TO ALLOCATION GRANULARITY
|
||
NETOFF ;NO INTERRUPTS WHILE LOOKING AT FREE-LISTS
|
||
SKIPG NTFREC##(T2) ;ARE THERE ANY PCB'S ON THIS FREE LIST?
|
||
JRST MAKPC1 ;NO FREE PCB'S, ALLOCATE A NEW ONE
|
||
HRRZ U,NTFREF##(T2) ;GET THE FIRST FREE PCB
|
||
HRRZ T1,PCBBLK(U) ;GET THE NEXT FREE PCB
|
||
HRRZM T1,NTFREF##(T2) ; AND MAKE THE "NEXT" ONE THE NEW "FIRST" ONE
|
||
SOSG NTFREC##(T2) ;DECREMENT THE FREE COUNT, IF ZERO, THEN
|
||
SKIPN NTFREF##(T2) ;MAKE SURE THAT PCB FREE LIST IS NULL
|
||
SKIPG U ;MAKE SURE THAT WE GOT A VALID PCB
|
||
STOPCD .,STOP,ANFPCL, ;++ PCB LISTS SCREWED UP
|
||
NETON ;ALL'S CONSISTENT. INTS BACK ON
|
||
HLLZS PCBBLK(U) ;MAKE SURE WE DON'T KEEP ANY POINTERS
|
||
|
||
IFN PARANOID&P$COR,< ;IF WE'RE BEING CAUTIOUS,
|
||
MOVE T1,PCBTAG(U) ;A PCB UNIQUENESS
|
||
CAME T1,['PCBTAG'] ;DOES ALLEGED PCB LOOK LIKE A PCB?
|
||
STOPCD .,STOP,ANFPCT ;++ PCB TRASHED
|
||
MOVE T1,PCBALN(U) ;LENGTH OF DATA BUFFER (WORDS)
|
||
LSH T2,MSGAGN## ;LENGTH IT SHOULD BE
|
||
CAME T1,T2 ;IF LENGTHS DIFFERENT
|
||
STOPCD .,STOP,ANFBLW, ;++ BUFFER LENGTH WRONG
|
||
MOVE T1,PCBADR(U) ;ADDRESS OF DATA BUFFER
|
||
PUSH P,T2 ;SAVE LENGTH
|
||
HLRZ T2,-1(T1) ;GET TOP-END CHECK WORD
|
||
ADD T1,0(P) ;ADJUST ADDRESS AND
|
||
MOVE T1,0(T1) ;GET BOTTOM-END CHECK WORD
|
||
CAMN T1,['NETMEM'] ;IS BOTTOM-END CHECK WORD OK?
|
||
CAIE T2,'NET' ;IS TOP-END CHECK WORD OK?
|
||
STOPCD .,STOP,ANFDMU, ;++ DATA BUFFER MESSED UP
|
||
> ;END IFN PARANOID&P$COR
|
||
|
||
MOVE T1,PCBADR(U) ;DATA BUFFER ADDRESS
|
||
HRLI T1,(POINT 8,) ;PROTOTYPE BYTE POINTER
|
||
MOVEM T1,PCBPTR(U) ;RESET PCB BYTE POINTER
|
||
; (CAN BE TRASHED BY ETHSER/D8EINT)
|
||
JRST TPOPJ1## ;GIVE SUCCESS RETURN
|
||
;HERE TO ALLOCATE THE PCB FROM MONITOR FREE CORE
|
||
|
||
MAKPC1: NETON ;NOT DIDDLING THE FREE LIST ANYMORE
|
||
PUSH P,T1 ;SAVE THE BUFFER SIZE
|
||
MOVEI T2,PCBLEN ;GET THE LENGTH OF A PCB
|
||
PUSHJ P,GETZWD ;GET A ZERO BLOCK OF FREE CORE
|
||
JRST TPOPJ ;NO SPACE
|
||
MOVEI U,(T1) ;COPY THE PCB POINTER
|
||
MOVE T2,(P) ;GET BUFFER SIZE BACK
|
||
JUMPE T2,TPOPJ1 ;IF NO BUFFER WANTED, LEAVE NOW
|
||
PUSHJ P,GETZWD ;GET THE BUFFER
|
||
PJRST [POP P,T1 ;IF NONE AVAILABLE, CLEAN STACK AND
|
||
PJRST RMVPCB] ;AND RETURN THE PCB
|
||
MOVEM T1,PCBADR(U) ;SAVE BUFFER ALLOCATED ADDRESS
|
||
HRLI T1,(POINT 8) ;MAKE BYTE POINTER TO THE BUFFER AREA
|
||
MOVEM T1,PCBPTR(U) ;AND SAVE IT AWAY
|
||
POP P,PCBALN(U) ;REMEMBER BUFFER ALLOCATED LENGTH
|
||
AOS (P) ;GIVE A GOOD RETURN
|
||
PJRST CLNPCB ; AND SET UP CACHE INFORMATION
|
||
;SUBROUTINE RMVPCB - REMOVE THE PCB FROM FREE CORE
|
||
;CALL MOVEI U,PCB
|
||
; S0PSHJ RMVPCB
|
||
;RETURN CPOPJ
|
||
|
||
RMVPCB: JUMPE U,CPOPJ## ;DON'T FREE A NON-EXISTANT PCB
|
||
|
||
IFN PARANOID&P$COR,< ;IF WE ARE BEING CAUTIOUS,
|
||
SKIPE PCBAL2(U) ;MAKE SURE THAT THE "SECONDARY"
|
||
STOPCD .,STOP,ANFSBA, ;++ SECONDARY BUFFER ALLOCATED ("OLD FEATURE")
|
||
>
|
||
|
||
MOVE T2,PCBALN(U) ;GET THE LENGTH OF THE PRIMARY BUFFER
|
||
JUMPE T2,ZAPPCB ;IF NO PRIMARY BUFFER, RETURN PCB TO FREE-CORE
|
||
PUSH P,T2 ;HANG ON TO DATA BUFFER LENGTH
|
||
|
||
IFN PARANOID&P$COR,< ;NOW WE CAN CHECK TO SEE IF SIZE IS REASONABLE
|
||
MOVE T1,PCBTAG(U) ;A PCB UNIQUENESS
|
||
CAMN T1,['PCBTAG'] ;DOES PCB STILL LOOK LIKE A PCB?
|
||
TRNE T2,MSGAGW##-1 ;IS PCB'S DATA BUFFER LENGTH NICELY GRANULAR?
|
||
STOPCD .,STOP,ANFPCR, ;++ PCB TAG WORD TRASHED WHEN REMOVING
|
||
LSH T2,-MSGAGN## ;CONVERT LENGTH TO GRANULARITY INDEX
|
||
CAILE T2,MSGALN## ;IS PCB'S DATA BUFFER A REASONABLE LENGTH?
|
||
STOPCD .,STOP,ANFMBL, ;++ BUFFER LENGTH WRONG
|
||
MOVE T1,PCBADR(U) ;ADDRESS OF DATA BUFFER
|
||
HLRZ T2,-1(T1) ;GET THE TOP-END CHECK WORD
|
||
ADD T1,0(P) ;ADVANCE BUFFER ADDRESS AND
|
||
MOVE T1,0(T1) ;GET THE BOTTOM-END CHECK WORD
|
||
CAMN T1,['NETMEM'] ;IS BOTTOM-END CHECK WORD OK?
|
||
CAIE T2,'NET' ;IS TOP-END CHECK WORD OK?
|
||
STOPCD .,STOP,ANFPCM, ;++ PCB MESSAGE CHECK WORDS TRASHED
|
||
>
|
||
|
||
PUSHJ P,CLNPCB ;REFRESH THE PCB
|
||
POP P,T2 ;RETRIEVE DATA BUFFER LENGTH
|
||
LSH T2,-MSGAGN## ;REDUCE TO ALLOCATION GRANULARITY
|
||
NETOFF ;DISABLE INTERRUPTS WHILE HACKING FREE-LISTS
|
||
SKIPG NTFREC##(T2) ;SEE IF FREE-LIST IS EMPTY
|
||
JRST [HRRZM U,NTFREF##(T2) ;IF EMPTY, THEN THIS PCB GOES ON FIRST
|
||
HRRZM U,NTFREL##(T2) ; AS WELL AS LAST
|
||
JRST RMVPC1] ;GO TO COMMON CODE TO CLEAN UP
|
||
HRRZ T1,NTFREL##(T2) ;GET THE ADDRESS OF THE "LAST" PCB IN THE LIST
|
||
HRRM U,PCBBLK(T1) ; PUT THIS PCB JUST AFTER IT IN THE FREE LIST
|
||
HRRM U,NTFREL##(T2) ; AND ALSO MAKE THIS THE NEW "LAST" PCB
|
||
RMVPC1: AOS NTFREC##(T2) ;COUNT THE NEW FREE PCB
|
||
SETZ U, ;CLEAR "U" TO INDICATE PCB HAS BEEN FREED
|
||
RMVPC7: NETON ;RE-ENABLE INTERRUPTS
|
||
POPJ P, ;RETURN WITH PCB NOW ON PROPER FREE LIST
|
||
;THIS ROUTINE DOES NOT 'RECYCLE' THE PCB. PCB IS RETURNED TO FREE-CORE
|
||
|
||
ZAPPCB: HLLZS PCBTAG(U) ;CLEAR THE 'UNIQUE' TAG
|
||
SKIPE PCBCT2(U) ;GET THE DATA LENGTH
|
||
STOPCD .,STOP,ANFOBS, ;++ OBSOLETE FEATURE
|
||
ZAPPC2: SKIPG T1,PCBALN(U) ;GET THE DATA BUFFER LENGTH
|
||
JRST ZAPPC3 ;NONE
|
||
MOVE T2,PCBADR(U) ;GET THE INPUT POINTER
|
||
PUSHJ P,GIVZWD ;REMOVE THE SPACE
|
||
ZAPPC3: MOVEI T2,(U) ;COPY THE ADDRESS
|
||
MOVEI T1,PCBLEN ;GET THE LENGTH
|
||
PUSHJ P,GIVZWD ;RETURN THE SPACE
|
||
SETZ U, ;CLEAR U TO FLAG PCB AS REMOVED
|
||
POPJ P,
|
||
|
||
|
||
|
||
;CLNPCB REFRESH A PCB.
|
||
;CALL MOVE U,PCB
|
||
; PUSHJ P,CLNPCB
|
||
;RETURN CPOPJ ;ALWAYS
|
||
;CLOBBERS T1,T2
|
||
CLNPCB: SETZM PCBBLK(U) ;CLEAR FLAGS AND LINK FIELDS
|
||
SETZM PCBFEK(U) ;CLEAR FEK AND NODE NUMBER
|
||
SETZM PCBCTR(U) ;CLEAR VALID DATA BYTE COUNT
|
||
SETZM PCBCT2(U) ;CLEAR SECONDARY DATA BYTE COUNT
|
||
SETZM PCBAL2(U) ;AND THE "ANFSBA" STOPCD GENERATOR
|
||
MOVE T1,[SIXBIT /PCBTAG/] ;GET AND SET THE "TAG"
|
||
MOVEM T1,PCBTAG(U) ; WORD SO WE KNOW IT'S A PCB
|
||
IFN FTKL10,<PUSHJ P,PCBMRK> ;SET UP THE CACHE INFORMATION IN THE PCB
|
||
POPJ P, ;ALL DONE
|
||
;"EMERGENCY" PCB MANAGEMENT.
|
||
|
||
Comment @
|
||
|
||
One of the most persistant problems with NETSER has been that
|
||
it uses a great deal of free core, and when free core runs low,
|
||
NETSER tends to crash. What follows it the latest in a
|
||
continuing series of HACKS to ameloiate the effects of finite
|
||
free-core. The routines involved are:
|
||
|
||
PCBECK This routine checks to make sure that there is
|
||
sufficient "emergency" free core available, and
|
||
that there are message numbers available. If it
|
||
skips, one may call PCBEGT with out fear.
|
||
|
||
PCBEGT This routine gets an "emergency" numbered pcb.
|
||
If one is not available, it STOPCD's.
|
||
|
||
Unfortunatly, NETSER is not organized in a fashion that makes
|
||
using these routines easy. The problem is that very low-level
|
||
subroutines are the ones that allocate messages (pcbs).
|
||
Figuring out if it is an "emergency" or not is beyond their
|
||
limited abilities. What is needed is a way for "middle" level
|
||
routines to inform lower level ones that there is an emergency.
|
||
This is currently accomplished by the gross hack of using
|
||
a global flag. The mechanisims for this are:
|
||
|
||
NTUEFC If this location is non-zero, then the next call
|
||
to MKNPCB will not fail. It will attempt to
|
||
use "normal" free-core, but if none is available,
|
||
it will use emergency free core.
|
||
|
||
EMRGCY This is a macro that currently SETOM's ntuefc.
|
||
It should be used just before calls to routine
|
||
such as NCSHDR when it is imperative that they
|
||
NOT fail.
|
||
|
||
End Comment @
|
||
;ROUTINES TO MANAGE EMERGENCY STORAGE
|
||
|
||
;PCBECK ROUTINE TO SEE IF EMERGENCY MESSAGES ARE AVAILABLE.
|
||
;CALL W := NDB POINTER
|
||
;RETURN CPOPJ ;EITHER NO FREE MESSAGE NUMBERS, OR NO CORE
|
||
; CPOPJ1 ;THERE ARE FREE MESSAGE NUMBERS, AND
|
||
; ; EMERGENCY STORAGE. IN PARTICULAR, A
|
||
; ; CALL TO PCBEGT WILL SUCCEED.
|
||
|
||
PCBECK: MOVE T1,NDBMOM(W) ;GET THE COUNT OF FREE MESSAGE NUMBERS,
|
||
CAIG T1,3 ; AND MAKE SURE IT IS REASONABLY LARGE
|
||
POPJ P, ;IF NOT ENOUGH FREE NUMBERS GIVE ERROR RETURN
|
||
MOVE T1,PCBECT ;GET THE COUNT OF "EMERGENCY" PCB'S
|
||
CAIL T1,2 ; AND IF THERE ARE 2 OR MORE, THEN
|
||
RETSKP ;GIVE "SUCCESS" RETURN
|
||
|
||
PUSH P,U ;"U" IS IN USE BY NETSCN AT THIS POINT
|
||
MOVEI T1,MSGMAW## ;IF NOT ENOUGH "EMERGENCY" PCB'S, TRY
|
||
PUSHJ P,MKUPCB ; TO ALLOCATE THE LARGEST POSSIBLE.
|
||
PJRST UPOPJ## ;IF NO MORE FREE-CORE, GIVE ERROR RETURN
|
||
NETOFF ;IF WE GOT ONE, TURN OFF INTERRUPTS
|
||
HRRZ T1,PCBELS ; AND INSERT THE NEW ONE
|
||
HRRM T1,PCBBLK(U) ; ON THE FRONT OF THE "EMERGENCY"
|
||
HRRM U,PCBELS ; PCB FREE LIST (PCBELS).
|
||
AOS PCBECT ;COUNT THE NEW "EMEGENCY" PCB
|
||
NETON ;RE-ENABLE INTERRUPT, AND
|
||
POP P,U ;GET NETSCN'S "U" BACK
|
||
JRST PCBECK ;GO SEE IF WE HAVE ENOUGH NOW.
|
||
|
||
;PCBEGT ROUTINE TO GET AN "EMERGENCY" NUMBERED PCB
|
||
;CALL W := NDB POINTER ;(WE NEED TO FIX NDBMOM)
|
||
;RETURN CPOPJ1 ;WITH U := "EMERGENCY" PCB
|
||
; ; (IF NONE AVAILABLE, WE STOPCD)
|
||
|
||
PCBEGT: NETOFF ;DISABLE INTERRUPTS WHILE HACKING LISTS
|
||
SOSL NDBMOM(W) ;DECREMENT THE FREE MESSAGE NUMBER COUNTER
|
||
SOSGE PCBECT ;DECREMENT THE COUNT OF "EMERGENCY" PCB'S
|
||
STOPCD .,STOP,ANFNFP, ;++ NO FREE PCBS OR NO FREE MESSAGES
|
||
HRRZ U,PCBELS ;GET THE FIRST FREE PCB,
|
||
HRRZ T1,PCBBLK(U) ;GET THE ADDRESS OF THE SECOND (IF ANY)
|
||
HRRM T1,PCBELS ;MAKE THE "SECOND" THE NEW "FIRST"
|
||
PJRST NTONP1 ;RE-ENABLE INTERRUPTS AND SKIP RETURN.
|
||
;ONCE/SECOND CODE FOR PCB MANAGEMENT.
|
||
;THIS CODE FREES EXCESS PCBS FROM THE FREE LISTS ONCE/SECOND.
|
||
;AT LEAST ONE FREE PCB IS ALWAYS KEPT IN ORDER TO MINIMIZE THE
|
||
;CONTENTION ON GENERAL MONITOR FREE CORE. IN PARTICULAR, FOR
|
||
;THE MSGMAX-SIZED PCB LIST TWO FREE PCBS ARE KEPT (SINCE ALL
|
||
;INPUT OPERATIONS MUST ALMOST-BY-DEFINITION USE THIS SIZE).
|
||
|
||
PCBSEC: MOVE T1,TIME## ;GET SYSTEM TIME (IN JIFFIES)
|
||
IDIV T1,TICSEC## ;GET SYSTEM TIME (IN SECONDS)
|
||
IDIVI T1,MSGALN##+1 ;TAKE MOD ALLOCATION TABLE MAXIMA
|
||
NETOFF ;MAKE SURE NOT INTERRUPTED
|
||
SKIPG T1,NTFREC##(T2) ;GOT A FREE PCB HERE?
|
||
PJRST RMVPC7 ;NO, JUST RE-ENABLE AND GO AWAY
|
||
CAIL T2,MSGALN## ;IS THIS THE MSGMAX-SIZED PCB LIST?
|
||
SUBI T1,1 ;YES, ALLOW FOR ONE MORE
|
||
SOJLE T1,RMVPC7 ;ALWAYS KEEP THE "LAST" ONE
|
||
HRRZ U,NTFREF##(T2) ;GET THE ADDRESS OF THE "FIRST" FREE ONE
|
||
HRRZ T1,PCBBLK(U) ;GET THE ADDRESS OF THE "NEXT" FREE ONE
|
||
HRRM T1,NTFREF##(T2) ;MAKE THE "NEXT" THE "FIRST"
|
||
SOSLE NTFREC##(T2) ;COUNT DOWN THE PCB COUNTER
|
||
JRST PCBSE3 ;ALL DONE
|
||
SKIPE NTFREF##(T2) ;THAT WAS THE LAST, BETTER NOT BE ANY MORE
|
||
STOPCD .,STOP,ANFFCW, ;++ FREE PCB COUNT WRONG
|
||
SETZM NTFREL##(T2) ;CLEAR POINTER TO LAST
|
||
PCBSE3: NETON ;NO LONGER PLAYING WITH FREE LISTS
|
||
HLLZS PCBBLK(U) ;NO STRAY POINTERS
|
||
PJRST ZAPPCB ;RETURN THE PCB TO FREE CORE
|
||
|
||
|
||
|
||
;RMVALP THIS ROUTINE FREES AN ENTIRE CHAIN OF PCB'S
|
||
;CALL U := FIRST ONE TO GO
|
||
;RETURN CPOPJ
|
||
RMVALP: PUSHJ P,SAVE1 ;SAVE P1 FOR THE DURATION
|
||
RMVAL1: JUMPE U,CPOPJ ;ALL DONE IF NO PCB
|
||
HRRZ P1,PCBBLK(U) ;GET AND KEEP POINTER TO NEXT PCB
|
||
S0PSHJ RMVPCB ;FREE THIS PCB
|
||
MOVEI U,(P1) ;CURRENT PCB := NEXT PCB
|
||
PJRST RMVAL1 ;TAIL-RECURSE
|
||
SUBTTL NDB -- ROUTINES TO MANAGE NODE DATA BLOCKS
|
||
|
||
;SUBROUTINE MAKNDB - BUILD A NODE DATA BLOCK (NDB)
|
||
;CALL MOVEI J,FEK
|
||
; MOVEI T1,NNM
|
||
; PUSHJ P,MAKNDB
|
||
;RETURN CPOPJ ;NO CORE
|
||
; CPOPJ1 ;W=NDB
|
||
|
||
MAKNDB: ;ENTRY
|
||
NTDBUG ;VERIFY THE INTERLOCK
|
||
PUSH P,T1 ;SAVE THE NODE NUMBER
|
||
MOVEI T2,NDBLEN ;LENGTH
|
||
PUSHJ P,GETZWD ;ALLOCATE
|
||
PJRST TPOPJ## ;NO SPACE
|
||
MOVEI W,(T1) ;COPY THE POINTER
|
||
HRRM J,NDBFEK(W) ;STORE THE FEK POINTER
|
||
HRRZ T1,NETNDB## ;GET THE START OF THE NDB CHAIN
|
||
NETOFF ;NEED PROTECTION SINCE 'STBOPR' AND
|
||
; OTHER ROUTINES SCAN THE NDB LIST WITH
|
||
; OUT FIRST GETTING THE 'NT' INTERLOCK
|
||
; (SEE FOOTNOTE AFTER ROUTINE "SRCNDB")
|
||
HRRM T1,NDBNNM(W) ;LINK THIS NDB TO THE START
|
||
HRRM W,NETNDB## ;LINK
|
||
POP P,T1 ;GET THE NODE NUMBER
|
||
CAIG T1,NODMAX ;RANGE CHECK
|
||
HRRM W,.GTNDA##(T1) ;STORE ADDRESS IF VALID
|
||
HRLM T1,NDBNNM(W) ;STORE
|
||
NETON ;ALL'S CLEAR
|
||
PJRST CPOPJ1## ;EXIT
|
||
SUBTTL SUBROUTINE TO RETURN STORAGE DATA BLOCK TO THE MONITOR
|
||
;SUBROUTINE RMVNDB - REMOVE A NODE DATA BLOCK NDB
|
||
;CALL MOVEI W,NDB
|
||
; PUSHJ P,RMVNDB
|
||
;RETURN CPOPJ
|
||
|
||
RMVNDB:
|
||
NTDBUG ;VERIFY THE INTERLOCK
|
||
PUSHJ P,SAVJW## ;SAVE J AND W
|
||
PUSHJ P,SAVE1## ;SAVE P1
|
||
PUSHJ P,NODEDN ;CALL "NODE DOWN"
|
||
PUSHJ P,CLNNDB ;CLEAN OUT STUFF HANGING ON THE NDB
|
||
MOVEI T1,NETNDB## ;GET THE START OF THE NDB CHAIN
|
||
NETOFF ;TURN OFF THE PI'S SINCE STBOPR
|
||
; DOESN'T ALWAYS GET THE 'NT' INTERLOCK
|
||
; (SEE FOOTNOTE AFTER ROUTINE "SRCNDB")
|
||
RMVNT2: HRRZ T2,NDBNNM(T1) ;GET THE NEXT POINTER
|
||
JUMPE T2,CPOPJ## ;EXIT IF END
|
||
CAIN T2,(W) ;IS THIS THE BLOCK
|
||
JRST RMVNT3 ;YES,
|
||
MOVEI T1,(T2) ;NO, STEP ALONG
|
||
JRST RMVNT2 ;TRY AGAIN
|
||
RMVNT3: HRRZ T3,NDBNNM(W) ;GET THE FORWARD LINK
|
||
HRRM T3,NDBNNM(T1) ;STORE BACKWARD
|
||
HLRZ T1,NDBNNM(W) ;GET NODE REMOVED
|
||
CAIG T1,NODMAX ;RANGE CHECK
|
||
HLLZS .GTNDA##(T1) ;AND CLEAR POINTER
|
||
NETON ;ALL'S CLEAR
|
||
MOVEI T1,NDBLEN ;GET THE LENGTH
|
||
PJRST GIVZWD ;RELEASE THE BLOCK
|
||
;CLNNDB CLEAN OUT AN NDB. THIS ROUTINE ZEROS ALL MESSAGE COUNTS
|
||
; AND OTHER APPROPRIATE FIELDS AND FREES ALL DATA HANGING OFF OF
|
||
; AN NDB. (CALL WHEN SENDING OR RECEIVING STARTS)
|
||
;CALL W := NDB
|
||
;RETURN CPOPJ
|
||
|
||
CLNNDB:
|
||
NTDBUG ;VERIFY THE INTERLOCK
|
||
PUSHJ P,SAVE4## ;THIS ROUTINE CLOBBERS EVERYTHING
|
||
PUSHJ P,SAVJW## ;THESE TOO
|
||
PUSH P,U ;AND EVEN THIS
|
||
|
||
IFN PARANOID&P$NDB,<PUSHJ P,NDBCHK> ;MAKE SURE WE DON'T DELETE OUR NDB
|
||
|
||
;HERE TO CHECK FOR STATION CONTROL RESOURCE
|
||
PUSH P,W ;SAVE NDB POINTER
|
||
HRRZ J,NDBICT(W) ;GET MESSAGE ADDR
|
||
SKIPE J ;IS THERE ONE ?
|
||
PUSHJ P,GIVSTC ;IF SO, FREE THEM
|
||
SKIPE T1,NDBSTC(W) ;ANYONE USING STATION CONTROL
|
||
PUSHJ P,EWAKE## ;IF SO, WAKE HIM UP.
|
||
POP P,W ;GET NDB POINTER BACK
|
||
|
||
;HERE TO CALL ALL THE NETWORK DEVICES AND INFORM THEM THAT THIS NODE HAS
|
||
; GONE AWAY. ALL THE SERVICE ROUTINES WILL BE CALLED ON THEIR "NDPNWD"
|
||
; ENTRY POINT. THE INTERFACE FOR A NDPNWD ENTRY SHOULD BEHAVE AS FOLLOWS.
|
||
;AT ENTRY
|
||
; P1 := NODE NUMBER OF CRASHED NODE.
|
||
; P2 := LAT INDEX ('SLA')
|
||
; F := LAT ENTRY FOR THIS DEVICE (XWD FLAGS,DDB/LDB)
|
||
;RETURN CPOPJ ;ALWAYS.
|
||
|
||
CLNND0: MOVSI P2,-LATLEN## ;MAKE AN AOBJN POINTER FOR ACCESSING THE LAT.
|
||
HLRZ P1,NDBNNM(W) ;GET THE NUMBER OF THE CRASHED NODE.
|
||
PUSH P,W ;WE MAY CLOBBER "W". PRESERVE IT FOR NOW.
|
||
JRST CLNND2 ;SKIP OVER THE ZERO'TH ENTRY (NETDDB)
|
||
|
||
CLNND1: SKIPN T2,NETLAT##(P2) ;GET THE NEXT LAT ENTRY
|
||
JRST CLNND2 ;THIS ENTRY NOT IN USE
|
||
LDB F,LATPP2 ;EXTRACT DDB/LDB ADDRESS (INDEX P2)
|
||
TLNN T2,LAT.TY ;IS THIS A DDB OR LDB
|
||
SKIPA T1,DEVNET(F) ;DDB, GET NODE NUMBER
|
||
LDB T1,LDPRNF## ;LDB, GET NODE NUMBER
|
||
ANDI T1,777 ;MASK OFF LH JUNK
|
||
CAIE T1,(P1) ;IS THIS DEVICE/TTY DOOMED?
|
||
JRST CLNND2 ;NO, LEAVE IT ALONE THEN
|
||
MOVEI T1,NDPNWD ;GET THE "NODE WENT DOWN" FCN CODE
|
||
PUSHJ P,ICMNDP ;AND CALL THE DISPATCH ROUTINE
|
||
CLNND2: AOBJN P2,CLNND1 ;LOOP OVER ALL LAT ENTRYS
|
||
POP P,W ;RECOVER OUR NDB POINTER
|
||
|
||
;CONTINUED ON NEXT PAGE
|
||
;CONTINUED FROM PREVIOUS PAGE
|
||
|
||
;HERE TO PURGE THE NDB NAME POINTERS
|
||
|
||
MOVEI T1,^D8 ;FOUR WORDS TO REMOVE
|
||
HLRZ T2,NDBSID(W) ;GE THE SOFTWARE ID POINTER
|
||
SKIPE T2 ;ASSIGNED
|
||
PUSHJ P,GIVZWD ;RETURN THE SPACE
|
||
MOVEI T1,^D8 ;FOUR WORDS TO RETURN
|
||
HRRZ T2,NDBSID(W) ;GET THE ADDRESS
|
||
SKIPE T2 ;NOT ASSIGNED
|
||
PUSHJ P,GIVZWD ;REMOVE THE SPACE
|
||
;HERE TO REMOVE THE QUEUES FOR THE NODES
|
||
HRRZ U,NDBQUE(W) ;GET AND FREE THE
|
||
PUSHJ P,RMVALP ; THE RIGHT HAND
|
||
HLRZ U,NDBQUE(W) ;GET AND FREE THE
|
||
PUSHJ P,RMVALP ; THE LEFT HAND
|
||
|
||
HRLZI T1,(W) ;BUILD A BLT POINTER
|
||
HRRI T1,1(W) ; TO ZERO THE NDB
|
||
NETOFF ;COVER OURSELVES WHILE NDB IS SCREWED UP
|
||
; (SEE FOOTNOTE AFTER ROUTINE "SRCNDB")
|
||
MOVE T2,NDBNNM(W) ;SAVE "XWD NODE#,LINK" FOR A WHILE
|
||
HRRZ T3,NDBFEK(W) ;SAVE THE ADDR OF THE FEK
|
||
SETZM (W) ;ZAP THE FIRST, AND THEN
|
||
BLT T1,NDBLEN-1(W) ; THE REST OF THE NDB.
|
||
MOVEM T3,NDBFEK(W) ;RESTORE THE FEK ADDRESS AND THE
|
||
MOVEM T2,NDBNNM(W) ; NODE#,,LINK WORD
|
||
NETON ;ALL IS CONSISTENT NOW
|
||
MOVEI T1,^D30 ;ONLY ALLOW A MAX OF 30 OUTSTANDING (IE.
|
||
; UN-ACKED) MESSAGES
|
||
MOVEM T1,NDBMOM(W) ;INITIALIZE MAX OUTSTANDING MESSAGES
|
||
PJRST UPOPJ ;RESTORE U AND RETURN
|
||
;ROUTINE TO HANDLE NODE ONLINE EVENTS
|
||
;CALL MOVX W,NDB-POINTER
|
||
; PUSHJ P,NODEUP
|
||
;RETURN CPOPJ ;DOES "ONLINE" PROCESSING ONLY IF NODE WAS NOT
|
||
; ; ONLINE BEFORE
|
||
NODEUP: MOVSI T1,NDB.UP ;GET THE NODE "ONLINE" FLAG
|
||
TDNE T1,NDBFLG(W) ;SEE IF WE ARE ALREADY ONLINE
|
||
POPJ P, ; IF ONLINE ALREADY, RETURN
|
||
IORM T1,NDBFLG(W) ;MARK THE NODE AS ONLINE
|
||
S0PSHJ ONLNDB ;PRINT THE ONLINE MESSAGE
|
||
PUSHJ P,PSINTC## ;SIGNAL THE ONLINE EVENT
|
||
|
||
MOVE T1,[XWD .CSCNO,.ERCSC] ;GET CODE TO TELL DAEMON NODE ONLINE
|
||
PJRST NODEAM ; AND GO TELL DAEMON
|
||
|
||
|
||
|
||
;ROUTINE TO HANDLE NODE OFFLINE EVENTS
|
||
;CALL MOVX W,NDBPOINTER
|
||
; PUSHJ P,NODEDN
|
||
;RETURN CPOPJ ;DOES "OFFLINE" PROCESSING ONLY IF THE
|
||
; ;NODE WAS ONLINE.
|
||
NODEDN: MOVSI T1,NDB.UP ;GET THE "ONLINE" BIT
|
||
TDNN T1,NDBFLG(W) ;IF WE'RE NOT ONLINE NOW,
|
||
POPJ P, ; THEN DON'T DO ANY OFFLINE STUFF
|
||
ANDCAM T1,NDBFLG(W) ;CLEAR THE ONLINE BIT
|
||
S0PSHJ OFLNDB ;TELL THE OPERATOR IT WENT AWAY
|
||
PUSHJ P,PSINTC## ;SIGNAL THE OFFLINE EVENT
|
||
|
||
MOVE T1,[XWD .CSCNF,.ERCSC] ;GET NODE OFF-LINE DAEMON CODE
|
||
; PJRST NODEAM ; AND GO TELL DAEMON
|
||
|
||
|
||
;ROUTINE TO CALL DAEMON FOR NODE ON/OFF LINE EVENTS
|
||
;CALL MOVX T1,"DAEMON CODE"
|
||
; PUSHJ P,NODEAM
|
||
;RETURN CPOPJ ;ALWAYS
|
||
NODEAM: PUSHJ P,SAVJW## ;"J" GETS MASHED BY DAEEIM
|
||
PUSH P,U ;DON'T WANT TO CLOBBER INCTSK'S PCB
|
||
SETZ F, ;CLEAR "F" SO AS NOT TO CONFUSE DAEMON
|
||
HLRZ U,NDBNNM(W) ;GET THE NODE NUMBER IN U
|
||
PUSHJ P,DAEEIM## ;CALL THE NON-BLOCKING FORM OF DAEMON
|
||
PJRST UPOPJ## ;CLEAN UP AND RETURN
|
||
;SRCNDB ROUTINE TO FIND A NDB GIVEN A NODE NAME OR NUMBER
|
||
;CALL MOVE T1,NNM ;NODE NUMBER
|
||
;OR MOVE T1,[SIXBIT /NODE NAME/] ;SIXBIT NODE NAME
|
||
; PUSHJ P,SRCNDB
|
||
;RETURN CPOPJ ;NOT FOUND
|
||
; CPOPJ1 ;FOUND W=NDB POINTER
|
||
SRCNDB::NTDBUG ;VERIFY THE INTERLOCK
|
||
SRCND0::TLNE T1,-1 ;IF IT'S A NAME,
|
||
JRST SRCND3 ; GO USE A DIFFERENT LOOP
|
||
SRCND1: SKIPN T1 ;IF NODE NUMBER IS ZERO,
|
||
MOVE T1,JBTLOC##+0 ;USE THE LOCAL NODE
|
||
CAILE T1,NODMAX ;RANGE CHECK
|
||
POPJ P, ;NOT IN RANGE
|
||
HRRZ W,.GTNDA##(T1) ;GET NDB ADDRESS
|
||
CAIE W,0 ;ONLINE
|
||
AOS (P) ;YES, SKIP
|
||
POPJ P, ;AND RETURN
|
||
|
||
SRCND3: PUSHJ P,SRCND4 ;FIRST TRY IT AS A "NAME"
|
||
CAIA ; AND IF THAT SUCCEEDS,
|
||
JRST CPOPJ1## ; THEN WE'RE DONE.
|
||
PUSH P,T1 ;OTHERWISE, TRY TO CONVERT
|
||
PUSHJ P,CVTOCT## ; A SIXBIT NUMBER
|
||
JRST TPOPJ## ; IF THAT FAILS, GIVE UP
|
||
PUSHJ P,SRCND1 ;TRY THE NUMBER
|
||
JRST TPOPJ## ; FAILED
|
||
JRST TPOPJ1## ; SUCCEEDED.
|
||
|
||
SRCND4: MOVEI W,NETNDB ;GET THE HEAD OF THE CHAIN
|
||
SRCND5: HLRZ T3,NDBSNM(W) ;GET THE ADDRESS OF THE NAME
|
||
JUMPE T3,SRCND6 ;IF NO NAME, NO ADDRESS OF NAME
|
||
CAMN T1,(T3) ; SEE IF THEY MATCH
|
||
JRST CPOPJ1## ;RETURN SUCCESS IF THEY DO
|
||
SRCND6: HRRZ W,NDBNNM(W) ;OTHERWISE GO TO THE NEXT
|
||
JUMPN W,SRCND5 ; AND CHECK THAT
|
||
POPJ P, ;ERROR RETURN IF NO MORE
|
||
|
||
;*** FOOTNOTE ***
|
||
|
||
COMMENT \
|
||
|
||
The entry SRCND0 should only be called under cover of a "NETOFF"
|
||
macro. One of the fundamental goals in the 7.01 NETSER was to eliminate
|
||
crashes caused by "stale" pointers to NDB's that had been destroyed.
|
||
In light of this, the only time that a pointer to an NDB is valid is
|
||
under the NETSER interlock. Unfortunatly, ocasionally the need arises
|
||
to look at some field in some NDB at a time when it is not convenient
|
||
to request the NETSER interlock. Examples of this are translating
|
||
a node name to a node number, and finding the OPR ldb of a particular
|
||
remote station. Both of these routines (STBSCA and STBOPR) are called
|
||
from clock and/or interrupt levels, and hence cannot do a NDTDBJ.
|
||
Routines like these MUST NETOFF for the period that they possess a
|
||
valid NDB address.
|
||
\
|
||
SUBTTL NDT -- ROUTINES TO SEARCH THE NDT
|
||
|
||
;SUBROUTINE SRCNDT - SEARCH THE NETWORK DEVICE TABLE
|
||
;CALL HRRZ T1,(SIXBIT /GENERIC NETWORK DEVICE NAME/)
|
||
; MOVEI P1,NDB
|
||
; PUSHJ P,SRCNDT
|
||
;RETURN CPOPJ ;DEVICE NOT FOUND
|
||
; CPOPJ1 ;DEVICE FOUND W(RT)=THE NDT POINTER
|
||
|
||
SRCNDT::CAIE T1,'MCR' ;THE "MONITOR COMMAND ROUTINE" ISN'T
|
||
CAIN T1,'MC ' ; A REAL DEVICE (TOO BAD, MIGHT BE NEAT)
|
||
POPJ P, ;REJECT MCR:
|
||
NTDBUG ;VERIFY THE INTERLOCK
|
||
PUSH P,T4 ;SAVE T4
|
||
MOVE T4,NDTXWD## ;GET THE SEARCH POINTER
|
||
SRCNDC: SKIPN W,(T4) ;GET AN NDT
|
||
AOBJN T4,.-1 ;KEEP SEARCHING
|
||
JUMPGE T4,SRCNDX ;DONE?
|
||
HLRZ T2,NDTNAM(W) ;GET THE -10 DEVICE NAME
|
||
HRRZ T3,NDTNAM(W) ;GET THE -11 DEVICE NAME
|
||
CAIE T1,(T2) ;IS IT A -10 DEVICE
|
||
CAIN T1,(T3) ;OR A -11 DEVICE
|
||
JRST SRCNDD ;CHECK THE CONFIGURATION
|
||
AOBJN T4,SRCNDC ;AND TRY AGAIN
|
||
SRCNDX: POP P,T4 ;RESTORE T4
|
||
POPJ P, ;DEVICE NOT FOUND
|
||
SRCNDD: MOVE T4,W ;COPY NDT POINTER
|
||
EXCH T4,(P) ;SAVE NDT AND RESTORE T4
|
||
LDB T1,NDTOBJ ;GET THE DEVICE TYPE
|
||
MOVEI W,(P1) ;COPY THE NDB POINTER
|
||
LDB T1,NETCNF##(T1) ;GET THE CONFIGURATION COUNT
|
||
JUMPE T1,WPOPJ## ;THAT NODE DOES NOT HAVE ANY
|
||
PJRST WPOPJ1## ;DEVICE IS OK
|
||
SUBTTL LAT -- ROUTINES FOR MANIPULATING THE LINK ADDRESS TABLE
|
||
|
||
;GETSLA ROUTINE TO GET A SOURCE LINK ADDRESS FROM THE LAT TABLE
|
||
;CALL: MOVE T1,<ADDR OF DDB/LDB TO BE STORED IN NETLAT>
|
||
; MOVEI T2,LAT.XX ;LAT STATE
|
||
; PUSHJ P,GETSLA
|
||
;RETURN CPOPJ ;NONE AVAILABLE
|
||
; CPOPJ1 ;T1=SLA
|
||
|
||
GETSLA::NTDBUG ;VERIFY THE INTERLOCK
|
||
PUSH P,T1 ;SAVE LAT ADDRESS AND FLAGS
|
||
|
||
IFN PARANOID&P$LAT,<
|
||
TLZ T1,777700 ;MASK OUT ALL BUT ADDRESS
|
||
PUSH P,T2 ;SAVE DESIRED INITIAL STATE
|
||
CAIL T2,0 ;RANGE
|
||
CAILE T2,LAT.MX ; CHECK
|
||
PUSHJ P,NTDSTP ;++ INITIAL LAT STATE ILLEGAL
|
||
MOVSI T2,-LATLEN## ;PROTOTYPE LAT INDEXER
|
||
GETSL1: LDB T3,LATPT2 ;GET THIS SLA'S DDB/LDB ADDRESS
|
||
CAMN T3,T1 ;DOES THIS DDB/LDB ALREADY HAVE A LAT SLOT?
|
||
STOPCD .,STOP,ANFWLA, ;++ WRONG LAT ASSIGNED
|
||
AOBJN T2,GETSL1 ;LOOP OVER ALL LAT ENTRIES
|
||
POP P,T2 ;RETRIEVE INITIAL LAT STATE
|
||
> ;IFN PARANOID&P$LAT
|
||
|
||
MOVSI T1,-LATLEN## ;GET THE LENGTH FOR THE AOBJN
|
||
SKIPE NETLAT##(T1) ;LOOK FOR AN AVAILABLE SLOT
|
||
AOBJN T1,.-1 ;CONTINUE STEPPING
|
||
JUMPGE T1,TPOPJ## ;NONE AVAILABLE
|
||
POP P,NETLAT(T1) ;MARK THE SLOT AS IN USE
|
||
DPB T2,LATSTA ;SET INITIAL STATE IN LAT ENTRY FOR THIS SLA
|
||
JRST CPOPJ1 ;T1=SLA
|
||
|
||
|
||
;GIVSLA ROUTINE TO RETURN A LAT ADDRESS
|
||
;CALL MOVEI F,DDB ;THIS DOESN'T WORK FOR TERMINAL
|
||
; PUSHJ P,GIVSLA ;RETURN THE LAT ENTRY, ZERO NETSLA
|
||
;RETURN CPOPJ ;UNLESS WE STOPCD.
|
||
;
|
||
;NOTE! THIS ROUTINE PRESERVES ALL REGISTERS (ESPECIALLY T1)
|
||
|
||
GIVSLA::NTDBUG ;VERIFY THE NETSER INTERLOCK
|
||
PUSHJ P,SAVE2## ;SAVE P1, P2 SO WE DON'T CLOBBER THE T'S
|
||
LDB P2,NETSLA ;GET THE CURRENT SLA FOR THIS DEVICE
|
||
HRRZ P1,NETLAT##(P2) ;GET [MOST OF] THE LAT ENTRY.
|
||
;IT'S OK TO ONLY LOOK AT 18 BITS HERE . . .
|
||
CAIE P1,(F) ;MAKE SURE EVERYTHING IS CONSISTENT.
|
||
STOPCD .,STOP,ANFLAT, ;++ DDB AND LAT DON'T AGREE
|
||
SETZB P1,NETLAT##(P2) ;FREE THE LAT
|
||
DPB P1,NETSLA ;CLEAR THE SLA IN THE DDB
|
||
DPB P1,NETDLA ; GET THE DLA SINCE NOT CONNECTED.
|
||
POPJ P, ;ALL DONE
|
||
SUBTTL NPD -- ROUTINES TO MANIPULATE NETWORK CONNECT DISCRIPTORS
|
||
|
||
|
||
;GETNPD ROUTINE TO ALLOCATE A NETWORK CONNECTION DESCRIPTOR BLOCK
|
||
;CALL MOVEI T1,LENGTH ;LENGTH OF DESIRED NPD (INCLUDES NPDBLK)
|
||
; PUSHJ P,GETNPD
|
||
;RETURN CPOPJ ;ERROR RETURN. NO CORE
|
||
; CPOPJ1 ;WITH J := A POINTER TO THE NPD
|
||
;
|
||
GETNPD:: ;HERE TO ALLOCATE AN NPD
|
||
MOVEI T2,(T1) ;COPY THE LENGTH FOR GETZWD
|
||
PUSH P,T1 ;SAVE IT SO WE CAN PUT IT IN NPDBLK
|
||
PUSHJ P,GETZWD ;ALLOCATE THE STORAGE
|
||
JRST TPOPJ## ;NO STORAGE. ERROR RETURN
|
||
POP P,T2 ;GET THE LENGTH BACK
|
||
MOVEI J,(T1) ;COPY THE NPD POINTER
|
||
HRLZM T2,NPDBLK(J) ;SAVE THE LENGTH
|
||
JRST CPOPJ1## ;GOOD RETURN
|
||
|
||
|
||
;GIVNPD ROUTINE TO RETURN A NETWORK CONNECTION DESCRIPTOR BLOCK
|
||
;CALL MOVEI J,NPD ADDRESS
|
||
; PUSHJ P,GIVNPD
|
||
;RETURN CPOPJ ;ALWAYS
|
||
;
|
||
GIVNPD::HLRZ T1,NPDBLK(J) ;GET THE ALLOCATED LENGTH OF THE NPD
|
||
MOVEI T2,(J) ;GET THE ADDRESS OF THE STORAGE
|
||
PUSHJ P,GIVZWD ;FREE THE NPD
|
||
SETZ J, ;INDICATE THAT IT IS GONE
|
||
POPJ P, ;GIVE A GOOD RETURN
|
||
|
||
|
||
;GV2NPD RETURN BOTH NPD'S OF A TASK
|
||
;CALL F := DDB
|
||
;RETURN CPOPJ ;ALWAYS
|
||
|
||
GV2NPD::PUSH P,J ;PRESERVE "J"
|
||
HRRZ J,DEVNPD(F) ;GET THE ADDRESS OF THE FIRST NPD
|
||
SKIPE J ;IF IT'S NOT NULL,
|
||
PUSHJ P,GIVNPD ;RETURN IT
|
||
HLRZ J,DEVNPD(F) ;GET THE ADDRESS OF THE REMOTE NPD
|
||
SKIPE J ;IF IT'S NOT NULL,
|
||
PUSHJ P,GIVNPD ;RETURN IT TOO
|
||
SETZM DEVNPD(F) ;CLEAR THE NPD POINTER
|
||
JRST JPOPJ## ;RESTORE "J" AND RETURN
|
||
SUBTTL STC -- ROUTINES TO MANIPULATE STATION CONTROL MESSAGE BLOCKS
|
||
|
||
;GETSTC ROUTINE TO ALLOCATE A STC (STATION CONTROL MESSAGE) BLOCK
|
||
;CALL T1 := NUMBER OF BYTES IN THE STC MESSAGE
|
||
; W := POINTER TO THE NDB WE'RE SENDING TO/RECEIVING FROM
|
||
;RETURN CPOPJ ;NO CORE
|
||
; CPOPJ1 ;STC ALLOCATED.
|
||
; ; J := POINTER TO STC BLOCK
|
||
|
||
GETSTC::PUSH P,T1 ;SAVE THE LENGTH (IN BYTES)
|
||
MOVEI T2,3+<4*STCDAT>(T1) ;SET T2 := LENGTH(BYTES) OF ENTIRE STC
|
||
LSH T2,-2 ;CHANGE WORDS TO BYTES (ROUNDED UP)
|
||
PUSHJ P,GETZWD ;GET A BLOCK OF FREE-CORE TO HOLD STC MSG
|
||
JRST TPOPJ## ; IF NO MORE MEMORY, GIVE ERROR RETURN
|
||
MOVEI J,(T1) ;MAKE "J" THE STC POINTER
|
||
POP P,T1 ;GET BACK THE LENGTH OF THE MESSAGE (BYTES)
|
||
HRLZM T1,STCBLK(J) ;STORE LENGTH IN STC BLOCK
|
||
RETSKP ;GIVE GOOD RETURN
|
||
|
||
;GIVSTC ROUTINE TO FREE A STC (STATION CONTROL MESSAGE) BLOCK
|
||
;CALL J := POINTER TO THE STC MESSAGE BLOCK
|
||
;RETURN CPOPJ ;ALWAYS
|
||
|
||
GIVSTC::MOVEI T2,(J) ;SET T2 := ADDRESS OF STC BLOCK
|
||
HLRZ T1,STCBLK(J) ;GET THE LENGTH (BYTES) OF THE STC DATA
|
||
ADDI T1,3+<STCDAT*4> ;GET THE LENGTH (BYTES) OF STC DATA + STC BLOCK
|
||
LSH T1,-2 ;SET T1 := LENGTH OF BLOCK (WORDS ROUNDED UP)
|
||
PJRST GIVZWD ;RETURN THE STORAGE AND RETURN
|
||
;FEK2LN ROUTINE TO CONVERT FROM FEK ADDRESS TO STATION CONTROL LINE NUMBER
|
||
;CALL J := FEK
|
||
;RETURN CPOPJ ;T1 := LINE NUMBER
|
||
; ;STOPS IF J /= A VALID FEK ADDRESS
|
||
|
||
FEK2LN: MOVEI T1,1 ;START WITH LINE NUMBER 1
|
||
MOVEI T2,FEKFST ;GET THE ADDRESS OF THE FIRST FEK
|
||
FEK2L1: CAIN T2,(J) ;IF THIS IS THE FEK WE'RE LOOKING FOR
|
||
POPJ P, ; RETURN WITH T1 := ITS LINE NUMBER
|
||
HRRZ T2,FEKBLK(T2) ;GET THE ADDRESS OF THE NEXT FEK
|
||
SKIPN T2 ;IF THERE AREN'T ANY MORE FEKS, THEN
|
||
STOPCD .,STOP,ANFGFK, ;++ GARBAGE FEK POINTER
|
||
AOJA T1,FEK2L1 ;INCREMENT THE LINE NUMBER AND CHECK NEXT FEK
|
||
|
||
|
||
;LN2FEK ROUTINE TO CONVERT FROM STATION CONTROL LINE NUMBER TO FEK ADDRESS
|
||
;CALL T1 := LINE NUMBER
|
||
;RETURN CPOPJ ;NO FEK CORRISPONDS TO THAT LINE
|
||
; CPOPJ1 ;J := ADDRESS OF FEK.
|
||
|
||
LN2FEK: MOVEI J,FEKFST ;GET THE ADDRESS OF FEK FOR LINE #1
|
||
SOJN T1,[HRRZ J,FEKBLK(J) ;DECREMENT THE LINE NUMBER, GO TO NEXT FEK
|
||
JUMPE J,CPOPJ ;IF DONE ALL FEKS, GIVE FAIL RETURN
|
||
JRST .] ;KEEP LOOKING
|
||
RETSKP ;RETURN WITH J := ADDRESS OF FEK
|
||
REPEAT 0,< ;USELESS CODE (I THINK)
|
||
|
||
;STCREJ ROUTINE TO SEND A STATION CONTROL REJECT <13> MESSAGE
|
||
;CALL J := POINTER TO STC MESSAGE WITH
|
||
; 1ST BYTE := LINE #
|
||
; LH(STCNNL) := NODE NUMBER TO SEND REJECT TO
|
||
;RETURN CPOPJ WITH STC FREED
|
||
|
||
STCREJ: PUSH P,W ;SAVE W (WE PUT DESTINATION NDB IN IT)
|
||
PUSH P,J ;SAVE THE STC POINTER
|
||
HLRZ T1,STCNNL(J) ;GET THE NODE NUMBER
|
||
PUSHJ P,SRCNDB ; AND LOOK UP THE NDB
|
||
JRST STCRE1 ;IF NODE NOT THERE, JUST FREE THE STC MSG
|
||
PUSHJ P,NCMHDR ;WRITE THE MESSAGE HEADER
|
||
JRST STCRE1 ;IF NO CORE, JUST TOSS THE STC BLOCK
|
||
;TYP
|
||
XMTI NC.CTL ;THIS IS A STATION CONTROL MESSAGE
|
||
;LINE
|
||
LDB T1,[POINT 8,STCDAT(J),7] ;GET THE LINE NUMBER
|
||
XMT T1 ; AND SEND THAT
|
||
;CODE
|
||
XMTI STC.RJ ;SEND THE REJECT CODE
|
||
JSP T1,NETWRC ;SEND THE MESSAGE (AND CLOBBER "J")
|
||
STCRE1: POP P,J ;GET THE STC POINTER BACK
|
||
PUSHJ P,GIVSTC ;RETURN THE STC BLOCK
|
||
JRST WPOPJ## ;RESTORE "W" AND RETURN
|
||
|
||
>;END REPEAT 0
|
||
;STCSEC ROUTINE CALLED ONCE/SEC TO DO STATION CONTROL TIMING FUNCTIONS
|
||
;CALL W := NDB POINTER
|
||
;RETURN CPOPJ ;ALWAYS
|
||
;ACTION IF THE "NDBSTC" TIMER GOES OFF, THE JOB OWNING NDBSTC
|
||
; IS WOKEN, AND NDBSTC(W) IS CLEARED
|
||
; IF THE "NDBICT" TIMER GOES OFF, THE INCOMING MESSAGE IS FREED
|
||
|
||
STCSEC: SKIPN T1,NDBSTC(W) ;IS THE STATION CONTROL DEVICE IN USE?
|
||
JRST STCSE1 ; IF NOT IN USE, GO TIME OUT BOOT REQUESTS
|
||
HLRZ T1,T1 ;GET THE TIMER FOR STATION CONTROL USERS
|
||
SOSLE T1 ;DECREMENT IT, SKIP IF IT COUNT'S OUT
|
||
JRST [HRLM T1,NDBSTC(W) ;IF NOT COUNTED OUT YET, STORE IT -1
|
||
JRST STCSE1] ; BACK AND GO TIME INCOMING MESSAGES
|
||
HRRZ T1,NDBSTC(W) ;GET THE JOB NUMBER OF THE USER THAT TIMED OUT
|
||
SKIPE T1 ; IF NO ONE WAS USING IT, DON'T WAKE ANYONE
|
||
PUSHJ P,EWAKE## ;WAKE THE USER NOW THAT HE'S TIMED OUT
|
||
SETZM NDBSTC(W) ;CLEAR STC TO SAY THAT NO-ONE IS USING IT.
|
||
STCSE1: SKIPN T1,NDBICT(W) ;SEE IF ANY BOOT MSGS ARE WAITING
|
||
JRST STCSE2 ;IF NONE, DON'T LOOK ANY FARTHER
|
||
HLRZ T1,T1 ;GET THE COUNTER FOR INCOMING STC MSGS
|
||
SOSLE T1 ;COUNT OFF ONE MORE SECOND. IF NOT TIMED OUT,
|
||
JRST [HRLM T1,NDBICT(W) ;THEN JUST STORE THE UPDATED COUNT
|
||
JRST STCSE2] ;BACK AND EXIT
|
||
PUSH P,J ;IF MESSAGE BEEN HERE TO LONG, FREE IT. SAVE J
|
||
HRRZ J,NDBICT(W) ;GET A POINTER TO THE STC BLOCK
|
||
PUSHJ P,GIVSTC ;RETURN THE STC BLOCK
|
||
POP P,J ;RESTORE "J"
|
||
SETZM NDBICT(W) ;INDICATE THAT NO STC MESSAGES ARE WAITING
|
||
STCSE2: POPJ P, ;RETURN.
|
||
SUBTTL FEK -- ROUTINES TO MANIPULATE FEKS
|
||
|
||
;CLNFEK THIS ROUTINE CLEANS OUT A FEK. IT RETURNS ALL
|
||
; BUFFER SPACE ASSOCIATED WITH A FEK, AND GIVES THE
|
||
; OUTPUT MESSAGES TO THE OUTPUT DONE ROUTINE IN NETSCN.
|
||
; IN THIS WAY MESSAGES BEING ROUTED THROUGH THE NODE WILL
|
||
; GET RE-ROUTED, AND MESSAGES TO THE NODE WILL BE DISCARDED.
|
||
;CALL MOVE J,FEK ;GET THE ADDRESS OF THE FEK
|
||
; PUSHJ P,CLNFEK ;CLEAN IT OUT
|
||
;RETURN CPOPJ ;ALWAYS
|
||
;CLOBBERS S,U,T1,T2
|
||
|
||
NTFONC==:CLNFK2 ;FOR NOW.
|
||
|
||
CLNFEK: ;HERE TO RECYCLE A FEK
|
||
IFN PARANOID&P$FEK,< ;DON'T REFURBISH NULL FEK
|
||
HLLZ S,FEKBLK(J) ;GET THE FEK'S FLAGS
|
||
TLNE S,FK.NUL ;SEE IF THIS IS A NULL FEK
|
||
STOPCD .,STOP,ANFNUL, ;++ NULL FEK BEING CLEANED
|
||
>
|
||
SKIPE U,FEKIAD(J) ;GET THE INPUT PCB, IF THERE WAS ONE
|
||
S0PSHJ RMVPCB ; THEN FREE THE INPUT BUFFER
|
||
SETZM FEKIAD(J) ;CLEAR THE INPUT PCB POINTER
|
||
|
||
|
||
SKIPG T2,FEKOCT(J) ;ARE THERE ANY OUTPUT PCBS?
|
||
JRST CLNFK2 ;IF NOT, THEN DON'T FREE ANY.
|
||
HRRZ U,FEKOAD(J) ;GET THE FIRST OUTPUT PCB
|
||
|
||
SKIPA T1,U ;INITIALIZE WHAT WILL BECOME POINTER TO LAST
|
||
CLNFK1: HRRZ T1,PCBBLK(T1) ;ADVANCE THE POINTER TOWARDS THE LAST
|
||
SKIPN T1 ;MAKE SURE WE'VE GOT A PCB
|
||
STOPCD .,STOP,ANFNPL, ;++ NO PCB'S ON LIST
|
||
SOJG T2,CLNFK1 ;ADVANCE N-1 TIMES WHERE N = # OF PCB'S
|
||
; (EXIT WITH T1 POINTING TO LAST PCB)
|
||
HRRZ T3,PCBBLK(T1) ;GET THE POINTER TO THE NTH+1 PCB
|
||
SKIPE T3 ; IF IT ISN'T ZERO, THEN
|
||
STOPCD .,STOP,ANFPCC, ;++ COUNT OF PCB'S ON LIST IS WRONG
|
||
NETOFF ;PROTECTION WHEN DIDDLING QUEUES
|
||
EXCH U,NTQOUT ;PUT THIS LIST ON THE HEAD OF NTQOUT
|
||
HRRM U,PCBBLK(T1) ;AND SPLICE THE OLD ONE ON THE END
|
||
NETON ;ALL CLEAR (WASN'T THAT EASY!)
|
||
|
||
CLNFK2: MOVSI S,FK.ONL!FK.NID!FK.STO!FK.STI!FK.OAC!FK.IAC!FK.CPD
|
||
ANDCAB S,FEKBLK(J) ;IN THE FEK STATUS WORD.
|
||
SETZM FEKOAD(J) ;CLEAR POINTER TO THE PCB'S
|
||
SETZM FEKODN(J) ;CLEAR OUTPUT DONE POINTER
|
||
SETZM FEKOCT(J) ;SET FEK IDLE
|
||
SETZM FEKHTM(J) ;CLEAR THE HUNG TIMER
|
||
HLLZS FEKNNM(J) ;CLEAR THE NODE NUMBER
|
||
SETOM FEKBSO(J) ;CLEAR OUTPUT BUSY
|
||
SETOM FEKBSI(J) ;CLEAR INPUT BUSY
|
||
POPJ P, ;AND WE ARE DONE
|
||
SUBTTL ROUTINE TO GENERATE THE NCL PROTOCOL HEADERS
|
||
;SUBROUTINE NCSHDR - CREATE<NCT><DNA><SNA><NCA><NCN>
|
||
;CALL MOVEI W,NDB
|
||
; MOVEI T1,NCT MESSAGE TYPE
|
||
; PUSHJ P,NCSHDR
|
||
;RETURN CPOPJ ;NO CORE
|
||
; CPOPJ1 ;P3=COUNT, P2=CURRENT BYTE POINTER
|
||
|
||
NCSHDR: ;ENTRY
|
||
NTDBUG ;VERIFY THE INTERLOCK
|
||
PUSHJ P,SAVE1## ;DON'T CLOBBER P1.
|
||
MOVE P1,T1 ;COPY THE FLAGS
|
||
MOVEI T1,^D16 ;MAKE A PCB WITH 16 WDS OF BUFFER
|
||
TRNE P1,7 ;IS THIS A NUMBERED MESSAGE?
|
||
JRST [PUSHJ P,MKUPCB ; IF NOT, THEN GET AN 'UN-NUMBERED' PCB
|
||
POPJ P, ; (EXIT NCSHDR IF NOT AVAILABLE)
|
||
JRST NCSHD1] ;RETURN TO MAIN FLOW WITH U := PCB
|
||
PUSHJ P,MKNPCB ;IF IT'S A DATA MESSAGE, GET A NUMBERED PCB
|
||
POPJ P, ; BUT GIVE ERROR RETURN IF NOT AVAILABLE.
|
||
NCSHD1: MOVE P2,PCBPTR(U) ;GET BYTE POINTER
|
||
AOS (P) ;WE WILL SUCCEED, SO GIVE GOOD RETURN
|
||
MOVE T1,P1 ;GET THE NCT FLAGS BACK FOR NCSWHD
|
||
; PJRST NCSWHD ;FILL IN THE HEADER
|
||
;NCSWHD ROUTINE TO WRITE THE HEADER OF AN NCS MESSAGE.
|
||
;CALL MOVE T1,NCT FLAGS
|
||
; MOVE U,POINTER TO VIRGIN PCB
|
||
; PUSHJ P,NCSWHD
|
||
;RETURN CPOPJ ;ALWAYS
|
||
; ; PCB HAS NCT, DNA, SNA, NCA, NCN FILLED IN,
|
||
; ; PCBCTR IS UPDATED AND P3 IS ZERO,
|
||
; ; P2 HAS THE POINTER TO THE "DLA" BYTE.
|
||
NCSWHD::
|
||
SETZ P3, ;CLEAR THE COUNT FIELD
|
||
TRO T1,NCT.RH!NCT.SQ ;INSERT THE ADDITIONAL FLAGS
|
||
PUSH P,T1 ;SAVE THE FLAGS FOR LATER
|
||
;NCT
|
||
PUSHJ P,BI2EBI ;OUTPUT THE FLAGS
|
||
;DNA
|
||
HLRZ T1,NDBNNM(W) ;GET THE DESTINATION NODE ADDRESS
|
||
HRRM T1,PCBNNM(U) ;STORE IN PCB FOR NETWRT TO USE WHEN SENDING
|
||
PUSHJ P,BI2EBI ;OUTPUT
|
||
;SNA
|
||
MOVEI T1,NETNDB## ;ADDRESS OF THE NODE DATA BLOCK
|
||
HLRZ T1,NDBNNM(T1) ;GET THE SOURCE NODE ADDRESS (US)
|
||
PUSHJ P,BI2EBI ;OUTPUT
|
||
;NCA
|
||
;REAL MESSAGE NUMBER IS ASSIGNED BY NETWRT
|
||
MOVEI T1,0 ;DUMMY MESSAGE NUMBER NOW
|
||
PUSHJ P,DPBBIN ;STORE
|
||
;NCN
|
||
MOVEI T1,0 ;AGAIN
|
||
PUSHJ P,DPBBIN
|
||
;EXIT
|
||
MOVSI T1,PCB.NM ;GET NUMBERED MESSAGE FLAG
|
||
POP P,T2 ;GET THE NCT FLAGS BACK
|
||
TRNN T2,NCT.TP ;NUMBERED MESSGE??
|
||
IORM T1,PCBBLK(U) ;YES, SET THE FLAG
|
||
ADDM P3,PCBCTR(U) ;UPDATE THE CURRENT COUNT
|
||
SETZ P3, ;CLEAR THE COUNT FIELD
|
||
POPJ P,
|
||
SUBTTL UNNUMBERED NCS CONTOL MESSAGES
|
||
;SUBROUTINE NCSSTR/NCSSAK - SEND A START/STACK MESSAGE
|
||
;CALL MOVEI W,NDB ;WHERE TO SEND THE MESSAGE
|
||
; PUSHJ P,NCSSSM ;SEND A START OR A STACK MESSAGE
|
||
;RETURN CPOPJ ;CAN'T NO CORE
|
||
; CPOPJ1 ;OK
|
||
|
||
NCSSSM: MOVE T1,NDBFLG(W) ;GET THE FLAGS, AND
|
||
TLNE T1,NDB.SK ; IF WE ARE SUPPOSED TO SEND A STACK
|
||
JRST NCSSS1 ; THEN SKIP THE SEND-START CODE
|
||
PUSHJ P,CLNNDB ;CLEAN OUT THE NDB FOR STARTERS
|
||
MOVEI T1,NCT.ST ;START FLAGS
|
||
SKIPA
|
||
NCSSS1: MOVEI T1,NCT.SK ;START ACK FLAGS
|
||
PUSHJ P,SAVE3## ;SAVE THE P'S
|
||
|
||
IFN PARANOID&P$NDB,<PUSHJ P,NDBCHK> ;MAKE SURE WE DON'T SEND OURSELF A START
|
||
|
||
PUSH P,T1 ;SAVE THE FLAGS
|
||
SETZ F, ;NCS MESSAGE
|
||
PUSHJ P,NCSHDR ;MAKE A HEADER (U = NEW PCB)
|
||
PJRST TPOPJ## ;EXIT NO CORE
|
||
PUSHJ P,NCSOPD ;GET THE <NNM><SNM><SID>
|
||
HRRZ T1,NETNDB##+NDBNVR ;GET OUR NCL VERSTION
|
||
PUSHJ P,BI2EBI ;SEND IT IN MESSAGE
|
||
ADDM P3,PCBCTR(U) ;UPDATE THE COUNT
|
||
POP P,T2 ;RESTORE THE FLAGS
|
||
PUSHJ P,NETWRT ;SEND THE STACK MESSAGE
|
||
JRST CPOPJ1 ;ALL DONE
|
||
;SUBROUTINE NCSNID - SEND A NODE ID MESSAGE
|
||
;CALL MOVEI J,FEK
|
||
; PUSHJ P,NCSNID
|
||
;RETURN CPOPJ ;NO CORE ETC
|
||
; CPOPJ1 ;SENT
|
||
|
||
NCSNID: PUSHJ P,SAVE3## ;SAVE THE P'S
|
||
|
||
IFN PARANOID&P$FEK,< ;MAKE SURE WE DON'T SEND THE NULL FEK A NODEID
|
||
|
||
HLLZ T1,FEKBLK(J) ;GET THE FEK'S FLAGS
|
||
TLNE T1,FK.NUL ;SEE IF IT'S A NULL FEK
|
||
STOPCD .,STOP,ANFNFI, ;++ SENDING NODE ID TO THE NULL FEK
|
||
>
|
||
SETZB W,F ;NO DDB OR NDB
|
||
MOVEI T1,^D16 ;MESSAGE SIZE
|
||
PUSHJ P,MKUPCB ;ALLOCATE THE MESSAGE SPACE
|
||
POPJ P, ;NO SPACE AVAILABLE
|
||
MOVE P2,PCBPTR(U) ;GET THE BYTE POINTER
|
||
SETZ P3, ;CURRENT COUNT IS ZERO
|
||
;NCT
|
||
MOVEI T1,NCT.ID!NCT.SQ ;GET ID FLAGS
|
||
PUSHJ P,BI2EBI ;WRITE THE FLAGS
|
||
;NCA
|
||
MOVEI T1,0 ;NO, ACKS FOR MESSAGE NUMBERS
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;NCN
|
||
MOVEI T1,0 ;SAME AS ABOVE
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;OPD
|
||
PUSHJ P,NCSOPD ;SEND THE <NNM><SNM><SID>
|
||
|
||
IFN FTENET,<
|
||
MOVE T1,FEKBLK(J) ;GET FEK FLAGS
|
||
TLNN T1,FK.ETM ;ETHERNET (MASTER) FEK?
|
||
JRST NCSNI4 ;NO, SEND A P-P NODEID
|
||
MOVEI T1,NIT.BC ;YES, MARK THIS AS A "BROADCAST" NODEID
|
||
PUSHJ P,BI2EBI ;AND NCL'IZE IT
|
||
AOS T1,FEKNIS(J) ;INCREMENT NODEID SERIAL NUMBER
|
||
PUSHJ P,BI2EBI ;NCL'IZE THE SERIAL NUMBER
|
||
HLRZ T2,FEKNIT(J) ;GET NEW BROADCAST TIMER INTERVAL
|
||
HRRM T2,FEKNIT(J) ;AND SET IT FOR ONCE/SECOND CHECKING
|
||
JRST NCSNI5 ;FINISH OFF NODE-ID
|
||
> ;END IFN FTENET
|
||
|
||
NCSNI4: XMTI NIT.PP ;THIS IS A POINT-TO-POINT NODE-ID
|
||
|
||
NCSNI5: HRRZ T1,NETNDB##+NDBNVR ;GET OUR NCL VERSION NUMBER
|
||
PUSHJ P,BI2EBI ;NCL-IZE IT
|
||
MOVSI T1,FK.NID ;GET NODE ID FLAG
|
||
IORM T1,FEKBLK(J) ;SET FLAG NODE ID SENT
|
||
ADDM P3,PCBCTR(U) ;UPDATE THE COUNT
|
||
AOS NCLXTP+NCT.ID ;COUNT THE MESSAGE TYPE
|
||
AOS (P) ;SKIP RETURN
|
||
IFN FTKL10,<PUSHJ P,PCBMRK> ;SET UP CACHE INFO FOR CALL TO FRCWRT
|
||
NETOFF ;NO RACE, "NETWRT" WILL RESTORE PI'S
|
||
PJRST FRCWRT ;FORCE WRITE THE MESSSAGE
|
||
;SUBROUTINE NCSOPD - GENERATE THE OPTIONAL DATA <NNM><SNM><SID>
|
||
;CALL MOVEI U,PCB
|
||
; PUSHJ P,NCSOPD
|
||
;RETURN CPOPJ
|
||
|
||
NCSOPD: ;ENTRY
|
||
PUSH P,W ;SAVE THE NDB POINTER
|
||
MOVEI W,NETNDB## ;GET THE NODE DATA BLOCK
|
||
;NNM
|
||
HLRZ T1,NDBNNM(W) ;GET THE NODE NUMBER
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;SNM
|
||
HLRZ T1,NDBSNM(W) ;GET THE POINTER TO THE SYSTEM NAME
|
||
MOVE T1,(T1) ;GET THE NAME
|
||
PUSHJ P,SX2EAS ;WRITE
|
||
;SID
|
||
HRRZ P1,NDBSID(W) ;SOFTWARE NAME
|
||
PUSHJ P,AS2EAZ ;WRITE
|
||
HLRZ P1,NDBSID(W) ;CREATION DATE
|
||
POP P,W ;RESTORE THE NDB
|
||
PJRST AS2EAZ ;WRITE
|
||
;NCSNAK THIS ROUTINE FIRST SCRAPS ALL UNPROCESSED MESSAGES ON
|
||
; LH(NDBQUE(W)). IT THEN SENDS A NAK.
|
||
; NOTE NAK'S ARE ONLY SENT AS A RESPONSE TO A REP.
|
||
; NOTE REPS ALWAYS ELICIT A NAK RESPONSE
|
||
NCSNAK: NETOFF ;PROTECT FROM FEK'S
|
||
HLRZ U,NDBQUE(W) ;GET THE LIST OF PCB'S
|
||
HRRZS NDBQUE(W) ;SPLICE OUT THE LIST
|
||
NETON ;ALL CLEAR NOW
|
||
PUSHJ P,RMVALP ;FREE THE LIST
|
||
MOVEI T1,NCT.NK ;GET THE NAK NCT
|
||
PJRST NCSANR ;GO TO COMMON CODE
|
||
|
||
;NCSREP THIS ROUTINE SENDS A REP MESSAGE (NO OTHER PROCESSING)
|
||
;CALL W := NDB
|
||
;RETURN CPOPJ FAILED
|
||
; CPOPJ1 SENT IT OK
|
||
NCSREP: MOVEI T1,NCT.RP ;GET REP NCT
|
||
PJRST NCSANR ;GO TO COMMON CODE
|
||
|
||
|
||
;SUBROUTINE NCSACK - NCSNAK SEND AN ACK MESSAGE
|
||
;CALL MOVEI W,NDB
|
||
;PUSHJ P,NCSACK/NCSNAK
|
||
;RETURN CPOPJ ;ERROR
|
||
; CPOPJ1 ;OK
|
||
|
||
NCSACK: MOVEI T1,NCT.AK ;GET THE ACK TYPE
|
||
; PJRST NCSANR ;COMMON CODE TO FINISH ACK/NAK/REP
|
||
|
||
NCSANR: ;COMMON CODE FOR ACK-NAK-REP
|
||
;CALL WITH T1 := NCT
|
||
|
||
IFN PARANOID&P$NDB,<PUSHJ P,NDBCHK> ;MAKE SURE WE AREN'T SENDING IT TO US
|
||
|
||
PUSHJ P,SAVE3## ;SAVE THE P'S
|
||
PUSH P,F ;SAVE F
|
||
SETZ F, ;CLEAR F NCS MESSAGE
|
||
PUSHJ P,NCSHDR ;WRITE THE HEADER
|
||
JRST FPOPJ ;RESTORE F AND GIVE ERROR EXIT
|
||
POP P,F ;RESTORE F
|
||
PJRST NETWSR ;SEND THE MESSAGE
|
||
SUBTTL NCS NUMBERED CONTROL MESSAGE HEADER
|
||
;NCMHDR ROUTINE TO BUILD THE HEADER FOR NUMBERED CONTROL MESSAGES.
|
||
;CALL MOVEI W,NDB
|
||
; PUSHJ P,NCMHDR
|
||
;RETURN CPOPJ ;NO CORE
|
||
; CPOPJ1 ;U := PCB, -1(P) := BYTE POINTER TO "CNT"
|
||
;
|
||
;NOTE!!!
|
||
; THIS ROUTINE DOES THE GROSS AND UGLY THING OF MEDDLING WITH THE
|
||
; STACK ON A SUCCESSFUL RETURN. SINCE EVERY PLACE THIS ROUTINE WAS
|
||
; CALLED IMMEDIATLY DID A "PUSH P,P2" THIS IS FAKED BEFORE NCMHDR
|
||
; GIVES A SUCCESSFUL RETURN. (THIS LEAVES THE STACK IN THE CORRECT
|
||
; STATE FOR A "JSP T1,NETWRC" TO SEND THE MESSAGE.)
|
||
;
|
||
NCMHDR:: ;HERE TO BUILD A NUMBERED MESSAGE HEADER
|
||
MOVEI T1,0 ;CONTROL MESSAGE
|
||
PUSHJ P,NCSHDR ;OUTPUT THE HEADER
|
||
POPJ P, ;NO CORE, GIVE ERROR RETURN
|
||
MOVEI T1,0 ;NUMBERED CONTROL MESSGE
|
||
PUSHJ P,BI2EBI ;DEPOSIT
|
||
MOVEI P3,2 ;ACCOUNT FOR THE FIRST
|
||
ADDM P3,PCBCTR(U) ; TWO BYTES
|
||
SETZ P3, ;CLEAR THE COUNT FIELD
|
||
IBP P2 ;STEP OVER THE <CNT> FIELD
|
||
POP P,T1 ;GET THE RETURN ADDRESS
|
||
PUSH P,P2 ;SAVE A POINTER TO THE "CNT" FIELD FOR NETWRC
|
||
JRST 1(T1) ;GIVE SKIP (CPOPJ1) RETURN
|
||
;NCSCNT ROUTINE TO SEND A CONNECT CONFIRM MESSAGE.
|
||
;CALL MOVE T1,[XWD "ROUTINE TO WRITE SPN","ROUTINE TO WRITE DPN"]
|
||
; MOVEI F,DDB
|
||
; PUSHJ P,NCSCNC
|
||
;RETURN CPOPJ ;SOMETHING WAS WRONG. ERROR CODE IN T1.
|
||
; CPOPJ1 ;CONNECT CONFIRM WAS SENT - DEVICE IS CONNECTED
|
||
|
||
NCSCNC::PUSHJ P,NCSCNT ;SEND A "CONNECT" MESSAGE
|
||
POPJ P, ;HO HUM
|
||
MOVSI S,IOSCON ;THE "DEVICE IS CONNECTED" FLAG
|
||
IORB S,DEVIOS(F) ;TELL THE WORLD THE DEVICE IS GOOD NOW
|
||
JRST CPOPJ1## ;SUCCESSFUL RETURN WITH HAPPY DEVICE
|
||
|
||
|
||
|
||
;NCSCNT ROUTINE TO SEND A CONNECT INITIATE MESSAGE.
|
||
;CALL MOVE T1,[XWD "ROUTINE TO WRITE SPN","ROUTINE TO WRITE DPN"]
|
||
; MOVEI F,DDB
|
||
; PUSHJ P,NCSCNT
|
||
;RETURN CPOPJ ;SOMETHING WAS WRONG. ERROR CODE IN T1.
|
||
; CPOPJ1 ;CONNECT WAS SENT. (BUT NOT CONFIRMED)
|
||
|
||
NCSCNT:: ;HERE TO SEND A CONNECT MESSAGE
|
||
NTDBUG ;JUST CHECKING...
|
||
PUSHJ P,SAVE3## ;SAVE THE P'S
|
||
PUSHJ P,SAVJW## ;WE WILL CLOBBER J(FEK) AND W(NDB)
|
||
PUSH P,U ;SAVE ANY MESSAGE WE MAY BE READING
|
||
|
||
MOVE P1,T1 ;SAVE ADDRESS TO WRITE "DPN" & "SPN"
|
||
HRRZ T1,DEVNET(F) ;GET THE NUMBER OF THE NODE THAT OWNS THIS
|
||
PUSHJ P,SRCNDB ;SET UP W TO POINT TO ITS NDB.
|
||
JRST [MOVEI T1,NRTUNN-NODERT ;GIVE A NODE-WENT-AWAY ERROR
|
||
JRST UPOPJ##] ;AND AN ERROR ROUTINE SO CALLER WILL NOTICE.
|
||
MOVEI T1,MSGMAW## ;BECAUSE CONNECT MSGS MAY BE VERY LONG
|
||
PUSHJ P,MKNPCB ; WE MUST GET A LARGE PCB
|
||
JRST [MOVEI T1,NRTNCE-NODERT ;BUT IF WE ARE OUT OF CORE, THEN
|
||
JRST UPOPJ##] ;GIVE A NODE-CAPACITY-EXCEEDED ERROR
|
||
|
||
MOVE P2,PCBPTR(U) ;GET THE ADDRESS OF THE MESSAGE BUFFER
|
||
SETZ T1, ;THIS IS A NUMBERED MSG (TYPE 0)
|
||
PUSHJ P,NCSWHD ;WRITE THE 5 HEADER BYTES
|
||
XMTI 0 ;NO DLA SIGNIFIES NUMBERED CONTROL
|
||
PUSH P,P2 ;REMEMBER WHERE THE "CNT" FIELD IS
|
||
XMT1 T1 ;WRITE TWO GARBAGE
|
||
XMT1 T1 ; BYTES. (WILL HOLD AN EXTENSIBLE COUNT)
|
||
ADDM P3,PCBCTR(U) ;UPDATE THE LENGTH OF THE MESSAGE SO FAR
|
||
SETZ P3, ;RESET P3 SO WE CAN MEASURE THE CONNECT MSG.
|
||
|
||
;FALL THROUGH TO WRITE THE BODY OF THE CONNECT MESSAGE
|
||
;TYP
|
||
MOVEI T1,NC.CNT ;THIS IS A CONNECT MESSAGE
|
||
PUSHJ P,BI2EBI ;WRITE THE TYPE
|
||
;DLA
|
||
LDB T1,NETDLA ;GET THE DLA FROM THE DDB
|
||
PUSHJ P,BI2EBI
|
||
;SLA
|
||
LDB T1,NETSLA ;GET THE SLA FROM THE DDB
|
||
|
||
IFN PARANOID&P$LAT,<
|
||
SKIPN T1 ;JUST A BIT OF PARANOIA AGAIN
|
||
STOPCD .,STOP,ANFSLA, ;++ NO SLA ON A CONNECT
|
||
>
|
||
PUSHJ P,BI2EBI
|
||
;DPN(OBJ,PID)
|
||
HRRZ T1,P1 ;GET SUBR
|
||
PUSHJ P,(T1) ;LET CALLER WRITE THE DEST PROCESS DESCRIPTOR
|
||
;SPN(OBJ,PID)
|
||
MOVS T1,P1 ;SWAP THE HALVES
|
||
HRRZS T1 ;WATCH THAT XADDR STUFF!
|
||
PUSHJ P,(T1) ;LET THE CALLER WRITE THE SOURCE PROCESS DESC.
|
||
;MML
|
||
LDB T1,NETMML ;GET SERVICE-ROUTINE-SPECIFIED MAX MESSAGE SIZE
|
||
CAIG T1,0 ;GO WITH IT IF ANYTHING SPECIFIED
|
||
MOVEI T1,MSGMAD## ;GET OUR LARGEST PERMISSABLE MESSAGE
|
||
; (*** SEE FOOTNOTE)
|
||
PUSHJ P,BI2EBI ;OUTPUT
|
||
;FEA(DCM)
|
||
PUSH P,W ;SAVE THE NDB POINTER FOR A BIT
|
||
HLRZ W,DEVNET(F)
|
||
LDB T1,NDTDCM ;GET THE DEVICE MODES POSSIBLE
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;FEA(,RLN)
|
||
MOVEI T1,0 ;RECORD LENGTH IS VARIABLE
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;FEA(,,DVT)
|
||
LDB T1,NDTDVT ;GET THE DEVICE ATTRIBUTES
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;FEA(,,,DVU)
|
||
LDB T1,NETDVU ;GET DEVICE "UNIT" TYPE
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;FEA(,,,,DVV)
|
||
LDB T1,NETDVV ;GET DEVICE "CONTROLLER" TYPE
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;FEA(,,,,,DFT)
|
||
HRRZ T1,NDBNVR(W) ;GET REMOTE'S NCL VERSION NUMBER
|
||
JUMPE T1,NCSCN1 ;SKIP DFT FIELD IF OLD NODE
|
||
MOVE T1,DEVDFT(F) ;GET FORMS TYPE WORD
|
||
PUSHJ P,SX2EAS ;WRITE IT OUT
|
||
|
||
;FALL THROUGH TO FIXUP THE LENGTH AND SEND THE MESSAGE
|
||
NCSCN1:
|
||
;CNT (GO BACK AND FILL IT IN)
|
||
POP P,W ;RESTORE THE NDB POINTER
|
||
CAILE P3,^D256 ;IS THE MSG LONGER THAN THIS ARBITRARY VALUE
|
||
STOPCD .,STOP,ANFCIL, ;++ CONNECT INITIATE MESSAGE TOO LONG,
|
||
; SOMEONE (TSKSER) SCREWED UP
|
||
ADDM P3,PCBCTR(U) ;UPDATE THE TOTAL MESSAGE LENGTH
|
||
POP P,T2 ;GET THE POINTER TO THE TWO BYTE "CNT" BACK
|
||
LDB T1,[POINT 7,P3,35] ;GET THE LOW 7 BITS
|
||
TRO T1,200 ; AND MAKE THEM EXTENSIBLE
|
||
IDPB T1,T2 ;STORE THE FIRST BYTE OF THE COUNT
|
||
LDB T1,[POINT 7,P3,28] ;GET THE REST OF THE LENGTH
|
||
IDPB T1,T2 ; AND STORE THAT
|
||
PUSHJ P,NETWRT ;SEND THE MESSAGE
|
||
PJRST UPOPJ1## ;GIVE GOOD RETURN
|
||
|
||
|
||
;*** FOOTNOTE ***
|
||
|
||
COMMENT \
|
||
|
||
Historically, this value was calculated by taking the minimum of
|
||
all message length's for all nodes in the path between the node we were
|
||
sending the connect to and ourself. This seems wrong to me. Given a
|
||
multi-path environment, we may find ourselves using an un-expected path.
|
||
The result of this is that the sender must calculate the maximum message
|
||
length based on the current minimum of all nodes in the network. In light
|
||
of this, my opinion is that the MML field should represent our "local"
|
||
maximum. It doesn't really matter though since no one uses the field anyway...
|
||
|
||
Matson
|
||
|
||
|
||
And I take offense at the above footnote - I tried to believe the
|
||
silly value in the DDP code in the -87, and look where it got me - into
|
||
trap service 'cuz the -10 sent some silly number that had no relation
|
||
with reality. Boo Hiss! Such are the trials and tribulations of life in
|
||
the small country pits . . .
|
||
|
||
-RDH
|
||
\
|
||
;NCSDSC ROUTINE TO SEND A DISCONNECT MESSAGE.
|
||
;CALL MOVEI F,DDB
|
||
; MOVEI T1,"REASON"
|
||
; PUSHJ P,NCSDSC
|
||
;RETURN CPOPJ ;NO CORE, OR NODE WENT AWAY.
|
||
; CPOPJ1 ;DISCONNECT SENT (BUT NOT CONFIRMED!)
|
||
;
|
||
NCSDSC:: ;HERE TO SEND A DISCONNECT MESSAGE
|
||
NTDBUG ;JUST CHECKING
|
||
PUSHJ P,SAVE3## ;SAVE THE P'S
|
||
PUSHJ P,SAVJW## ;WE CLOBBER J(FEK) AND W(NDB)
|
||
PUSH P,U ;SAVE ANY INPUT MESSAGE WE MAY BE PROCESSING
|
||
|
||
MOVEI P1,(T1) ;SAVE THE REASON IN A SAFE REGISTER
|
||
|
||
IFN PARANOID&P$LAT,<
|
||
LDB T1,NETSLA ;JUST A QUICK CHECK TO MAKE SURE THAT THE LAT
|
||
HRRZ T1,NETLAT##(T1) ; AND THE DDB AGREE WITH RESPECT TO THE SLA
|
||
;IT'S OK TO ONLY LOOK AT 18 BITS . . .
|
||
CAIE T1,(F) ;DOES THE SLA POINT BACK TO THE DDB?
|
||
STOPCD .,STOP,ANFLDD, ;++ LAT AND DDB DISAGREE
|
||
>
|
||
|
||
HRRZ T1,DEVNET(F) ;GET THE NODE NUMBER
|
||
PUSHJ P,SRCNDB ;SET UP "W" WITH THE NDB POINTER
|
||
STOPCD .,STOP,ANFNWA, ;++ NODE WENT AWAY, DRIVER SHOULD HAVE NOTICED
|
||
PUSHJ P,NCMHDR ;MAKE A CONTROL MESSAGE HEADER.
|
||
JRST UPOPJ ; IF NO CORE, GIVE AN ERROR RETURN
|
||
;TYP
|
||
MOVEI T1,NC.DSC ;WE ARE A DISCONNECT MESSAGE
|
||
PUSHJ P,BI2EBI ;SEND THE DISCONNECT TYPE
|
||
;DLA
|
||
LDB T1,NETDLA ;GET THE REMOTE'S ADDRESS FOR THIS CONNECTION
|
||
IFN PARANOID&P$LAT,<
|
||
SKIPN T1 ;JUST A LITTLE PARANOIA
|
||
STOPCD .,STOP,ANFDLA, ;++ NO DLA ON CONNECT
|
||
>
|
||
PUSHJ P,BI2EBI ;SEND THE DLA
|
||
;SLA
|
||
LDB T1,NETSLA ;GET OUR ADDRESS FOR THIS CONNECTION
|
||
PUSHJ P,BI2EBI ;SEND THE SLA
|
||
;RSN
|
||
MOVEI T1,(P1) ;GET THE CALLER SPECIFIED REASON
|
||
PUSHJ P,BI2EBI ;SEND THE REASON
|
||
;CNT
|
||
JSP T1,NETWRC ;SEND THE MESSAGE
|
||
PJRST UPOPJ1## ;GIVE A GOOD RETURN
|
||
|
||
;*** FOOTNOTE ***
|
||
|
||
COMMENT \
|
||
|
||
Since this routine must be called under the protection of the
|
||
NETSER interlock, there is no reason that the device driver cannot
|
||
check to make sure that the node he is attempting to send a disconnect
|
||
to is still up. The reason for replacing the "UPOPJ" with a STOPCD
|
||
is to enforce such practices in device drivers
|
||
|
||
\
|
||
|
||
;SUBROUTINE NCSNBN - SEND NEIGHBOR NAME MESSAGE
|
||
;CALL PUSHJ P,NCSNBN
|
||
;RETURN CPOPJ
|
||
; CPOPJ1
|
||
|
||
NCSNBN: ;ENTRY
|
||
PUSHJ P,SAVE3## ;SAVE THE P'S
|
||
PUSHJ P,SAVJW## ;SAVE J AND W
|
||
SETZ F, ;CONTROL MESSAGE
|
||
PUSHJ P,NCMHDR ;WRITE NUMBERED HEADER (PUSH BYTE PTR ON STK)
|
||
POPJ P, ;NO CORE
|
||
MOVEI T1,NC.NBN ;GET HEIGHBOR NAMES
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
PUSH P,W ;SAVE THE NDB POINTER
|
||
MOVEI W,NETNDB## ;GET OUR NDB
|
||
MOVE T4,[POINT 9,NDBTOP(W)] ;SEARCH THE TOPOLOGY TABLE
|
||
MOVEI T3,NGHMAX ;GET THE SIZE OF THE NEIGHBORS TABLE
|
||
NCSNB1: ILDB T1,T4 ;GET THE NODE NUMBER
|
||
JUMPE T1,[IBP T4 ;IF NO NODE IN THIS SLOT. SKIP USLESS COST
|
||
JRST NCSNB2] ;AND GO DO NEXT SLOT
|
||
;NNM
|
||
XMT T1 ;SEND THE NODE NUMBER
|
||
;LVL
|
||
ILDB T1,T4 ;GET THE COST
|
||
XMT T1 ;SEND THE COST
|
||
NCSNB2: SOJG T3,NCSNB1 ;LOOP OVER ALL NEIGHBORS
|
||
POP P,W ;RESTORE THE TARGET NODE
|
||
MOVSI T1,NDB.NB ;GET NEIGHBORS SENT
|
||
IORM T1,NDBFLG(W) ;SET IT
|
||
JSP T1,NETWRC ;SEND THE MESSAGE
|
||
JRST CPOPJ1 ;GIVE GOOD (SKIP) RETURN
|
||
|
||
;SUBROUTINE SETNBN - SET THE BITS TO SEND NEIGHBORS MESSAGES TO ALL
|
||
;CALL PUSHJ P,SETNBN
|
||
;RETURN CPOPJ
|
||
|
||
SETNBN: ;ENTRY ON CHANGE OF NEIGHBORS
|
||
PUSHJ P,SAVJW## ;SAVE J AND W
|
||
MOVSI T1,NDB.NB ;GET NEIGHBORS BIT
|
||
MOVEI W,NETNDB ;START OF NDB'S
|
||
SETNB1: HRRZ W,NDBNNM(W) ;GET THE FIRST NDB LESS OURS
|
||
JUMPE W,CPOPJ## ;END OF LIST
|
||
ANDCAM T1,NDBFLG(W) ;CLEAR THE BIT
|
||
JRST SETNB1 ;CONTINUE
|
||
;SUBROUTINE NCSRCF - REQUEST CONFIGURATION MESSAGE
|
||
;CALL MOVEI W,NDB
|
||
; PUSHJ P,NCSRCF
|
||
;RETURN CPOPJ ;NO CORE
|
||
; CPOPJ1 ;RETURN
|
||
|
||
NCSRCF: ;ENTRY
|
||
PUSHJ P,SAVE3## ;SAVE THE P'S
|
||
|
||
IFN PARANOID&P$NDB,<PUSHJ P,NDBCHK> ;MAKE SURE WE AREN'T SENDING IT TO US
|
||
|
||
PUSHJ P,SAVJW## ;SAVE J AND W
|
||
SETZ F, ;CONTROL MESSAGE
|
||
PUSHJ P,NCMHDR ;WRITE A HEADER (AND PUSH "CNT" POSITION ON STK)
|
||
POPJ P, ;CAN'T
|
||
MOVEI T1,NC.RCF ;TYPE REQUEST CONFIGURATION
|
||
PUSHJ P,BI2EBI ;SEND
|
||
JSP T1,NETWRC ;SEND THE MESSAGE
|
||
PJRST CPOPJ1## ;SKIP RETURN
|
||
;SUBROUTINE NCSCNF - SEND A CONFIGURATION MESSAGE UPON REQUEST
|
||
;CALL MOVEI W,NDB
|
||
; PUSHJ P,NCSCNF
|
||
;RETURN CPOPJ
|
||
; CPOPJ1
|
||
|
||
NCSCNF: ;ENTERY
|
||
PUSHJ P,SAVE3## ;SAVE THE P'S
|
||
|
||
IFN PARANOID&P$NDB,<PUSHJ P,NDBCHK> ;MAKE SURE WE AREN'T SENDING IT TO THIS NODE
|
||
|
||
PUSHJ P,SAVJW## ;SAVE J W
|
||
SETZ F, ;CLEAR THE DDB
|
||
PUSHJ P,NCMHDR ;GET A HEADER (AND PUSH "CNT" POSITION)
|
||
POPJ P, ;NO CORE AVAILABLE
|
||
MOVEI W,NETNDB## ;GET OUR NODE DATA BLOCK
|
||
MOVEI T1,NC.CNF ;CONFIGURATION MESSAGE
|
||
PUSHJ P,BI2EBI ;SEND
|
||
;OBJ
|
||
MOVSI P1,-<OBJ.MX+1> ;NUMBER OF DEVICE TYPES
|
||
NCSCF1: LDB T1,NETCNF##(P1) ;GET THE COUNT
|
||
JUMPE T1,NCSCF2 ;DON'T HAVE ANY
|
||
MOVEI T1,(P1) ;GET THE TYPE BACK
|
||
PUSHJ P,BI2EBI ;SEND THE DEVICE TYPE
|
||
;NDV
|
||
LDB T1,NETCNF##(P1) ;DEVICE COUNT
|
||
PUSHJ P,BI2EBI ;SEND
|
||
;PID
|
||
MOVEI T1,0 ;ZERO PID
|
||
PUSHJ P,BI2EBI ;SEND
|
||
NCSCF2: AOBJN P1,NCSCF1 ;CONTINUE THROUGH THE LIST
|
||
JSP T1,NETWRC ;SEND THE MESSAGE
|
||
JRST CPOPJ1## ;GIVE SKIP RETURN
|
||
;SUBROUTINE NCSDRQ - SEND A DATA REQUEST
|
||
;CALL MOVEI T1,DATA REQUEST COUNT
|
||
; MOVEI F,DDB
|
||
; PUSHJ P,NCSDRQ
|
||
;RETURN CPOPJ ;NO CORE
|
||
; CPOPJ1 ;REQUEST SENT
|
||
|
||
NCSDRQ:: ;ENTRY
|
||
NTDBUG ;VERIFY THE INTERLOCK
|
||
MOVE S,DEVIOS(F) ;GET THE DEVICE STATUS
|
||
TLNN S,IOSCON ;ARE WE STILL CONNECTED?
|
||
JRST CPOPJ1## ;NO, GOOD RETURN, OUTPUT BETTER TRAP ERROR
|
||
PUSHJ P,SAVE3## ;SAVE THE P'S
|
||
PUSHJ P,SAVJW## ;SAVE J AND W
|
||
PUSH P,U ;SAVE U (SELF CONTAINED ROUTINE)
|
||
MOVEI P1,(T1) ;SAVE THE DRQ COUNT
|
||
HRRZ T1,DEVNET(F) ;GET THE NODE NUMBER
|
||
PUSHJ P,SRCNDB ;SET UP W FROM THE NODE NUMBER
|
||
SKIPA ;NODE WENT AWAY. GIVE ERROR RETURN
|
||
PUSHJ P,NCMHDR ;WRITE THE HEADER (AND PUSH "CNT" POINTER)
|
||
JRST UPOPJ## ;RESTORE U AND GIVE ERROR RETURN
|
||
MOVEI T1,NC.DQR ;DATA REQUEST
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;DLA
|
||
LDB T1,NETDLA ;GET THE DESTINATION LINK ADDRESS
|
||
IFN PARANOID&P$LAT,<
|
||
SKIPN T1 ;JUST A BIT OF PARANOIA AGAIN
|
||
STOPCD .,STOP,ANFDRZ, ;++ SENDING DRQ'S TO DEVICE ZERO
|
||
>
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;DQR
|
||
MOVEI T1,(P1) ;GET THE DQR
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;CNT
|
||
JSP T1,NETWRC ;SEND THE MESSAGE (POP "CNT" POINTER OFF STK)
|
||
PJRST UPOPJ1## ;SKIP EXIT
|
||
SUBTTL MEMORY CONTROL ROUTINES
|
||
|
||
;SUBROUTINE GETZWD - GET A BLOCK OF MONITOR FREE CORE AND ZERO
|
||
;CALL MOVEI T2,#WORDS
|
||
; PUSHJ P,GETZWD
|
||
;RETURN CPOPJ ;NO CORE AVAILABLE
|
||
; CPOPJ1 ;T1=ADDRESS
|
||
|
||
GETZWD::
|
||
IFN PARANOID&P$COR,< ;KEEP A LINKED LIST OF ALL NETWORK CORE
|
||
|
||
ADDI T2,3 ;WE USE 3 EXTRA WORDS IF WE ARE PARANOID
|
||
>
|
||
PUSH P,T2 ;SAVE THE NUMBER OF WORDS
|
||
HLRE T1,FREPTR## ;GET LENGTH OF FREE CORE MAP
|
||
MOVNS T1
|
||
IMULI T1,^D36 ;MAKE #4 WORD BLOCKS (=1/4 FREE CORE TOTAL)
|
||
JFCL
|
||
; CAML T1,%NTCOR ;DON'T USE MORE THAN 1/4 OF FREE CORE
|
||
PUSHJ P,GETWDS## ;ALOCATE THE SPACE
|
||
PJRST T2POPJ## ;NO, SPACE AVAILABLE
|
||
SETZM (T1) ;CLEAR THE FIRST WORD
|
||
MOVE T2,(P) ;GET THE NUMBER OF WORDS
|
||
ADDM T2,%NTCOR ;ACCOUNT FOR CORE USED
|
||
MOVEM T1,(P) ;SAVE THE STARTING ADDRESS
|
||
ADDI T2,-1(T1) ;POINT TO THE END OF THE LIST
|
||
HRLI T1,1(T1) ;MAKE A BLT POINTER
|
||
MOVSS T1 ;FROM,,TO
|
||
BLT T1,(T2) ;CLEAR THE BLOCK
|
||
MOVE T1,%NTCOR ;IF WE NOW ARE USING MORE
|
||
CAMLE T1,%NTMAX ; CORE THAN EVER BEFORE
|
||
MOVEM T1,%NTMAX ; RECORD FOR PRYING EYES
|
||
IFN PARANOID&P$COR,< ;NOW LINK IN THE BLOCK AND SET LAST WORD
|
||
|
||
MOVE T1,[SIXBIT /NETMEM/] ;"UNIQUE" PATTERN FOR END WORD
|
||
MOVEM T1,(T2) ;SO WE CAN SEE IF USER WROTE TOO FAR.
|
||
MOVE T1,(P) ;GET ADDRESS OF START OF THE BLOCK
|
||
NETOFF ;WE NEED PROTECTION WHILE HACKING LISTS
|
||
MOVE T2,%NTMEM ;GET POINTER TO FIRST BLOCK IN THE CHAIN
|
||
HRLI T2,%NTMEM ;MAKE OUR BACK LINK POINT TO "%NTMEM"
|
||
MOVEM T2,(T1) ;STORE DOUBLE LINK IN FIRST WORD
|
||
ANDI T2,-1 ;STRIP OFF IME-INDUCING LH GARBAGE
|
||
MOVEM T1,%NTMEM ;MAKE THE LIST START WITH US
|
||
HRLM T1,(T2) ;FIX UP BACKWARD LINK IN NEXT BLOCK
|
||
NETON ;ALL'S CLEAR
|
||
MOVE T2,-1(P) ;GET THE CALLER'S PC
|
||
HRLI T2,'NET' ;GET A "UNIQUE" 18 BIT STRING
|
||
MOVEM T2,1(T1) ;AND PUT "XWD STRING,PC" IN SECOND WORD
|
||
ADDI T1,2 ;MAKE POINTER POINT TO THE THIRD WORD
|
||
MOVEM T1,(P) ;AND GIVE THAT TO THE USER
|
||
>
|
||
PJRST TPOPJ1## ;RESTORE THE ADDRESS AND EXIT
|
||
;SUBROUTINE GIVZWD - RETURN MONITOR FREE CORE
|
||
;CALL MOVEI T1,#WORDS
|
||
; MOVEI T2,ADDRESS
|
||
; PUSHJ P,GIVZWD
|
||
;RETURN CPOPJ
|
||
|
||
GIVZWD::
|
||
IFN PARANOID&P$COR,< ;CHECK FOR ILLEGAL MEMORY USAGE
|
||
ADDI T1,3 ;ACCOUNT FOR CHECK WORDS
|
||
SUBI T2,2 ;ADJUST POINTER TO BEGINNING OF BLOCK
|
||
> ;END IFN PARANOID&P$COR
|
||
|
||
PUSH P,T1 ;SAVE THE LENGTH
|
||
|
||
IFN PARANOID&P$COR,< ;CHECK FOR ILLEGAL MEMORY USAGE
|
||
PUSH P,T2 ;SAVE THE ADDRESS
|
||
NETOFF ;PROTECTION WHILE HACKING LISTS
|
||
MOVE T1,(T2) ;GET THE "XWD BACKWARD,FORWARD" LINK WORD
|
||
HRRZ T3,T1 ;JUST THE ADDRESS FOR IME-LESS INDEXING
|
||
HLLM T1,(T3) ;SPLICE OUT ONE POINTER
|
||
MOVS T1,T1 ;SWAP HALVES
|
||
HRRZ T3,T1 ;JUST THE ADDRESS FOR IME-LESS INDEXING
|
||
HLRM T1,(T3) ;SPLICE OUT THE OTHER POINTER
|
||
NETON ;ALL IS CLEAR. WE ARE SPLICED OUT
|
||
HLRZ T1,1(T2) ;GET THE LEFT OF THE SECOND CHECK WORD
|
||
CAIE T1,'NET' ;MAKE SURE IT WASN'T CLOBBERED
|
||
STOPCD .,STOP,ANFWMB, ;++ USER WROTE IN MEMORY BEFORE BLOCK
|
||
ADD T2,-1(P) ;GET A POINTER TO ONE PAST THE END OF THE BLOCK
|
||
EXCH T2,-1(T2) ;GET THE LAST CHECK WORD (AND MAKE IT GARBAGE)
|
||
CAME T2,[SIXBIT /NETMEM/] ;VERIFY THAT HE DIDN'T CLOBBER IT
|
||
STOPCD .,STOP,ANFWPE, ;++ USER WROTE PAST THE END OF THE BLOCK
|
||
POP P,T2 ;GET THE ADDRESS BACK
|
||
> ;END IFN PARANOID&P$COR
|
||
|
||
MOVN T1,0(P) ;"SUB'ABLE" LENGTH
|
||
ADDB T1,%NTCOR ;REDUCE CORE USED
|
||
SKIPGE T1 ;CHECK RESULT
|
||
STOPCD TPOPJ##,DEBUG,CWN,;++CORE ALLOCATION WENT NEGATIVE
|
||
POP P,T1 ;RESTORE WORD COUNT
|
||
PJRST GIVWDS## ;RETURN THE CORE
|
||
;SUBROUTINE SVEVM - SAVE THE JOB EVM AND RESTORE ON POPJ
|
||
;CALL PUSHJ P,SVEVM
|
||
;RETURN CPOPJ
|
||
|
||
SVEVM:: JUMPE F,CPOPJ## ;NO EVM IF NO DDB
|
||
SKIPN DEVEVM(F) ;ANY EVM
|
||
POPJ P, ;NO RETURN
|
||
PUSHJ P,RTEVM## ;YES, RETURN THE EVM
|
||
POP P,(P) ;PUT THE RETURN ON THE END OF THE STACK
|
||
PUSHJ P,@1(P) ;RETURN TO THE CALLER
|
||
PJRST RSTEVM## ;NON-SKIP RESTORE EVM
|
||
AOS (P) ;SKIP RETURN
|
||
PJRST RSTEVM## ;RESTORE EVM AND EXIT
|
||
SUBTTL COMMON SUBROUTINES TO CONVERT EXTENSIBLE ASCII/BINARY
|
||
;SUBROUTINE EAS2SX CONVERT EXTENSIBLE ASCII TO SIXBIT
|
||
;CALL MOVEI P1,[INPUT POINTER]
|
||
; PUSHJ P,EAS2SX
|
||
;RETURN CPOPJ ;T1=SIXBIT
|
||
|
||
EAS2SX::MOVE T2,[POINT 6,T1] ;GET BYTE POINTER
|
||
SETZB T1,T4 ;CLEAR OUTPUT
|
||
EAS2S1: SOJL P4,CPOPJ## ;EXIT IF NO MORE DATA
|
||
ILDB T3,P1 ;GET THE BYTE
|
||
TRZN T3,200 ;CONTINUE BIT
|
||
SETO T4, ;NO, SET FLAG
|
||
TRNE T3,140 ;MAKE SURE ASCII BEFOR SUBI
|
||
SUBI T3,40 ;CONVERT TO SIXBIT
|
||
TRNN T3,177 ;CHECK FOR A BLANK CHARACTER
|
||
JUMPE T1,EAS2S2 ;AND A LEADING BLANK
|
||
CAIE T3,'[' ;CHECK TO [XXX,XXX]
|
||
CAIN T3,']' ;AND EXIT
|
||
POPJ P, ;IF FOUND
|
||
CAIN T3,',' ;ALSO A COMMA
|
||
POPJ P, ;WILL EXIT
|
||
TLNE T2,(77B5) ;END OF WORD
|
||
IDPB T3,T2 ;STORE WORD
|
||
EAS2S2: JUMPGE T4,EAS2S1 ;NO CONTINUE
|
||
POPJ P, ;RETURN
|
||
|
||
;SUBROUTINE SX2EAS CONVERT SIXBIT TO EXTENSIBLE ASCII
|
||
;CALL MOVE T1,[SIXBIT /.../]
|
||
; MOVE P2,[OUTPUT BYTE POINTER]
|
||
; PUSHJ P,SX2EAS
|
||
;RETURN CPOPJ ;P3 COUNTED UP
|
||
|
||
SX2EAS::SKIPE T2,T1 ;COPY THE SIXBIT NAME
|
||
SX2EA1: SETZ T1, ;CLEAR THE OUTPUT AC
|
||
LSHC T1,6 ;GET A SIXBIT CHARACTER
|
||
ADDI T1,240 ;CONVERT TO ASCII WITH CONTINUE BIT
|
||
IDPB T1,P2 ;STORE CHARACTER
|
||
ADDI P3,1 ;COUNT THE CHARACTER
|
||
JUMPE T2,CLRBT8 ;EXIT AND CLEAR CONTINUE BIT
|
||
JRST SX2EA1 ;COUNT AND CONTINUE
|
||
;SUBROUTINE AS2EAS CONVERT ASCIZ TO EXTENSIBLE ASCII
|
||
;CALL MOVE P1,[INPUT BYTE POINTER] ASCII 7
|
||
; MOVE P2,[OUTPUT BYTE POINTER] EXTENSIBLE ASCII 8
|
||
; PUSHJ P,AS2EAS
|
||
;RETURN CPOPJ ;P3 UPDATED WITH CHARACTER COUNT
|
||
|
||
AS2EAZ: JUMPE P1,CPOPJ## ;DO NOTHING IF NO POINTER
|
||
|
||
AS2EAS::TLNN P1,-1 ;IS THERE A BYTE POINTER
|
||
HRLI P1,(POINT 7) ;NO, SUPPLY ONE
|
||
AS2EA1: ILDB T1,P1 ;GET AN ASCII CHARACTER
|
||
JUMPE T1,CLRBT8 ;JUMPE IF END
|
||
TRO T1,200 ;SET HIGH ORDER BIT
|
||
IDPB T1,P2 ;STORE 8 BIT BYTE
|
||
AOJA P3,AS2EA1 ;COUNT CHARACTER TRY AGAIN
|
||
CLRBT8::LDB T1,P2 ;GET LAST STORED CHARACTER BACK
|
||
TRZ T1,200 ;CLEAR THE CONTINUE BIT
|
||
DPB T1,P2 ;STORE CHARACTER
|
||
POPJ P, ;RETURN
|
||
|
||
;SUBROUTINE EAS2AZ SEE IF ANYTHING FOR EAS2AS TO CONVERT
|
||
;CALL MOVE P1,[INTPUT BYTE POINTER]
|
||
; PUSHJ P,EAS2AZ
|
||
;RETURN 1 NOTHING TO COPY
|
||
;RETURN 2 SOMETHING FOR EAS2AS TO DO
|
||
;USES T1 & T2
|
||
|
||
EAS2AZ: JUMPE P4,CPOPJ## ;RETURN IF NOTHING TO COPY
|
||
MOVE T1,P1 ;COPY BYTE POINTER
|
||
ILDB T2,T1 ;EXAMINE FIRST CHARACTER
|
||
JUMPN T2,CPOPJ1## ;SKIP IF SOMETHING TO COPY
|
||
MOVE P1,T1 ;NO, COPY INCREMENTED BYTE POINTER
|
||
SOJA P4,CPOPJ## ;ACCOUNT FOR CHARACTER AND GIVE 'NONE' RETURN
|
||
|
||
;SUBROUTINE EAS2AS CONVERT AN EXTENSIBLE ASCII STRING TO ASCIZ
|
||
;CALL MOVE P1,[INPUT BYTE POINTER]
|
||
; MOVE P2,[OUTPUT BYTE POINTER]
|
||
; PUSHJ P,EAS2AS
|
||
;EXIT
|
||
|
||
EAS2AS::HRLI P2,(POINT 7) ;MAKE A BYTE POINTER
|
||
MOVEI T2,^D37 ;ALLOW A MAX CHARACTER COUNT
|
||
EAS2A1: SOJL P4,CPOPJ## ;EXIT IF NO MORE
|
||
ILDB T1,P1 ;GET AN 8 BIT CHARACTER
|
||
IDPB T1,P2 ;STORE A SEVEN BIT CHARACTER
|
||
TRNE T1,200 ;IS CONTINUE BIT ON
|
||
SOJG T2,EAS2A1 ;YES, CONTINUE
|
||
SETZ T1, ;SET UP A NULL
|
||
IDPB T1,P2 ;STORE THE NULL
|
||
POPJ P, ;RETURN
|
||
;SUBROUTINE BI2EBI CONVERT A BINARY NUMBER TO EXTENSIBLE BINARY
|
||
;CALL MOVE T1,[A BINARY NUMBER]
|
||
; MOVE P2,[OUTPUT BYTE POINTER] 8 BIT
|
||
; PUSHJ P,BI2EBI,OCT2EBI,DE2EBI
|
||
;RETURN CPOPJ ;P3 UPDATED
|
||
BI2EBI::CAIG T1,177 ;GREATER THAN 177
|
||
JRST DPBBIN ;NO OUTPUT
|
||
LSHC T1,-7 ;SHIFT OFF THE BITS
|
||
ROT T2,7 ;SAVE IN T2
|
||
TRO T2,200 ;SET CONTINUE BIT
|
||
IDPB T2,P2 ;STORE IN MESSAGE
|
||
AOJA P3,BI2EBI ;CONTINUE
|
||
|
||
|
||
|
||
;SUBROUTINE EBI2BI TO CONVERT EXTENSIBLE BINARY TO BINARY
|
||
;CALL MOVE P1,[INPUT BYTE POINTER
|
||
; PUSHJ P,EBI2BI
|
||
;RETURN CPOPJ ;T1=BINARY NUMBER
|
||
|
||
EBI2BI::SETZB T1,T2 ;INITIALIZE FOR NUMBER-BUILDING LOOP
|
||
EBI2B1: SOJL P4,CPOPJ## ;EXIT IF THE END OF DATA
|
||
ILDB T3,P1 ;GET THE NEXT CHARACTER
|
||
TRZN T3,200 ;IS THE NUMBER EXTENDED
|
||
JRST EBI2B5 ;NO, ACCUMLATE END OF NUMBER AND EXIT
|
||
LSH T3,(T2) ;POSITION NEXT "DIGIT"
|
||
IOR T1,T3 ;AND ACCUMULATE NUMBER
|
||
ADDI T2,7 ;"ADVANCE" ACCUMULATOR-POSITIONER
|
||
JRST EBI2B1 ;CONTINUE
|
||
|
||
EBI2B5: LSH T3,(T2) ;POSITION NEXT "DIGIT"
|
||
IOR T1,T3 ;AND ACCUMLATE NUMBER
|
||
POPJ P, ;RETURN WITH BINARY IN T1
|
||
|
||
|
||
|
||
;SUBROUTINE BYT2BI READ ONE BYTE FROM THE STREAM
|
||
;CALL JUST LIKE THE REST
|
||
;RETURN CPOPJ ;T1 = THE 8 BIT BYTE
|
||
|
||
BYT2BI::SOJL P4,CPOPJ## ;EXIT IF END OF MESSAGE
|
||
ILDB T1,P1 ;GET THE BYTE
|
||
POPJ P, ; AND RETURN
|
||
;SUBROUTINE XX2EAS CONVERT NUMBER TO EXTENSIBLE ASCII
|
||
;CALL P2/ OUTPUT BYTE POINTER P3/ COUNTER T1/ NUMBER
|
||
; PUSHJ P,OC2EAS/DC2EAS/RX2EAS
|
||
;RETURN CPOPJ WITH P2/P3 UPDATED
|
||
|
||
DC2EAS: SKIPA T3,[^D10] ;DECIMAL CONVERSION
|
||
OC2EAS::MOVEI T3,^D8 ;OCTAL CONVERSION
|
||
RX2EAS: IDIVI T1,(T3) ;SEPERATE AGAIN
|
||
PUSH P,T2 ;STORE THE BYTE
|
||
SKIPE T1 ;ANY LEFT NOW
|
||
PUSHJ P,RX2EAS ;YES, TRY AGAIN
|
||
POP P,T1 ;NO, GET THE LAST DIGIT BACK
|
||
ADDI T1,"0" ;CONVERT TO ASCII
|
||
DPBEAS: TRO T1,200 ;SET THE CONTINUE BIT
|
||
DPBBIN::ADDI P3,1 ;COUNT
|
||
IDPB T1,P2 ;NO STORE THE DIGIT
|
||
POPJ P, ;RETURN
|
||
|
||
;SUBROUTINE EAS2 - CONVERT ASCII TO OCTAL/DECIMAL/RADIX
|
||
;CALL P1, P4:= POINTER TO INPUT
|
||
; PUSHJ P,EAS20C/EAS2DC/2ASRX
|
||
;RETURN CPOPJ; T1:= NUMBER, T2:= TERMINATING CHARACTER
|
||
|
||
EAS2DC::SKIPA T3,[^D10] ;DECIMAL RADIX
|
||
EAS2OC::MOVEI T3,^D8 ;OCTAL RADIX
|
||
EAS2RX::SETZB T1,T4 ;ARBITRARY RADIX IN T3
|
||
EAS2NN::SOJL P4,CPOPJ## ;COUNT DOWN INPUT
|
||
ILDB T2,P1 ;NEXT INPUT CHARACTER
|
||
TRZN T2,200 ;END OF FIELD
|
||
SETO T4, ;YES
|
||
CAIL T2,"0" ;VALID ?
|
||
CAILE T2,"0"(T3) ; DIGIT ?
|
||
POPJ P, ;NO, END OF NUMBER
|
||
IMULI T1,(T3) ;ROOM FOR NEXT
|
||
ADDI T1,-"0"(T2) ;ADD UP NUMBER
|
||
JUMPE T4,EAS2NN ;LOOP FOR WHOLE NUMBER
|
||
POPJ P, ;OR UNITL END OF EXTENSIBLE ASCII
|
||
;XSKIP ROUTINE TO SKIP OVER AN EXTENSIBLE FIELD
|
||
;CALL P1, P4 := POINT TO FIELD
|
||
; PUSHJ P,XSKIP
|
||
;RETURN CPOPJ ;ALWAYS
|
||
;
|
||
XSKIP:: SOJL P4,CPOPJ## ;COUNT OFF THIS BYTE
|
||
ILDB T1,P1 ;GET THE BYTE
|
||
TRNE T1,200 ;EXTENSIBLE
|
||
JRST XSKIP ;YES. KEEP LOOKING FOR THE END
|
||
POPJ P, ; NO. ALL DONE
|
||
|
||
|
||
|
||
;SKIP1 ROUTINE TO SKIP OVER A 1 BYTE FIELD
|
||
;CALL P1, P4 := POINT TO BYTE TO SKIP
|
||
; PUSHJ P,SKIP1
|
||
;RETURN CPOPJ
|
||
;
|
||
SKIP1:: SOJL P4,CPOPJ## ;COUNT DOWN THE BYTE
|
||
IBP P1 ;INCREMENT THE BYTE POINTER
|
||
POPJ P, ;ALL DONE
|
||
;SUBROUTINE PP2EAS - OUTPUT A PPN IN EXTENSIVE ASCII
|
||
;CALL MOVE T1,[PPN]
|
||
; PUSHJ P,PP2EAS
|
||
;RETURN CPOPJ
|
||
|
||
PP2EAS::PUSH P,T1 ;SAVE THE PPN
|
||
MOVEI T1,"[" ;OPEN BRACKET
|
||
PUSHJ P,DPBEAS ;OUTPUT
|
||
HLRZ T1,(P) ;GET THE PROGRAMMER NUMBER
|
||
PUSHJ P,OC2EAS ;OUTPUT
|
||
MOVEI T1,"," ;SEPERATOR
|
||
PUSHJ P,DPBEAS ;OUTPUT
|
||
POP P,T1 ;RESTORE THE STACK GET PROGRAMMER #
|
||
HRRZS T1 ;RT HALF
|
||
PUSHJ P,OC2EAS ;OUTPUT
|
||
MOVEI T1,"]" ;CLOSING BRACKET
|
||
PUSHJ P,DPBEAS ;OUTPUT
|
||
PJRST CLRBT8 ;CLEAR THE LAST BIT
|
||
|
||
;SUBROUTINE EAS2PP - INPUT A PROCESS ANEM AND UIC
|
||
;CALL PUSHJ P,EAS2PP
|
||
;RETURN CPOPJ
|
||
|
||
EAS2PP:: ;ENTRY
|
||
PUSHJ P,EAS2SX ;GET THE SIXBIT NAME
|
||
PUSH P,T1 ;SAVE
|
||
SETZ T2, ;CLEAR THE PPN WORD
|
||
CAIE T3,'[' ;DOES A PPN FOLLOW
|
||
PJRST TPOPJ## ;NO EXIT T1=NAME T2=PPN
|
||
PUSHJ P,EAS2OC ;GET THE PROJECT NUMBER
|
||
TLNE T1,-1 ;LESS THAN 7 DIGITS ?
|
||
SETZ T1, ;ILLEGAL SET TO ZERO
|
||
PUSH P,T1 ;SAVE THE PROJECT NUMBER
|
||
PUSHJ P,EAS2OC ;GET THE PROGRAMMER NUMBER
|
||
TLNE T1,-1 ;LESS THAN 7 DIGITS ?
|
||
SETZ T1, ;ILLEGAL
|
||
HRL T1,(P) ;GET THE PROGRAMMER NUMBER BACK
|
||
MOVE T2,T1 ;COPY TO T2
|
||
POP P,(P) ;REMOVE SCRATCH FROM THE STACK
|
||
PJRST TPOPJ## ;EXIT T1=NAME T2=PPN
|
||
SUBTTL NTFSEC - ONCE A SECOND CODE
|
||
|
||
;CALLED ONCE A SECOND WITH J SET FOR EACH FEK
|
||
;
|
||
NTFSEC::PUSHJ P,SAVJW## ;SAVE J AND W ETC
|
||
SKIPN T1,FEKBJN(J) ;SEE IF SOME NODE OWNS THE BOOT
|
||
JRST NTFSE1 ; IF NOT BOOT-STRAPING, GO CHECK REST OF FEK
|
||
HLRZ T1,T1 ;GET THE TIMER VALUE
|
||
SOJLE T1,[HRRZ T1,FEKBJN(J) ;IF TIMER RAN OUT, GET JOB NUMBER
|
||
PUSHJ P,EWAKE## ;WAKE THE USER
|
||
SETZM FEKBJN(J) ;RELINQUISH OWNERSHIP OF STC
|
||
JRST NTFSE1] ;AND GO CHECK FOR STALE MESSAGES
|
||
HRLM T1,FEKBJN(J) ;STORE THE NEW TIMER VALUE
|
||
NTFSE1: SKIPN T1,FEKICT(J) ;SEE IF THERE ARE ANY INPUT MSGS QUEUED
|
||
JRST NTFSE2 ; IF NO INPUT STC MSGS, CHECK REST OF FEK
|
||
HLRZ T1,T1 ;GET JUST THE TIMER VALUE
|
||
SOJLE T1,[PUSH P,J ;IF THE MESSAGE TIMES OUT, SAVE FEK
|
||
HRRZ J,FEKICT(J) ;GET J := STC MESSAGE
|
||
PUSHJ P,GIVSTC ;FREE THE STC MESSAGE
|
||
POP P,J ;GET THE FEK ADDRESS BACK
|
||
SETZM FEKICT(J) ;CLEAR THE (NOW FREED) STC MSG POINTER
|
||
JRST NTFSE2] ;AND CONTINUE WITH OTHER CHECKING
|
||
HRLM T1,FEKICT(J) ;STORE THE UPDATED COUNTER
|
||
NTFSE2: HLLZ S,FEKBLK(J) ;SET UP THE FEK'S FLAGS
|
||
JUMPGE S,CPOPJ ;IF IT'S NOT ONLINE, DON'T CHECK ANY FARTHER
|
||
TLNN S,FK.NID ;NODE ID SENT
|
||
PUSHJ P,NCSNID ;NO, SEND IT
|
||
JFCL ;ERROR NO CORE (SEND NEXT TIME)
|
||
SKIPG FEKIAD(J) ;IS THERE AN INPUT PCB?
|
||
PUSHJ P,NETRDD ;IF NO INPUT PCB, TRY TO SET UP READ REQUEST
|
||
SKIPG FEKOCT(J) ;IS THERE AN OUTPUT PCB BEING SERVICED?
|
||
POPJ P, ; IF NOT, THEN DON'T DO HUNG CHECK.
|
||
AOS T1,FEKHTM(J) ;INCREMENT THE TIME THAT THIS PCB HAS TAKEN.
|
||
CAIG T1,^D5 ;HAS THIS PCB TAKEN MORE THAN 5 SECONDS?
|
||
POPJ P, ; IF NOT, THEN IT'S POSSIBLY ALL RIGHT
|
||
|
||
;HERE IF FEK HAS TIMED OUT. (IE. MORE THAN 5 SECONDS TO SEND LAST MESSAGE)
|
||
|
||
MOVEI T1,FF.CRS ;ASK THIS FEK TO "CRASH" ITSELF
|
||
XCT FEKDSP(J) ;CALL THE FRONT-END SERVICE ROUTINE
|
||
POPJ P, ;AND RETURN
|
||
|
||
|
||
;NETSEC THIS ROUTINE IS CALLED ONCE A SECOND FROM CLOCK1
|
||
NETSEC::
|
||
IFN FTMP,<SKPCPU (1)> ;ONLY DO SECOND STUFF ON THE BOOT CPU
|
||
SETOM NTQSEC ;SIGNAL THE SECOND
|
||
POPJ P, ;LET JIFFY CODE CALL NETSCN
|
||
SUBTTL NETCTC - CALL ON RESET OR ^C^C AND NOT CCON/CON
|
||
NETCTC:: ;CALLED BY UUOCON
|
||
NETDBJ ;GET THE INTERLOCK TO DO THIS.
|
||
PUSHJ P,SAVJW## ;SAVE J AND W
|
||
;CHECK FOR REMOTE DIALER IN USE
|
||
CAMN J,DIALJB ;DOES THIS JOB HAVE THE [NETWORK] DIALER?
|
||
SETZM DIALDB ;YES, CLEAR THE DIALER
|
||
|
||
|
||
;CLEAR THE STATION CONTROL DEVICE IF THERE
|
||
MOVEI W,NETNDB## ;GET THE START ON THE NDB CHAIN
|
||
NETCT1: SKIPN T1,NDBSTC(W) ;IS STATION CONTROL BUSY
|
||
JRST NETCT2 ;NO, CONTINUE
|
||
HRRZS T1 ;GET THE JOB NUMBER FOR COMPARE
|
||
CAIN T1,(J) ;DOES THIS JOB HAVE THE DEVICE
|
||
SETZM NDBSTC(W) ;YES, CLEAR THE DEVICE
|
||
NETCT2: HRRZ W,NDBNNM(W) ;GET THE NEXT STATION POINTER
|
||
JUMPN W,NETCT1 ;CONTINUE UNLESS THE END OF NDB
|
||
|
||
;HERE TO CHECK FOR STATION CONTROL IN USE ON ANY FEKS
|
||
IFN FTKS10,< ;ONLY THE KS-10 HAS SMART FEKS...
|
||
MOVEI W,FEKFST## ;GET THE ADDRESS OF THE FIRST FEK
|
||
CAIA ;SKIP INTO THE LOOP
|
||
NETCT3: HRRZ W,FEKBLK(W) ;ADVANCE TO THE NEXT FEK
|
||
JUMPE W,NETCT4 ;IF NO MORE FEKS, GO CHECK FOR OTHER THINGS
|
||
SKIPN T1,FEKBJN(W) ;SEE IF THIS FEK'S STC IS IN USE
|
||
JRST NETCT3 ;IF NO ONE IS USING IT, GO CHECK NEXT FEK
|
||
HRRZ T1,T1 ;CLEAR OUT THE TIMER VALUE
|
||
CAIN T1,(J) ;ARE WE THE ONE USING THE STC?
|
||
SETZM FEKBJN(W) ; IF WE'RE USING IT, RELEASE IT
|
||
JRST NETCT3 ;GO CHECK THE REST...
|
||
>;END IFN FTKS10
|
||
|
||
;HERE TO CHECK FOR PENDING CONNECT/DISCONNECT MESSAGES
|
||
NETCT4: PUSHJ P,FNDPDS## ;FIND THE PDB FOR THE JOB
|
||
PUSH P,F ;SAVE THE DDB POINTER
|
||
HLRZ F,.PDNET##(W) ;GET THE POSSIBLE DDB POINTER
|
||
JUMPE F,NETCT5 ;NONE
|
||
HRRZS .PDNET##(W) ;CLEAR THE POINTER
|
||
MOVE T1,DEVMOD(F) ;GET DEVICE'S DV??? FLAGS
|
||
TRNE T1,ASSPRG ;IS DEVICE OPEN/INITED?
|
||
JRST NETCT5 ;YES, RELEASE SHOULD GET IT LATER
|
||
TLNE T1,DVTTY ;IS DEVICE A TTY?
|
||
JRST [PUSHJ P,TTYKIL## ;YES, THEN USE A DIFFERENT
|
||
JRST NETCT5] ; ROUTINE TO FREE THE DDB
|
||
MOVE S,DEVIOS(F) ;IF THE DEVICE NEVER GOT CONNECTED
|
||
TLNN S,IOSCON ;OR IS BEING DISCONNECTED,
|
||
JRST [MOVSI S,IOSZAP ;THEN SET IOSZAP. THIS CAUSES ALL
|
||
IORB S,DEVIOS(F) ;RIGHT THINGS TO HAPPEN AS MSGS COME IN
|
||
JRST NETCT5] ;RETURN TO MAIN LINE
|
||
PUSHJ P,ZAPNE0 ;IF CONNECTED, SEND A DISCONNECT
|
||
NETCT5: JRST FPOPJ## ;RESTORE F AND EXIT
|
||
;NDBCHK ROUTINE TO VERIFY THAT W DOES NOT POINT AT NETNDB. (THIS
|
||
; ROUTINE CHECKS TO MAKE SURE THAT WE AREN'T TALKING TO OURSELF.)
|
||
;CALL PUSHJ P,NDBCHK
|
||
;RETURN CPOPJ ;OR STOPCD
|
||
;
|
||
NDBCHK: PUSH P,T1 ;SAVE THIS FOR A BIT
|
||
MOVEI T1,NETNDB## ;GET THE ADDRESS OF NETNDB
|
||
CAIN T1,(W) ;MAKE SURE RH(W) DOESN'T POINT AT IT
|
||
STOPCD .,STOP,ANFTLK, ;++ TALKING TO OURSELVES
|
||
PJRST TPOPJ ;RESTORE T1 AND RETURN
|
||
|
||
|
||
;FRCNLD ROUTINE TO START UP NETLDR
|
||
;CALL PUSHJ P,FRCNLD
|
||
;RETURN CPOPJ ;STARTS NETLDR ONLY IF NOT DEBUGGING
|
||
|
||
FRCNLD: MOVE T1,STATES## ;BEFORE WE START UP NETLDR, MAKE SURE
|
||
TRNN T1,ST.DDL ; OPR SAYS IT'S OK. IF NO NETLDR,
|
||
SKIPGE DEBUGF ; OR WE'RE DEBUGGING THIS MESS
|
||
POPJ P, ;DON'T RUN NETLDR
|
||
PUSH P,U ;FIRST WE NEED AN LDB, SO SAVE POSSIBLE PCB
|
||
PUSH P,W ;WE ALSO MUST SET UP "W" FOR GETLDB
|
||
SETZ T1, ;SIGNIFY THAT THERE'S NO REMOTE INVOLVED
|
||
MOVEI T3,ERRDSP## ;SET UP NULL ISR DISPATCH
|
||
PUSHJ P,GETLDB## ;GET A FREE LDB
|
||
JRST FRCNL1 ;IF NO FREE LDB'S JUST IGNORE THE REQUEST
|
||
MOVEI T1,M.AIDL## ;ANF-10 IDLE MAX
|
||
PUSHJ P,SCNADT## ;START TIMER LOGIC ON LINE
|
||
MOVEI T1,TTFCXL## ;GET THE ".NETLD" FORCE COMMAND INDEX
|
||
PUSHJ P,TTFORC## ;FORCE IT ON THE TERMINAL
|
||
PUSHJ P,FRELDB## ;*** KROCK *** MUST GET THIS ONTO FRCLIN ***
|
||
FRCNL1: POP P,W ;RESTORE ANY NDB POINTER
|
||
PJRST UPOPJ## ;RETURN. NETLDR WILL START UP SOON.
|
||
;NETWRC ROUTINE TO FINISH OFF A MESSAGE STARTED BY NCMHDR & FRIENDS
|
||
;CALL P3 := "CNT" OF THE CONTROL MESSAGE
|
||
; (P) := A BYTE POINTER TO THE "CNT" FIELD IN THE MESSAGE
|
||
; T1 := RETURN ADDRESS
|
||
;RETURN JRST (T1) ;VIA A CPOPJ FROM NETWRT
|
||
;
|
||
NETWRC:: ;HERE TO SEND A CONTROL MESSAGE
|
||
EXCH T1,(P) ;GET THE POINTER TO "CNT" (SAVE RETURN ADDR)
|
||
DPB P3,T1 ;STORE THE COUNT
|
||
ADDM P3,PCBCTR(U) ;UPDATE THE PCB'S LENGTH
|
||
PJRST NETWRT ;SEND THE MESSAGE
|
||
SUBTTL NETWRT - SEND A MESSAGE TO THE FRONT END KONTROLLER FEK
|
||
|
||
;SUBROUTINE NETWRT - SEND A MESSAGE
|
||
;CALL MOVEI U,PCB
|
||
; PUSHJ P,NETWRT ;CALLED AT INTERRUPT OR UUO LEVEL
|
||
;RETURN CPOPJ ;ALWAYS
|
||
|
||
NETWSR: AOS (P) ;SKIP RETURN
|
||
NETWRT:: ;ENTRY
|
||
NTDBUG ;VERIFY THE INTERLOCK
|
||
PUSHJ P,SAVJW## ;SAVE J/W
|
||
HRRZ T1,PCBNNM(U) ;GET THE NODE NUMBER
|
||
PUSHJ P,SRCNDB ;SET UP W FROM THE NODE NUMBER
|
||
S0JRST RMVPCB ;NODE WENT AWAY, DELETE PCB
|
||
HRRZ J,NDBFEK(W) ;GET THE FEK POINTER
|
||
MOVE T4,PCBPTR(U) ;GET ADDRESS OF MESSAGE
|
||
HRLI T4,(POINT 8,0,7);POINT TO NCT
|
||
LDB T1,T4 ; AND GET IT
|
||
ANDI T1,NCT.TP ;ISOLATE MESSAGE TYPE
|
||
AOS NCLXTP(T1) ;COUNT IT
|
||
JUMPN T1,NETWR2 ;WE'RE DONE IF THIS IS UNNUMBERED CONTROL
|
||
ADD T4,[<POINT 8,1,15>-<POINT 8,0,7>] ;POINT TO DLA
|
||
LDB T1,T4 ; AND GET IT
|
||
JUMPN T1,NETWR1 ;NON-ZERO MEANS DATA MESSAGE
|
||
ILDB T1,T4 ;GET THE COUNT BYTE
|
||
TRNE T1,200 ; AND IF IT'S EXTENSIBLE
|
||
JRST .-2 ; KEEP READING
|
||
ILDB T1,T4 ;GET NUMBERED MESSAGE TYPE
|
||
CAIG T1,NC.MAX ;IN RANGE?
|
||
AOS NCLXMT(T1) ;YES, COUNT IT
|
||
JRST NETWR2 ;ALL DONE, OKAY TO SEND
|
||
NETWR1: MOVE T1,PCBCTR(U) ;GET LENGTH OF ENTIRE MESSAGE
|
||
ADD T1,PCBCT2(U) ;INCLUDING SECONDARY (USER) DATA, IF ANY
|
||
SUBI T1,6 ;DISCARD PROTOCOL OVERHEAD
|
||
CAIGE T1,1_<NETLNH-1> ; IN RANGE OF TABLE?
|
||
JFFO T1,.+2 ;YES, GET APPROPRIATE RANGE
|
||
TDZA T1,T1 ;OUT OF RANGE, INCREMENT ENTRY 0
|
||
MOVNI T1,-^D36(T2) ;MAKE ASCENDING ENTRIES MEAN LONGER LENGTHS
|
||
AOS NCLXDL(T1) ; AND RECORD IT
|
||
|
||
NETWR2: NETOFF ;TURN OF THE PI SYS
|
||
;ASSIGN MESAGE NUMBERS HERE
|
||
;NCA
|
||
MOVE T4,PCBPTR(U) ;GET THE OUTPUT POINTER
|
||
HRLI T4,(POINT 8,0,31) ;POINT TO THE NCA/NCN FIELDS
|
||
LDB T1,NDBLMP ;GET THE LAST MESSAGE PROCESSED
|
||
DPB T1,NDBLAS ;SAVE AS LAST ACK
|
||
DPB T1,T4 ;STORE THE ACK NUMBER
|
||
; MOVSI T1,NDB.XA ;GET AND CLEAR THE "NEED TO ACK" FLAG
|
||
; ANDCAB T1,NDBFLG(W) ; TO SIGNIFY ACK WENT THIS JIFFY
|
||
;NCN
|
||
LDB T1,NDBLMA ;GET THE LAST MESSAGE NUMBER ASSIGNED
|
||
SKIPGE PCBBLK(U) ;NUMBERED MESSAGE
|
||
ADDI T1,1 ;YES, UPATE THE COUNT
|
||
DPB T1,NDBLMA ;STORE AS LAST ASSIGNED
|
||
IDPB T1,T4 ;STORE THIS MESSAGE NUMBER
|
||
DPB T1,PCBMSN ;SAVE THE MESSAGE NUMBER OF THIS PCB
|
||
IFN FTKL10,<PUSHJ P,PCBMRK> ;UPDATE THE CACHE SWEEP SERIAL IN THE PCB
|
||
|
||
;DROP THRU INTO FRCWRT
|
||
;DROP THRU FROM NETWRT (WITH NETOFF)
|
||
|
||
FRCWRT: ;PCBMRK MUST HAVE BEEN CALLED
|
||
IFN PARANOID&P$PCB,< ;IF CHECKING PCB'S
|
||
MOVE T1,[SIXBIT /PCBTAG/] ;GET THE PCB IDENTIFIER,
|
||
CAME T1,PCBTAG(U) ; AND MAKE SURE WE HAVE A PCB.
|
||
STOPCD .,STOP,ANFPCV, ;++ PCB NOT VALID
|
||
>
|
||
HLLZS PCBBLK(U) ;MAKE SURE WE ONLY GOT 1 PCB
|
||
|
||
SETZ T3, ;CLEAR "CHECK" COUNTER
|
||
MOVEI T1,FEKOAD-PCBBLK(J) ;GET ADDRESS OF OUTPUT LIST
|
||
CAIA ;SKIP INTO LOOP
|
||
FRCWR1: MOVEI T1,(T2) ;COPY THE PCB ADDRESS
|
||
HRRZ T2,PCBBLK(T1) ;GET ADDRESS OF "NEXT" PCB
|
||
SKIPE T2 ;IF NO NEXT PCB, SKIP OUT OF LOOP
|
||
AOJA T3,FRCWR1 ;COUNT THE PCB AND KEEP LOOPING
|
||
|
||
CAME T3,FEKOCT(J) ;MAKE SURE THAT THE COUNT IS RIGHT
|
||
STOPCD .,STOP,ANFFEK, ;++ FEK BAD, FEKOAD AND FEKOCT IN CONFLICT
|
||
|
||
HRRM U,PCBBLK(T1) ;QUEUE THIS PCB ON THE "END" OF THE LIST
|
||
AOS T3,FEKOCT(J) ;COUNT THIS PCB.
|
||
|
||
NETON ;QUEUES ARE CONSISTENT. INTS OK NOW
|
||
|
||
MOVEI T1,FF.WRT ;GET "FEKWRT" FUNCTION CODE AND CALL KONTROLLER
|
||
XCT FEKDSP(J) ; TO SET UP A WRITE REQUEST
|
||
POPJ P, ;RETURN WITH MESSAGE ON ITS WAY
|
||
;ENQPCB THIS ROUTINE IS USED TO INSERT A PCB INTO A QUEUE SUCH
|
||
; AS NDBQUE. THE QUEUES ARE MAINTAINED WITH ALL UN-NUMBERED
|
||
; MESSAGES FIRST FOLLOWED BY ALL NUMBERED MESSAGES IN ASCENDING
|
||
; ORDER.
|
||
;CALL T1 := BYTE POINTER TO BEGINNING OF QUEUE
|
||
; U := ADDR OF PCB TO ENQUEUE
|
||
;RETURN CPOPJ
|
||
|
||
ENQPCB: LDB T2,T1 ;GET ADDRESS OF FIRST PCB ON LIST
|
||
JUMPE T2,ENQPC3 ;IF EMPTY, THEN PUT THIS FIRST
|
||
MOVSI T3,PCB.NM ;GET THE "THIS IS A NUMBERED MESSAGE" FLAG
|
||
TDNE T3,PCBBLK(U) ;IF THIS MSG IS NUMBERED,
|
||
JRST ENQPC2 ; THEN USE DIFFERENT ROUTINE
|
||
TDNE T3,PCBBLK(T2) ;IF FIRST MESSAGE IN QUEUE IS NUMBERED,
|
||
JRST ENQPC3 ; THEN SPLICE THIS IN AT BEGINNING
|
||
ENQPC1: MOVSI T1,(POINT 18,0,35) ;ELSE BUILD A BYTE POINTER,
|
||
HRRI T1,(T2) ;AND RECURSE
|
||
PJRST ENQPCB ;DOWN THE LIST
|
||
|
||
ENQPC2: ;HERE FOR NUMBERED MESSAGES
|
||
TDNN T3,PCBBLK(T2) ;IF FIRST MESSAGE IS UNNUMBERED,
|
||
JRST ENQPC1 ;THEN RECURSE ONWARD
|
||
PUSH P,U ;SAVE U, WE NEED IT FOR A TEMP
|
||
LDB T3,PCBMSN ;GET OUR MESSAGE NUMBER
|
||
MOVE U,T2 ;COPY OTHER POINTER TO MAKE -
|
||
LDB U,PCBMSN ; THIS LDB WORK RIGHT
|
||
SUB T3,U ;COMPARE THE TWO MESSAGE NUMBERS,
|
||
POP P,U ;GET OUR PCB PTR BACK
|
||
TRNN T3,200 ;SKIP IF OUR PCB .LT. FIRST.
|
||
JRST ENQPC1 ;OUR PCB .GT. FIRST, RECURSE ON
|
||
ENQPC3: HRRM T2,PCBBLK(U) ;HERE TO INSERT PCB. MAKE LINK ONWARD,
|
||
DPB U,T1 ;AND LINK US IN.
|
||
POPJ P, ;AND THAT'S ALL
|
||
|
||
|
||
|
||
;ENQNDB THIS ROUTINE QUEUES AN NDB FOR SERVICE ON OR ABOUT THE
|
||
; NEXT CLOCK TICK. THE QUEUE IS NOT ORDERED, AS ALL NDB'S
|
||
; IN THE QUEUE ARE PROCESSED. THE HEAD OF THE QUEUE IS
|
||
; CONTAINED IN THE LOCATION "NTQNDB". THE BIT ".NDBNQ"
|
||
; INDICATES THAT THE NDB HAS ALREADY BEEN QUEUED.
|
||
;CALL W := ADDR OF NDB
|
||
;RETURN CPOPJ
|
||
|
||
ENQNDB: NETOFF ;PROTECT OURSELVES FROM FEK'S
|
||
MOVSI T1,NDB.NQ ;GET THE "THIS NDB IS QUEUED" BIT
|
||
TDOE T1,NDBFLG(W) ;SEE IF NDB HAS ALREADY BEEN QUEUED
|
||
JRST NTONPJ ;IF SO, THEN EXIT NOW
|
||
HRR T1,NTQNDB ;OTHERWISE ENQUEUE THIS ONE BY GETTING
|
||
MOVEM T1,NDBFLG(W) ;THE CURRENT HEADER AND SAVEING IT HERE
|
||
HRRZM W,NTQNDB ;AND MAKING THE START OF THE QUEUE US.
|
||
JRST NTONPJ ;ALL DONE, TURN THE PI'S BACK ON
|
||
SUBTTL NETHIB/NETWAK - HIBERNATE AND SLEEP ROUTINE FOR .CPJOB ON THE NET
|
||
;SUBROUTINE NETHIB - PUT THE JOB IN THE HIBER STATE
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,NETHIB
|
||
;RETURN CPOPJ ;WHEN AWAKEN BY NETWAK
|
||
|
||
NETHIC: SKIPA T1,[EXP EV.NTC] ;CONNECT WAIT (NO ^C ALLOWED)
|
||
NETHIB::MOVEI T1,EV.NET ;GET REASON FOR EVENT WAKE
|
||
SKIPN F ;MUST HAVE A DDB
|
||
STOPCD CPOPJ##,STOP,FFU,;++F FOULED UP
|
||
NTSAVE ;RETURN 'NT' FOR REST OF THIS ROUTINE
|
||
LDB J,PJOBN## ;GET THE JOB NUMBER
|
||
PUSHJ P,FNDPDS## ;GET THE PDB
|
||
HRLM F,.PDNET##(W) ;STORE THE DDB POINTER IN CASE OF RESET(^C^C)
|
||
PUSHJ P,ESLEEP## ;WAIT
|
||
HRRZ W,JBTPDB##(J) ;GET THE PDB BACK
|
||
HRRZS .PDNET##(W) ;CLEAR THE POINTER
|
||
POPJ P, ;YES, EXIT TO CALLER
|
||
|
||
|
||
;SUBROUTINE NETWAK - WAKE THE JOB UP PUT TO SLEEP BY NETHIB
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,NETWAK
|
||
;RETURN CPOPJ ;JOB(PC) WILL BE @ NETHIB
|
||
|
||
NETWAK::PUSHJ P,SAVJW## ;SAVE J AND W
|
||
LDB T1,PJOBN## ;GET THE JOB NUMBER
|
||
PJRST EWAKE## ;WAKE THE JOB
|
||
|
||
;SUBROUTINE NETSLP - PUT THE JOB TO SLEEP FOR 2 SECONDS
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,NETSLP
|
||
;RETURN CPOPJ ;AFTER 2 SECOND
|
||
|
||
NETSLP::PUSHJ P,SAVT## ;SAVE THE T'S DON'T KNOW WHO IS CALLING
|
||
NTSAVE ;RETURN 'NT' FOR REST OF THIS ROUTINE
|
||
LDB J,PJOBN## ;GET THE JOB NUMBER
|
||
MOVEI T1,2 ;TWO SECONDS
|
||
PUSHJ P,SLEEPF## ;SLEEP
|
||
JFCL ;MAYBE
|
||
POPJ P, ;RETURN
|
||
|
||
;*** FOOTNOTE ***
|
||
|
||
COMMENT \
|
||
|
||
Note that both these routines clobber "J" and "W". In general
|
||
these routines are called with contents(J) pointing to a FEK, and
|
||
contents(W) pointing to an NDB. Since these pointers would no longer
|
||
be valid (the FEK or node might have crashed) these registers are
|
||
intentionally clobbered.
|
||
|
||
\
|
||
;SUBROUTINE INCTBD - RECORD AND DISCARD A BAD INPUT MESSAGE
|
||
;CALL MOVEI U,PCB
|
||
; MOVEI J,FEK
|
||
; MOVEI T1,.
|
||
; PUSHJ P,INCTBD ;USUALLY PJSP T1,INCTBD
|
||
;RETURN CPOPJ
|
||
|
||
INCTBP: HRRZ T1,(P) ;GET PC FOR THOSE WHO PUSHJ
|
||
INCTBD::AOS %NTBAD ;COUNT THIS MESSAGE
|
||
HRLI U,(T1) ;KEEP PC OF FINDER IN LH OF %NTBLC
|
||
EXCH U,%NTBLC ;SAVE, GET LAST ONE
|
||
S0JRST RMVPCB ;FLUSH THE PCB AND RETURN
|
||
|
||
;SUBROUTINE NETHRU - SEND A ROUTE THROUGH MESSAGE
|
||
;CALL MOVEI U,PCB
|
||
; MOVE T1,NODE NUMBER OF DESTINATION
|
||
; JRST NETHRU
|
||
;RETURN CPOPJ
|
||
|
||
NETHRU: ;ENTRY
|
||
PUSH P,J ;SAVE THE INPUT FEK
|
||
PUSHJ P,SRCNDB ;FIND THE NODE TO SEND THE MESSAGE
|
||
JSP T1,[POP P,J ;RESTORE THE INPUT FEK
|
||
JRST INCTBD] ;ILLEGAL MESSAGE
|
||
HRRZ J,NDBFEK(W) ;GET THE OUTPUT FEK
|
||
IFN FTKL10,<PUSHJ P,PCBMRK> ;MSG WAS LOOKED AT, CLEAR VALID BIT
|
||
NETOFF
|
||
PUSHJ P,FRCWRT ;SEND THE MESSAGE
|
||
|
||
JRST JPOPJ## ;RESTORE THE INPUT FEK AND RETURN
|
||
;SUBROUTINE NETRDD - SET UP A READ REQUEST TO THE FRONT END
|
||
;CALL MOVE J,FEK
|
||
; PUSHJ P,NETRDD
|
||
;RETURN CPOPJ
|
||
|
||
NETRDD: SETZ W, ;CLEAR THE NODE POINTER
|
||
SKIPE FEKIAD(J) ;CURSORY CHECK TO SEE IF INPUT BUFFER POSTED
|
||
POPJ P, ;IF SO, DON'T GO THROUGH THE HAIR
|
||
|
||
IFN FTENET,<
|
||
MOVE T1,FEKBLK(J) ;GET FEK FLAGS
|
||
TLNN T1,FK.ETH ;ETHERNET FEK?
|
||
JRST NETRD1 ;NO, NORMAL DEVICE FEK
|
||
TLNN T1,FK.ETM ;ETHERNET MASTER FEK?
|
||
POPJ P, ;NO, SLAVE FEKS DON'T DO INPUT
|
||
MOVE T1,FEKNIQ(J) ;GET COUNT OF INPUT PCBS ALREADY QUEUED
|
||
CAIL T1,4 ;GOT PLENTY?
|
||
POPJ P, ;YES, DON'T QUEUE UP TOO MANY
|
||
> ;END IFN FTENET
|
||
|
||
;ALLOCATE AN INPUT PCB
|
||
|
||
NETRD1: MOVEI T1,MSGMAW## ;BUFFER SIZE THAT IS THE LARGEST PCB
|
||
PUSHJ P,MKUPCB ;GET THE BUFFER SPACE
|
||
POPJ P, ;IF NO CORE, JUST EXIT (WILL TRY AGAIN LATER)
|
||
MOVEI T1,MSGMAX## ;GET, AND SET THE NUMBER OF BYTES
|
||
MOVEM T1,PCBCTR(U) ; AVAILABLE IN THE PCB.
|
||
|
||
;NOW QUEUE THE INPUT REQUEST
|
||
|
||
NETOFF ;WE MUST WORRY ABOUT RACES AGAIN.
|
||
SKIPE FEKIAD(J) ;MAKE SURE WE DIDN'T GET BEAT. IF SOMEONE SET
|
||
JRST [NETON ; A READ REQUEST JUST NOW, TURN INTERRUPTS ON
|
||
PJRST RMVPCB] ; RETURN THE BUFFER AND EXIT
|
||
HRRZM U,FEKIAD(J) ;POST THE INPUT BUFFER
|
||
NETON ;RE-ENABLE INTERRUPTS WITH BUFFER SET UP
|
||
|
||
;KICK THE FEK (POST READ REQUEST)
|
||
|
||
MOVEI T1,FF.RDD ;GET THE READ-REQUEST FUNCTION CODE
|
||
XCT FEKDSP(J) ; AND CALL THE FRONT END KONTROLLER
|
||
IFE FTENET,<POPJ P,> ;ALL DONE
|
||
IFN FTENET,<JRST NETRDD> ;SEE IF NEED MORE BUFFERS
|
||
SUBTTL FEKINT -- ENTRY POINT TO NETSER FROM FRONT END'S
|
||
;CALL J := FEK ADDRESS
|
||
; T1 := FUNCTION CODE
|
||
;RETURN CPOPJ ;CALLING ROUTINE MUST DISMISS THE INTERRUPT
|
||
|
||
FEKINT::TRNN J,-1 ;MAKE SURE FEK IS SET UP
|
||
STOPCD .,STOP,ANFZFK, ;++ ZERO FEK POINTER
|
||
CAIL T1,FI.RDD ;RANGE CHECK THE FUNCTION CODE
|
||
CAILE T1,FI.IDN ; (BETWEEN 0 & 4)
|
||
STOPCD .,STOP,ANFIFC, ;++ ILLEGAL FEKINT FUNCTION CODE
|
||
JRST @.+1(T1) ;DISPATCH TO APPROPRIATE ROUTINE
|
||
IFIW INPINT ;INPUT DONE INTERRUPT (VIA FEKIAD)
|
||
IFIW OUTINT ;OUTPUT DONE INTERRUPT
|
||
IFIW STCINT ;WE JUST GOT A BOOT MESSAGE IN "U"
|
||
IFIW KONDWN ;FRONT END JUST DIED
|
||
IFIW INPIDN ;INPUT DONE INTERRUPT (VIA FEKIDN)
|
||
;HERE WHEN A KONTROLLER GOES DOWN
|
||
KONDWN:
|
||
PUSHJ P,CLNFEK ;CLEAN OUT THE FEK
|
||
SETOM NTQRCT ;TELL NETSCN TO RECOMPUTE THE TOPOLOGY
|
||
PJRST NETQUE ;AND GO DO IT.
|
||
SUBTTL OUTINT - OUTPUT INTERRUPT PROCESSOR FOR ALL FEK'S
|
||
;OUTINT ROUTINE TO HANDLE THE OUTPUT DONE INTERRUPT FROM FEK'S
|
||
;CALL J := FEK ADDRESS
|
||
;RETURN CPOPJ
|
||
|
||
OUTINT: PUSH P,U ;SAVE U (THE FRONT END MAY CARE...)
|
||
SETZ U, ;GET A ZERO
|
||
EXCH U,FEKODN(J) ;GET THE PCB, CLEAR OUTPUT-DONE
|
||
SKIPN U ;MAKE SURE WE GOT A PCB
|
||
STOPCD .,STOP,ANFOUT, ;++ OUTPUT DONE WITH NO PCB
|
||
|
||
;NOW QUEUE THE PCB FOR NETSCN TO PROCESS (QUEUE TO WAIT FOR ACK)
|
||
NETOFF ;NO INTERRUPTS WHILE HACKING QUEUES
|
||
HRRZ T1,NTQOUT ;GET THE "REST" OF THE LIST
|
||
HRRM T1,PCBBLK(U) ;MAKE OUR PCB POINT TO THE "REST"
|
||
HRRZM U,NTQOUT ;MAKE THE LIST HEAD BE OUR PCB
|
||
NETON ;INTERRUPTS OK. QUEUE IS CONSISTENT
|
||
|
||
SETZM FEKHTM(J) ;CLEAR THE HUNG TIMER. FEK IS RUNNING
|
||
POP P,U ;GET FEK'S "U" BACK
|
||
; PUSHJ P,NETQUE ;QUEUE AN INTERRUPT TO NETSCN AND RETURN
|
||
; (SEE FOOTNOTE)
|
||
POPJ P, ;RETURN TO INTERRUPT ROUTINE
|
||
|
||
|
||
;*** FOOTNOTE ***
|
||
|
||
;We don't really need to run netser at this point. Since we are
|
||
; just going to queue the output PCB and wait for the ACK, we
|
||
; can postpone queueing the PCB until we get an input messsage.
|
||
SUBTTL INPINT - INPUT INTERRUPT PROCESSOR FOR ALL FEK'S
|
||
;INPINT ROUTINE TO HANDLE THE INPUT DONE INTERRUPT FROM FEK'S
|
||
;CALL J := FEK ADDRESS
|
||
;RETURN CPOPJ
|
||
|
||
INPIDN: PUSH P,U ;PRESERVE FEK'S "U"
|
||
SETZ U, ;GET A ZERO
|
||
EXCH U,FEKIDN(J) ;GET INPUT PCB, CLEAR INPUT-DONE POINTER
|
||
JRST INPIN0 ;CONTINUE WITH INPUT PROCESSING
|
||
|
||
INPINT: PUSH P,U ;PRESERVE FEK'S "U"
|
||
SETZ U, ;GET A ZERO
|
||
EXCH U,FEKIAD(J) ;GET INPUT PCB, CLEAR INPUT BUFFER POINTER
|
||
INPIN0: SKIPN U ;MAKE SURE THERE WAS ONE
|
||
STOPCD .,STOP,ANFINP, ;++ INPUT DONE, NO INPUT BUFFER
|
||
MOVE T2,PCBALN(U) ;ALLOCATED (I.E., MAX) SIZE OF PCB DATA BUFFER
|
||
LSH T2,2 ;CONVERT WORD SIZE TO BYTES
|
||
CAMGE T2,PCBCTR(U) ;IF DATA OVERFLOWED PCB'S BUFFER ALLOCATION
|
||
STOPCD CPOPJ##,STOP,PBO, ;++ PCB BUFFER OVERFLOW
|
||
|
||
;NOW QUEUE THIS PCB AT THE END OF THE INPUT PCB CHAIN
|
||
|
||
HRLM J,PCBFEK(U) ;REMEMBER THE FEK (FOR NODE ID)
|
||
NETOFF ;PROTECTION
|
||
SKIPE T1,NTQINP ;GET THE CURRENT INPUT PCB QUEUE
|
||
JRST INPIN2 ;AND PUT THIS PCB AT ITS TAIL
|
||
HRRZM U,NTQINP ;NO INPUT PCBS, THIS IS THE NEW FIRST PCB
|
||
JRST INPIN4 ;INPUT PCB SAFELY QUEUED
|
||
|
||
INPIN2: MOVE T2,T1 ;SAVE POTENTIAL NEW LAST PCB
|
||
HRRZ T1,PCBBLK(T1) ;LINK TO NEXT PCB IN CHAIN
|
||
JUMPN T1,INPIN2 ;KEEP GOING TILL FIND THE END
|
||
HRRM U,PCBBLK(T2) ;QUEUE THIS PCB AT THE END OF THE INPUT CHAIN
|
||
INPIN4: NETON ;ALL'S CLEAR NOW
|
||
|
||
;REPLENISH THE FEK AND START UP NETSER INPUT PROCESSING
|
||
|
||
PUSHJ P,NETRDD ;GIVE THE FEK A NEW INPUT BUFFER
|
||
POP P,U ;GET THE FEK'S "U" BACK
|
||
PUSHJ P,NETQUE ;AND QUEUE A CALL TO NETSCN
|
||
POPJ P, ;RETURN
|
||
SUBTTL STCINT -- ROUTINE TO QUEUE INCOMING MAINTENANCE MESSAGES
|
||
|
||
;STCINT ROUTINE TO ACCEPT MAINTENANCE MESSAGES FROM THE FRONT ENDS
|
||
;CALL U := POINTER TO STC BLOCK. NOTHING IN STCNNL(U) IS SET UP
|
||
|
||
STCINT: PUSHJ P,SAVJW## ;FOR CONVENIENCE... STC USUALLY GOES IN J
|
||
PUSHJ P,FEK2LN ;GET T1 := THE LINE NUMBER
|
||
HRRZM T1,STCLNN(U) ;STORE THE LINE NUMBER TO RETURN TO USER
|
||
MOVE W,J ;GET W := FEK
|
||
MOVE J,U ;AND J := STC
|
||
SKIPE FEKICT(W) ;IF THERE IS ALREADY A MESSAGE QUEUED,
|
||
PJRST GIVSTC ; FREE THIS ONE IMMEDIATLY AND RETURN.
|
||
HRLI J,^D10 ;GIVE THE MESSAGE A 10 SEC TIME OUT
|
||
MOVEM J,FEKICT(W) ;STORE THE NEW "XWD TIMER,MSG" IN THE FEK
|
||
SKIPE T1,FEKBJN(W) ;IF SOMEONE IS WAITING FOR A STC MSG
|
||
JRST EWAKE## ; THEN WAKE HIM AND RETURN
|
||
PJRST FRCNLD ;OTHERWISE WAKE NETLDR TO LOOK AT IT.
|
||
;HERE ONCE A TICK TO START TERMINAL OUTPUT FOR ALL LINES IN THE QUEUE
|
||
; WE ALSO CHECK EACH OF THE FEKS ON THIS CPU TO SEE IF THEY
|
||
; NEED SUCH THINGS DONE AS THEIR INPUT, OR OUTPUT STARTED
|
||
|
||
NETSTO::SKIPA J,[FEKFST##] ;GET THE ADDRESS OF THE FIRST FEK
|
||
NETST1: HRRZ J,FEKBLK(J) ;GET THE ADDRESS OF THE NEXT FEK
|
||
JUMPE J,NETST5 ;IF NO MORE, GO DO REST OF JIFFY CODE
|
||
IFN FTMP,< ;IF A SMP SYSTEM, ONLY TIME ON OWNING CPU
|
||
HLRE T1,FEKUNI(J) ;GET THE CPU NUMBER
|
||
SKIPGE T1 ;IF IT CAN RUN ON ANY CPU,
|
||
MOVE T1,BOOTCP## ; CALL IT ONLY ON THE BOOT CPU
|
||
CAME T1,.CPCPN## ; AND SKIP IF IT'S US
|
||
JRST NETST1 ;WRONG CPU. GO CHECK NEXT FEK
|
||
>
|
||
NETST2: SKIPL T1,FEKBLK(J) ;GET THE FLAGS AND CHECK FK.ONL
|
||
JRST NETST1 ;EITHER FEK OFFLINE, OR NOT ON THIS CPU
|
||
MOVSI T2,FK.STO ;GET THE "FEK WANTS OUTPUT STARTED" BIT
|
||
TDNN T2,FEKBLK(J) ;DOES THE FEK WANT TO GET POKED
|
||
JRST NETST3 ;DOESN'T WANT A KICK
|
||
ANDCAB T2,FEKBLK(J) ;CLEAR THE BIT NOW (PREVENTS A RACE)
|
||
MOVEI T1,FF.WRT ;GET THE FEK WRITE FUNCTION CODE
|
||
XCT FEKDSP(J) ;DISPATCH TO GIVE THE FEK AN OUTPUT POKE
|
||
NETST3: MOVSI T2,FK.STI ;GET THE "NEEDS INPUT STARTED" BIT
|
||
TDNN T2,FEKBLK(J) ;DOES THE FEK WANT TO DO INPUT
|
||
JRST NETST4 ;DOESN'T WANT A KICK
|
||
ANDCAB T2,FEKBLK(J) ;CLEAR NOW BEFORE OTHER CPU MAY SET IT
|
||
MOVEI T1,FF.RDD ;GET THE "SET UP READ REQUEST" FUNCTION
|
||
XCT FEKDSP(J) ;TELL THE FEK IT HAS AN INPUT BUFFER TO FILL
|
||
NETST4: JRST NETST1 ;LOOP OVER ALL FEK'S
|
||
|
||
NETST5:
|
||
IFN FTMP,<
|
||
SKPCPU (0) ;IF NOT ON THE BOOT CPU
|
||
POPJ P, ;DON'T CALL NETSCN (NO NEED TO)
|
||
>
|
||
SETOM NTQJIF ;SIGNAL A JIFFY.
|
||
PJRST NETSCN ; AND GO PROCESS INTERLOCKED CODE
|
||
;NETINT THIS IS WHERE THE NETSER SOFTWARE GENERATED INTERRUPTS ARE
|
||
; HANDLED. AN INTERRUPT IS GENERATED BY THE SUBROUTINE
|
||
; "NETLKU" ONLY WHEN THE "NT" INTERLOCK IS RELEASED AND THE
|
||
; FLAG "NTRQST" IS SET. THE PURPOSE OF THIS IS TO LET
|
||
; NETSER CONTINUE WITH SOMETHING THAT HAPPENED AT INTERRUPT
|
||
; LEVEL WHILE SOME JOB HAD THE "NT" INTERLOCK. THE ONLY
|
||
; REASON THAT THIS INTERRUPT IS USED, RATHER THAN CALLING
|
||
; NETSCN DIRECTLY, IS THAT IT TURNS OFF THE ACCOUNTING
|
||
; METERS.
|
||
NETINT::
|
||
SETZM .CPNTF## ;CLEAR THE INDICATOR
|
||
CONO PI,CLRNET## ;CLEAR THE INTERRUPT
|
||
PJRST NETSCN ;AND SEE WHAT NETSCN WANTED.
|
||
|
||
|
||
;NETQUE THIS IS THE ROUTINE TO CALL TO SET UP A INTERRUPT TO RUN NETSCN
|
||
|
||
NETQUE::CONO PI,PI.OFF ;MAKE SURE THAT DIFFERENT PI LEVELS
|
||
SETOM .CPNTF## ; DON'T SET THE FLAG AT ONCE
|
||
CONO PI,PI.ON+REQNET## ;CAUSE THE INTERRUPT
|
||
POPJ P, ; AND RETURN
|
||
SUBTTL NETSCN -- QUEUE DRIVEN NETSER 'LOOP' LEVEL
|
||
|
||
;NETSCN -- THIS ROUTINE IS CALLED AT INTERRUPT LEVEL. IT PROCESSES ENTRIES
|
||
; IN THE FOLLOWING QUEUES
|
||
; A) NTQRCT THIS IS A QUEUE OF FEK REQUESTS.
|
||
; B) NTQJIF THIS IS A FLAG THAT IS SET ONCE A JIFFY. IT
|
||
; ENABLES 'JIFFY' PROCESSING. (IE STARTING TERMINAL OUTPUT)
|
||
; C) NTQOUT THIS IS A QUEUE OF UN-SORTED OUTPUT MESSAGES. (IE JUST AS
|
||
; THEY ARE GIVEN BACK BY THE FEK'S). NETSCN REMOVES MESSAGES
|
||
; FROM THIS QUEUE AND APPENDS THEM TO THE RH(NDBQUE) OF THE
|
||
; APPRIOATE NDB WHERE THEY THEN WAIT FOR AN ACK TO FREE THEM.
|
||
; D) NTQINP THIS IS A QUEUE OF UN-SORTED INPUT MESSAGES.
|
||
; NTSC.I ROUTES THEM TO THE APPROPRIATE NDB'S
|
||
; E) NTQNDB THIS IS A QUEUE OF NDB'S THAT NEED SERVICE.
|
||
; THE PRIMARY REASON THAT AN NDB WILL NEED SERVICE IS
|
||
; THAT IT HAS INPUT DATA TO PROCESS (FROM NTQINP)
|
||
; F) NTQSEC THIS IS A FLAG THAT ENABLES THE ONCE PER SECOND
|
||
; PROCESSING (IE REP TIMING ETC)
|
||
;
|
||
; NETSCN IS MEANT TO BE CALLED FROM INTERRUPT LEVEL. IT FIRST CHECKS
|
||
; THE INTERLOCK (THE NT INTERLOCK) TO SEE IF IT CAN PROCESS IMEDIATLY.
|
||
; IF IT CAN, IT SETS THE INTERLOCK BUSY AND GOES TO WORK. IF IT CAN'T
|
||
; GET THE INTERLOCK IT RETURNS IMMEDIATLY.
|
||
; NOTE!! ANY ONE WHO REQUESTS THE INTERLOCK SHOULD CALL NETSCN UPON
|
||
; RELEASING IT. (THIS WILL BE DONE AUTOMATICALLY BY NETLKU)
|
||
|
||
NETSCN: SE1ENT ;ENTER SECTION 1
|
||
PUSHJ P,INTLVL## ;NETSCN MUST RUN AT A INTERRUPT LEVEL.
|
||
STOPCD .,STOP,ANFNIL, ;++ NOT AT INTERRUPT LEVEL
|
||
NTDBLI ;TRY TO GET THE INTERLOCK
|
||
JRST [SETOM NTRQST ; BUT IF WE CAN'T, JUST SET THIS FLAG
|
||
POPJ P,] ; AND RETURN
|
||
PUSHJ P,SAVJW## ;SAVE THESE
|
||
PUSHJ P,SAVE4 ; AND THESE
|
||
|
||
SKIPE NTQRCT ;NEED TO RECOMPUTE TOPOLOGY??
|
||
PUSHJ P,NTSC.R ; IF SO, GO DO IT.
|
||
SKIPE NTQJIF ;JIFFY?
|
||
PUSHJ P,NTSC.J ; IF SO ...
|
||
SKIPE NTQOUT ;OUTPUT DONE INTERRUPTS??
|
||
PUSHJ P,NTSC.O ; ...
|
||
SKIPE NTQINP ;INPUT MESSAGES TO PROCESS??
|
||
PUSHJ P,NTSC.I ; ...
|
||
SKIPE NTQNDB ;NDB'S THAT WANT SERVICING??
|
||
PUSHJ P,NTSC.N ; ...
|
||
SKIPE NTQSEC ;ONCE/SECOND PROCESSING TO DO???
|
||
PUSHJ P,NTSC.S
|
||
|
||
SETZM NTRQST ;CLEAR THE "REQUEST INTERRUPT" FLAG
|
||
NTDBUI ;RETURN THE 'NT' INTERLOCK
|
||
POPJ P, ;AND RETURN
|
||
;HERE WHEN NETSCN WANTS TO RECOMPUTE THE TOPOLOGY
|
||
|
||
NTSC.R: ;HERE TO REBUILD OUR NEIGHBORS TABLE
|
||
SETZM NTQRCT ;CLEAR THE REQUEST
|
||
PUSHJ P,RCMPTP ;RECOMPUTE THE TOPOLOGY
|
||
PUSHJ P,SETNBN ;NOW SEND NEIGHBORS MESSAGES TO EVERYONE
|
||
POPJ P, ;ALL DONE
|
||
;HERE FOR ONCE/JIFFY STUFF. FUNCTIONS PERFORMED ONCE/JIFFY ARE
|
||
; 1) STARTING TERMINALS AND VTMS
|
||
; 2) WE CHECK TO SEE IF WE OWE ANYONE AN ACK AND IF SO, SEND IT
|
||
|
||
NTSC.J: SETZM NTQJIF ;SAY WE PROCESSED THE JIFFY,
|
||
|
||
PUSHJ P,MCRJIF## ;START UP NETWORK MCRS
|
||
PUSHJ P,VTMJIF## ;START UP NETWORK VIRTUAL TERMINALS
|
||
|
||
;NOW SEE IF ANY NODES NEED ACK'S SENT
|
||
|
||
SKIPN NTFACK ;DID WE RECEIVE ANY MSGS LAST JIFFY
|
||
JRST NTSCJ2 ;IF NOT, THEN WE DON'T NEED TO SEND ACKS
|
||
SETZM NTFACK ;CLEAR THE "MAY NEED TO ACK" FLAG
|
||
|
||
MOVEI W,NETNDB ;GET THE ADDRESS OF THE FIRST NDB
|
||
NTSCJ1: HRRZ W,NDBNNM(W) ;GET THE NEXT NDB (SKIP NETNDB)
|
||
JUMPE W,NTSCJ2 ;EXIT IF WE'VE CHECKED ALL NODES
|
||
LDB T1,NDBLMP ;GET THE LAST MESSAGE PROCESSED
|
||
LDB T2,NDBLAS ; AND THE LAST ACK SEND
|
||
CAMN T1,T2 ;IF WE OWE THE REMOTE AN ACK,
|
||
JRST NTSCJ1 ;DON'T COUNT NEED ACK FLAG
|
||
PUSHJ P,NCSACK ; THEN SEND HIM ONE
|
||
AOS NTFACK ;IF WE FAIL, SET THE FLAG AGAIN
|
||
JRST NTSCJ1 ;LOOP OVER ALL NDBS
|
||
|
||
NTSCJ2: POPJ P, ;ALL DONE WITH JIFFY PROCESSING
|
||
;NTSC.O -- ROUTINE TO PROCESS MESSAGES THAT HAVE BEEN OUTPUT BY FEK'S
|
||
; AFTER A MESSAGE HAS BEEN SENT OUT BY A FEK, IT IS PUT ON THE QUEUE
|
||
; "NTQOUT". THIS ROUTINE (UNDER PROTECTION OF THE NETSER INTERLOCK)
|
||
; ATTEMPTS TO PROPERLY DISPOSE OF THESE MESSAGES. THE BASIC ALGORITHM IS:
|
||
; 1) IF IT IS A NUMBERED MESSAGE, THEN WE MUST QUEUE IT ON
|
||
; RH(NDBQUE) FOR THE APPROPRIATE NDB. THE MESSAGE WILL
|
||
; REMAIN HERE UNTIL DESTROYED BY AN ACK FROM THE OTHER
|
||
; NODE
|
||
; 2) IF IT IS AN UNNUMBERED MESSAGE THE MESSAGE IS DESTROYED
|
||
; IMMEDIATLY. (NOTE THAT ROUTE-THROUGH MESSAGES ARE
|
||
; UNNUMBERED, AND HENCE THEY WILL NOT BE PUT ON THE
|
||
; THE RH(NDBQUE). THIS IS A CONVENIENT ARTIFACT OF THE MANNER
|
||
; IN WHICH THE "NUMBERED MESSAGE FLAG" (PCB.NM) IS KEPT)
|
||
|
||
NTSC.O: SKIPN NTQOUT ;ANYTHING IN THE QUEUE
|
||
POPJ P, ;NOPE. LOOK ELSE WHERE FOR BUSY WORK
|
||
|
||
NETOFF ;NO PI WHILE MODIFYING THE LIST
|
||
HRRZ U,NTQOUT ;GET THE HEAD OF THE LIST
|
||
HRRZ T1,PCBBLK(U) ; GET THE REST OF THE LIST
|
||
HRRZM T1,NTQOUT ; AND MAKE THAT THE LIST
|
||
NETON
|
||
MOVE T1,PCBCTR(U) ;GET THE FIRST OUTPUT BYTE COUNT
|
||
ADD T1,PCBCT2(U) ;PLUS THE SECOND BUFFER'S BYTE COUNT
|
||
ADDM T1,%NTBYO ;COUNT TOTAL BYTES OUTPUT
|
||
MOVE T1,PCBBLK(U) ;GET THE FLAGS AND POINTER
|
||
HLLZS PCBBLK(U) ;CLEAR THE LINK POINTER
|
||
JUMPGE T1,NTSCO1 ;UNNUMBERED. FLUSH IT NOW
|
||
HRRZ T1,PCBNNM(U) ;GET THE NODE NUMBER
|
||
PUSHJ P,SRCNDB ;SET UP W FROM THE NODE NUMBER
|
||
JRST NTSCO1 ;THE NODE WENT AWAY. FLUSH THE PCB
|
||
CAIN W,NETNDB## ;IF THIS MESSAGE IS FROM THE NULFEK,
|
||
JRST [AOS NDBMOM(W) ; BUMP OUR MAX OUTSTANDING MSG COUNTER
|
||
JRST NTSCO1] ; AND FREE THE PCB (WE DON'T ACK OURSELF...)
|
||
LDB T1,PCBMSN ;GET THE NUMBER OF THE MESSAGE SENT
|
||
DPB T1,NDBLMS ;SAVE AS LAST SENT
|
||
MOVSI T1,(POINT 18,0,35) ;HERE GENERATE A POINTER TO THE
|
||
HRRI T1,NDBQUE(W) ;RH OF NDBQUE(W)
|
||
S0PSHJ ENQPCB ;AND USE IT TO QUEUE THE PCB.
|
||
JRST NTSC.O ;AND GO BACK FOR MORE
|
||
|
||
NTSCO1: ;HERE DELETE THE PCB AND GO BACK
|
||
S0PSHJ RMVPCB ;DELETE THE PCB
|
||
JRST NTSC.O ;AND DO NEXT MESSAGE
|
||
;NTSC.I -- ROUTINE TO PROCESS INPUT MESSAGES.
|
||
; WHEN MESSAGES COME IN FROM A FEK, THEY ARE ENQUEUED ON THE QUEUE NTQINP.
|
||
; THIS ROUTINE (UNDER PROTECTION OF THE NETSER INTERLOCK) ATTEMPTS TO
|
||
; ROUTE THE MESSAGES TO THE APPROPRIATE QUEUES FOR FURTHER PROCESSING. THE
|
||
; BASIC ALGORITHM IS:
|
||
; A) REMOVE THE MESSAGE AND LOOK AT ITS NCT. IF IT IS
|
||
; A NODE ID, THEN QUEUE IT ON THE LH(NDBQUE) OF NETNDB.
|
||
; B) READ THE DESTINATION ADDRESS, AND IF IT'S NOT FOR US,
|
||
; ATTEMPT TO ROUTE IT THROUGH TO THE DESTINATION NODE.
|
||
; C) IF IT IS FOR US, THEN QUEUE IT (ORDERED BY MESSAGE NUMBER)
|
||
; ON THE LH(NDBQUE) OF THE SOURCE NODE'S NDB. ALSO MARK
|
||
; THE NDB AS "NEEDING SERVICE". NTSC.N WILL TAKE OVER FROM
|
||
; THERE.
|
||
; POINTS TO NOTE:
|
||
; 1) ACK'S ARE NOT PROCESSED AT THIS TIME. (THERE MAY BE
|
||
; SOMETHING "WRONG" WITH THE MESSAGE)
|
||
; 2) THIS CODE SETS THE NUMBERED MESSAGE FLAG (PCB.NM) ON
|
||
; NUMBERED MESSAGES DESTINED FOR US. (BUT NOT ROUTE-THROUGH
|
||
; MESSAGES)
|
||
|
||
NTSC.I: SKIPN NTQINP ;ANY MORE INPUT??
|
||
POPJ P, ;NOPE. GO BACK TO NETSCN.
|
||
NETOFF ;PROTECTION
|
||
HRRZ U,NTQINP ;GET FIRST PCB
|
||
HRRZ T1,PCBBLK(U) ;GET REST OF LIST
|
||
HRRZM T1,NTQINP ; AND SAVE IT FOR LATER.
|
||
NETON ;ALL'S CLEAR
|
||
MOVE T1,PCBCTR(U) ;GET THE INPUT BYTE COUNT,
|
||
ADDM T1,%NTBYI ; AND COUNT THESE INPUT BYTES
|
||
MOVSI T1,PCB.NM ;ASSUME THAT THIS IS AN UN-NUMBERED
|
||
ANDCAM T1,PCBBLK(U) ; MESSAGE. (IN CASE ROUTE-THROUGH)
|
||
HLLZS PCBBLK(U) ;CLEAR ANY STRAY POINTERS
|
||
SETZB W,F ;CLEAR THE NDB POINTER,DDB POINTER
|
||
MOVE P1,PCBPTR(U) ;GET THE INPUT MESSAGE POINTER
|
||
MOVE P4,PCBCTR(U) ;GET THE INPUT BYTE COUNT
|
||
JUMPLE P4,NTSCI3 ;ZERO LENGTH IS ILLEGAL
|
||
;NCT
|
||
PUSHJ P,EBI2BI ;READ THE FLAGS
|
||
HRLZM T1,NTFLGS ;SAVE THE FLAGS
|
||
ANDI T1,NCT.TP ;JUST THE MESSAGE TYPE
|
||
MOVE T2,NTFLGS ;GET FLAGS BACK
|
||
TLNE T2,NCT.RH ;ROUTING HEADER PRESENT
|
||
JRST NTSCI1 ;YES,
|
||
CAIE T1,NCT.ID ;IS THIS AN ID MESSAGE
|
||
JRST NTSCI3 ;NO, BAD MESSAGE
|
||
|
||
MOVEI W,NETNDB ;QUEUE NODE ID AS INPUT FROM OUR NODE
|
||
; SINCE WE PROBABLY DON'T HAVE AN NDB FOR IT
|
||
PJRST NTSCI2 ;AND NOW ENQUEUE THE MESSAGE FOR NEXT LEVEL
|
||
NTSCI1:
|
||
;DNA
|
||
PUSHJ P,EBI2BI ;GET <DNA>
|
||
HLRZ T2,NDBNNM+NETNDB;GET OUR NODE NUMBER
|
||
CAIE T1,(T2) ;IS IT FOR US?
|
||
JRST [S0PSHJ NETHRU ;IN ONE EAR AND OUT THE OTHER
|
||
JRST NTSC.I] ; AND CHECK FOR ANY OTHER INPUT
|
||
;SNA
|
||
PUSHJ P,EBI2BI ;YES, GET THE <SNA>
|
||
PUSHJ P,SRCNDB ;FIND THE NODE BLOCK
|
||
JRST NTSCI3 ;SOURCE NODE WENT AWAY
|
||
;NCA
|
||
|
||
ILDB T1,P1 ;GET THE ACK NUMBER
|
||
PUSHJ P,CHKNCA ;ACK IT NOW TO PREVENT DEADLOCKS
|
||
;NCN
|
||
ILDB T1,P1 ;GET THIS MESSAGE NUMBER
|
||
MOVE T2,NTFLGS ;FLAGS
|
||
TLNE T2,NCT.TP ;IS THIS A NUMBERED MESSAGE?
|
||
JRST NTSCI2 ;IF NOT, DON'T PLAY WITH IT ANY MORE
|
||
DPB T1,PCBMSN ;SAVE THE NUMBER IN THE PCB
|
||
MOVSI T1,PCB.NM ;GET AND
|
||
IORM T1,PCBBLK(U) ; SET THE NUMBERED MESSAGE FLAG
|
||
NTSCI2: MOVSI T1,(POINT 18,0,17) ;BUILD A BYTE POINTER
|
||
HRRI T1,NDBQUE(W) ; TO NDBQUE (LH)
|
||
S0PSHJ ENQPCB ;AND QUEUE THE PCB FOR CLOCK LEVEL
|
||
S0PSHJ ENQNDB ;MAKE SURE THE NDB GETS SCANNED
|
||
JRST NTSC.I ;NOW GO BACK AND SEE IF THERE ARE ANY MORE
|
||
|
||
NTSCI3: PUSHJ P,INCTBP ;HERE WE FLUSH A GARBAGE MESSAGE
|
||
JRST NTSC.I ;SEE IF THERE ARE ANY MORE
|
||
;NTSC.N -- ROUTINE TO SERVICE AN NDB.
|
||
; THIS ROUTINE PROCESSES NDB'S THAT HAVE BEEN "QUEUED" ON THE QUEUE
|
||
; "NTQNDB". THIS ROUTINE PERFORMS THE FOLLOWING SERVICES FOR AN
|
||
; NDB:
|
||
; 1) IT PROCESSED QUEUED INPUT MESSAGES FROM THE RH(NDBQUE)
|
||
; 2) IT SENDS ANY OTHER "SPECIAL" MESSAGES THAT MAY BE
|
||
; REQUIRED BY THE NODE. (MOST NOTABLY NAK'S)
|
||
; THE PROCESSING OF INPUT MESSAGES (1) CAN BE BROKEN UP INTO THE
|
||
; FOLLOWING PHASES:
|
||
; A) TAKE THE FIRST MESSAGE OFF OF THE RH(NDBQUE) AND
|
||
; GET ITS NETWORK CONTROL TYPE (NCT). IF IT'S A NODE-ID
|
||
; THEN GO PROCESS IT IMMEDIATLY
|
||
; B) IF WE ARE NOT CURRENTLY IN CONTACT (START-STACK EXCHANGED)
|
||
; WITH THE NODE, THROW AWAY ALL MESSAGES EXCEPT START OR
|
||
; STACK.
|
||
; C) PERFORM A CURSORY VALIDITY CHECK OF THE MESSAGE AND
|
||
; PROCESS THE NETWORK CONTROL ACK (NCA) FIELD.
|
||
; D) IF IT IS AN UNNUMBERED MESSAGE, THEN PROCESS IT
|
||
; IMMEDIATLY.
|
||
; E) IF IT IS A NUMBERED MESSAGE, THEN CHECK TO SEE IF IT IS
|
||
; THE "NEXT" MESSAGE IN SEQUENCE. IF IT IS
|
||
; 1) A REPEATED MESSAGE, THEN DELETE IT
|
||
; 2) THE NEXT MESSAGE, THEN PROCESS IT
|
||
; 3) AN "OUT OF ORDER" MESSAGE, THEN RE-QUEUE IT ON THE
|
||
; RH(NDBQUE) AND EXIT PROCESSING INPUT MESSAGES.
|
||
; NOTE THAT THERE IS NO 100% SAFE WAY TO TELL WEATHER OR
|
||
; NOT A MESSAGE IS A REPEATED MESSAGE, OR ONE THAT
|
||
; ARRIVED EARLY. THE ALGORITHM IMPLEMENTED HERE ASSUMES
|
||
; THAT MESSAGES UP TO 127 AHEAD OF THE LAST MESSAGE PROCESSED
|
||
; ARE MESSAGES THAT ARRIVED EARLY, AND ALL OTHERS (EXCEPT THE
|
||
; "NEXT") ARE REPEATED MESSAGES.
|
||
|
||
NTSC.N: SKIPN T2,NTQNDB ;ANY NDB'S TO PROCESS
|
||
POPJ P, ;NO. GO CHECK SOMETHING ELSE
|
||
NETOFF ;GUARD AGAINST UNRULY FEK'S
|
||
HRRZ W,NTQNDB ;GET THE NDB,
|
||
HRRZ T1,NDBFLG(W) ;GET THE LINK TO NEXT NDB IN QUEUE
|
||
HRRZM T1,NTQNDB ;SPLICE THIS NDB OUT OF THE QUEUE
|
||
HRLOI T1,NDB.NQ ;GET THE 'THIS NDB IS QUEUED' BIT
|
||
ANDCAM T1,NDBFLG(W) ;AND CLEAR IT IN NDBFLG
|
||
NETON ;NTQNDB QUEUE IS CONSISTENT AGAIN
|
||
HRRZ J,NDBFEK(W) ;SET UP J FOR INCTNK AND NCSSTR (AND OTHERS)
|
||
;DROP THROUGH
|
||
;FROM ABOVE
|
||
;W := NEXT NDB TO PROCESS
|
||
|
||
NTSCN1: ;HERE TO PROCESS THE NEXT INPUT MESSAGE ON THE LH OF NDBQUE(W)
|
||
NETOFF ;WATCH OUT. A FEK MIGHT PUT ONE ON
|
||
HLRZ U,NDBQUE(W) ;GET FIRST PCB
|
||
JUMPE U,[ NETON ;IF NONE, THEN
|
||
JRST NTSCN5]; SEE WHAT ELSE NEEDS TO BE DONE
|
||
MOVE T1,PCBBLK(U) ;GET "XWD FLAGS,LINK" FROM PCB
|
||
HRLM T1,NDBQUE(W) ; AND SPLICE OUT THE PCB
|
||
NETON ;NDBQUE IS CONSISTENT AGAIN.
|
||
HLLZS PCBBLK(U) ;IT'S NOT POLITE TO POINT. (TO BE SURE!)
|
||
|
||
; NOW PROCESS THE PCB
|
||
|
||
IFN PARANOID&P$EAT,< ;HACK TO EAT EVERY N'TY MESSAGE
|
||
MOVEI T1,NETNDB## ;SEE IF THIS IF FROM US
|
||
CAIN T1,(W) ;IF SO, THEN
|
||
JRST STARVE ;DON'T EAT THE MESSAGE (WE DON'T REP OURSELF)
|
||
SOSG %TROLL ;HAVE WE COUNTED DOWN YET?
|
||
PJSP T1,[PUSHJ P,INCTBD ;IF SO, TOSS THIS MESSAGE
|
||
MOVEI T1,100 ;RESET THE
|
||
MOVEM T1,%TROLL; COUNTER
|
||
JRST NTSCN1] ;AND GO GET THE NEXT ONE
|
||
STARVE: ;HERE IF WE CAN'T EAT THE MSG
|
||
|
||
>
|
||
MOVE P4,PCBCTR(U) ;GET THE LENGTH OF THE MESSAGE.
|
||
MOVE P1,PCBPTR(U) ;GET THE BYTE POINTER
|
||
;NCT
|
||
PUSHJ P,EBI2BI ;GET THE FLAGS
|
||
HRLZM T1,NTFLGS ;WEVE ALREADY GOT THEM BUT..
|
||
|
||
ANDI T1,NCT.TP ;ISOLATE THE TYPE
|
||
AOS NCLRTP(T1) ;TALLY
|
||
MOVE T2,NTFLGS ;GET FLAGS BACK
|
||
TLNE T2,NCT.RH ;ROUTING INFORMATION PRESENT?
|
||
JRST NTSCN2 ;YES. CONTINUE
|
||
CAIE T1,NCT.ID ;NO ROUTINE, IS IT A NODE-ID?
|
||
STOPCD .,STOP,ANFMSQ, ;++ MESSAGE QUEUES ARE SCREWED UP
|
||
S0PSHJ INCTID ;GO PROCESS THE NODE-ID MESSAGE
|
||
JRST NTSCN8 ;FREE PCB AND GET NEXT MESSAGE
|
||
;HERE FROM ABOVE IF THE MESSAGE HAS A ROUTING HEADER (IE ISN'T A NODE-ID)
|
||
|
||
NTSCN2: MOVE T2,NDBFLG(W) ;IS THIS NODE UP AND RUNNING?
|
||
TLNE T2,NDB.UP ;SKIP IF NOT
|
||
JRST NTSCN3 ;IT IS, CONTINUE PROCESSING
|
||
CAIE T1,NCT.ST ;SINCE IT'S NOT RUNNING, SEE IF THIS
|
||
CAIN T1,NCT.SK ;IS A START OR A STACK
|
||
JRST NTSCN3 ;IF IT IS, OK
|
||
TLNE T2,NDB.SK ;IF WE ARE SENDING STACKS,
|
||
JRST [PUSHJ P,NODEUP ;THEN ANY MESSAGE GETS US INTO "RUN" STATE
|
||
JRST NTSCN3] ;NOW GO PROCESS THE MESSAGE
|
||
PUSHJ P,INCTBP ;IF WE AREN'T RUNNING, SIGNAL BAD MESSAGE,
|
||
JRST NTSCN1 ;AND GO BACK FOR ANOTHER
|
||
|
||
NTSCN3: ;HERE TO DO A LITTLE MORE CHECKING
|
||
;DNA
|
||
PUSHJ P,EBI2BI ;GET DNA
|
||
HLRZ T2,NETNDB+NDBNNM;GET OUR NODE NUMBER
|
||
CAIE T1,(T2) ;BETTER BE THE SAME
|
||
STOPCD .,STOP,ANFRDN, ;++ ROUTING HEADER HAS BAD DESTINATION NODE
|
||
;SNA
|
||
PUSHJ P,EBI2BI ;GET SOURCE NODE NUMBER
|
||
HLRZ T2,NDBNNM(W) ;GET THE NODE NUMBER OF THIS NDB
|
||
CAIE T1,(T2) ;BETTER BE THE SAME
|
||
STOPCD .,STOP,ANFRSN, ;++ ROUTING HEADER HAS BAD SOURCE NODE
|
||
;NCA
|
||
PUSHJ P,BYT2BI ;GET THE IMPLICIT ACK (ALREADY PROCESSED)
|
||
;NCN
|
||
PUSHJ P,BYT2BI ;GET THE MESSAGE NUMBER AND
|
||
MOVE T2,NTFLGS ;GET FLAGS BACK
|
||
TLNE T2,NCT.TP ;SKIP IF IT IS A NUMBERED MESSAGE
|
||
JRST INCTUN ;IT'S NOT, GO PROCESS UNNUMBERED MESSAGE
|
||
DPB T1,NDBLMR ;SET LAST MESSAGE RECEIVED
|
||
LDB T2,NDBLMP ;GET LAST MESSAGE PROCESSED
|
||
ADDI T2,1 ;GET NUMBER OF NEXT MESSAGE TO PROCESS
|
||
ANDI T2,377 ;MAKE SURE IT'S MOD(1000)
|
||
SUBI T1,(T2) ;IF THIS IS 'NEGATIVE' WE'VE SEEN IT BEFORE
|
||
TRNE T1,200 ;IF THIS MESSAGE HAS BEEN SEEN
|
||
JRST NTSCN8 ; BEFORE, THEN TOSS IT
|
||
JUMPN T1,NTSCN4 ;AN OUT OF ORDER (EARLY) MESSAGE
|
||
|
||
;DROP THROUGH IF THIS IS THE NEXT MESSAGE TO PROCESS (IE IS IN
|
||
; SEQUENCE)
|
||
;HERE FROM ABOVE WITH U POINTING TO THE NEXT MESSAGE TO PROCESS
|
||
; SINCE SOME MESSAGES REQUIRE IMMEDIATE RESPONSE, MAKE SURE THAT WE CAN
|
||
; SEND AT LEAST ONE RESPONSE BEFORE WE PROCESS THE MESSAGE. I THINK
|
||
; THAT THIS IS TERRIBLE CODE, BUT I'M AT A LOSS AS TO HOW TO
|
||
; HANDLE THIS PROBLEM.
|
||
|
||
PUSHJ P,PCBECK ;MAKE SURE THERE ARE "EMERGENCY"
|
||
; RESERVES AVAILABLE
|
||
JRST NTSCN4 ;NO FREE MESSAGES
|
||
JRST INCTNM ;ALL'S OK. GO PROCESS THE 'NEXT' MESSAGE.
|
||
; (INCTNM WILL RETURN TO NTSCN8)
|
||
|
||
;HERE IF A MESSAGE ARRIVES OUT OF ORDER OR FOR SOME REASON (NO CORE
|
||
; OR NO FREE MESSAGE NUMBERS) WE CAN'T PROCESS IT
|
||
|
||
NTSCN4: MOVSI T1,(POINT 18,0,17);CONJURE UP A POINTER TO THE
|
||
HRRI T1,NDBQUE(W) ;THE LH OF NDBQUE
|
||
S0PSHJ ENQPCB ;RE-QUEUE THE PCB (BUT NOT THE NDB)
|
||
; PJRST NTSCN5 ;"FINISH" UP WITH ANY SPECIAL MESSAGES
|
||
;HERE WHEN WE ARE DONE PROCESSING MESSAGES FROM NDBQUE. (EITHER
|
||
; BECAUSE THERE ARE NO MORE, WE ARE OUT OF CORE, NO FREE MESSAGE
|
||
; NUMBERS, OR THERE ARE OUT OF ORDER MESSAGES). THIS CODE CHECKS
|
||
; TO SEE IF ANY SPECIAL (ACK, NAK) MESSAGES ARE REQUIRED.
|
||
|
||
|
||
NTSCN5: MOVEI T1,NETNDB## ;FIRST CHECK TO MAKE SURE THAT WE AREN'T
|
||
CAIN T1,(W) ; TRYING TO SEND ANY ACK'S, NAK'S OR REP'S
|
||
JRST NTSCN7 ; TO OURSELF.
|
||
MOVSI T1,NDB.XN ;GET THE 'NEED TO NAK' FLAG
|
||
TDNN T1,NDBFLG(W) ;SKIP IF WE DO.
|
||
JRST NTSCN6 ;NOPE. DON'T NEED TO
|
||
PUSHJ P,NCSNAK ;TRY TO SEND THE NAK
|
||
JRST NTSCN6 ;WE CAN'T. TRY LATER
|
||
MOVSI T1,NDB.XN ;GET THE FLAG BACK
|
||
ANDCAM T1,NDBFLG(W) ;AND CLEAR IT
|
||
NTSCN6: AOS NTFACK ;SET FLAG SAYING WE MAY NEED TO ACK IN JIFFY
|
||
NTSCN7: JRST NTSC.N ;NOW GO DO THE NEXT NODE
|
||
|
||
|
||
;HERE ON RETURNS FROM INCTUN AND INCTNM AS WELL AS FROM VARIOUS
|
||
; PLACES IN NTSC.N. FLUSH THE PCB (IF ANY) AND ATTEMPT TO PROCESS
|
||
; THE NEXT MESSAGE IN ORDER.
|
||
|
||
NTSCN8: S0PSHJ RMVPCB ;RETURN THE PCB
|
||
AOS NTFACK ;SIGNAL THAT AN ACK IS PENDING
|
||
JRST NTSCN1 ;GET NEXT ITEM OFF OF LH(NDBQUE)
|
||
;HERE FOR ONCE PER SECOND PROCESSING
|
||
|
||
NTSC.S: SETZM NTQSEC ;CLEAR THE SECOND FLAG
|
||
|
||
;HERE TO SCAN THE NDB'S
|
||
|
||
MOVEI W,NETNDB## ;FIRST NODE TO CHECK
|
||
JRST NTSCS6 ;JUMP IN TO MIDDLE (DON'T DO NETNDB!)
|
||
|
||
NTSCS2: HRRZ T1,NDBFEK(W) ;GET FEK FOR THIS NODE
|
||
HLL J,NDBFLG(W) ;CARRY THE BITS IN LH(J)
|
||
TLNE J,NDB.UP ;IS THIS NODE UP
|
||
JRST NTSCS4 ;IF SO, JUMP OFF AND CHECK IT
|
||
LDB T1,NDBTIM ;GET THE TIMER
|
||
SOJG T1,NTSCS3 ;COUNT IT DOWN. JUMP IF NOT TIME FOR START
|
||
PUSHJ P,NCSSSM ;SEND EITHER A START OR STACK
|
||
TDZA T1,T1 ;START DIDN'T GO. DON'T RESET TIMER
|
||
MOVEI T1,^D15 ;SET TIMER FOR 15 SECONDS
|
||
NTSCS3: DPB T1,NDBTIM ;PUT THE NEW VALUE BACK FOR NEXT TIME
|
||
JRST NTSCS8 ;GO PROCESS THE NEXT NDB
|
||
;HERE NODE IS UP. CHECK VARIOUS THINGS
|
||
|
||
NTSCS4: MOVE T1,LOCSEC## ;GET A TIMER
|
||
TLNN J,NDB.CF ;HAVE WE GOT A CONFIG YET?
|
||
TRNE T1,7 ;NO, TIME TO ASK?(EVERY 8 SECONDS)
|
||
CAIA ;YES, OR NOT TIME YET
|
||
PUSHJ P,NCSRCF ;IF NOT, LETS ASK HIM FOR ONE
|
||
JFCL ;IF NO CORE, WE'LL GET IT LATER
|
||
;NEIGHBORS
|
||
TLNN J,NDB.NB ;HAS HE HEARD ABOUT OUR FRIENDS
|
||
PUSHJ P,NCSNBN ;LET'S TELL HIM WHO'S NEXT DOOR
|
||
JFCL ;BIT DIDN'T GET CLEARED. WE'LL GET IT LATER
|
||
;REP CHECK
|
||
HRRZ T1,NDBQUE(W) ;ANY MESSAGES WAITING FOR AN ACK??
|
||
JUMPE T1,NTSCS5 ;IF NONE, DON'T REP, BUT CLEAR TIMER
|
||
LDB T1,NDBTIM ;GET THE NODE'S REP TIMER
|
||
CAIG T1,^D10 ;NO ACKS IN 10 SECONDS??
|
||
AOJA T1,NTSCS5 ;IF IT HASN'T BEEN THAT LONG, JUST MARK TIME
|
||
PUSHJ P,NCSREP ;OTHERWISE TRY TO SEND THE REP
|
||
SKIPA T1,[^D10] ;IF IT DIDN'T GO, THEN DON'T RESET TIMER
|
||
SETZ T1, ;OTHERWISE SET TIMER TO ZERO
|
||
NTSCS5: DPB T1,NDBTIM ;STORE TIMER BACK,
|
||
;NAK CHECK
|
||
HLRZ T1,NDBQUE(W) ;GET POINTER TO 'OUT OF ORDER' MESSAGES
|
||
JUMPE T1,NTSCS6 ;IF NONE, THEN THIS CHECK IS COMPLETE
|
||
MOVEI T2,1 ;THIS IS THE COUNT OF QUEUED INPUT MSGS
|
||
HRRZ T1,PCBBLK(T1) ;STEP TO THE NEXT MESSAGE,
|
||
SKIPE T1 ;SKIP IF THERE ISN'T ONE
|
||
AOJA T2,.-2 ;IF THERE IS ONE, COUNT IT AND RECURSE.
|
||
CAIL T2,^D5 ;ARE THERE MORE THAN 5 MSGS QUEUED?
|
||
PUSHJ P,NCSNAK ;IF SO, WE PROBABLY LOST ONE, SEND A NAK
|
||
JFCL ;IGNORE ERROR RETURN
|
||
|
||
NTSCS6: PUSHJ P,STCSEC ;GO TIME OUT STATION CONTROL MSGS FOR
|
||
; THIS NODE.
|
||
NTSCS8: HRRZ W,NDBNNM(W) ;STEP TO THE NEXT NODE.
|
||
JUMPN W,NTSCS2 ;IF THERE IS A NEXT NODE, GO PROCESS IT
|
||
|
||
PUSHJ P,PCBSEC ;LET PCB MANAGEMENT CONTROL FREE-LISTS
|
||
PUSHJ P,TSKSEC## ;CALL TSKSER ONCE/SEC FOR ITS STORAGE MGT
|
||
PUSHJ P,NMCSEC## ;CALL NETMCR ONCE/SEC SO IT CAN DO ITS AUTO-
|
||
; DISCONNECT TIMING
|
||
|
||
POPJ P, ;DONE WITH ONCE/SECOND STUFF. BACK TO TOP LEVEL
|
||
SUBTTL CHKNCA - CHECK ACK'S FOR MESSAGE SENT BUT BEING HELD
|
||
;SUBROUTINE CHKNCA - DELETE MESSAGES THAT HAVE ACK'S
|
||
;CALL MOVEI W,NDB
|
||
; MOVEI T1,NCA - MESSAGE ACK NUMBER
|
||
;RETURN CPOPJ
|
||
|
||
CHKNCA: ;ENTRY
|
||
JUMPE W,CPOPJ## ;EXIT IN NDB UNDEFINED
|
||
LDB T2,NDBLMS ;GET THE LAST MESSAGE SENT
|
||
SUB T2,T1 ; AND MAKE SURE THAT WE ARE LESS
|
||
TRNE T2,200 ; THAN IT. IF NOT, THEN THIS
|
||
POPJ P, ; IS A VERY OUT-OF-DATE ACK
|
||
LDB T2,NDBLAP ;GET THE LAST ACK PROCESSED, AND
|
||
SUB T2,T1 ; SEE IF THIS ACK IS .GT. THE OLD
|
||
TRNN T2,200 ;IF "LAP" IS .GE. THIS ACK,
|
||
POPJ P, ; THEN THIS ACK IS OLD NEWS
|
||
DPB T1,NDBLAR ;SAVE THE LAST ACK RECEIVED
|
||
PUSH P,U ;SAVE THE OLD PCB
|
||
CHKNC1: LDB T2,NDBLAP ;GET THE LAST ACK PROCESSED
|
||
LDB T1,NDBLAR ;GET LAST ACK RECEIVED
|
||
CAIN T1,(T2) ;IF LAP = LAR, THEN WE'VE PROCESSED ALL
|
||
JRST UPOPJ ; IF PROCESSED ALL, RESTORE "U" AND EXIT
|
||
ADDI T2,1 ;GET NUMBER OF NEXT ACK TO PROCESS
|
||
ANDI T2,377 ; JUST 8 BITS OF IT PLEASE
|
||
HRRZ U,NDBQUE(W) ;GET THE NEXT MESSAGE ON THE AWAIT ACK QUEUE
|
||
JUMPE U,UPOPJ ; IF NONE, GET OUT WITHOUT UP-INT LAP
|
||
LDB T1,PCBMSN ;GET THIS MESSAGE'S NUMBER
|
||
CAIE T1,(T2) ; AND MAKE SURE IT IS THE ONE WE WANT
|
||
JRST UPOPJ ;IF NEXT MSG IS AT FEK, GET OUT AND WAIT FOR
|
||
; IT TO COME BACK (WE MUSTA GOT NAK'ED)
|
||
DPB T1,NDBLAP ;WE'RE GOING TO FREE THIS MSG, UPDATE LAP
|
||
HRRZ T1,PCBBLK(U) ;GET ADDRESS OF NEXT MESSAGE ON THE QUEUE
|
||
HRRM T1,NDBQUE(W) ; AND MAKE IT THE FIRST
|
||
S0PSHJ RMVPCB ;FREE THIS MESSAGE
|
||
SETZ T1, ;GET A ZERO, AND USE IT
|
||
DPB T1,NDBTIM ; CLEAR THE REP TIMER. (THINGS SEEM TO BE OK)
|
||
AOS NDBMOM(W) ;INDICATE ONE LESS MESSAGE OUTSTANDING
|
||
JRST CHKNC1 ;GO TRY TO PROCESS ANOTHER ACK
|
||
SUBTTL PROCESS NEXT MESSAGE
|
||
|
||
INCTNM: ;HERE TO PROCESS A NUMBERED MESSAGE
|
||
LDB T1,P1 ;GET THIS MESSAGE'S NUMBER BACK AGAIN
|
||
DPB T1,NDBLMP ;SAVE LAST MESSAGE PROCESSED
|
||
INCTUN: HLRZ T1,NTFLGS ;GET THE FLAGS
|
||
ANDI T1,NCT.TP ;GET THE TYPE FIELD
|
||
NTDBUG ;VERIFY THE INTERLOCK
|
||
|
||
|
||
CAIE T1,NCT.ID ;IF THIS IS A NODE ID, OR
|
||
CAIN T1,NCT.DM ; A DATA MESSAGE, THEN WE NEED NOT CHECK
|
||
JRST INCTU1 ; FOR DUPLICATE NODES
|
||
|
||
MOVEI T2,NETNDB## ;IF MSG IS START, STACK ETC.
|
||
CAIE T2,(W) ; SEE IF NODE HAS THE SAME NUMBER AS US.
|
||
JRST INCTU1 ; IF NOT, THEN EVERYTHING'S OK
|
||
|
||
PUSHJ P,TYPILT ;TELL THE OPERATOR ABOUT THE ILLEGAL TOPOLOGY
|
||
PUSHJ P,INCTBP ; AND THROW AWAY THE MESSAGE
|
||
JRST INCTU2 ; AND DON'T PROCESS THE MESSAGE.
|
||
|
||
INCTU1: HRRZS U ;CLEAR FLAG BITS SO U CAN BE USED IN SECTION 1
|
||
PUSHJ P,NCTTBL(T1) ;DISPATCH BY THE MESSAGE TYPE
|
||
INCTU2: JRST NTSCN8 ;GO BACK FOR MORE
|
||
STOPCD .,STOP,ANFNCT, ;++ NCT PROCESSORS SHOULDN'T SKIP
|
||
|
||
|
||
;NCL MESSAGE TYPE DISPATCH TABLE
|
||
|
||
NCTTBL: JRST INCTDM ;(0) DATA MESSAGE
|
||
JRST INCTAK ;(1) ACK
|
||
JRST INCTNK ;(2) NAK
|
||
JRST INCTRP ;(3) REP
|
||
JRST INCTST ;(4) START
|
||
JRST INCTSK ;(5) STACK
|
||
JRST INCTID ;(6) NODE ID
|
||
JRST INCTBP ;(7) ILLEGAL INPUT MESSAGE TYPE. FLUSH
|
||
;INCTID -- ROUTINE TO PROCESS THE NODE ID MESSAGE
|
||
;THIS ROUTINE READS THE NODE NUMBER FROM THE NODE ID MESSAGE.
|
||
; IF AN NDB DOES NOT YET EXIST FOR THE NODE ONE IS CREATED AND
|
||
; THE OPTIONAL DATA IS READ INTO IT. THEN TOPOLOGY IS
|
||
; RECOMPUTED.
|
||
;
|
||
;MESSAGE = NCT NCA NCN OPD(NNM SNM SID NIT [NIS] NVR)
|
||
;SO FAR = NCT.ID /$\
|
||
|
||
INCTID:
|
||
PUSHJ P,SAVJW## ;WE SET UP A DIFFERENT "W" UNLIKE OTHER MSGS
|
||
HLR J,PCBFEK(U) ;GET FEK POINTER FROM PCB
|
||
|
||
IFN PARANOID&P$FEK,< ;MAKE SURE WE DON'T SEND OURSELF A NODE-ID
|
||
|
||
HLLZ T1,FEKBLK(J) ;GET THE FLAGS FOR THE FEK
|
||
TLNE T1,FK.NUL ;IS THIS A NULL FEK?
|
||
STOPCD .,STOP,ANFNFK, ;++ THIS IS THE NULL FEK
|
||
>
|
||
;NCA
|
||
ILDB T1,P1 ;GET THE ACK START
|
||
;NCN
|
||
ILDB T1,P1 ;GET THE STARTING MESSAGE NUMBER
|
||
;NNM
|
||
PUSHJ P,EBI2BI ;READ THE NODE NUMBER
|
||
HRRM T1,FEKNNM(J) ;STORE THE NODE NUMBER FOR THIS FEK
|
||
PUSHJ P,SRCNDB ;DOES THE NODE EXIST
|
||
JRST INCTI5 ;NO, NEED TO CREATE AN NDB
|
||
PUSHJ P,SKOPDD ;YES, SKIP OVER OPD(,SNM,SID) FIELDS
|
||
PUSHJ P,EBI2BI ;READ NODEID TYPE
|
||
JUMPE T1,INCTI8 ;IF 0/BLANK, THEN NOT BROADCAST NODEID
|
||
IFE FTENET,<PJSP T1,INCTBD> ;INVALID NODEID "TYPE" FIELD
|
||
|
||
;CONTINUED ON NEXT PAGE
|
||
;CONTINUED FROM PREVIOUS PAGE
|
||
|
||
;HERE TO HANDLE PERIODIC BROADCAST NODEID MESSAGE
|
||
|
||
IFN FTENET,<
|
||
CAIE T1,NIT.BC ;ONLY OTHER LEGAL VALUE IS BROADCAST
|
||
PJSP T1,INCTBD ;INVALID NODEID "TYPE" FIELD
|
||
HLLZS FEKNNM(J) ;ETHERNET MASTER FEK'S DON'T HAVE A NEIGHBOR
|
||
HLRZ T4,NDBNNM(W) ;GET NODE NUMBER TO MATCH
|
||
SKIPA T2,J ;"LOCAL" START OF FEK CHAIN
|
||
INCTI1: HRRZ T2,FEKBLK(T2) ;ADVANCE TO NEXT FEK IN CHAIN
|
||
JUMPE T2,INCTI6 ;NO FEK??? TIME FOR A NEW TOPOLOGY!
|
||
HRRZ T3,FEKNNM(T2) ;PICK UP NODE NUMBER
|
||
CAIE T4,(T3) ;DOES THIS FEK BELONG TO THIS NODE?
|
||
JRST INCTI1 ;NO, KEEP LOOKING
|
||
MOVE T3,FEKBLK(T2) ;GET FEK FLAGS
|
||
TLNE T3,FK.ETH ;ETHERNET FEK?
|
||
CAME J,FEKNIF(T2) ;YES, SLAVED TO THE RIGHT MASTER?
|
||
JRST INCTI1 ;NO (???), BROADCAST NODEID NOT FROM HERE
|
||
MOVE J,T2 ;POSITION SLAVE FEK ADDRESS IN A SAFE PLACE
|
||
PUSHJ P,EBI2BI ;READ IN NODEID SERIAL NUMBER
|
||
CAMG T1,FEKNIS(J) ;MONOTONICALLY INCREASED?
|
||
JRST INCTI3 ;NO, NODE MUST HAVE RESTARTED
|
||
MOVEM T1,FEKNIS(J) ;YES, SET NEW SERIAL NUMBER
|
||
MOVE T1,%NTNIJ ;TIMEOUT (OR KEEP-ALIVE) INTERVAL
|
||
MOVEM T1,FEKNIT(J) ;RESET SLAVE FEK KEEP-ALIVE TIMER
|
||
MOVE J,FEKNIF(J) ;RESTORE MASTER FEK ADDRESS
|
||
POPJ P, ;AND JUST RETURN (NO TOPOLOGY CHANGE)
|
||
|
||
;HERE WHEN ETHERNET NCL PROTOCOL RESTARTED
|
||
|
||
INCTI3: MOVEI T1,FF.DFK ;FUNCTION: DESTROY DEAD SLAVE FEK
|
||
XCT FEKDSP(J) ;LET FEK SERVICE DO IT
|
||
POPJ P, ;JUST RETURN (AWAIT ANOTHER NODEID)
|
||
> ;END IFN FTENET
|
||
INCTI5: PUSHJ P,MAKNDB ;MAKE A NODE DATA BLOCK
|
||
POPJ P, ;NO CORE. DO IT LATER
|
||
;OPD
|
||
PUSHJ P,RDOPDD ;READ THE OPTIONAL DATA
|
||
POPJ P, ;NO CORE. LATER
|
||
;NIT
|
||
PUSHJ P,EBI2BI ;READ NODEID "CLASS"
|
||
JUMPE T1,INCTI8 ;IF POINT-TO-POINT (OR BLANK) THEN NORMAL FEK
|
||
IFE FTENET,<PJSP T1,INCTBD> ;ONLY OTHER LEGAL VALUE IS "BROADCAST"
|
||
|
||
IFN FTENET,<
|
||
CAIE T1,NIT.BC ;ONLY OTHER LEGAL VALUE IS "BROADCAST"
|
||
PJSP T1,INCTBD ;BAD MESSAGE
|
||
INCTI6: MOVE T2,FEKBLK(J) ;GET FEK FLAGS
|
||
TLNN T2,FK.ETM ;IS THIS AN ETHERNET MASTER FEK?
|
||
PJSP T1,INCTBD ;NO (???)
|
||
MOVEI T1,FF.CFK ;FUNCTION: CREATE NEW SLAVE FEK
|
||
XCT FEKDSP(J) ;GET A NEW SLAVE FEK (ADDRESS IN T1)
|
||
JUMPE T1,CPOPJ ;IGNORE IF NO CORE FOR NEW FEK
|
||
HRRM T1,NDBFEK(W) ;LINK NDB TO SLAVE FEK
|
||
HLRZ T2,NDBNNM(W) ;RETRIEVE NNM FROM NDB
|
||
HRRM T2,FEKNNM(T1) ;AND SET SLAVE FEK NNM
|
||
HLLZS FEKNNM(J) ;AND CLEAR IN MASTER FEK (SINCE NOT A NEIGHBOR)
|
||
DMOVE T2,PCBNIA(U) ;GET REMOTE ETHERNET ADDRESS
|
||
DMOVEM T2,FEKNIA(T1) ;AND SAVE IN THE NEW SLAVE FEK
|
||
PUSHJ P,EBI2BI ;READ BROADCAST "SERIAL" NUMBER
|
||
HRRZ T2,NDBFEK(W) ;RETRIEVE ADDRESS OF SLAVE FEK
|
||
MOVEM T1,FEKNIS(T2) ;AND SET LATEST RECEIVED SERIAL NUMBER
|
||
MOVSI T3,4 ;RESET THE MASTER BROADCAST NODEID TIMER
|
||
MOVEM T3,FEKNIT(J) ;SO AS TO SEND A NODEID ASAP
|
||
> ;END IFN FTENET
|
||
|
||
INCTI8: PUSHJ P,EBI2BI ;READ REMOTE'S NCL VERSION NUMBER
|
||
HRRM T1,NDBNVR(W) ;SAVE FOR LATER EXAMINATION
|
||
SETOM NTQRCT ;WE MUST RECOMPUTE TOPOLOGY
|
||
POPJ P, ;ALL DONE
|
||
;INCTST -- ROUTINE TO PROCESS A START MESSAGE.
|
||
;
|
||
;MESSAGE = NCT DNA SNA NCA NCN OPD(NNM SNM SID) NVR
|
||
;SO FAR = NCT.ST US HIM IGNORED IGNORED /$\
|
||
|
||
INCTST:
|
||
|
||
IFN PARANOID&P$NDB,<PUSHJ P,NDBCHK> ;MAKE SURE THIS DIDN'T COME FROM US.
|
||
|
||
;NNM
|
||
PUSHJ P,EBI2BI ;READ THE NODE NUMBER
|
||
HLRZ T2,NDBNNM(W) ;GET WHAT SHOULD BE THE NODE NUMBER
|
||
CAIE T1,(T2) ;BETTER BE THE SAME
|
||
PJSP T1,INCTBD ;INCONSISTENT MESSAGE
|
||
PUSHJ P,CLNNDB ;MAKE THIS NDB PRISTINE
|
||
;OPD
|
||
PUSHJ P,RDOPDD ;READ THE OPTIONAL DATA
|
||
POPJ P, ;NO CORE. DISMISS
|
||
;NVR
|
||
PUSHJ P,EBI2BI ;READ NCL VERSION NUMBER
|
||
HRRM T1,NDBNVR(W) ;SAVE FOR LATER USE
|
||
|
||
PUSH P,U ;SAVE THE PCB POINTER
|
||
MOVSI T1,NDB.SK ;GET THE "NOW-SENDING-STACKS" FLAG
|
||
IORM T1,NDBFLG(W) ; TO TELL NCSSSM NOT TO SEND A START
|
||
PUSHJ P,NCSSSM ;SEND A STACK BACK
|
||
JFCL ;TRY LATER
|
||
;NOTE! THIS WILL MEAN THAT WE WON'T
|
||
;TRY TO OPEN THE CONNECTION FOR ANOTHER
|
||
;15 SECONDS OR UNTIL WE RECEIVE THE NEXT
|
||
;START. THIS MAY BE A "FEATURE". IF WE ARE
|
||
;THIS SHORT OF CORE WE MAY NOT WANT TO
|
||
;START ALL THIS RIGHT AWAY
|
||
JRST UPOPJ## ;RESTORE THE PCB AND GO BACK FOR MORE
|
||
;SUBROUTINE INCTSK - STACK MESSAGE PROCESSOR
|
||
;
|
||
;MESSAGE = NCT DNA SNA NCA NCN OPD(NNM SNM SID) NVR
|
||
;SO FAR = NCT.SK US HIM IGNORED IGNORED /$\
|
||
|
||
INCTSK: ;ENTRY
|
||
|
||
IFN PARANOID&P$NDB,<PUSHJ P,NDBCHK> ;MAKE SURE THIS DIDN'T COME FROM US.
|
||
|
||
;NNM
|
||
PUSHJ P,EBI2BI ;READ THE NODE NUMBER
|
||
HLRZ T2,NDBNNM(W) ;GET WHAT SHOULD BE THE NODE NUMBER
|
||
CAIE T1,(T2) ;BETTER BE THE SAME
|
||
PJSP T1,INCTBD ;INCONSISTENT MESSAGE
|
||
;OPD
|
||
PUSHJ P,RDOPDD ;READ THE OPTIONAL DATA
|
||
POPJ P, ;NO CORE. DISMISS
|
||
;NVR
|
||
PUSHJ P,EBI2BI ;READ THE NCL VERSION NUMBER
|
||
HRRM T1,NDBNVR(W) ;SAVE FOR LATER USE
|
||
|
||
PUSH P,U ;SAVE THE INCOMING MESSAGE
|
||
PUSHJ P,NCSACK ;ACK THE STACK
|
||
JFCL ;IF WE CAN'T, THEN SOME-ONE WILL TIME OUT
|
||
POP P,U ;GET THE INCOMING MESSAGE BACK (TO FREE IT)
|
||
PJRST NODEUP ;SIGNAL THAT THE NODE IS UP
|
||
;SUBROUTINE INCTAK - ACK MESSAGE PROCESSOR
|
||
;
|
||
;MESSAGE = NCT DNA SNA NCA NCN
|
||
;SO FAR = NCT.AK US HIM CHECKED IGNORED /$\
|
||
|
||
INCTAK: ;ACK'S HAPPEN IN NETSCN
|
||
|
||
IFN PARANOID&P$NDB,<PUSHJ P,NDBCHK> ;MAKE SURE THIS DIDN'T COME FROM US.
|
||
|
||
POPJ P, ;GO BACK FOR MORE
|
||
|
||
|
||
|
||
|
||
|
||
|
||
;SUBROUTINE INCTNK NAK MESSAGE PROCESSOR
|
||
;
|
||
;MESSAGE = NCT DNA SNA NCA NCN
|
||
;SO FAR = NCT.NK US HIM CHECKED IGNORED /$\
|
||
|
||
INCTNK: ;RE-SEND ALL UN-ACKED MESSAGES
|
||
|
||
IFN PARANOID&P$NDB,<PUSHJ P,NDBCHK> ;MAKE SURE THIS DIDN'T COME FROM US.
|
||
|
||
PUSHJ P,SAVE1 ;SAVE P1
|
||
PUSHJ P,SAVJW## ;WE'LL CLOBBER J TOO
|
||
PUSH P,U ;SAVE THE PCB
|
||
HRRZ P1,NDBQUE(W) ;GET THE POINTER
|
||
HLLZS NDBQUE(W) ;NO LONGER WAITING FOR ACK
|
||
JUMPE P1,INCTN2 ;EMPTY
|
||
INCTN1: MOVEI U,(P1) ;GET THE NEXT ENTRY
|
||
HRRZ P1,PCBBLK(U) ;GET THE NEXT ENTRY
|
||
HLLZS PCBBLK(U) ;BREAK ANY FORWARD LINK
|
||
NETOFF ;FRCWRT WILL TURN IT BACK ON ...
|
||
PUSHJ P,FRCWRT ;RESEND THE MESSAGE (SEE FOOTNOTE)
|
||
JUMPN P1,INCTN1 ;CHECK FOR THE END
|
||
INCTN2: JRST UPOPJ ;RESTORE U AND RETURN
|
||
;SUBROUTINE INCTRP REP PROCESSOR
|
||
;
|
||
;MESSAGE = NCT DNA SNA NCA NCN
|
||
;SO FAR = NCT.RP US HIM CHECKED IGNORED /$\
|
||
|
||
INCTRP: ;PROPER RESPONSE TO A REP IS TO DELETE
|
||
; ALL OUT OF ORDER MESSAGES ON NDBQUE
|
||
IFN PARANOID&P$NDB,<PUSHJ P,NDBCHK> ;MAKE SURE THIS DIDN'T COME FROM US.
|
||
|
||
MOVSI T1,NDB.XN ;GET THE 'NEED TO NAK' FLAG
|
||
IORM T1,NDBFLG(W) ;AND SET IT. THIS WILL CAUSE
|
||
POPJ P, ;THE NAK TO GO OUT SOON ENOUGH.
|
||
; NCSNAK WILL REMOVE OUT OF ORDER
|
||
; MESSAGES FROM NDBQUE.
|
||
|
||
;***FOOTNOTE***
|
||
COMMENT\
|
||
It is assumed that any message on the right half of NDBQUE
|
||
has already been given to NETWRT once before. If this is the
|
||
case, then we do not need to set up CACHE information by a call
|
||
to PCBMRK
|
||
\
|
||
;SUBROUTINE RDOPDD - READ THE SOFTWARE ID FIELDS
|
||
;
|
||
;MESSAGE = ??? ... ??? OPD(NNM SNM SID)
|
||
;SO FAR = READ /$\
|
||
;
|
||
;RETURN CPOPJ ;NO CORE
|
||
; CPOPJ1 ;W=NDB
|
||
|
||
RDOPDD: ;ENTRY
|
||
;SNM
|
||
MOVEI P2,NDBSN2(W) ;POINTER TO STATION NAME
|
||
HRLM P2,NDBSNM(W) ;SALT IT AWAY
|
||
RDOPD1: PUSHJ P,EAS2SX ;COPY THE STATION NAME
|
||
MOVEM T1,(P2) ;STORE THE STATION NAME
|
||
;SID
|
||
HRRZ P2,NDBSID(W) ;CHECK FOR A POINTER
|
||
JUMPN P2,RDOPD2 ;YES
|
||
PUSHJ P,EAS2AZ ;SEE IF WE NEED SPACE FOR THE NAME
|
||
JRST RDOPD3 ;NO, DON'T GET IT
|
||
MOVEI T2,^D8 ;YES, ALLOCATE SPACE FOR THE SYSTEM NAME
|
||
PUSHJ P,GETZWD ;FROM FREE CORE
|
||
POPJ P, ;NO CORE
|
||
HRRM T1,NDBSID(W) ;STORE THE POINTER
|
||
MOVEI P2,(T1) ;GET THE POINTER
|
||
RDOPD2: PUSHJ P,EAS2AS ;COPY THE SYSTEM NAME
|
||
RDOPD3: HLRZ P2,NDBSID(W) ;GET THE POINTER
|
||
JUMPN P2,RDOPD4 ;JUMP IF ONE
|
||
PUSHJ P,EAS2AZ ;SEE IF NEED SPACE FOR DATE
|
||
JRST RDOPD5 ;NO, DON'T GET IT
|
||
MOVEI T2,^D8 ;YES, ALLOCATE SPACE FOR THE CREATION DATE
|
||
PUSHJ P,GETZWD ;FROM FREE CORE
|
||
POPJ P, ;NO SPACE
|
||
HRLM T1,NDBSID(W) ;STORE THE POINTER
|
||
MOVEI P2,(T1) ;COPY THE POINTER
|
||
RDOPD4: PUSHJ P,EAS2AS ;COPY THE CREATION DATE
|
||
RDOPD5: PJRST CPOPJ1## ;EXIT
|
||
|
||
|
||
;SKOPDD - LIKE RDOPDD BUT JUST DISCARDS THE OPD FIELDS
|
||
|
||
SKOPDD: PUSHJ P,EAS2SX ;SLURP UP THE SNM "STATION NAME" FIELD
|
||
; PUSHJ P,EAS2AZ ;IS THERE A SID "SYSTEM NAME" FIELD?
|
||
; CAIA ;NO
|
||
PUSHJ P,XSKIP ;YES, SLURP IT UP
|
||
; PUSHJ P,EAS2AZ ;IS THERE A SID "SYSTEM DATE" FIELD?
|
||
; CAIA ;NO
|
||
PUSHJ P,XSKIP ;YES, SLURP IT UP
|
||
POPJ P, ;OPD(...,SNM,SID) READ AND DISCARDED
|
||
SUBTTL INCTDM - PROCESS OF NUMBERED CONTROL/DATA MESSAGES
|
||
|
||
;MESSAGE = NCT DNA SNA NCA NCN DLA ...
|
||
;SO FAR = NCT.DM US HIM CHECKED CHECKED /$\
|
||
|
||
INCTDM:
|
||
;DLA
|
||
PUSHJ P,EBI2BI ;GET THE DESTINATION LINK ADDRESS
|
||
JUMPN T1,IDCCTL ;DEVICE CONTROL MESSAGE
|
||
|
||
;HERE TO PROCESS NUMBERED CONTROL MESSAGES. THESE HAVE A DLA OF ZERO
|
||
; AND HENCE ARE NODE (AS OPPOSED TO DEVICE) CONTROL
|
||
;
|
||
;MESSAGE = NCT DNA SNA NCA NCN DLA (CNT CM)*
|
||
;SO FAR = NCT.DM US HIM ACK NUMBER 0 /$\
|
||
;
|
||
|
||
NCTDSP: JUMPE P4,CPOPJ## ;IF WE'RE AT END-OF-MESSAGE, RETURN
|
||
|
||
;CNT
|
||
|
||
PUSHJ P,EBI2BI ;GET THE LENGTH OF THE SUB MESSAGE
|
||
SUB P4,T1 ;P4 := THE LENGTH OF THE REST OF THE MSG
|
||
SKIPGE P4 ;MAKE SURE THAT SUB-MSG NOT LONGER THAN
|
||
PJSP T1,INCTBD ; THE REST OF THE MESSAGE. IF SO, ERROR
|
||
PUSH P,P4 ;SAVE THE LENGTH OF THE "REST" OF THE MSG
|
||
MOVE P4,T1 ;SET THE LENGTH (P4) TO BE THAT OF THIS SUB-MSG
|
||
|
||
;CM
|
||
|
||
PUSHJ P,EBI2BI ;GET THE CONTROL MESSAGE TYPE
|
||
CAILE T1,NC.MAX ;RANGE CHECK IT
|
||
PJSP T1,NCTDS1 ;GIVE "BAD MESSAGE" IF TYPE OUT OF RANGE
|
||
AOS NCLRMT(T1) ;COUNT THE MESSAGE TYPE
|
||
PUSHJ P,[SE1ENT ;CALL IN SECTION 1
|
||
PJRST ICMTBL(T1)] ;DISPATCH TO THE MESSAGE PROCESSOR
|
||
PJSP T1,NCTDS1 ;IF ERROR, RESTORE P4 AND POST BAD MSG
|
||
JUMPG P4,[PUSHJ P,XSKIP ;MAKE SURE ALL OF SUB MSG WAS
|
||
JRST .] ; PROCESSED
|
||
POP P,P4 ;GET LENGTH OF THE REMAINDER OF THE MESSAGE
|
||
JRST NCTDSP ; AND GO PROCESS IT.
|
||
|
||
NCTDS1: POP P,P4 ;RESTORE P4 (JUST TO CLEAN UP STACK)
|
||
PJRST INCTBD ;GO MARK THE MESSAGE AS BAD
|
||
|
||
ICMTBL: JRST CPOPJ## ;<0> IS ILLEGAL
|
||
JRST ICMCNT ;<1> CONNECT
|
||
JRST ICMDSC ;<2> DISCONNECT
|
||
JRST ICMNBN ;<3> NEIGHBOURS
|
||
JRST ICMRCF ;<4> REQUEST CONFIGURATION
|
||
JRST ICMCNF ;<5> CONFIGURATION
|
||
JRST ICMDRQ ;<6> DATA REQUEST
|
||
JRST ICMCTL ;<7> STATION CONTROL
|
||
COMMENT @
|
||
|
||
Connect and Disconnect message processing
|
||
|
||
For each device an attempt is made to call the device driver for all
|
||
the connect/disconnect messages. Here follows a list of the actions taken
|
||
for the three connect related messages.
|
||
|
||
Connect initiate.
|
||
This is the complicated one. There are two phases to the
|
||
processing of the connect initiate message.
|
||
|
||
1) The Link Address Table (LAT) is scaned for devices in the
|
||
LAT.CI (waiting for connect) state. When a device is found
|
||
in that state it is called on its NDPCNI dispatch entry in
|
||
in the following context.
|
||
|
||
P3 := XWD SLA,OBJ (As read from the message)
|
||
P1, P4 := Pointer to the first byte after the "OBJ" field.
|
||
|
||
If the driver does not wish to accept the connect it should
|
||
CPOPJ. If it accepts the connect it should skip return.
|
||
(Note. The driver MUST respect the P's)
|
||
|
||
2) If no driver is found to accept the connect, a default connect
|
||
processor is called. (Via the DCITAB entry indexed by the
|
||
ofject type of the incoming message.) This default handler
|
||
is called in the same context as above. If it accepts the
|
||
connect, it should skip return. If the connect is to be
|
||
rejected, the handler should CPOPJ return with T1 containing
|
||
the reason for failure. (RSN field of a disconnect message)
|
||
|
||
Connect confirm
|
||
The driver will be called via the NDPCNC vectored entry. in the
|
||
the following context.
|
||
|
||
P1, P4 := Point to the "SLA" byte of the message.
|
||
|
||
A skip return accepts the message. A non-skip return says that the
|
||
message was bad. (The message will then be given to INCTBD)
|
||
|
||
Disconnect
|
||
Same as connect confirm, except that the NDPDSC entry is used.
|
||
|
||
Note. When ever any of the NDP vectored connect/disconnect entries
|
||
are taken the registers P1 and P4 (message pointer and count) will point to
|
||
the DLA. In other words, the first item to be read by the service routine
|
||
will be the DLA.
|
||
|
||
@
|
||
;ICMCNT ROUTINE TO PROCESS INCOMING CONNECT MESSAGE.
|
||
;CALLED WITH
|
||
; P1 := POINTER TO THE DLA SECTION OF THE MESSAGE
|
||
; P4 := COUNT OF THE BYTES LEFT IN THE MESSAGE
|
||
; W := POINTER TO THE NDB OF THE NODE THAT SENT THIS MESSAGE
|
||
;RETURN CPOPJ1 ;WITH EITHER THE DEVICE ACCEPTING THE MESSAGE,
|
||
; ; OR A CONNECT REJECT BEING SENT
|
||
;
|
||
ICMCNT:: ;HERE TO PROCESS AN INCOMING CONNECT.
|
||
;DLA
|
||
|
||
PUSHJ P,EBI2BI ;GET THE DESTINATION
|
||
JUMPN T1,ICMCNC ; IF NONZERO, GO PROCESS CONNECT CONFIRM
|
||
|
||
;SLA
|
||
|
||
PUSHJ P,EBI2BI ;GET THE SOURCE
|
||
HRLZI P3,(T1) ;COPY IT INCASE WE DECIDE TO DISCONNECT.
|
||
|
||
;DPN(OBJ)
|
||
|
||
PUSHJ P,EBI2BI ;GET THE DESTINATION OBJECT TYPE.
|
||
HRRI P3,(T1) ;COPY THE OBJECT TYPE FOR INDEXING ETC.
|
||
|
||
;LOOP THROUGH NETLAT LOOKING FOR A DDB WAITING FOR THIS CONNECT
|
||
|
||
MOVSI P2,-LATLEN## ;MAKE AN AOBJN POINTER TO THE NETLAT TABLE.
|
||
ICMCN1: AOBJP P2,ICMCN3 ;NO DDB'S WERE INTERESTED, TRY DEFAULT CI'ER
|
||
LDB T3,LATSP2 ;GET THE STATE OF THIS LAT ENTRY
|
||
CAIE T3,LAT.CI ;IS IT CONNECT INITIATE?
|
||
JRST ICMCN1 ;IF NOT, TRY THE NEXT ENTRY
|
||
LDB F,LATPP2 ;GET DDB ADDRESS FROM LAT ENTRY
|
||
MOVEI T1,NDPCNI ;SET UP TO USE THE CONNECT INITIATE ENTRY.
|
||
MOVE T2,NETLAT(P2) ;WANT NETLAT FLAGS IN T2
|
||
PUSHJ P,ICMNDP ;DO THE DISPATCH
|
||
JRST ICMCN1 ;FAILURE, TRY THE NEXT ONE
|
||
JRST CPOPJ1## ; SUCCESS. GIVE GOOD RETURN
|
||
|
||
|
||
;HERE WHEN NO LAT ENTRIES WANTED THE CONNECT. CALL THE DEFAULT HANDLER.
|
||
|
||
ICMCN3: MOVEI T1,(P3) ;GET JUST THE OBJECT TYPE.
|
||
CAIL T1,0 ;RANGE CHECK IT BEFORE
|
||
CAILE T1,OBJ.MX ; WE TRY USING IT FOR AN INDEX.
|
||
JRST ICMCN6 ;OUT OF RANGE. SEND A DISCONNECT.
|
||
SKIPN T2,NDTTAB##(T1) ;ADDRESS OF OBJECT-TYPE'S NDT
|
||
JRST ICMCN6 ;NONE - WE DON'T HANDLE THAT TYPE
|
||
HRRZ T2,NDTCNI(T2) ;DISPATCH ADDRESS
|
||
SE1ENT ;CALL IN SECTION 1
|
||
PUSHJ P,(T2) ;PROCESS THE INCOMING CONNECT INIT
|
||
JRST ICMCN7 ; REJECTED, REASON CODE IS IN T1
|
||
JRST CPOPJ1## ;IT LIKED IT. GIVE A GOOD RETURN
|
||
ICMCN6: MOVEI T1,RSN.OT ;OBJECT TYPE NOT AVAILABLE
|
||
; NETPRM WOULD SEEM TO PREFER RSN.NP AS A MORE
|
||
; APPROPRIATE RESPONSE - HOWEVER, RSN.OT IS WHAT
|
||
; WAS RETURNED IN PREVIOUS MONITORS, AND I DON'T
|
||
; HAVE THE COURAGE TO CHANGE IT . . .
|
||
ICMCN7: ;HERE TO SEND REJECT (DISCONNECT) RSN IN T1.
|
||
; (WE CAN'T USE NCSDSC SINCE WE HAVE NO DDB)
|
||
PUSH P,U ;PROTECT OUR INCOMING MESSAGE
|
||
HLL T1,P3 ;PUT SLA (NOW DLA) IN LH OF REASON CODE
|
||
PUSH P,T1 ;SAVE "XWD SLA,RSN"
|
||
EMRGCY ;SET GLOBAL FLAG TO USE "EMERGENCY" MEMORY
|
||
PUSHJ P,NCMHDR ;GET A MESSAGE WITH A CONTROL HEADER WRITTEN
|
||
STOPCD .,STOP,ANFCGM, ;++ CAN'T GET MESSAGE. NETSCN SHOULD CHECK
|
||
|
||
;TYP
|
||
|
||
MOVEI T1,NC.DSC ;THIS IS A DISCONNECT MESSAGE
|
||
PUSHJ P,BI2EBI ;WRITE THE CONTROL MESSAGE TYPE
|
||
|
||
;DLA
|
||
|
||
HLRZ T1,-1(P) ;RECOVER THE SLA (NOW DLA) FROM THE STACK
|
||
PUSHJ P,BI2EBI ;WRITE THE DLA
|
||
|
||
;SLA
|
||
|
||
SETZ T1, ;WE NEVER ASSIGNED A SLA
|
||
PUSHJ P,BI2EBI ;WRITE THE SLA
|
||
|
||
;RSN
|
||
|
||
HRRZ T1,-1(P) ;RECOVER THE RSN FROM THE STACK
|
||
PUSHJ P,BI2EBI ;WRITE THE REASON FOR THE DISCONNECT.
|
||
JSP T1,NETWRC ;SEND THE MESSAGE
|
||
POP P,(P) ;THROW AWAY THE TEMP ON THE STACK
|
||
PJRST UPOPJ1## ;RESTORE OUR PCB AND SKIP RETURN
|
||
|
||
|
||
|
||
;DUMMY CONNECT INIT PROCESSOR FOR THOSE OBJECTS WHICH DON'T ACCEPT A CI.
|
||
|
||
NJNKCI::MOVEI T1,RSN.OT ;JUNK CI (FAKE WITH NO SUCH OBJECT TYPE)
|
||
POPJ P, ;"ERROR" RETURN TO ICMCN7
|
||
;ICMCNC ROUTINE TO PROCESS CONNECT CONFIRM MESSAGES.
|
||
;CALL AS WITH ICMCNT, EXCEPT THAT P1 AND P4 HAVE BEEN PUSHED
|
||
; AND T1 := THE DLA
|
||
|
||
ICMCNC: PUSHJ P,ICMLAF ;GET LAT'S ADDRESS AND FLAGS
|
||
POPJ P, ;SLA OUT OF RANGE, OR UNASSIGNED
|
||
MOVEI T1,NDPCNC ;CONNECT CONFIRM DISPATCH ENTRY
|
||
PJRST ICMNDP ;GO DO THE DISPATCH
|
||
|
||
|
||
|
||
;ICMDSC ROUTINE TO HANDLE THE DISCONNECT.
|
||
;CALLED WITH
|
||
; P1 := BYTE POINTER TO THE DLA OF THE DISCONNECT
|
||
; P4 := LENGTH OF THE REST OF THE DISCONNECT MESSAGE
|
||
; W := POINTER TO THE NDB OF THE NODE THAT SENT THIS MESSAGE.
|
||
;RETURN CPOPJ ;DLA WRONG. MESSAGE IS BAD
|
||
; CPOPJ1 ;MESSAGE PROCESSED OK.
|
||
|
||
ICMDSC: PUSHJ P,ICMLAE ;GET LAT'S ADDRESS AND FLAGS
|
||
POPJ P, ;SLA OUT OF RANGE, OR UNASSIGNED
|
||
MOVEI T1,NDPDSC ;DISCONNECT VECTOR ENTRY
|
||
PJRST ICMNDP ;GO DO THE DISPATCH
|
||
;SUBROUTINE ICMNBN - NEIGHBOURS
|
||
ICMNBN: ;ENTRY
|
||
|
||
IFN PARANOID&P$NDB,<PUSHJ P,NDBCHK> ;MAKE SURE THIS DIDN'T COME FROM US.
|
||
|
||
PUSHJ P,SAVJW## ;WE WILL CLOBBER THESE
|
||
PUSH P,U ;SAVE THE PCB
|
||
MOVE T4,[POINT 9,NDBTOP(W)] ;GET A POINTER TO THE NEIGHBORS TABLE
|
||
MOVEI T3,NGHMAX ;COUNT OF MAXIMUM NUMBER OF NEIGHBORS.
|
||
|
||
ICMNB1: JUMPLE P4,ICMNB2 ;IF WE'VE READ ALL THE MSG, CLEAR UNUSED SLOTS
|
||
PUSH P,T3 ;SAVE T3 (EBI2BI CLOBBERS IT)
|
||
PUSHJ P,EBI2BI ;GET THE NODE NUMBER OF THE NEXT NEIGHBOR
|
||
IDPB T1,T4 ;PUT IT IN THE TABLE
|
||
PUSHJ P,EBI2BI ;GET THE COST OF THAT LINK
|
||
IDPB T1,T4 ;AND PUT THAT IN THE TABLE TOO
|
||
POP P,T3 ;GET OUR COUNTER BACK
|
||
SOJG T3,ICMNB1 ;LOOP OVER THE ENTIRE MESSAGE
|
||
JRST ICMNB4 ;TOO MANY NEIGHBORS. THINGS WILL GET SCREWED.
|
||
|
||
ICMNB2: SETZ T1, ;ZERO THE UNUSED PART OF THE TABLE
|
||
ICMNB3: IDPB T1,T4 ;CLEAR THE NODE NUMBER
|
||
IDPB T1,T4 ;CLEAR THE COST
|
||
SOJG T3,ICMNB3 ;LOOP OVER ALL UNUSED SLOTS
|
||
|
||
ICMNB4: PUSHJ P,RCMPTP ;RECOMPUTE THE TOPOLOGY,
|
||
PJRST UPOPJ1 ;AND GIVE SUCCESSFUL RETURN
|
||
;SUBROUTINE ICMRCF - REQUEST CONFIGURATION
|
||
ICMRCF: ;ENTRY
|
||
|
||
IFN PARANOID&P$NDB,<PUSHJ P,NDBCHK> ;MAKE SURE THIS DIDN'T COME FROM US.
|
||
|
||
PUSH P,U ;SAVE THE PCB
|
||
PUSHJ P,NCSCNF ;SEND THE CONFIGURATION MESSAGE
|
||
JFCL ;LATER
|
||
PJRST UPOPJ1## ;EXIT
|
||
|
||
|
||
;SUBROUTINE ICMCNF - CONFIGURATION
|
||
ICMCNF: ;ENTRY
|
||
|
||
IFN PARANOID&P$NDB,<PUSHJ P,NDBCHK> ;MAKE SURE THIS DIDN'T COME FROM US.
|
||
PUSHJ P,PSINTC## ;INFORM OF TOPOLOGY (CONFIG) CHANGE
|
||
|
||
MOVSI T1,NDB.CF ;GET THE CONFIGURATION BIT
|
||
IORM T1,NDBFLG(W) ;SEEN THE CONFIGURATION MESSAGE
|
||
ZZ==0
|
||
REPEAT <OBJ.MX/4>+1,<
|
||
SETZM NDBDEV+ZZ(W) ;CLEAR THE DEVICE TABLE(S)
|
||
ZZ==ZZ+1
|
||
>;END OF REPEAT
|
||
JUMPE P4,CPOPJ1## ;NO DEVICES
|
||
PUSH P,P2 ;SAVE P2
|
||
ICMCF1:
|
||
;OBJ
|
||
PUSHJ P,EBI2BI ;GET THE OBJECT TYPE
|
||
CAILE T1,OBJ.MX ;CHECK THE RANGE
|
||
JRST [POP P,P2 ;RESTORE P2
|
||
POPJ P,] ;DISMISS THE MESSAGE
|
||
MOVEI P2,(T1) ;COPY THE DEVICE NUMBER
|
||
;NDEV
|
||
PUSHJ P,EBI2BI ;GET THE COUNT
|
||
DPB T1,NETCNF##(P2) ;STORE NEW COUNT
|
||
;PID
|
||
ICMCF3: PUSHJ P,EAS2SX ;GET THE PID
|
||
JUMPG P4,ICMCF1 ;CONTINUE THROUGH THE MESSAGE
|
||
POP P,P2 ;RESTORE P2
|
||
JRST CPOPJ1##
|
||
;SUBROUTINE ICMDRQ - DATA REQUEST
|
||
|
||
ICMDRQ: PUSHJ P,ICMLAE ;GET LAT'S ADDRESS AND FLAGS
|
||
POPJ P, ;SLA OUT OF RANGE, OR UNASSIGNED
|
||
|
||
;DRQ
|
||
|
||
PUSH P,T2 ;SAVE NETLAT FLAGS
|
||
PUSHJ P,EBI2BI ;GET THE REQUEST COUNT
|
||
MOVE T4,T1 ;COPY THE DRQ COUNT FOR THE DRIVER TO HANDLE
|
||
POP P,T2 ;RESTORE NETLAT FLAGS
|
||
MOVEI T1,NDPDRQ ;GET THE DATA REQUEST VECTOR OFFSET
|
||
PJRST ICMNDP ;GO DO THE DISPATCH
|
||
|
||
|
||
;*** FOOTNOTE ***
|
||
|
||
COMMENT @
|
||
|
||
The Data Request Dispatch is much like the connects. When the driver
|
||
is called, the following registers are set up.
|
||
|
||
U := The PCB
|
||
P1, P4 := Pointer to the byte after the "DRQ" (Should be after the
|
||
end of the message
|
||
T4 := The Data Request Count.
|
||
|
||
The driver should normally return with a "CPOPJ1" indicating a good return,
|
||
but if for some reason he thinks that he is being screwed by the remote, he
|
||
may "CPOPJ" return (error) and the message will be INCTBD'ed
|
||
|
||
@
|
||
;ICMCTL ROUTINE TO PROCESS INCOMING STATION CONTROL MESSAGES
|
||
;CALL W := NDB POINTER
|
||
; P1 := POINTER TO THE FIRST BYTE OF THE STC MESSAGE
|
||
; P4 := LENGTH OF THE STC MESSAGE
|
||
;RETURN CPOPJ ;IF SOMETHING'S "WRONG" WITH THE MESSAGE
|
||
; CPOPJ1 ;WITH STC-BLOCK ON "NDBICT" OF THE NDB
|
||
;
|
||
;ACTION THIS ROUTINE COPIES THE INCOMING STATION CONTROL MESSAGE
|
||
; INTO AN "STC" BLOCK. IT QUEUES THIS OFF OF THE "NDBICT"
|
||
; WORD OF THE NDB. IF THERE IS A JOB WAITING FOR A STATION
|
||
; CONTROL RESPONSE ("NDBSTC" /= 0) THEN THAT JOB IS AWOKEN.
|
||
; OTHERWISE NETLDR IS STARTED.
|
||
|
||
ICMCTL: SKIPE NDBICT(W) ;SEE IF THERE IS A MESSAGE ALREADY WAITING
|
||
RETSKP ; IF MSG ALREADY THERE, JUST TOSS THIS ONE
|
||
JUMPLE P4,CPOPJ## ;MAKE SURE IT HAS DATA, "BAD MSG" IF NOT
|
||
PUSHJ P,SAVJW## ;SAVE J (STC-BLOCK) AND W
|
||
MOVEI T1,(P4) ;COPY THE LENGTH OF THE STC MESSAGE
|
||
PUSHJ P,GETSTC ;GET A STC-BLOCK TO HOLD IT
|
||
RETSKP ; IF NO CORE, TOSS MSG BUT SAY MSG IS "OK"
|
||
MOVE T2,[POINT 8,STCDAT(J)] ;GET A BYTE POINTER TO STC DATA PART
|
||
ICMCT1: ILDB T1,P1 ;LOOP OVER ALL STC-MESSAGE BYTES
|
||
IDPB T1,T2 ; STORING THEM IN THE STC-BLOCK
|
||
SOJG P4,ICMCT1 ; P4 HAS COUNT OF BYTES
|
||
|
||
HRLI J,^D10 ;GET A 10 SECOND TIMER, AND QUEUE THIS STC
|
||
MOVEM J,NDBICT(W) ;MESSAGE ON THE NDB. IF NO ONE READS IT
|
||
; IN 10 SECONDS, IT WILL SELF-DESTRUCT
|
||
SKIPE T1,NDBSTC(W) ;SEE IF ANYONE IS WAITING FOR A MESSAGE
|
||
JRST [HRRZS T1 ; ONLY WANT JOB NUMBER, THROW AWAY TIMER
|
||
AOS (P) ; IF SOMEONE'S WAITING, INDICATE MESSAGE "OK"
|
||
PJRST EWAKE##] ; WAKE THE USER AND SKIP RETURN
|
||
|
||
PUSHJ P,FRCNLD ;IF NO ONE EXPECTING IT, START UP NETLDR
|
||
; IN HOPES THAT IT WILL WANT IT.
|
||
RETSKP ;GIVE GOOD RETURN (ACCEPTING THE MESSAGE)
|
||
SUBTTL ICM HELPERS
|
||
|
||
;ICMLAE/ICMLAF - READ IN LINK ADDRESS AND SETUP FOR ICMNDP DISPATCH
|
||
;CALL P1/P4 SETUP
|
||
; PUSHJ P,ICMLAE/F
|
||
; ERROR RETURN
|
||
; NORMAL RETURN
|
||
;
|
||
;ON ERROR RETURN THE LINK ADDRESS WAS OUT OF RANGE, OR UNASSIGNED
|
||
;
|
||
;ON NORMAL (SKIP) RETURN, THE NETLAT FLAGS ARE IN T2 AND THE
|
||
;LINK ADDRESS DDB/LDB ADDRESS IS IN F
|
||
|
||
ICMLAE: PUSHJ P,EBI2BI ;READ IN DESTINATION LINK ADDRESS
|
||
ICMLAF: CAIL T1,0 ;RANGE
|
||
CAILE T1,LATLEN## ; CHECK
|
||
POPJ P, ;LINK ADDRESS OUT OF RANGE
|
||
SKIPN T2,NETLAT(T1) ;GET NETLAT ENTRY
|
||
POPJ P, ;UNASSIGNED
|
||
LDB F,LATPTR ;GET DDB/LDB ADDRESS
|
||
JRST CPOPJ1## ;SUCCESSFUL RETURN
|
||
|
||
|
||
|
||
;ICMNDP ROUTINE TO PERFORM THE NETWORK DISPATCH
|
||
;CALL MOVEI T1,DISPATCH FUNCTION
|
||
; MOVE T2,NETLAT FLAGS (LAT.TY, LAT.VT)
|
||
; MOVE F, DDB/LDB ADDRESS
|
||
; PUSHJ P,ICMNDP
|
||
;RETURN PJRSTS TO THE ROUTINE SPECIFIED
|
||
|
||
ICMNDP: JUMPGE T2,ICMND2 ;DISPATCH FOR DDBS
|
||
TLNN T2,LAT.VT ;IF IT'S A LDB, SEE IF IT'S A VTM
|
||
JRST @MCRNDP##(T1) ;IF IT'S NOT A VTM, USE MCR DISPATCH
|
||
JRST @TTYNDP##(T1) ;USE NETWORK VIRTUAL TERMINAL DISPATCH
|
||
|
||
ICMND2: HLRZ T2,DEVNET(F) ;GET ADDRESS OF DEVICE SERVICE "NDP" DISPATCH
|
||
S0JRST @NDTNDP(T2) ;THEN USE THE DEVICE DISPATCH VECTOR
|
||
SUBTTL IDCCTL - INPUT DEVICE CONTROL (DAP) MESSAGE PROCESSOR
|
||
|
||
;SUBROUTINE IDCCTL - DEVICE CONTROL (DAP) MESSAGES
|
||
;CALL MOVEI U,PCB
|
||
; MOVEI W,NDB
|
||
; MOVEI T1,DLA
|
||
; PUSHJ P,IDCCTL
|
||
;RETURN POPJ P,
|
||
|
||
IDCCTL: NTDBUG ;VERIFY THE INTERLOCK
|
||
|
||
;DLA
|
||
|
||
CAIL T1,0 ;RANGE
|
||
CAILE T1,LATLEN## ; CHECK DLA
|
||
PJSP T1,INCTBD ;BAD LINK ADDRESS
|
||
LDB F,LATPTR ;GET DDB/LDB ADDRESS
|
||
MOVE T2,NETLAT(T1) ;AND NETLAT FLAGS
|
||
TLNN T2,LAT.TY ;DDB OR LDB?
|
||
SKIPA T3,DEVNET(F) ;DDB, GET NODE NUMBER
|
||
LDB T3,LDPRNF## ;LDB, GET NODE NUMBER
|
||
ANDI T3,777 ;MASK OUT JUNK
|
||
HLRZ T1,NDBNNM(W) ;GET OUR NODE NUMBER
|
||
CAIE T3,(T1) ;BETTER MATCH
|
||
PJSP T1,INCTBD ;NOPE, DON'T LET MESSAGE BE PROCESSED
|
||
PUSH P,T2 ;SAVE NETLAT FLAGS
|
||
MOVE T1,PCBCTR(U) ;GET MESSAGE LENGTH
|
||
SUBI T1,6 ;DISCOUNT PROTOCOL
|
||
CAIGE T1,1_<NETLNH-1> ;IN RANGE FOR JFFO?
|
||
JFFO T1,.+2 ;GET HIGHEST BIT NUMBER
|
||
TDZA T1,T1 ;OUT OF RANGE, USE ENTRY 0
|
||
MOVNI T1,-^D36(T2) ;IN RANGE, PUT IN PROPER ORDER
|
||
AOS NCLRDL(T1) ;RECORD DATA LENGTH
|
||
POP P,T2 ;RESTORE NETLAT FLAGS
|
||
MOVEI T1,NDPICM ;NOW PASS MESSAGE VIA THE ICM DISPATCH
|
||
PJRST ICMNDP ;GIVE THE PCB TO THE DEVICE SERVICE ROUTINE.
|
||
; IT MAY EITHER BE PROCESSED IMMEDIATLY AT
|
||
; "INTERRUPT" LEVEL (E.G., LPT'S) OR QUEUED
|
||
; FOR LATER PROCESSING AT UUO LEVEL (CDR'S)
|
||
;RCMPTP THIS ROUTINE RECOMPUTES THE NETWORK TOPOLOGY. IT SHOULD BE CALLED
|
||
; EVERY TIME THE TOPOLOGY CHANGES (NODEID & NEIGHBORS MESSAGE)
|
||
; IT IS RESPONSIBLE FOR GARBAGE COLLECTING UNREACHABLE NDB'S AND
|
||
; RE-ALLOCATING FEK'S. IT HAS THREE PHASES.
|
||
; 1) RECOMPUTE OUR NEIGHBORS. (FOR NEIGHBORS MSG)
|
||
; 2) RESET ALL NDB'S (CLEAR NDB.TP, SET COST TO 777777)
|
||
; 3) MARK ALL REACHABLE NODES AND REALLOCATE FEK'S (TPMARK)
|
||
; (NODES FOUND BY TRACING OUT PATHS STARTING WITH
|
||
; OUR FEK'S)
|
||
; 4) GARBAGE COLLECT ALL UNREACHABLE NODES.
|
||
;PRESERVES ALL P'S
|
||
;CLOBBERS ALL T'S
|
||
;RETURNS CPOPJ
|
||
|
||
RCMPTP: NTDBUG ;VERIFY THE INTERLOCK
|
||
PUSHJ P,SAVE4## ;USES ALL THE P'S
|
||
|
||
;REBUILD OUR NEIGHBORS TABLE (FOR SENDING NEIGHBORS MSG)
|
||
|
||
MOVE P1,[POINT 9,NETNDB##+NDBTOP] ;POINTER TO NEIGHBORS TABLE
|
||
MOVEI P2,NGHMAX ;MAXIMUM NUMBER OF NEIGHBORS TABLE CAN HOLD
|
||
SKIPA J,[FEKFST##] ;LOOP OVER ALL FEK'S STARTING WITH FIRST
|
||
RCMPT1: HRRZ J,FEKBLK(J) ;GET THE ADDRESS OF THE NEXT FEK
|
||
JUMPE J,RCMPT2 ;EXIT IF WE'VE LOOKED AT ALL FEKS
|
||
HRRZ T1,FEKNNM(J) ;GET NODE NUMBER
|
||
JUMPE T1,RCMPT1 ;NEED ONE IF WE HAVE A NEIGHBOR
|
||
SKIPL T3,FEKBLK(J) ;SKIP IF THE FEK IS DEAD
|
||
JRST RCMPT1 ;EITHER FEK IS DEAD, OR NO NODE ID
|
||
IFN FTENET,<
|
||
TLNE T3,FK.ETM ;IS THIS AN ETHERNET MASTER FEK?
|
||
JRST RCMPT1 ;YES, IGNORE IT, ONLY SLAVES ARE NEIGHBORS
|
||
> ;END IFN FTENET
|
||
HLRZ T2,FEKCST(J) ;GET COST FOR THIS FEK
|
||
IDPB T1,P1 ;SAVE HIS NUMBER AS A NEIGHBOR
|
||
IDPB T2,P1 ;SAVE COST
|
||
SOJGE P2,RCMPT1 ;LOOP OVER ALL FEK'S
|
||
STOPCD .,STOP,ANFTMF, ;++ TOO MANY FEK'S.
|
||
|
||
;HERE TO ZERO THE UNUSED PART OF OUR NEIGHBORS TABLE
|
||
|
||
RCMPT2: SOJL P2,RCMPT3 ;EXIT WHEN WE'VE SET ALL THE NEIGHBORS
|
||
IDPB J,P1 ;CLEAR THIS NODE NUMBER (J IS ZERO...)
|
||
IDPB J,P1 ;CLEAR ITS COST ALSO.
|
||
JRST RCMPT2 ;LOOP OVER ALL UNUSED SLOTS
|
||
;HERE TO CLEAR THE MARK BIT (NDB.TP) IN ALL NDB'S
|
||
|
||
RCMPT3: MOVSI T1,NDB.TP ;GET THE MARK BIT
|
||
MOVEI W,NETNDB## ;GET THE FIRST NODE IN THE LIST
|
||
RCMPT4: ANDCAM T1,NDBFLG(W) ;CLEAR THE BIT
|
||
HRRZ W,NDBNNM(W) ;ADVANCE TO THE NEXT NDB
|
||
JUMPN W,RCMPT4 ;LOOP UNTIL WE REACH A ZERO LINK
|
||
|
||
;HERE TO MARK ALL REACHABLE NODES AND DETERMINE WHICH FEK THEY SHOULD USE.
|
||
|
||
SKIPA J,[FEKFST##] ;GET THE ADDRESS OF THE FIRST FEK
|
||
RCMPT5: HRRZ J,FEKBLK(J) ;GET THE ADDRESS OF THE NEXT FEK
|
||
JUMPE J,RCMPT6 ;EXIT IF WE HAVE DONE ALL FEKS
|
||
SKIPGE T1,FEKBLK(J) ;SKIP IF FEK IS DEAD
|
||
IFN FTENET,<TLNN T1,FK.ETM> ;EXIT IF NEIGHBORLESS ETHERNET MASTER FEK
|
||
TLNE T1,FK.NUL ;EXIT IF THIS IS A NUL FEK
|
||
JRST RCMPT5 ;EITHER DEAD OR NULL. GO DO NEXT FEK
|
||
HRRZ T1,FEKNNM(J) ;GET NODE NUMBER
|
||
JUMPE T1,RCMPT5 ;NO NEIGHBOR
|
||
PUSHJ P,SRCNDB ;SET UP "W" WITH THE NDB ADDRESS
|
||
JRST RCMPT5 ;JUST HIT VERY-VERY NARROW CROSS CPU RACE...
|
||
SETZ T2, ;SAY THAT IT'S A ZERO COST TO HIM
|
||
; (JUST A WHITE LIE TO MAKE SURE WE USE FEK)
|
||
JSP T1,TPMARK ;MARK ALL NODES WHOSE BEST PATH (SO FAR)
|
||
; IS THROUGH THIS FEK
|
||
JRST RCMPT5 ;LOOP OVER ALL FEKS
|
||
|
||
;NOW WE SWEEP AND DELETE ALL UNREACHABLE NODES
|
||
|
||
RCMPT6: HRRZ W,NETNDB##+NDBNNM ;GET START OF THE LIST
|
||
RCMPT7: JUMPE W,CPOPJ ;IF AT END, THEN EXIT
|
||
MOVSI T1,NDB.TP ;GET THE MARK BIT, AND
|
||
TDNE T1,NDBFLG(W) ;SEE IF IT'S SET.
|
||
JRST [HRRZ W,NDBNNM(W) ;IF SO, THEN STEP TO NEXT NDB
|
||
JRST RCMPT7] ;AND CONTINUE
|
||
HRRZ P1,NDBNNM(W) ;OTHERWISE GET THE LINK TO THE NEXT NDB
|
||
PUSHJ P,RMVNDB ;BLAST THE NOW USELESS NDB
|
||
MOVEI W,(P1) ;GET ADDR OF NEXT NDB TO CHECK
|
||
JRST RCMPT7 ;AND GO DO IT.
|
||
;TPMARK THIS SUBROUTINE PERFORMS THE RECURSIVE MARK PHASE AS WELL AS
|
||
; THE TASK OF FRONT-END-KONTROLLERS TO EACH NDB.
|
||
; BECAUSE OF THE SMALL AMOUNT OF STACK SPACE ALLOWED, AND THE
|
||
; POSSIBILITY OF LARGE NETWORKS THE PDL STORAGE FOR THESE
|
||
; RECURSIVE ROUTINES IS IN THE NDB'S THEMSELVES. THESE LOCATIONS
|
||
; ARE THE THREE 'NDBTMP' LOCATIONS
|
||
;REGISTER USAGE
|
||
;CALL WITH
|
||
; J := THE ADDRESS OF THE FEK THAT STARTED THIS CHAIN
|
||
; W := THE ADDRESS OF THE CURRENT NDB
|
||
; T1 := THE RETURN ADDRESS (JSP T1, ...)
|
||
; T2 := THE 'COST' OF THE PATH FROM NETNDB TO THIS NDB.
|
||
;
|
||
; P1, P2, AND P3 MUST BE PERSERVED. THEY ARE USED AS FOLLOWS:
|
||
;
|
||
; P1 OUR NDB(W)
|
||
; P2 A BYTE POINTER TO THE CURRENT ENTRY IN OUR NEIGHBORS TABLE
|
||
; P3 RETURN ADDR(T1),,THE NUMBER OF NEIGHBOR SLOTS LEFT TO LOOK AT.
|
||
;
|
||
|
||
TPMARK: JUMPE W,(T1) ;IF NO NDB, WE CAN'T MARK FROM IT...
|
||
MOVEI T3,NETNDB## ;GET THE ADDRESS OF THE PROTOTYPE NDB
|
||
CAIN W,(T3) ; IF THIS IS THE PROTOTYPE
|
||
JRST (T1) ;THEN LEAVE NOW (DON'T CHANGE ITS FEK)
|
||
MOVSI T3,NDB.TP ;GET THE "MARK BIT"
|
||
TDNN T3,NDBFLG(W) ;HAVE WE VISITED THIS NODE BEFORE.
|
||
JRST [IORM T3,NDBFLG(W) ;IF NOT, MARK THAT WE HAVE NOW.
|
||
JRST TPMRK1] ; AND DON'T BOTHER TO COMPARE COSTS.
|
||
HLRZ T3,NDBFEK(W) ;GET HIS BEST COST SO FAR
|
||
CAIL T2,(T3) ;IS THIS A CHEAPER ROUTE
|
||
JRST (T1) ; IF NOT CHEAPER, THEN EXIT NOW
|
||
TPMRK1: HRLM T2,NDBFEK(W) ;SAVE CURRENT COST AT BEST SO FAR
|
||
HRRM J,NDBFEK(W) ;SAVE THIS FEK AS BEST FEK SO FAR
|
||
DMOVEM P1,NDBTMP(W) ;SAVE P1 AND P2
|
||
MOVEM P3,NDBTMP+2(W) ; DON'T FORGET P3
|
||
MOVSI P3,(T1) ;SAVE OUR RETURN ADDRESS IN A PROTECTED LOC
|
||
HRRZ P1,W ;KEEP OUR NDB POINTER SAFE ALSO
|
||
MOVE P2,[POINT 9,NDBTOP(P1)] ;BUILD A POINTER TO OUR NEIGHBORS
|
||
HRRI P3,NGHMAX ;GET A COUNT OF MAX NUMBER OF NEIGHBORS
|
||
|
||
;CONTINUED ON NEXT PAGE
|
||
;CONTINUED FROM PREVIOUS PAGE
|
||
|
||
;NOW LOOP OVER EACH NEIGHBOR RECURSIVLY CALLING TPMARK. (IF ALL PATHS
|
||
; ARE POSITIVE COST, THERE IS NO DANGER OF LOOPING...)
|
||
|
||
TPMRK2: TRNN P3,-1 ;IF WE'VE PROCESSED ALL NEIGHBORS
|
||
JRST TPMRK4 ;THEN EXIT
|
||
SUBI P3,1 ;COUNT DOWN
|
||
ILDB T1,P2 ;GET THE NUMBER OF OUR NEXT NEIGHBOR
|
||
JUMPE T1,TPMRK3 ;IF THERE ISN'T ONE, SKIP COST AND GO TO NEXT
|
||
PUSHJ P,SRCNDB ;SET UP "W" WITH NEIGHBORS NDB ADDRESS
|
||
JRST [PUSHJ P,MAKNDB ;IF HE'S A NEW NEIGHBOR, MAKE AN NDB FOR HIM.
|
||
JRST TPMRK3 ;IF NO CORE. JUST SKIP IT. WE'LL GET HIM LATER
|
||
JRST .+1] ;REJOIN MAIN FLOW WITH "W" SET UP.
|
||
ILDB T1,P2 ;GET THE COST OF THE LINK FROM US TO HIM.
|
||
HLRZ T2,NDBFEK(P1) ;GET THE COST SO FAR TO GET TO US.
|
||
ADD T2,T1 ;THE SUM IS TOTAL COST TO HIM VIA THIS PATH
|
||
JSP T1,TPMARK ;RECURSIVLY MARK HIM
|
||
JRST TPMRK2 ;LOOP OVER ALL NEIGHBORS.
|
||
|
||
TPMRK3: ILDB T1,P2 ;SKIP COST IF NO NODE, OR NO CORE
|
||
JRST TPMRK2 ;LOOP OVER ALL NEIGHBORS.
|
||
|
||
TPMRK4: HLRZ T1,P3 ;ALL NEIGHBORS MARKED. GET RETURN ADDRESS
|
||
MOVE P3,NDBTMP+2(P1) ;RESTORE P3
|
||
DMOVE P1,NDBTMP(P1) ;RESTORE P1 AND P2
|
||
JRST (T1) ;RETURN TO CALLER
|
||
;SUBROUTINE ONLNDB/OFLNDB - TYPE ONLINE/OFFLINE FOR A NETWORK NODE
|
||
;CALL MOVEI W,NDB
|
||
; PUSHJ P,ONLNDB/OFLNDB
|
||
;RETURN CPOPJ
|
||
|
||
ONLNDB: SKIPA T1,[[ASCIZ /up at /]]
|
||
OFLNDB: MOVEI T1,[ASCIZ /down at /]
|
||
SKIPN %SIOPR## ;LET OPR REPORT IT IF ORION IS RUNNING
|
||
SKIPGE DEBUGF## ;CHECK FOR DEBUG
|
||
POPJ P, ;YES, SKIP THE MESSAGES
|
||
PUSH P,U
|
||
PUSH P,T1 ;SAVE THE MODE
|
||
MOVE U,OPRLDB## ;GET THE OPERATOR LINE
|
||
PUSHJ P,INLMES## ;TYPE %%
|
||
ASCIZ /%% Node /
|
||
PUSHJ P,TYPNOD ;TYPE OUT JUST "SNM(NNM)"
|
||
POP P,T1 ;GET ONLINE/OFFLINE BACK
|
||
PUSHJ P,CONMES## ;TYPE IT
|
||
PUSHJ P,PRDTIM## ;FINISH OFF WITH TIME OF DAY
|
||
PJRST UPOPJ## ;EXIT
|
||
;SUBROUTINE TYPNDB - TYPE OUT THE NODE INFOR
|
||
;CALL MOVEI W,NDB
|
||
; PUSHJ P,TYPENDB
|
||
;RETURN CPOPJ
|
||
|
||
TYPNDB::NTDBUG ;VERIFY THE INTERLOCK
|
||
MOVEI T1,[ASCIZ \ANF \] ;ASSUME NCL.
|
||
CAIN W,NETNDB## ;IS THE NDB THE LOCAL NODE NDB?
|
||
MOVEI T1,[ASCIZ \Local \] ;YES, DISTINGUISH.
|
||
PUSHJ P,CONMES## ;TYPE OUT QUALIFIER
|
||
PUSHJ P,TYPNOD ;TYPE "SNM(NNM)"
|
||
HRRZ T1,NDBSID(W) ;GET THE MONITOR NAME
|
||
SKIPE T1 ;SKIP IF UNKNOWN
|
||
PUSHJ P,CONMES## ;TYPE
|
||
PUSHJ P,PRSPC## ;SPACE
|
||
HLRZ T1,NDBSID(W) ;GET THE CREATION DATE
|
||
JUMPE T1,CPOPJ## ;EXIT IF UNKNOWN
|
||
PJRST CONMES## ;TYPE
|
||
|
||
|
||
;TYPNOD ROUTINE TO TYPE OUT "STA-NAME(NUMBER)"
|
||
;CALL MOVX U,LDB
|
||
; MOVX W,NDB
|
||
; PUSHJ P,TYPNOD
|
||
;RETURN CPOPJ
|
||
|
||
TYPNOD::NTDBUG
|
||
HLRZ T1,NDBSNM(W) ;GET THE STATION NAME POINTER
|
||
MOVE T2,(T1) ;GET THE STATION NAME
|
||
SKIPN T1 ;IF THE NAME HASN'T BEEN RECEIVED YET,
|
||
MOVE T2,[SIXBIT /?????/] ;USE THIS FOR A NAME
|
||
PUSHJ P,PRNAME## ;PRINT IT
|
||
MOVEI T3,"(" ;PAREN
|
||
PUSHJ P,COMTYO## ;PRINT
|
||
HLRZ T1,NDBNNM(W) ;GET THE NODE NUMBER
|
||
PUSHJ P,PRTDI8## ;TYPE
|
||
PJSP T1,CONMES## ;TYPE TERMINATOR AND RETURN
|
||
ASCIZ /) /
|
||
|
||
|
||
;TYPILT ROUTINE TO "SEND OPR" TO TELL HIM THAT THE TOPOLOGY IS ILLEGAL
|
||
;CALL MOVX W,NODE THAT IS DUPLICATED
|
||
; PUSHJ P,TYPILT
|
||
;RETURN CPOPJ
|
||
|
||
TYPILT: PUSHJ P,FRCSET## ;WE ARE GOING TO DO A SEND ON FRCLIN
|
||
MOVEI T1,[ASCIZ /SEND OPR Illegal network topology. Two nodes /]
|
||
PUSHJ P,CONMES## ;SEND THE FIRST PART
|
||
HLRZ T1,NDBNNM(W) ;GET THE NODE'S NUMBER
|
||
PUSHJ P,PRTDI8## ; AND TYPE THAT OUT
|
||
PUSHJ P,PRPER## ;FINISH THE SENTENCE
|
||
PJRST PCRLF## ;FINISH THE LINE AND RETURN
|
||
SUBTTL ABMT -- NeTwork Device subroutines. (An imitation UUOCON)
|
||
|
||
|
||
COMMENT \
|
||
|
||
Here is a list of the subroutines that should be used to write network
|
||
device drivers. It is hoped that the routines are device independant
|
||
enough to be useful for almost any network device. The routines fall
|
||
into the following classes.
|
||
|
||
General purpose:
|
||
NTDSET
|
||
This routine sets up S, J, and W and makes sure that the device is
|
||
still connected. (Sets IOSERR and IODERR if not)
|
||
NTDREL
|
||
This routine sets IOSREL in the lh of DEVIOS. Primarly used as
|
||
something to put in the dispatch entry for release.
|
||
NTDONL
|
||
This routine checks the bit IOSERR and skips if it's not set.
|
||
NTDHNG
|
||
This routine sets DVOFLN, returns "NT" and calls HNGSPT.
|
||
NTDCLO
|
||
Close output. This routine returns "NT" and calls "OUT".
|
||
NTDIBA
|
||
This routine checks to see if there is an input buffer available.
|
||
It skips if there is, non-skips if not.
|
||
NTDOBA
|
||
This routine checks to see if there is an output buffer available.
|
||
It skips if there is, non-skips if not.
|
||
NTDIDA
|
||
This routine skips if the device has input data available
|
||
NTDCBC
|
||
This routine calculates the number of bytes (given a byte pointer
|
||
in T4) that will fit in a buffer of size "T3". (Kind of random
|
||
calling convention I know, but this is only meant to be used by
|
||
a few of the "NTD" routines.
|
||
NTDPRV
|
||
This routine skip's if the user has network privs (poke JACCT etc)
|
||
|
||
Input buffer handling. (Interface to UUOCON)
|
||
NTDSIB
|
||
Setup Input Buffer. This routine sets up the two DEVAXI words
|
||
so the device service routine can do buffered "output" into the
|
||
users "input" buffer...
|
||
NTDAIB
|
||
Advance Input Buffer. Returns the input buffer to the user.
|
||
(Using the buffered I/O analogy, this is just like the "OUT" UUO)
|
||
|
||
Output buffer handling. (Interface to UUOCON)
|
||
NTDSOB
|
||
Setup Output Buffer. This routine sets up the two DEVAXO words
|
||
so the device service routine can do buffered "input" from the
|
||
users buffer. Also, this is necessary for NTDXMT to run.
|
||
NTDAOB
|
||
Advances the users output buffer. Clears DEVAXO to indicate that
|
||
the buffer is no longer setup.
|
||
NTDXMT
|
||
This routine sends one PCB's worth of data from the users buffer.
|
||
It updates both DEVAXO and DEVAXO+1.
|
||
|
||
Input message handling. (PCB's)
|
||
NTDISP
|
||
This is the DAP dispatch routine. Called with P1 pointing to the
|
||
first "CNT" field of the DAP portion of the NCL message.
|
||
NTDILD
|
||
This is the "interrupt" level dispatch. It is meant to be used
|
||
by drivers that do not wish to queue their input message handling.
|
||
To use this routine simply make the NDPICM dispatch entry point
|
||
to NTDILD.
|
||
NTDQIP
|
||
This is the routine to queue an incoming PCB to be processed at
|
||
UUO level. (Use this routine as the NDPICM dispatch if you wish
|
||
to do low level processing of input messages)
|
||
NTDDID
|
||
This is the routine that takes PCB's off the queue (DEVPCB(f))
|
||
and calls NTDISP with them. (Use this routine to process messages
|
||
queued by NTDQIP)
|
||
|
||
Data request handling.
|
||
NTDCDQ
|
||
For output devices. This routine checks to see if you have
|
||
any available data requests.
|
||
NTDDDQ
|
||
For output devices. This routine decrements DEVDRQ(F). Should
|
||
be called only after data has been sent. Stops if no data requests
|
||
are available.
|
||
NTDDOD
|
||
For input devices. This routine takes a PCB in "U" and if it
|
||
is not an interrupt message, decrements the number of outstanding
|
||
data-requests (ie. lh(devdrq(f))).
|
||
NTDXDQ
|
||
For input devices. This routine looks at the input buffer
|
||
chain and determines if it should send any data requests.
|
||
(Must NEVER be called from interrupt level since it doesn't OUCHE
|
||
the buffer headers.)
|
||
NTDRDQ
|
||
Standard "canned" routine for handling incoming data requests.
|
||
(ie. It is meant to be pointed to by the "DRQ" vector entry.)
|
||
|
||
Delaying jobs for data or data requests.
|
||
NTDWTI
|
||
Used to wait for input (understands asynch i/o)
|
||
NTDWTO
|
||
Used to wait for output.
|
||
NTDIAV
|
||
Called to signify input available
|
||
NTDOAV
|
||
Called to signify output data requests available
|
||
|
||
Connect and Disconnect processing.
|
||
NTDCNC
|
||
This is the default Connect Confirm dispatch handler. Used for most
|
||
"normal" (eg LPT, CDR ...) devices
|
||
NTDCNF
|
||
This is a subset of NTDCNC (and is called by same) to process the
|
||
MML and FEA(DCM,RLN,DVT,DVU,DVV) fields.
|
||
NTDDSC
|
||
This is the default Disconnect (both Initiate and Confirm) handler.
|
||
NTDCNT
|
||
This routine performs the connect function for "normal" devices.
|
||
It assigns a SLA and waits for the connect to complete.
|
||
NTDXPN
|
||
This is a small routine to generate the "DPN" field of a connect
|
||
for "normal" devices.
|
||
NTDXSN
|
||
This is line NTDXPN except that it writes an "SPN" field consisting
|
||
of OBJ = OBJ.TK, PID = "JOB-NAME[P,PN]"
|
||
NTDXDS
|
||
This is a routine to send a disconnect and set the LAT state to
|
||
"LAT.DC" (ie disconnect confirm wait)
|
||
NTDNWD
|
||
This is a routine that handles the NDPNWD (Node Went Down) entry
|
||
for "normal" devices
|
||
|
||
Message construction and sending
|
||
NTDHDR
|
||
This builds a NCL header with the DLA field filled in.
|
||
NTDHDI
|
||
This is the same as NTDHDR except that the "interrupt message"
|
||
bit is turned on in the NCT.
|
||
NTDSST
|
||
This is used to send a "set" status bits message
|
||
NTDCST
|
||
This is used to send a "clear" status bits message
|
||
NTDXST
|
||
This is used to send a status message.
|
||
NTDWRT
|
||
This routine gives a PCB to the network for delivery.
|
||
|
||
\
|
||
;NTDSET GENERAL PURPOSE SET-UP ROUTINE
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,NTDSET
|
||
;RETURN CPOPJ ;ALWAYS.
|
||
;SETS UP J, S AND W. IF THE DEVICE IS NOT CONNECTED (NODE WENT AWAY, OR
|
||
; DISCONNECTED) IOSERR WILL BE SET IN DEVIOS(F)
|
||
;
|
||
NTDSET:: ;GENERAL PURPOSE SET-UP ROUTINE
|
||
LDB J,PJOBN## ;GET JOB NUMBER FROM THE DDB
|
||
HRRZ T1,DEVNET(F) ;GET THE NUMBER OF THE NODE OWNING THE DEVICE
|
||
MOVE S,DEVIOS(F) ;SET UP S
|
||
TLNE S,IOSCON ;IF WE ARE CONNECTED, THEN
|
||
PUSHJ P,SRCNDB ; SET UP W WITH THE NDB ADDRESS
|
||
JRST NTDSE1 ;HERE IF NOT CONNECTED (OR NODE WENT AWAY)
|
||
POPJ P, ;ALL DONE. RETURN WITH REG'S SETUP
|
||
|
||
NTDSE1: ;HERE IF THE DEVICE IS NO LONGER CONNECTED
|
||
MOVSI S,IOSCON ;GET AND CLEAR THE
|
||
ANDCAB S,DEVIOS(F) ; "DEVICE IS CONNECTED" BIT
|
||
MOVSI S,IOSERR ;SET THIS ERROR
|
||
IORB S,DEVIOS(F) ; BIT FOR NTDONL TO SEE.
|
||
POPJ P, ;RETURN WITH REGS SETUP AND ERROR BITS ON.
|
||
;NTDCLO ROUTINE TO PERFORM NORMAL "OUTPUT CLOSE" PROCESSING
|
||
;CALL MOVE F,DDB ;DEVICE TO CLOSE OUTPUT ON
|
||
; PUSHJ P,NTDCLO ;SAVE "NT", CALL OUT AND WAIT FOR COMPLETION
|
||
;RETURN CPOPJ ;ALWAYS FROM WAIT1
|
||
;
|
||
NTDCLO::NTSAVE ;RETURN THE "NT" INTERLOCK (WE BETTER HAVE IT)
|
||
PUSHJ P,OUT## ;FORCE OUT ANY UN-EMPTIED BUFFERS
|
||
PJRST WAIT1## ;WAIT FOR EVERYTHING TO GO OUT.
|
||
|
||
|
||
|
||
;NTDREL ROUTINE TO SET IOSREL WHEN A DEVICE IS RELEASED
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,NTDREL ;MARK DEVICE AS RELEASED SO DATA REQUESTS
|
||
; ; WON'T CAUSE FALSE "WAKES" TO HAPPEN
|
||
;RETURN CPOPJ ;ALWAYS
|
||
;
|
||
NTDREL:: ;HERE ON A RELEASE
|
||
MOVSI S,IOSTBL!IOSERR ;CLEAR THESE TWO ERROR BITS
|
||
ANDCAB S,DEVIOS(F)
|
||
MOVSI S,IOSREL ;SET THE BIT THAT SAYS
|
||
IORB S,DEVIOS(F) ; WE HAVE RELEASED THIS DEVICE
|
||
SETZM DEVAXO(F) ;CLEAR POINTER TO OUTPUT BUFFER
|
||
SETZM DEVAXI(F) ;CLEAR POINTER TO INPUT AS WELL
|
||
TLNE S,IOSCON ;IF WE ARE STILL CONNECTED, THEN JUST
|
||
POPJ P, ; RETURN AND LET ZAPNET DISCONNECT LATER.
|
||
LDB T1,NETSLA ;IF NOT CONNECTED, CHECK FOR A LAT ENTRY
|
||
JUMPE T1,CPOPJ## ;IF NONE, THEN NO MORE TO DO
|
||
|
||
IFN PARANOID&P$LAT,< ;MAKE SURE WE ARE IN A VALID STATE.
|
||
|
||
LDB T2,LATSTA ;GET THE STATE.
|
||
CAIN T2,LAT.OK ;WE SHOULDN'T BE "OK" IF NOT CONNECTED
|
||
STOPCD .,STOP,ANFWLS, ;++ WRONG LAT STATE
|
||
>
|
||
PUSHJ P,GIVSLA ;RETURN THE LAT ENTRY (GO TO IDLE STATE)
|
||
PJRST CLNNET ;CLEAN OUT THE DDB (DRQ, NPD'S ETC...)
|
||
;NTDONL ROUTINE TO SEE IF THE DEVICE IS ONLINE (NO ERROR CONDITIONS)
|
||
;CALL MOVE S,DEVIOS(F) ;GET DEVIOUS BITS IN S
|
||
; PUSHJ P,NTDONL ;SEE IF ON LINE
|
||
;RETURN CPOPJ ;DEVICE HAS ERROR BITS SET.
|
||
; CPOPJ1 ;EVERYTHING SEEMS OK.
|
||
;
|
||
;NOTE! THIS ROUTINE MAY BE USED AS THE ONLINE DISPATCH ENTRY.
|
||
;
|
||
NTDONL:: ;CHECK TO SEE IF DEVICE IN ONLINE
|
||
TLNN S,IOSERR ;EVERYTHING OK?
|
||
AOS (P) ;LOOKS GOOD (NO ERROR BITS)
|
||
POPJ P,
|
||
|
||
|
||
;NTDHNG ROUTINE TO PERFORM NORMAL DEVICE OFFLINE PROCESSING
|
||
;CALL MOVE F,DDB ;DEVICE TO MARK AS OFF-LINE
|
||
; PUSHJ P,NTDHNG ;SET DVOFLN, SAVE "NT", CALL HNGSTP
|
||
;RETURN CPOPJ ;FROM HNGSTP
|
||
;
|
||
NTDHNG::MOVSI T1,DVOFLN ;GET THE OFF-LINE BIT AND SET IT
|
||
IORM T1,DEVCHR(F) ; SO THAT WE WILL GET ON-LINE INTERRUPT
|
||
NTSAVE ;"SAVE" THE "NT" INTERLOCK
|
||
PJRST HNGSTP## ;CALL HUNGSTP AND RETURN
|
||
|
||
|
||
|
||
;NTDGON ROUTINE TO SET ERROR WHEN DEVICE HAS "GONE" AWAY
|
||
;CALL MOVE F,DDB ;DEVICE WHICH IS KROAKED
|
||
; PJRST NTDGON ;MARK ERROR AND RETURN TO UUOCON
|
||
|
||
NTDGON::MOVEI S,IODERR!IODTER ;DEVICE AND DATA ERRORS
|
||
IORB S,DEVIOS(F) ;ASSERT ERROR FLAGS
|
||
POPJ P, ;RETURN (PRESUMABLY TO UUOCON)
|
||
;NTDIBA ROUTINE TO SEE IF THIS DEVICE HAS AN AVAILABLE INPUT BUFFER.
|
||
;CALL MOVE F,DDB
|
||
; PUSHJ P,NTDIBA
|
||
;RETURN CPOPJ ;ALL INPUT BUFFERS ARE IN USE
|
||
; CPOPJ1 ;THERE IS AT LEAST ONE FREE INPUT BUFFER.
|
||
;
|
||
NTDIBA:: ;HERE TO SEE IF THERE ARE ANY FREE INPUT BUFFERS
|
||
MOVE S,DEVIOS(F) ;GET A COPY OF DEVIOUS
|
||
TLNE S,IOSUSI ;DOES UUOCON WANT INPUT STOPPED (GOING TO SWAP)
|
||
POPJ P, ; IF SO, THEN GIVE "NO BUFFER" RETURN
|
||
HRRZ T1,DEVIAD(F) ;GET POINTER TO FIRST INPUT BUFFER
|
||
JUMPE T1,CPOPJ## ;IF NO BUFFER, NONE ARE FREE
|
||
EXCTUX <SKIPL (T1)> ;CHECK THE USE BIT.
|
||
AOS (P) ;IT'S NOT SET. THE BUFFER IS FREE
|
||
POPJ P,
|
||
|
||
;NTDOBA ROUTINE TO SEE IF THIS DEVICE HAS ANY OUTPUT TO GO.
|
||
;CALL MOVE F,DDB
|
||
; PUSHJ P,NTDOBA
|
||
;RETURN CPOPJ ;NO OUTPUT AVAILABLE
|
||
; CPOPJ1 ;THERE IS AT LEAST ONE FULL OUTPUT BUFFER
|
||
;
|
||
NTDOBA:: ;HERE TO SEE IF THERE IS A FULL OUTPUT BUFFER
|
||
MOVE S,DEVIOS(F) ;GET A COPY OF THE STATUS BITS
|
||
TLNE S,IOSUSO ;DOES UUOCON WANT OUTPUT STOPPED (FOR SWAP)
|
||
POPJ P, ; IF SO, THEN GIVE THE "NO BUFFER" RETURN
|
||
HRRZ T1,DEVOAD(F) ;GET A POINTER TO THE USERS BUFFER
|
||
JUMPE T1,CPOPJ## ;IF NO BUFFER, NONE ARE FREE
|
||
EXCTUX <SKIPGE (T1)> ;CHECK THE USE BIT
|
||
AOS (P) ;THE BUFFER HAS DATA.
|
||
POPJ P,
|
||
;NTDIDA ROUTINE THAT SKIPS IF AN "IN" UUO WOULD BE APPROPRIATE
|
||
; CALLED FROM MSGSER TO SEE IF INPUT DATA IS AVAILABLE
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,NTDIDA
|
||
;RETURN CPOPJ ;NO PCB'S QUEUED FOR PROCESSING
|
||
; CPOPJ1 ;PCB'S ARE QUEUED. MSGSER SHOULD "CALIN"
|
||
;
|
||
NTDIDA::SETZM DEVAXI(F) ;CLEAR BOTH THE AUX INPUT POINTERS
|
||
SETZM DEVAXI+1(F) ; SINCE MSGSER WILL GIVE US A NEW BUFFER.
|
||
HRRZ T1,DEVPCB(F) ;FIRST SEE IF THERE IS AN INPUT PCB QUEUED
|
||
JUMPN T1,CPOPJ1## ; IF THERE IS, TELL MSGSER TO DO AN "IN"
|
||
MOVE S,DEVIOS(F) ;SEE IF WE ARE STILL
|
||
TLNN S,IOSCON ; CONNECTED. IF NOT, WE
|
||
POPJ P, ; HAD BETTER NOT SEND A DRQ.
|
||
HLRZ T1,DEVDRQ(F) ;SEE IF WE'VE REQUESTED DATA
|
||
JUMPN T1,CPOPJ## ; IF WE'VE ALREADY SEND DRQ, THEN WE'RE DONE
|
||
NETDBJ ;THE REST OF THIS CODE MUST BE INTERLOCKED
|
||
MOVEI T1,1 ;MSGSER WILL SUPPLY US WITH ONLY "1" BUFFER
|
||
PUSHJ P,NCSDRQ ;SEND THE DATA-REQUEST (FOR 1 MSG)
|
||
POPJ P, ;IF NO CORE, EXIT WITH-OUT UPDATING DEVDRQ
|
||
MOVSI T1,1 ;GET A LEFT-HALF "1"
|
||
ADDM T1,DEVDRQ(F) ;INCREMENT THE OUTSTANDING DATA-REQUEST COUNT
|
||
POPJ P, ;TELL MSGSER THAT THERE'S NO DATA FOR IT.
|
||
;NTDCBC ROUTINE TO CALCULATE BYTE COUNT.
|
||
;CALL MOVE T4,BYTE POINTER ;THIS ROUTINE USES ONLY THE "SIZE" FIELD
|
||
; MOVEI T3,WORD COUNT ;THIS IS THE SIZE OF THE BUFFER TO FILL
|
||
;RETURN CPOPJ WITH T1 := NUMBER OF BYTES THAT WILL FIT IN THE BUFFER.
|
||
;
|
||
;NOTE!! SORRY ABOUT THE SCREWY AC CONVENTIONS, BUT IT FITS IN WITH
|
||
; THE OTHER "NTD" ROUTINES.
|
||
|
||
NTDCBC::LDB T2,[POINT 6,T4,11] ;GET THE "SIZE" OF THE BYTE
|
||
MOVEI T1,^D36 ;NUMBER OF BITS IN A WORD
|
||
IDIVI T1,(T2) ;T1 := NUMBER OF BYTES IN A WORD
|
||
IMULI T1,(T3) ;T1 := NUMBER OF BYTES IN "T3" WORDS
|
||
POPJ P,
|
||
|
||
|
||
|
||
;NTDPRV ROUTINE TO CHECK PRIVS. SKIPS IF USER MAY HACK THE NET
|
||
;CALL PUSHJ P,NTDPRV
|
||
;RETURN CPOPJ ;DON'T LET HIM HACK
|
||
; CPOPJ1 ;HE CAN DO ANYTHING HE WANTS.
|
||
|
||
NTDPRV::PUSH P,J ;SAVE FEK OR WHATEVER
|
||
SKIPN J,.CPJOB## ;GET THIS JOB'S NUMBER
|
||
JRST JPOPJ1## ;INTERRUPT LEVEL IS ALWAYS A GOOD GUY
|
||
PUSH P,T1 ;NTDPRV CLOBBERS NO REGISTERS
|
||
MOVSI T1,JP.POK ;POKE, 1-2, OR JACCT ARE GOOD GUYS
|
||
PUSHJ P,PRVBIT## ;CALL COMCON'S ROUTINE
|
||
AOS -2(P) ;PRVBIT SKIPS IF NOT PRIV
|
||
POP P,T1 ;RESTORE T1 (AREN'T WE NICE)
|
||
JRST JPOPJ## ;RESTORE J AND (SKIP) RETURN
|
||
|
||
|
||
|
||
;NTDSTP ROUTINE TO GENERATE A STOP CODE. USED WHERE TOO LAZY TO THINK ONE UP.
|
||
;CALL PUSHJ P,NTDSTP ;?? HORRIBLE BUG ??
|
||
;RETURN HA.
|
||
|
||
NTDSTP::STOPCD CPOPJ##,STOP,WEM, ;++ DAMN!
|
||
COMMENT \
|
||
|
||
Protocol for using the Input Buffer Management routines.
|
||
|
||
When using the input buffer management routines the following
|
||
words in the DDB are used to contain status information:
|
||
|
||
DEVAXI This word is anaglous to the ".BFPTR" word in a user-mode
|
||
buffer control block. It is a byte pointer to the users
|
||
buffer.
|
||
DEVAXI+1 This word is analogous to the ".BFCTR" word. It is initialized
|
||
to be the number of bytes that will fit in the user's buffer.
|
||
|
||
Here is a skeleton routine that should indicate how these routines are
|
||
intended to be used.
|
||
|
||
|
||
;Assume that calling the routine "D.NEXT" will supply the next data byte
|
||
; (i.e., from the NCL message) and skip return unless the message is exhausted
|
||
; in which case it will error (non-skip) return.
|
||
|
||
;Before we start copying we must set up the buffer.
|
||
|
||
MOVSI S,IOSUSI ;FIRST CLEAR "UUOCON STOPPED INPUT"
|
||
ANDCAB S,DEVIOS(F) ; SO THAT NTDSIB WILL WORK
|
||
PUSHJ P,NTDSIB ;SET UP THE INPUT BUFFER (DEVAXI, +1)
|
||
|
||
;Now we merely loop copying the data
|
||
|
||
LOOP: ;EVERY PROG SHOULD HAVE A LOOP!!
|
||
PUSHJ P,D.NEXT ;GET THE NEXT CHARACTER.
|
||
PJRST NTDA1B ;IF NO MORE, THEN ADVANCE THE BUFFER AND
|
||
; GIVE A SKIP RETURN TO NTDISP SO THAT
|
||
; IT WILL ADVANCE TO THE NEXT NCL SUB-
|
||
; MESSAGE.
|
||
SOSGE DEVAXI+1(F) ;DECREMENT THE NUMBER OF UN-USED BYTES IN
|
||
JRST SET-IOBKTL ; THE BUFFER. (IT IS IMPORTANT TO KEEP THIS
|
||
; COUNT CORRECT. NTDAIB USES IT TO CALCULATE
|
||
; THE ITEM-COUNT TO PUT IN THE BUFFER-HEADER)
|
||
; IF THE COUNT COUNTS OUT, THEN SET BLOCK-TO-
|
||
; LARGE, OR IF YOU WANT TO KEEP GOING CALL
|
||
; "NTDAIB" FOLLOWED BY "NTDSIB" AND CONTINUE
|
||
EXCTUU <IDPB T1,DEVAXI(F)> ; STORE THE BYTE IN "T1"
|
||
JRST LOOP ;CONTINUE UNTIL MESSAGE IS EXHAUSTED
|
||
|
||
|
||
|
||
\
|
||
;NTDSIB ROUTINE TO SET UP AN INPUT BUFFER
|
||
;CALL MOVEI F,DDB ;DEVIAD(F) = USERS INPUT BUFFER
|
||
; MOVEI T4,BYTE-SIZE ;USED IN CALCULATING ITEM COUNT (DEVAXI+1)
|
||
; PUSHJ P,NTDSIB ;SET UP INPUT BUFFER
|
||
;RETURN NOT-AT-ALL ;IF THE USERS BUFFER IS NOT IN CORE (PAGE FAULT)
|
||
; CPOPJ ;NO USER BUFFER AVAILABLE
|
||
; CPOPJ1 ;BUFFER IS SET UP. THE FOLLOWING ANALOG OF
|
||
; ; THE STANDARD BUFFER CONTROL BLOCK IS SET UP.
|
||
; ; DEVAXI(F) := BYTE POINTER TO USERS BUFFER
|
||
; ; DEVAXI+1(F) := COUNT OF BYTES IN BUFFER.
|
||
; ;IF YOU JUST PRETEND THAT YOU ARE DOING USER-
|
||
; ; LEVEL BUFFERED OUTPUT AND EVERYTHING SHOULD
|
||
; ; WORK FINE!
|
||
;NOTE IF THIS ROUTINE IS CALLED WITH THE BUFFER ALREADY SET UP, IT WILL
|
||
; MERELY RANGE CHECK THE USERS BUFFER AND RETURN. THIS MAKES IT EASY
|
||
; TO USE COMMON CODE TO PACK MANY NCL MESSAGES INTO ONE USER BUFFER.
|
||
;
|
||
NTDSIB:: ;SETUP INPUT BUFFER
|
||
SKIPE DEVAXI(F) ;HAVE WE ALREADY SET THIS UP?
|
||
JRST [HRRZ T1,DEVIAD(F) ;YES, RANGE CHECK THE BUFFER TO
|
||
PUSHJ P,BRNGE## ; ENSURE THAT IT IS STILL IN CORE
|
||
JRST NTDSI1] ;CLEAR USER'S BUFFER AND SKIP RETURN
|
||
PUSHJ P,NTDIBA ;SINCE NOT SET-UP, SEE IF A BUFFER IS AVAILABLE
|
||
POPJ P, ; IF NOT, THEN GIVE ERROR RETURN
|
||
HRRZ T1,DEVIAD(F) ;SECTION-LOCAL ADDRESS OF USER BUFFER
|
||
PUSHJ P,BRNGE## ;MAKE SURE THAT THE BUFFER'S IN BEFORE POKING IT
|
||
LSH T4,^D24 ;MAKE T4 INTO A BYTE POINTER
|
||
HRRZ T1,DEVIAD(F) ; TO THE BYTE JUST BEFORE THE FIRST BYTE
|
||
HRRI T4,1(T1) ; IN THE USER'S BUFFER. (SO "I"LDB WORKS)
|
||
EXCTUX <HLRZ T3,(T1)> ;GET THE BUFFER SIZE+1 (IN WORDS)
|
||
SUBI T3,1 ;GET THE BUFFER SIZE (IN WORDS)
|
||
PUSHJ P,NTDCBC ;GET THE BUFFER SIZE (IN BYTES)
|
||
MOVEM T4,DEVAXI(F) ;SET UP THE ".BFPTR" WORD
|
||
MOVEM T1,DEVAXI+1(F) ;SET UP THE ".BFCTR" WORD
|
||
NTDSI1: HRRZ T1,DEVIAD(F) ;GET THE BUFFER ADDRESS
|
||
PUSHJ P,BUFCLR## ;CLEAR USER'S BUFFER BEFORE RETURNING
|
||
JFCL ;ZERO LENGTH: SHOULD NEVER OCCUR
|
||
JRST CPOPJ1## ;SKIP RETURN: THE BUFFER IS SET UP
|
||
;NTDAIB ROUTINE TO ADVANCE A USERS BUFFER (ANALOG OF THE OUTPUT UUO)
|
||
;CALL MOVEI F,DDB ;DEVAXI(F) := BYTE POINTER
|
||
; ;DEVAXI+1(F) := NUMBER OF UNUSED BYTES IN BUFFER
|
||
; PUSHJ P,NTDAIB ;ADVANCE INPUT BUFFER (GIVE DATA TO THE USER)
|
||
;RETURN CPOPJ ;DEVAXI(F) := 0 INDICATING NO BUFFER IS SETUP
|
||
;
|
||
NTDA1B::AOS (P) ;SPECIAL ENTRY FOR THOSE WHO WANT A SKIP RETURN
|
||
NTDAIB::SKIPN T4,DEVAXI(F) ;GET BYTE POINTER
|
||
STOPCD .,STOP,ANFAIB, ;++ NO BUFFER SET UP WHEN ADVACING INPUT
|
||
|
||
HRRZ T1,T4 ;GET A COPY OF THE ADDRESS OF THE LAST WORD
|
||
SETZ T2, ;GET A ZERO (TO ZERO FILL LAST WORD)
|
||
NTDAI1: IBP T4 ;INCREMENT T4 ONE MORE BYTE
|
||
CAIN T1,(T4) ;IF GOES TO NEW WORD, THEN DONE ZERO FILLING
|
||
JRST [EXCTUU <DPB T2,T4> ;STORE A ZERO BYTE
|
||
JRST NTDAI1] ; AND LOOP OVER REST OF THE WORD
|
||
|
||
HRRZ T1,DEVIAD(F) ;GET POINTER TO BUFFER HEADER
|
||
LDB T2,PIOMOD## ;GET I/O MODE AND
|
||
CAIE T2,A8 ; IF IT'S 8-BIT ASCII OR
|
||
CAIN T2,BYTMOD ; IF IT'S BYTE MODE, THEN
|
||
JRST NTDAI2 ; COMPUTE ITEM-COUNT IN BYTES
|
||
|
||
SUBI T4,2(T1) ;COMPUTE WORD COUNT (SUBTRACT BYTE POINTERS)
|
||
EXCTUU <HRRM T4,1(T1)> ;STORE THE WORD-COUNT IN THE BUFFER HEADER
|
||
JRST NTDAI3 ;GO REJOIN COMMON CODE
|
||
|
||
NTDAI2: ;HERE IF WE WANT ITEM COUNT TO BE BYTE COUNT
|
||
EXCTUX <HLRZ T3,(T1)> ;TO COMPUTE BYTE COUNT, FIRST GET
|
||
SUBI T3,1 ; THE SIZE OF THE BUFFER IN WORDS.
|
||
PUSHJ P,NTDCBC ;NOW GET THE SIZE OF THE BUFFER IN BYTES.
|
||
SUB T1,DEVAXI+1(F) ;SUBTRACT UNUSED BYTE COUNT TO GET BYTES USED.
|
||
HRRZ T2,DEVIAD(F) ;NOW TO STORE THE COUNT FIRST GET BUFFER HEADER
|
||
EXCTUU <HRRM T1,1(T2)> ; AND USE THAT TO STORE THE ITEM COUNT FOR USER.
|
||
|
||
NTDAI3: ;COMMON CODE TO ADVANCE USERS BUFFER.
|
||
SETZM DEVAXI(F) ;CLEAR ".BFPTR" TO INDICATE BUFFER NOT SETUP
|
||
PUSHJ P,ADVBFF## ;ADVANCE USERS INPUT BUFFER
|
||
JRST .+2 ;WE MUST REMEMBER IF UUOCON WANT'S INPUT STOPED
|
||
POPJ P, ;RETURN WITH USER'S BUFFER ADVANCED
|
||
MOVSI S,IOSUSI ;GET AND SET "UUOCON STOPED INPUT" BIT. THIS
|
||
IORB S,DEVIOS(F) ; GETS SET WHEN SWAPING, ^C ETC.
|
||
POPJ P, ;RETURN. NTDIBA WILL NOTICE THE BIT AND STOP IO
|
||
COMMENT \
|
||
|
||
Protocol for using the output buffer management routines.
|
||
|
||
When using the output buffer management routines the following
|
||
words in the DDB are used to contain status information:
|
||
|
||
DEVAXO This word contains a byte pointer to the unsent portion
|
||
of the users buffer.
|
||
DEVAXO+1 This word contains the number of unsent bytes in the users
|
||
buffer.
|
||
|
||
You may criticize me on the design of this mechanism and contend that
|
||
this is not the most efficient way to represent the state of the users buffer.
|
||
To this I will have to agree. (Consider all the trouble that NTDXMT has to
|
||
go through to convert back and forth from byte to word counts...) I have
|
||
only two points to make in my defense:
|
||
|
||
1) Byte mode falls out with no added effort.
|
||
|
||
2) This scheme forms a symmetry with the input routines that, in my
|
||
opinion, lends a rather pleasant feeling of completeness to this
|
||
whole mess.
|
||
|
||
|
||
Now for a skeleton routine showing how to use these routines.
|
||
|
||
MOVSI S,IOSUSO ;FIRST CLEAR THE "UUOCON STOPPED OUTPUT" BIT
|
||
ANDCAB S,DEVIOS(F) ; SO THAT NTDSOB WILL WORK
|
||
LOOP: ;HERE TO SEND MORE DATA.
|
||
PUSHJ P,NTDSET ;SET UP W & S. THIS MUST BE DONE AFTER
|
||
; A CALL TO ANY OF THE WAIT ROUTINES AS
|
||
; THEY ALL CLOBBER W. (ON PURPOSE.)
|
||
MOVE S,DEVIOS(F) ;RELOAD S (WAIT ROUTINES CLOBBER S)
|
||
MOVEI T1,^DBYTE-SIZE ;GET THE BYTE SIZE SO THAT
|
||
; "NTDSOB" CAN SET UP THE PROPER BYTE COUNT.
|
||
PUSHJ P,NTDSOB ;SET UP DEVAXO, DEVAXO+1
|
||
JRST NO-MORE-DATA ; ERROR RETURN INDICATES WE ARE DONE.
|
||
|
||
PUSHJ P,NTDCDQ ;CHECK TO SEE IF WE HAVE A DATA REQUEST.
|
||
JRST WAIT-AWHILE ; IF NOT, EITHER WAIT, OR RETURN TO UUOCON.
|
||
|
||
MOVEI T1,COMPRESSION ;COMPRESSION/CONVERSION (PCV.??)
|
||
PUSHJ P,NTDXMT ;SEND ONE PCB'S WORTH OF DATA.
|
||
JRST PROCESS ERROR ;IF OUT OF CORE OR IOBKTL
|
||
PUSHJ P,NTDDDQ ;DECREMENT DRQ NOW THAT MSG HAS GONE
|
||
|
||
SKIPN NETAXO+1(F) ;HAVE WE EMPTIED THIS BUFFER??
|
||
PUSHJ P,NTDAOB ; IF SO, THEN ADVANCE THE USERS BUFFER
|
||
JRST LOOP ;KEEP IT UP TILL WE GET IT WRONG.
|
||
*** NOTE ***
|
||
|
||
If one were so inclined one could do something like replace the
|
||
call to NTDXMT by a loop of the form:
|
||
|
||
LOOP1: SOSGE DEVAXO(F) ;DECREMENT ".BFCTR"
|
||
JRST DONE
|
||
EXCTUX <ILDB T1,DEVAXO(F)> ;GET NEXT BYTE
|
||
PUSHJ P,PUT-BYTE-SOMEWHERE
|
||
JRST LOOP1 ;CONTINUE UNTIL BUFFER IS EXHAUSTED.
|
||
|
||
|
||
For network devices I see no reason to do this since NTDXMT is not
|
||
only faster (It copys a PCB's worth of data with a single BLT) but its
|
||
a lot easier too!
|
||
|
||
\
|
||
;NTDSOB ROUTINE TO SET UP A BUFFER FOR OUTPUT
|
||
;CALL
|
||
; MOVEI T1,BYTE SIZE (USUALLY DEPENDS ON THE CONVERSION CODE)
|
||
; PUSHJ P,NTDSOB ;SET UP OUTPUT BUFFER
|
||
;RETURN NOT-AT-ALL ;IF THE USERS BUFFER WAS NOT INCORE (PAGE FAULT)
|
||
; CPOPJ ;NO OUTPUT BUFFER AVAILABLE
|
||
; CPOPJ1 ;BUFFER SET UP.
|
||
; ; DEVAXO(F) := BYTE POINTER TO USERS BUFFER
|
||
; ; DEVAXO+1(F) := COUNT OF BYTES LEFT TO GO.
|
||
;
|
||
NTDSOB:: ;SET UP OUTPUT BUFFER
|
||
SKIPE DEVAXO(F) ;IS THE BUFFER ALREADY SET UP?
|
||
JRST [AOS (P) ;IF SO, GIVE A GOOD RETURN.
|
||
HRRZ T1,DEVOAD(F) ; BUT FIRST MAKE SURE THAT THE BUFFER
|
||
PJRST BRNGE##] ; IS STILL IN CORE.
|
||
PUSH P,T1 ;SAVE THE BYTE SIZE OVER CALL TO NTDOBA
|
||
PUSHJ P,NTDOBA ;IS THERE AN OUTPUT BUFFER AVAILABLE?
|
||
JRST TPOPJ## ;IF NOT, THEN GIVE THE ERROR RETURN
|
||
POP P,T4 ;GET BYTE SIZE BACK IN T4
|
||
LSH T4,^D24 ;MAKE T4 INTO A BYTE POINTER
|
||
HRRZ T1,DEVOAD(F) ; THAT WHEN INCREMENTED POINTS TO THE
|
||
HRRI T4,1(T1) ; FIRST BYTE IN THE USER'S BUFFER.
|
||
EXCTUX <HRRZ T3,1(T1)> ;GET THE BUFFER ITEM COUNT (WORDS OR BYTES)
|
||
MOVEI T1,(T3) ;COPY THE WORD COUNT
|
||
LDB T2,PIOMOD## ;GET THE MODE THAT WE ARE IN.
|
||
CAIE T2,BYTMOD ; AND IF WE ARE NOT IN BYTE MODE,
|
||
CAIN T2,A8 ; OR 8-BIT ASCII MODE,
|
||
TRNA ; (WRONG)
|
||
PUSHJ P,NTDCBC ; THEN WE NEED TO CONVERT WORD-COUNT TO BYTES.
|
||
MOVEM T4,DEVAXO(F) ;STORE THE BYTE POINTER
|
||
MOVEM T1,DEVAXO+1(F) ;STORE THE BYTE COUNT
|
||
JRST CPOPJ1## ;GIVE GOOD (SKIP) RETURN
|
||
|
||
|
||
|
||
;NTDAOB ROUTINE TO ADVANCE THE USERS OUTPUT BUFFER
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,NTDAOB ;ADVANCE OUTPUT BUFFER
|
||
;RETURN CPOPJ ;ALWAYS
|
||
;
|
||
NTDAOB:: ;ADVANCE OUTPUT BUFFER
|
||
SKIPN DEVAXO(F) ;HAS THE BUFFER BEEN SETUP
|
||
STOPCD .,STOP,ANFAOB, ;++ NO BUFFER SET UP WHEN CALLING NTDAOB
|
||
SETZM DEVAXO(F) ;INDICATE THAT IT'S NO LONGER SET UP
|
||
PUSHJ P,ADVBFE## ;ADVANCE THE BUFFER
|
||
JRST .+2 ;WE MUST SHUT DOWN OUTPUT FOR SOME REASON
|
||
POPJ P, ;ALL DONE
|
||
MOVSI S,IOSUSO ;GET AND SET THE "UUOCON STOPPED OUTPUT"
|
||
IORB S,DEVIOS(F) ; NTAOBA WILL NOTICE THIS BIT AND SAY
|
||
POPJ P, ; THAT NO BUFFERS ARE AVAILABLE FOR OUTPUT.
|
||
;NTDXMT ROUTINE TO SEND ONE PCB'S WORTH OF DATA FROM A USERS BUFFER.
|
||
; UNDERSTANDS ABOUT BREAKING USERS BUFFERS INTO MANY PCB'S
|
||
;CALL MOVEI T1,COMPRESSION CODE (PCV.??)
|
||
; MOVEI T2,IDCTYP+INTERRUPT BIT(=1B18)
|
||
; MOVEI F,DDB ;WITH DEVAXO, +1 SET UP
|
||
; PUSHJ P,NTDXMT ;SEND A PCB'S WORTH OF DATA
|
||
;RETURN NOT-AT-ALL ;IF A PAGE FAULT OCCURS
|
||
; CPOPJ ;IO-ERROR BIT IN T1. IF T1 = 0, NO CORE
|
||
; CPOPJ1 ;THE PCB WAS SENT OK.
|
||
|
||
NTDXMT::SKIPE %NTNIP ;DOING ETHERNET-TYPE STUFF?
|
||
JRST NTDXNT ;YEAH, MUST USE CONTIGUOUS BUFFERS
|
||
SKIPN DEVAXO(F) ;IS THE BUFFER SET UP?
|
||
STOPCD .,STOP,ANFXMT, ;++ NO BUFFER SET UP WHEN CALLING NTDXMT
|
||
|
||
PUSH P,T1 ;SAVE THE COMPRESSION CODE (UNTIL THE VERY END)
|
||
PUSH P,T2 ;SAVE THE INTERRUPT-BIT+IDCTYP
|
||
HRRZ T1,DEVOAD(F) ;NOW RANGE CHECK THE BUFFER.
|
||
PUSHJ P,BRNGE## ; JUST INCASE HE DECIDED TO SWAP
|
||
|
||
LDB T2,[POINT 6,DEVAXO(F),11] ;NOW GET NUMBER OF WORDS IN BUFFER.
|
||
MOVEI T3,^D36 ;START WITH BYTE SIZE AND 36/BYTE SIZE
|
||
IDIVI T3,(T2) ; YIELDS T3 := NUMBER OF BYTES/WORD
|
||
MOVE T2,DEVAXO+1(F) ;GET THE NUMBER OF BYTES LEFT.
|
||
SETZ T1, ;CLEAR THE HIGH ORDER WORD
|
||
DIVI T1,(T3) ;CONVERT INTO WORDS
|
||
SKIPE T2 ; BUT BE SURE TO
|
||
ADDI T1,1 ; ROUND UP TO GET TOTAL WORDS IN BUFFER.
|
||
PUSH P,T3 ;SAVE THE BYTE/WORD FOR LATER
|
||
PUSH P,T1 ;SAVE LENGTH FOR A BIT.
|
||
NTDXM0: MOVEI T1,4 ;GET A PCB START WITH 4 WORDS (MAX) OF HEADER
|
||
ADD T1,(P) ; ADD IN THE LENGTH OF THE BUFFER
|
||
CAILE T1,MSGXMW## ;IF THIS IS MORE THAN THE "MAXIMUM" PCB SIZE
|
||
MOVEI T1,MSGXMW## ; THEN JUST REQUEST THE "MAXIMUM"
|
||
MOVEI T3,NTDHDR ;ASSUME THAT THIS IS NOT AN INTERRUPT MESSAGE
|
||
MOVEI T2,(1B0) ;GET THE "INTERRUPT MESSAGE" BIT
|
||
TDNE T2,-2(P) ; AND IF IT'S SET
|
||
MOVEI T3,NTDHDI ; THEN GET AN INTERRUPT HEADER.
|
||
PUSHJ P,(T3) ;GO BUILD THE HEADER
|
||
JRST [ADJSP P,-4 ;IF NO CORE, CLEAN UP THE STACK
|
||
SETZ T1, ; CLEAR T1 TO SAY ERROR WAS NO FREE CORE
|
||
POPJ P,] ; AND GIVE AN ERROR RETURN TO THE CALLER
|
||
MOVE T2,PCBCTR(U) ;NOW CALCULATE THE NUMBER OF FREE DATA WORDS
|
||
ADDI T2,3+3(P3) ;START WITH BYTES IN HEADER, ALLOW FOR "CNT"
|
||
LSH T2,-2 ; AND "TYP", +3 TO ROUND UP. LSH TO GET WORDS.
|
||
MOVE T4,PCBALN(U) ;GET THE TOTAL NUMBER OF WORDS IN THE PCB
|
||
SUBI T4,(T2) ;SUBTRACT WORDS USED, GET WORDS LEFT IN PCB.
|
||
POP P,T1 ;GET THE BUFFER LENGTH BACK
|
||
POP P,T3 ;GET THE BYTES/WORD BACK
|
||
CAIL T4,(T1) ;SKIP IF PCB WON'T FINISH OFF THE BUFFER
|
||
JRST NTDXM1 ;GO TO CODE TO SEND FINAL FRAGMENT OF BUFFER.
|
||
|
||
;CONTINUED ON NEXT PAGE
|
||
;CONTINUED FROM PREVIOUS PAGE
|
||
|
||
;HERE IF WE HAVE TO "FRACTURE" THE BUFFER INTO SEVERAL MESSAGES, AND THIS
|
||
; IS NOT THE LAST FRAGMENT OF THE BUFFER.
|
||
; T3 := BYTES/WORD
|
||
; T4 := NUMBER OF WORDS LEFT IN THE PCB (WE WILL USE THEM ALL)
|
||
|
||
POP P,T1 ;GET THE IDC TYPE FIELD
|
||
ANDI T1,77 ;AND JUST THE TYPE (MASK OUT THE INTERRUPT BIT)
|
||
CAIL T1,DC.DAT ;NOW SEE IF THIS IS A MESSAGE TYPE THAT WE
|
||
CAILE T1,DC.DAR ; CAN LEGALLY FRAGMENT INTO MULTIPLE MESSAGES
|
||
JRST [POP P,T1 ;IF WE CAN'T BREAK THE MESSAGE, CLEAN UP STACK
|
||
MOVEI T1,IOBKTL; TELL OUR CALLER THAT ERROR WAS BLOCK TO LARGE
|
||
POPJ P,] ; AND GIVE AN ERROR RETURN
|
||
PUSH P,[DC.DAT] ;CHANGE THE MESSAGE TYPE TO BE DATA W/O E-O-R.
|
||
|
||
MOVEI T1,(T4) ;GET THE NUMBER OF WORDS LEFT IN THE PCB
|
||
IMULI T1,(T3) ;CONVERT WORD COUNT TO BYTE COUNT
|
||
MOVN T2,T1 ;GET MINUS THAT BYTE COUNT
|
||
ADDM T2,DEVAXO+1(F) ; AND UPDATE THE NUMBER OF UNSENT BYTES.
|
||
|
||
SKIPG DEVAXO+1(F) ;JUST A QUICK CHECK OF MY ARITHMETIC
|
||
STOPCD .,STOP,ANFUBN, ;++ UNSENT BYTES COUNT WENT NEGATIVE
|
||
JRST NTDXM2 ;GO SEND "CNT", "TYP", AND THE DATA.
|
||
|
||
|
||
|
||
;HERE IF THE PCB WILL HOLD ALL THE REST OF THE BUFFER.
|
||
; T1 := WORDS LEFT IN THE USER'S BUFFER
|
||
|
||
NTDXM1: MOVEI T4,(T1) ;COPY THE NUMBER OF WORDS TO GO (FOR THE BLT)
|
||
SETZ T1, ;GET A "ZERO"
|
||
EXCH T1,DEVAXO+1(F) ;GET THE NUMBER OF "BYTES" TO GO. CLEAR BUF CNT.
|
||
; JRST NTDXM2 ;GO SEND "CNT", "TYP", AND THE DATA
|
||
|
||
;CONTINUED ON NEXT PAGE
|
||
;CONTINUED FROM PREVIOUS PAGE
|
||
|
||
;NTDXM2 HERE TO SEND "CNT", "TYP", AND DATA PORTIONS OF THE MESSAGE.
|
||
; -1(P) := CONVERSION CODE (WE MUST HANDLE BINARY MODE ESPECIAL)
|
||
; (P) := IDC TYPE
|
||
; T1 := NUMBER OF "BYTES" (OF WHATEVER SIZE) TO GO.
|
||
; T4 := NUMBER OF "WORDS" TO GO (USED BY THE BLT, AND BINARY MODE)
|
||
;
|
||
;NOTE. BECAUSE THE FEK IS LAZY WHEN IT DOES THE BINARY CONVERSION, WE MUST
|
||
; CALCULATE BY HAND WHAT THE LENGTH OF THE DATA MESSAGE WILL BE AFTER
|
||
; CONVERSION. BINARY CONVERSION PACKS THE DATA 2 WORDS INTO 9 BYTES.
|
||
|
||
NTDXM2: MOVEM T1,PCBCT2(U) ;SET THE BYTE COUNT FOR THE SECOND BUFFER
|
||
MOVE T2,-1(P) ;GET THE CONVERSION CODE
|
||
CAIE T2,PCV.BN ; AND SEE IF IT'S BINARY.
|
||
JRST NTDXM3 ;IF NOT BINARY, THEN USE BYTE COUNT IN "T1"
|
||
MOVEI T1,(T4) ;CALCULATE BYTE COUNT BY HAND. START WITH WORDS.
|
||
LSHC T1,-1 ;GET DOUBLE-WORDS. (REMAINDER = SIGN OF T2)
|
||
IMULI T1,^D9 ;2 WORDS FIT IN 9 BYTES.
|
||
SKIPGE T2 ;IF THERE IS AN "ODD" WORD, THAT WORD
|
||
ADDI T1,5 ; FIVE EXTRA BYTES.
|
||
NTDXM3: ADDI T1,1 ;ACCOUNT FOR THE "TYP" FIELD IN THE LENGTH
|
||
;CNT
|
||
XMT T1 ;SEND THE LENGTH OF THE DAP MSG
|
||
;TYP
|
||
POP P,T1 ;GET THE IDC TYPE BACK
|
||
XMT1 T1 ;THIS WILL MASK THE TYPE TO 8 BITS
|
||
|
||
;CONTINUED ON NEXT PAGE
|
||
;CONTINUED FROM PREVIOUS PAGE
|
||
|
||
;HERE TO COPY THE DATA FROM THE USERS BUFFER AND INTO THE PCB. AT THIS POINT:
|
||
; 1) DEVAXO+1(F) HAS BEEN UPDATED TO REFLECT THE NUMBER OF BYTES COPIED.
|
||
; 2) T4 := THE NUMBER OF WORDS TO GO
|
||
; 3) (P) := THE CONVERSION CODE (REMEMBER...)
|
||
; 4) P3 := THE NUMBER OF BYTES IN PCB'S FIRST BUFFER (FROM "CNT", "TYP" ETC)
|
||
; 5) P2 - LAST USED BYTE IN THE PCB
|
||
|
||
ADDB P3,PCBCTR(U) ;FIRST UPDATE THE PRIMARY BUFFER'S LENGTH
|
||
MOVEI T1,1(P2) ;GET A POINTER TO THE FIRST FREE WORD IN THE PCB
|
||
LDB T2,[POINT 6,DEVAXO(F),11] ;GET THE BYTE SIZE
|
||
LSH T2,6 ;POSITION THE SIZE (BYTE POINTER STYLE)
|
||
TLO T1,440000(T2) ;MAKE T1 INTO A FULL-FLEDGED BYTE POINTER
|
||
MOVEM T1,PCBPT2(U) ;STORE AS THE SECONDARY BUFFER POINTER
|
||
MOVE T2,DEVAXO(F) ;GET THE ADDRESS OF THE USER'S DATA
|
||
ADDM T4,DEVAXO(F) ;UPDATE THE ADDRESS FOR NEXT TIME
|
||
IBP T2 ;MAKE SURE WE POINT TO THE RIGHT WORD
|
||
|
||
IFE FTXMON,<
|
||
HRLI T1,(T2) ;SET UP THE BLT'S SOURCE FIELD
|
||
ADDI T4,-1(T1) ;SET UP THE BLT'S TERMINATING ADDRESS
|
||
EXCTUX <BLT T1,(T4)> ;COPY THE DATA
|
||
> ;END IFE FTXMON
|
||
|
||
IFN FTXMON,<
|
||
HRRZ T3,T1 ;FORM MONITOR DESTINATION ADDRESS
|
||
XSFM T1 ;GET PCS
|
||
HRLI T2,(T1) ;FORM USER SOURCE ADDRESS
|
||
MOVE T1,T4 ;GET LENGTH WHERE WE NEED IT
|
||
XBLTUX T1 ;COPY THE DATA
|
||
> ;END IFN FTXMON
|
||
|
||
POP P,T1 ;GET THE CONVERSION CODE (FINALLY)
|
||
PUSHJ P,NTDWRT ;SEND THE PCB.
|
||
JRST CPOPJ1## ;GIVE GOOD RETURN
|
||
;TEMP SCRATCH FOR TESTING OUT ANF/NI
|
||
|
||
NTDXNT::SKIPN DEVAXO(F) ;IS THE BUFFER SET UP?
|
||
STOPCD .,STOP,ANIXMT, ;++ NO BUFFER SET UP WHEN CALLING NTDXNT
|
||
PUSH P,T1 ;SAVE THE COMPRESSION CODE (UNTIL THE VERY END)
|
||
PUSH P,T2 ;SAVE THE INTERRUPT-BIT+IDCTYP
|
||
HRRZ T1,DEVOAD(F) ;NOW RANGE CHECK THE BUFFER.
|
||
PUSHJ P,BRNGE## ; JUST INCASE HE DECIDED TO SWAP
|
||
MOVE T1,DEVAXO+1(F) ;GET THE NUMBER OF BYTES LEFT.
|
||
MOVE T3,-1(P) ;RETRIEVE PCV.XX CODE
|
||
CAIE T3,PCV.BN ;12-BIT BINARY?
|
||
JRST NTDXN0 ;NO, ONE USER-BYTE PER NETWORK-BYTE THEN
|
||
LSHC T1,-1 ;YES. T1=PAIRS OF BYTES (=24 BITS)
|
||
IMULI T1,^D3 ;EACH PAIR OF BYTES IS WORTH 3 NETWORK BYTES
|
||
CAIGE T2,0 ;DANGLING ("ODD") BYTE?
|
||
ADDI T1,^D2 ;YES, THAT'S WORTH ANOTHER 1.5 (OR SO) BYTES
|
||
NTDXN0: PUSH P,T1 ;SAVE BYTE COUNT
|
||
ADDI T1,3 + <4*4> ;START WITH 4 WORDS (MAX) OF HEADER
|
||
LSH T1,-2 ;T1=WORD SIZE FOR PCB BUFFER
|
||
CAILE T1,MSGXMW## ;IF THIS IS MORE THAN THE "MAXIMUM" PCB SIZE
|
||
MOVEI T1,MSGXMW## ; THEN JUST REQUEST THE "MAXIMUM"
|
||
MOVEI T3,NTDHDR ;ASSUME THAT THIS IS NOT AN INTERRUPT MESSAGE
|
||
MOVEI T2,(1B0) ;GET THE "INTERRUPT MESSAGE" BIT
|
||
TDNE T2,-2(P) ; AND IF IT'S SET
|
||
MOVEI T3,NTDHDI ; THEN GET AN INTERRUPT HEADER.
|
||
PUSHJ P,(T3) ;GO BUILD THE HEADER
|
||
JRST [ADJSP P,-3 ;IF NO CORE, CLEAN UP THE STACK
|
||
SETZ T1, ; CLEAR T1 TO SAY ERROR WAS NO FREE CORE
|
||
POPJ P,] ; AND GIVE AN ERROR RETURN TO THE CALLER
|
||
MOVE T1,PCBALN(U) ;GET THE TOTAL NUMBER OF WORDS IN THE PCB
|
||
LSH T1,2 ;T1=TOTAL BYTES IN THE PCB
|
||
SUB T1,PCBCTR(U) ;DISCOUNT BYTES USED IN NCL HEADER
|
||
CAML T1,0(P) ;SKIP IF PCB WON'T FINISH OFF THE BUFFER
|
||
JRST NTDXN1 ;GO TO CODE TO SEND FINAL FRAGMENT OF BUFFER.
|
||
|
||
;CONTINUED ON NEXT PAGE
|
||
;CONTINUED FROM PREVIOUS PAGE
|
||
|
||
;HERE IF WE HAVE TO "FRACTURE" THE BUFFER INTO SEVERAL MESSAGES, AND THIS
|
||
; IS NOT THE LAST FRAGMENT OF THE BUFFER.
|
||
; T4 := NUMBER OF BYTES LEFT IN THE PCB (WE WILL USE THEM ALL)
|
||
|
||
MOVE T1,-1(P) ;GET THE IDC TYPE FIELD
|
||
ANDI T1,77 ;AND JUST THE TYPE (MASK OUT THE INTERRUPT BIT)
|
||
CAIL T1,DC.DAT ;NOW SEE IF THIS IS A MESSAGE TYPE THAT WE
|
||
CAILE T1,DC.DAR ; CAN LEGALLY FRAGMENT INTO MULTIPLE MESSAGES
|
||
JRST [ADJSP P,-3 ;CAN'T BREAK THE MESSAGE, CLEAN UP STACK
|
||
MOVEI T1,IOBKTL ;TELL CALLER ERROR WAS BLOCK-TOO-LARGE
|
||
POPJ P,] ; AND GIVE AN ERROR RETURN
|
||
MOVEI T1,DC.DAT ;CHANGE THE MESSAGE TYPE TO BE DATA W/O E-O-R.
|
||
MOVEM T1,-1(P) ; . . .
|
||
MOVN T2,0(P) ;GET MINUS THE BYTE COUNT THAT WILL FIT
|
||
MOVE T3,-2(P) ;RETRIEVE PCV.XX CODE AGAIN
|
||
CAIN T3,PCV.BN ;12-BIT BINARY?
|
||
JRST [IDIVI T2,^D3 ;T2:=COUNT OF 12-BIT-BYTE PAIRS
|
||
CAIE T3,0 ;DANGLING BYTE?
|
||
SUBI T2,1 ;YES, DISCOUNT IT TOO
|
||
JRST .+1] ;BLUNDER ONWARDS
|
||
ADDM T2,DEVAXO+1(F) ; AND UPDATE THE NUMBER OF UNSENT BYTES.
|
||
|
||
SKIPG DEVAXO+1(F) ;JUST A QUICK CHECK OF MY ARITHMETIC
|
||
STOPCD .,STOP,ANIUBN, ;++ UNSENT BYTES COUNT WENT NEGATIVE
|
||
JRST NTDXN2 ;GO SEND "CNT", "TYP", AND THE DATA.
|
||
|
||
|
||
|
||
;HERE IF THE PCB WILL HOLD ALL THE REST OF THE BUFFER.
|
||
; T4 := BYTES LEFT IN THE USER'S BUFFER
|
||
|
||
NTDXN1: SETZM DEVAXO+1(F) ;CLEAR BUFFER BYTE COUNT (THEY'LL ALL FIT)
|
||
; JRST NTDXN2 ;GO SEND "CNT", "TYP", AND THE DATA
|
||
|
||
;CONTINUED ON NEXT PAGE
|
||
;CONTINUED FROM PREVIOUS PAGE
|
||
|
||
;NTDXN2 HERE TO SEND "CNT", "TYP", AND DATA PORTIONS OF THE MESSAGE.
|
||
; -2(P) := CONVERSION CODE (WE MUST HANDLE BINARY MODE ESPECIAL)
|
||
; -1(P) := IDC TYPE
|
||
; -0(P) := NUMBER OF NETWORK BYTES TO GO.
|
||
;
|
||
;NOTE. BECAUSE THE ETHERNET SERVICE LAYER REQUIRES 8-BIT BYTES ONLY, AND
|
||
; CANNOT DEAL WITH ANYTHING ELSE, WE MUST HANDLE ALL THE SHANNANIGANS
|
||
; NORMALLY SLOUGHED OFF ONTO THE FEK, LIKE LPT CHARACTER COMPRESSION,
|
||
; AND THE HANDWAVING ABOUT 12-BIT "BINARY" DATA CONVERSION.
|
||
|
||
NTDXN2: MOVE P4,P2 ;COPY OF POINTER TO "CNT" FIELD
|
||
POP P,T4 ;RETRIEVE DATA BYTE COUNT
|
||
MOVEI T1,1(T4) ;ACCOUNT FOR THE "TYP" FIELD IN THE LENGTH
|
||
XMT T1 ;SEND THE LENGTH OF THE DAP MSG
|
||
POP P,T1 ;GET THE IDC TYPE BACK
|
||
XMT1 T1 ;THIS WILL MASK THE TYPE TO 8 BITS
|
||
MOVE P1,DEVAXO(F) ;USER'S BYTE POINTER
|
||
POP P,T1 ;RETRIEVE DATA COMPRESSION TYPE
|
||
CAIN T1,PCV.BN ;12-BIT BINARY DATA BYTES?
|
||
JRST [MOVE T3,T4 ;YES, MUST ADJUST BYTE COUNT
|
||
IDIVI T3,^D3 ;COUNT OF 12-BIT-BYTE-PAIRS
|
||
LSH T3,1 ;COUNT OF 12-BIT-BYTES
|
||
CAIE T4,0 ;ODD BYTE LEFT OVER?
|
||
ADDI T3,1 ;YEAH, ACCOUNT FOR IT TOO
|
||
MOVE T4,T3 ;REPOSITION DATA BYTE COUNT
|
||
JRST .+1] ;AND COPY C(T4) USER DATA BYTES INTO PCB
|
||
|
||
;CONTINUED ON NEXT PAGE
|
||
;CONTINUED FROM PREVIOUS PAGE
|
||
|
||
;HERE TO COPY THE DATA FROM THE USERS BUFFER AND INTO THE PCB. AT THIS POINT:
|
||
; 1) DEVAXO+1(F) HAS BEEN UPDATED TO REFLECT THE NUMBER OF BYTES COPIED.
|
||
; 2) T1 := THE CONVERSION CODE (PCV.XX)
|
||
; 3) T4 := THE NUMBER OF USER N-BIT-DATA-BYTES TO GO
|
||
; 4) P1 := BYTE POINTER TO USER DATA BUFFER
|
||
; 5) P2 := BYTE POINTER TO PCB DATA BUFFER (PCBPTR)
|
||
; 6) P3 := THE NUMBER OF BYTES IN PCB'S FIRST BUFFER (FROM "CNT", "TYP" ETC)
|
||
; 7) P4 := BYTE POINTER TO "CNT" FIELD
|
||
|
||
JRST @.+1(T1) ;DISPATCH ON CONVERSION TYPE
|
||
IFIW NTDX00 ;00 -- PCV.NC -- NO CONVERSION
|
||
IFIW NTDX10 ;01 -- PCV.LC -- LPT COMPRESSION
|
||
IFIW NTDX20 ;02 -- PCB.BN -- 12-BIT BINARY BYTES
|
||
|
||
|
||
;HERE AFTER DATA COPY, GIVE PCB TO FEK/NETWORK
|
||
|
||
NTDXN8: MOVEM P1,DEVAXO(F) ;SET BYTE POINTER FOR NEXT TIME (IF ANY)
|
||
ADDM P3,PCBCTR(U) ;COUNT UP BYTES COPIED
|
||
SETZM PCBCT2(U) ;NO SECONDARY BUFFER
|
||
SETZM PCBPT2(U) ; . . .
|
||
MOVEI T1,PCV.NC ;STRAIGHT 8-BIT BYTES FOR THE FEK
|
||
PUSHJ P,NTDWRT ;SEND THE PCB.
|
||
JRST CPOPJ1## ;GIVE GOOD RETURN
|
||
;HERE FOR NO CONVERSION TRANSMIT (STRAIGHT BYTE COPY)
|
||
|
||
NTDX00: ADD P3,T4 ;ACCOUNT FOR DATA BYTES
|
||
; (IF NULL, THEN WILL MAKE ONE USELESS LOOP)
|
||
NTDX02: EXCTUX <ILDB T1,P1> ;GET NEXT USER DATA BYTE
|
||
IDPB T1,P2 ;STORE IN PCB
|
||
SOJG T4,NTDX02 ;LOOP FOR REST OF PCB'S WORTH OF DATA
|
||
JRST NTDXN8 ;CAP OFF PCB AND SEND IT TO NETWORK
|
||
;HERE FOR LPT COMPRESSION
|
||
;
|
||
;COMPRESSED [7-BIT-ASCII] DATA IS FORMATTED AS FOLLOWS:
|
||
;
|
||
; 1CCCCCCC "CCCCCCC" IS THE 7-BIT ASCII CHARACTER
|
||
; 01SSSSSS "SSSSSS" IS THE COUNT OF SPACE CHARACTERS
|
||
; 001NNNNN "NNNNN" IS THE REPEAT COUNT FOR THE FOLLOWING CHARACTER
|
||
|
||
NTDX10: ADDM P3,PCBCTR(U) ;ACCOUNT FOR HEADER DATA
|
||
SETZ P3, ;USED TO COUNT ACTUAL DATA OUTPUT
|
||
|
||
REPEAT 1,<
|
||
ADD P3,T4 ;ACCOUNT FOR STRAIGHT BYTE COPY
|
||
NTDX1L: EXCTUX <ILDB T1,P1> ;GET NEXT USER DATA BYTE
|
||
TRO T1,200 ;MARK IT UNCOMPRESSED
|
||
IDPB T1,P2 ;STASH IT IN THE PCB
|
||
SOJG T4,NTDX1L ;LOOP FOR WHOLE BUFFER
|
||
JRST NTDXN8 ;OUTPUT THE PCB
|
||
> ;END REPEAT 1
|
||
|
||
REPEAT 0,<
|
||
PUSH P,P4 ;SAVE P4/"CNT" BYTE POINTER
|
||
SETZ T1, ;INITIALIZE CHAR-REPEAT COUNT
|
||
SOJL T4,NTDX18 ;COUNT A DATA BYTE
|
||
EXCTUX <ILDB T2,P1> ;READ FIRST USER DATA CHARACTER
|
||
|
||
;LOOP COUNTING CHARACTER REPEATITION
|
||
|
||
NTDX11: SOJL T4,NTDX12 ;END OF USER DATA IS END OF CHAR REPEAT
|
||
EXCTUX <ILDB T3,P1> ;READ NEXT USER DATA CHARACTER
|
||
CAMN T2,T3 ;REPEAT CHARACTER?
|
||
AOJA T1,NTDX11 ;YES, COUNT NUMBER OF REPEATS
|
||
|
||
;HERE WHEN CHARACTERS DIDN'T MATCH, FLUSH PREVIOUS REPEATED CHARS
|
||
|
||
NTDX12: JUMPE T1,[IORI T2,200 ;ONLY ONE CHAR, FLAG UNCOMPRESSED
|
||
JRST NTDX17] ;AND STASH IN THE PCB BUFFER
|
||
CAIN T2," " ;COMPRESSING SPACES?
|
||
JRST NTDX15 ;YES, DIFFERENT FROM OTHER CHARACTERS
|
||
|
||
;T1 := REPEAT COUNT MINUS ONE, T2 := REPEATED CHARACTER
|
||
|
||
NTDX13: CAILE T1,36 ;WAS THIS CHARACTER REPEATED A LOT?
|
||
AOJA P3,[MOVEI P4,37+040 ;MAX REPEAT COUNT + COMPRESSION FLAG
|
||
IDPB P4,P2 ;STORE REPEAT COUNT BYTE
|
||
IDPB T2,P2 ;AND COMPRESSED CHARACTER
|
||
SUBI T1,37 ;ACCOUNT FOR THIS PASS
|
||
AOJA P3,NTDX13] ;SEE IF DONE WITH THIS CHARACTER
|
||
ADDI T1,1+040 ;MAKE T1 INTO REPEAT COUNT + REPEAT FLAG
|
||
IDPB T1,P2 ;STORE REPEAT COUNT BYTE
|
||
AOJA P3,NTDX17 ;GO STORE COMPRESSED CHARACTER AND LOOP
|
||
;T1 := REPEAT COUNT MINUS ONE, T2 := SPACE CHARACTER
|
||
|
||
NTDX15: CAILE T1,76 ;WAS THIS SPACE REPEATED A LOT?
|
||
AOJA P3,[MOVEI P4,77+100 ;MAX REPEAT COUNT + COMPRESSION FLAG
|
||
IDPB P4,P2 ;STORE REPEAT COUNT BYTE
|
||
IDPB T2,P2 ;AND COMPRESSED SPACE
|
||
SUBI T1,77 ;ACCOUNT FOR THIS PASS
|
||
AOJA P3,NTDX15] ;SEE IF CAN FINISH WITH THIS SPACE
|
||
ADDI T1,1+100 ;MAKE T1 INTO REPEAT COUNT + COMPRESSION FLAG
|
||
IDPB T1,P2 ;STORE REPEAT COUNT BYTE
|
||
AOJA P3,NTDX17 ;GO STORE COMPRESSED SPACE AND LOOP
|
||
|
||
;OUTPUT CHARACTER IN T2, LOOP FOR NEXT USER DATA CHARACTER
|
||
|
||
NTDX17: IDPB T2,P2 ;OUTPUT CHARACTER IN T2
|
||
ADDI P3,1 ;ACCOUNT FOR IT
|
||
SETZ T1, ;CLEAR REPEAT COUNT
|
||
MOVE T2,T3 ;NEXT CHARACTER BECOMES CURRENT CHARACTER
|
||
JUMPGE T4,NTDX11 ;LOOP FOR REST OF USER DATA BUFFER
|
||
|
||
;USER BUFFER EMPTIED, ADJUST OUTPUT BYTE COUNT AND SHIP THE PCB
|
||
|
||
NTDX18: POP P,P4 ;RETRIEVE POINTER TO "CNT" FIELD
|
||
AOS T1,P3 ;BYTE COUNT (DON'T FORGET THE "TYP" BYTE!)
|
||
NTDX19: IDIVI T1,200 ;GET SEVEN-BIT'S WORTH OF NEW "CNT" FIELD
|
||
ILDB T3,P4 ;ORIGINAL "CNT" BYTE
|
||
TRNE T3,200 ;WAS IT EXTENSIBLIZED?
|
||
TRO T2,200 ;YES, THEN SO IS NEW "CNT" BYTE
|
||
DPB T2,P4 ;SET MODIFIED "CNT" BYTE
|
||
TRNE T3,200 ;MORE "CNT" FIELD TO PROCESS?
|
||
JRST NTDX19 ;YES, FLUSH IT OUT
|
||
SOJA P3,NTDXN8 ;GO TRANSMIT THIS PCB
|
||
> ;END REPEAT 0
|
||
;HERE FOR BINARY (12-BIT BYTES) CONVERSION
|
||
|
||
NTDX20: SOJL T4,NTDXN8 ;IF NO MORE DATA BYTES LEFT, XMIT THE PCB
|
||
EXCTUX <ILDB T1,P1> ;GET NEXT USER DATA BYTE
|
||
SOJL T4,[LSHC T1,-^D4 ;ONLY ONE 12-BIT DATA BYTE LEFT
|
||
AOJA P3,NTDX25] ;SEND IT AS TWO NETWORK BYTES
|
||
ADDI P3,2 ;TWO 12-BIT BYTES COUNT AS THREE NETWORK BYTES
|
||
EXCTUX <ILDB T2,P1> ;GET NEXT USER DATA BYTE
|
||
LSH T2,^D24 ;T1 AND T2 CONTIGUOUS DATA BITS
|
||
LSHC T1,-^D4 ;T1 HAS 8 BITS, T2 HAS 16 BITS
|
||
IDPB T1,P2 ;STORE FIRST 8 DATA BITS IN PCB
|
||
LSHC T1,^D8 ;POSITION NEXT 8 DATA BITS
|
||
NTDX25: IDPB T1,P2 ;AND STASH THEM IN THE PCB ALSO
|
||
LSHC T1,^D8 ;POSITION LAST 8 DATA BITS
|
||
IDPB T1,P2 ;AND STUFF THEM IN THE PCB AS WELL
|
||
AOJA P3,NTDX20 ;LOOP FOR MORE DATA BITS
|
||
COMMENT @
|
||
|
||
Protocol for writing Network DisPatch service routines.
|
||
|
||
1) Service routines should skip return if they liked the message,
|
||
and non-skip (error) return if the message was bad.
|
||
|
||
2) Service routines may NOT assume that "U" points to the PCB
|
||
that contains the current message. In particular, service
|
||
routines may NOT call INCTBD. To "discard" a bad message,
|
||
the service routine should simply non-skip (error) return.
|
||
|
||
3) Upon entry to the service routine the following registers are setup.
|
||
P1 Contains a byte pointer pointing to the TYP field of this
|
||
sub-message. (ie. an ILDB will get the first data byte
|
||
after the TYP)
|
||
P4 Contains the number of data bytes in the msg. (Excluding
|
||
the TYP byte. (ie. CNT -1))
|
||
|
||
4) Service routines (When called at UUO level) may page fault
|
||
as long as they don't mind getting called again with the
|
||
same sub-message. (ie. The sub-message isn't considered delivered
|
||
until the service routine returns.)
|
||
|
||
Implementation Notes.
|
||
|
||
1) In order to maintain the information regarding how much of a message
|
||
we have processed, the following locations in the DDB are used.
|
||
(Remember that a single NCL message may have numerous "sub-messages"
|
||
for the designated device. In particular it may have 25 data-with-
|
||
end-of-record messages. In that the user may have to do 25 "IN" uuo's
|
||
in order to get all of the data. Another problem to worry about
|
||
is that the way TOPS-10 handles page faults is to cease executing
|
||
the uuo, and start the user at his page fault handler. The only way
|
||
to get back to processing the message is for the PFH to start the
|
||
uuo over again. Sigh)
|
||
|
||
DEVPCB The rh of this word the head of the queue of unprocessed
|
||
input PCB's for this device. The queue is in order of the
|
||
messages' arrival. The top message on the queue is the
|
||
one currently being processed. It should NOT be removed
|
||
until all sub-messages have been processed.
|
||
The lh currently contains the number of bytes left to be
|
||
read in the current message.
|
||
|
||
DEVPBP This is a byte pointer that points to the "CNT" field of
|
||
the next NCL sub-message to process. (This will be a sub-
|
||
message of the top PCB on the DEVPCB queue.) This pointer
|
||
should not be advanced until the the sub-message has been
|
||
accepted by the device service routine. In particular,
|
||
it should not be ILDB'ed.
|
||
|
||
@
|
||
;NTDISP ROUTINE TO PERFORM THE DAP DISPATCH ON MULTIPART MESSAGES.
|
||
; CALL ONCE FOR EACH SUB-MESSAGE.
|
||
;CALL PUSHJ P,NTDISP ;CALL DEVICE DRIVER WITH NEXT SUB-MESSAGE
|
||
;RETURN CPOPJ ;IF MESSAGE WAS BAD. T1 WILL HAVE THE
|
||
; ; PC OF THE CODE THAT COMPLAINED.
|
||
; CPOPJ1 ;MESSAGE WAS ACCEPTED BY THE SERVICE ROUTINE.
|
||
; ;IF DEVPBP(F) = 0 THEN ALL SUBMESSAGES HAVE
|
||
; ; BEEN PROCESSED.
|
||
|
||
NTDISP: MOVE P1,DEVPBP(F) ;GET THE POINTER TO THE NEXT SUB-MESSAGE
|
||
HLRZ P4,DEVPCB(F) ;GET THE NUMBER OF BYTES LEFT IN THE MESSAGE
|
||
|
||
;CNT
|
||
|
||
PUSHJ P,EBI2BI ;GET THE LENGTH OF THIS SUB-MESSAGE
|
||
JUMPE T1,NTDIS1 ;IF ZERO, THEN ALL DONE WITH THIS MESSAGE
|
||
SUBI P4,(T1) ;UPDATE THE NUMBER OF BYTES LEFT BY THIS SUB-MSG
|
||
JUMPL P4,NTDIS2 ;BAD MESSAGE IF GOES PAST THE END.
|
||
HRLM P4,DEVPCB(F) ;REMEMBER HOW MANY LEFT AFTER THIS SUB-MSG
|
||
MOVEI P4,(T1) ;COPY THE LENGTH OF THIS SUBMESSAGE
|
||
|
||
;TYP
|
||
|
||
PUSHJ P,EBI2BI ;GET THE IDC TYPE
|
||
CAILE T1,0 ;NOW DO A LITTLE RANGE CHECKING
|
||
CAILE T1,DC.MAX ; SO WE DON'T GO FLYING OFF INTO TROUBLE
|
||
JSP T1,NTDIS2 ; BAD MESSAGE TYPE. PUT PC IN T1 AND RETURN
|
||
MOVE S,DEVIOS(F) ;SET UP DEVICE STATUS
|
||
HLRZ T2,DEVNET(F) ;GET THE ADDRESS OF THE NETWORK DEVICE TABLE
|
||
PUSHJ P,@NDTNDP(T2) ;DISPATCH (T1 IS USED IN THE INDIRECTION...)
|
||
JSP T1,NTDIS2 ;SERVICE ROUTINE CHOKED ON THAT ONE. GIVE ERROR.
|
||
|
||
;SERVICE ROUTINE ACCEPTED SUB-MESSAGE - MAKE SURE IT ATE IT ALL
|
||
|
||
SOJGE P4,[IBP P1 ;IF THE SERVICE ROUTINE DIDN'T EAT ALL THE MSG,
|
||
JRST .] ; MAKE SURE THAT P1 GETS ADVANCED.
|
||
MOVEM P1,DEVPBP(F) ;SAVE POINTER TO NEXT SUB-MSG.
|
||
HLRZ P4,DEVPCB(F) ;GET THE NUMBER OF BYTES LEFT IN MESSAGE
|
||
JUMPG P4,CPOPJ1## ;IF THERE ARE SOME LEFT, RETURN TO NTDDID
|
||
|
||
;HERE WHEN ALL DONE WITH THE MESSAGE
|
||
|
||
NTDIS1: SETZM DEVPBP(F) ;MARK MSG AS DONE
|
||
PJRST CPOPJ1## ;GIVE GOOD (SKIP) RETURN
|
||
|
||
|
||
;HERE WHEN MSG IS BAD. RETURN WITH T1 := ADDRESS OF THE CODE THAT FOUND
|
||
; THE MESSAGE WAS BAD
|
||
|
||
NTDIS2: SETZM DEVPBP(F) ;INDICATE NO PARTIAL MSG TO DO.
|
||
POPJ P, ;GIVE ERROR RETURN
|
||
;NTDILD ROUTINE TO PROCESS INPUT MESSAGES AT "INTERRUPT" LEVEL
|
||
;CALL MOVEI U,PCB
|
||
; MOVE P1,BYTE POINTER TO FIRST "CNT"
|
||
; PUSHJ P,NTDILD
|
||
;RETURN CPOPJ
|
||
;
|
||
;NOTE!! THIS ROUTINE HANDLES DATA-REQUESTS.
|
||
;NOTE!! IF THE DEVICE SERVICE ROUTINE FINDS AN ERROR IN THE MESSAGE
|
||
; IT WILL PROBABLY ZERO U.
|
||
NTDILD:: ;INTERRUPT LEVEL DAP DISPATCH
|
||
PUSHJ P,NTDDOD ;ATTEMPT TO MAINTAIN CORRECT DRQ COUNT.
|
||
MOVEM P1,DEVPBP(F) ;SET UP "PBP" FOR CALL TO NTDISP
|
||
HRLM P4,DEVPCB(F) ;SAVE THE NUMBER OF BYTES LEFT IN THE MESSAGE
|
||
NTDIL1: PUSHJ P,NTDISP ;DO THE DAP LEVEL DISPATCHING.
|
||
JRST INCTBD ; BAD MESSAGE. T1 HAS PC OF CODE THAT NOTICED.
|
||
SKIPE DEVPBP(F) ;HAVE WE PROCESSED ALL SUB-MESSAGES?
|
||
JRST NTDIL1 ; IF NOT, GO BACK AND DO THE NEXT ONE.
|
||
S0JRST RMVPCB ;ALL DONE WITH THE MESSAGE. RETURN PCB
|
||
;NTDQIP ROUTINE TO QUEUE INPUT PCB'S AT INTERRUPT LEVEL FOR PROCESSING AT
|
||
; LOWER (UUO) LEVEL.
|
||
;CALL MOVEI U,PCB
|
||
; MOVEI P1,POINTER TO THE FIRST "CNT" AFTER THE "DLA"
|
||
; PUSHJ P,NTDQIP
|
||
;RETURN CPOPJ ;WITH PCB QUEUED
|
||
;
|
||
;NOTE IF THIS IS THE ONLY PCB QUEUED, WE SAVE "P1" SO WE WON'T HAVE TO
|
||
; SCAN THE NCL HEADER AGAIN.
|
||
|
||
NTDQIP::PUSHJ P,NTDDOD ;ATTEMPT TO MAINTAIN CORRECT DRQ COUNT.
|
||
HLLZS PCBBLK(U) ;CLEAR ANY STRAY POINTERS
|
||
HRRZ T1,DEVPCB(F) ;GET HEADER OF QUEUE OF PCB'S
|
||
JUMPE T1,NTDQI2 ; IF WE ARE FIRST, THEN WE ARE SPECIAL.
|
||
CAIA ; OTHERWISE SKIP INTO LOOP TO FIND LAST PCB
|
||
NTDQI1: MOVEI T1,(T2) ;ADVANCE TO THE NEXT PCB IN THE QUEUE
|
||
HRRZ T2,PCBBLK(T1) ;GET NEXT PCB (OR NULL)
|
||
JUMPN T2,NTDQI1 ;IF THERE IS ANOTHER PCB, THEN LOOP DOWN CHAIN
|
||
HRRM U,PCBBLK(T1) ;LINK THIS PCB ON AS THE LAST IN THE QUEUE
|
||
SETZ U, ;CLEAR U SO NETSCN WILL KNOW THAT PCB IS GONE.
|
||
POPJ P, ;AND THAT'S ALL FOR NOW.
|
||
|
||
NTDQI2: HRRM U,DEVPCB(F) ;SAVE THE PCB AS THE HEAD OF THE QUEUE.
|
||
HRLM P4,DEVPCB(F) ; SAVE THE COUNT OF UN-PROCESSED BYTES IN MSG
|
||
MOVEM P1,DEVPBP(F) ; STORE THE POINTER TO FIRST NCL SUB-MESSAGE.
|
||
SETZ U, ;TELL NETSCN NOT TO FREE THE PCB
|
||
PJRST NTDIAV ;TELL THE JOB THAT INPUT IS AVAILABLE.
|
||
;*** NOTE *** WE ONLY WAKE THE JOB ON THE
|
||
; THE ARRIVAL OF THE FIRST MESSAGE.
|
||
|
||
|
||
;*** FOOTNOTE ***
|
||
|
||
COMMENT \
|
||
Because the count of outstanding data requests is decremented when
|
||
the message is queued, the routine NTDXDQ should never be called while
|
||
there are queued input messages. (If it is, it will not realize that there
|
||
are unprocessed messages, and possibly request more data than the program
|
||
has buffers for.) This enforces my belief that one does not want to send
|
||
data requests if one has any unprocessed input data. Remember, these input
|
||
PCB's are not going to a physical device. They should not have to wait
|
||
to be processed. If there is some reason that they cannot be processed
|
||
immediatly (ie the job has swapped) I don't think that it is a good
|
||
idea to send more requests.
|
||
|
||
\
|
||
;NTDDID HERE TO PERFORM A "DELAYED INPUT DISPATCH" AT UUOLEVEL.
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,NTDDID ;DO DELAYED DISPATCH
|
||
;RETURN CPOPJ
|
||
;
|
||
;NOTE!! THIS ROUTINE (IN CONTRAST TO NTDILD) ONLY DISPATCHES 1 NCL SUB
|
||
; MESSAGE AT A TIME. IN OTHER WORDS, YOU MUST CALL THIS ROUTINE
|
||
; ONCE FOR EACH SUB-MESSAGE OF AN NCL MESSAGE. THE REASONING BEHIND
|
||
; THIS IS THAT IT ALLOWS THE DEVICE SERVICE ROUTINE TO DETERMING
|
||
; IF THERE ARE ENOUGH FREE BUFFERS TO ACCEPT THE DATA.
|
||
;
|
||
;NOTE!! THE FOLLOWING LOCATIONS IN THE DDB ARE USED TO MAINTAIN INFORMATION
|
||
; REGARDING HOW FAR WE HAVE GOTTEN WHEN TAKING APART MULTI-PART NCL
|
||
; MESSAGES.
|
||
;
|
||
; DEVPCB
|
||
; THE RIGHT HAND PART OF THIS IS THE HEAD OF THE QUEUE OF UNPROCESSED
|
||
; INPUT PCB'S FOR THIS DEVICE.
|
||
; THE LEFT HAND PART OF THIS IS THE COUNT OF THE NUMBER OF BYTES LEFT
|
||
; TO PROCESS IN THE CURRENT PCB. (IT IS THE GLOBAL "P4" FOR THE DISPATCH
|
||
; ROUTINES) IT IS INITIALIZED TO "PCBCTR - HEADER LENGTH" AND IS
|
||
; DECREMENTED BY THE LENGTH OF EACH SUB-MESSAGE PROCESSED.
|
||
; DEVPBP
|
||
; THIS IS A BYTE POINTER INTO THE MESSAGE THAT IS AT THE HEAD OF THE
|
||
; DEVPCB QUEUE. IT POINTS TO THE FIRST UN-PROCESSED SUB-MESSAGE.
|
||
;
|
||
;
|
||
NTDDID:: ;HERE TO PROCESS NEXT PCB ON DEVPCB
|
||
MOVE P1,DEVPBP(F) ;SEE IF WE HAVE TO PARSE THE NCL HEADER
|
||
JUMPN P1,NTDDI1 ; WE WON'T IF WE ALREADY HAVE A POINTER TO DAP
|
||
|
||
HRRZ U,DEVPCB(F) ;GET POINTER TO THE FIRST PCB.
|
||
JUMPE U,CPOPJ## ; BUT RETURN NOW IF THERE ISN'T ONE.
|
||
MOVE P1,PCBPTR(U) ;WE HAVE TO PARSE THE NCL, SO GET POINTER TO MSG
|
||
MOVE P4,PCBCTR(U) ;GET THE LENGTH OF THIS MESSAGE.
|
||
;NCT
|
||
PUSHJ P,SKIP1 ;SKIP OVER THE NCT
|
||
;DNA
|
||
PUSHJ P,XSKIP ;SKIP OVER THE DESTINATION NODE ADDRESS
|
||
;SNA
|
||
PUSHJ P,XSKIP ;SKIP OVER THE SOURCE
|
||
;NCA
|
||
PUSHJ P,SKIP1 ;SKIP OVER THE ACK
|
||
;NCN
|
||
PUSHJ P,SKIP1 ;SKIP OVER THE MESSAGE NUMBER
|
||
;DLA
|
||
PUSHJ P,XSKIP ;SKIP OVER OUR LINK ADDRESS
|
||
|
||
MOVEM P1,DEVPBP(F) ;SET UP PBP FOR NTDISP
|
||
HRLM P4,DEVPCB(F) ;SAVE THE LENGTH OF THE REST OF THE MESSAGE
|
||
NTDDI1: ;HERE TO DISPATCH THE NEXT SUB-MESSAGE
|
||
PUSHJ P,NTDISP ;DO THE DISPATCH
|
||
JRST NTDDI2 ;ERROR RETURN. GIVE THE BAD PCB TO INCTBD.
|
||
SKIPE DEVPBP(F) ;HAVE WE READ ALL SUB-MESSAGES?
|
||
POPJ P, ;IF NOT, DON'T FREE THE PCB YET.
|
||
|
||
HRRZ U,DEVPCB(F) ;ALL DONE WITH THIS PCB. GET ADDRESS TO IT
|
||
HRRZ T2,PCBBLK(U) ; GET ADDRESS OF THE NEXT ONE
|
||
HRRZM T2,DEVPCB(F) ; SET THE NEXT ONE UP TO BE PROCESSED NEXT TIME.
|
||
S0JRST RMVPCB ;RETURN THE PCB AND EXIT
|
||
|
||
NTDDI2: ;HERE IF THE SERVICE ROUTINE DIDN'T LIKE MSG.
|
||
HRRZ U,DEVPCB(F) ;GET THE OFFENDING PCB
|
||
HRRZ T2,PCBBLK(U) ;GET POINTER TO NEXT PCB IN THE CHAIN
|
||
HRRZM T2,DEVPCB(F) ; AND MAKE THAT THE NEXT TO BE PROCESSED.
|
||
PJRST INCTBD ;SIGNAL ERROR (PC OF ERROR IS IN T1)
|
||
;NTDCDQ CHECK FOR OUTPUT DATA REQUESTS.
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,NTDCDQ
|
||
;RETURN CPOPJ ;NO DATA-REQUEST AVAILABLE (DEVDRQ = 0)
|
||
; CPOPJ1 ;DATA REQUEST IS AVAILABLE
|
||
;
|
||
NTDCDQ:: ;CHECK FOR OUTPUT DATA REQUESTS
|
||
HRRZ T1,DEVDRQ(F) ;GET NUMBER OF OUTSTANDING DATA REQUESTS
|
||
JUMPG T1,CPOPJ1## ;IF POSITIVE, GIVE GOOD RETURN
|
||
POPJ P, ; RETURN
|
||
|
||
|
||
|
||
;NTDDDQ DECREMENT DATA REQUEST COUNT
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,NTDCDQ
|
||
;RETURN CPOPJ ;ALWAYS (DEVDRQ := DEVDRQ-1)
|
||
;
|
||
NTDDDQ::PUSHJ P,NTDCDQ ;MAKE SURE WE HAVE OUTSTANDING DRQ'S
|
||
STOPCD .,STOP,ANFDDQ, ;++ DATA REQUEST COUNT WENT NEGATIVE
|
||
SOS DEVDRQ(F) ;COUNT DOWN THIS REQUEST
|
||
POPJ P, ;AND RETURN
|
||
|
||
|
||
|
||
;NTDDOD DECREMENT OUTSTANDING DATA REQUEST COUNT.
|
||
;CALL MOVEI U,INCOMING PCB TO CHECK
|
||
; MOVEI F,DDB CONTAINING DATA-REQUEST INFORMATION
|
||
; PUSHJ P,NTDDOD
|
||
;RETURN CPOPJ ;WITH LH(DEVDRQ(F)) DECREMENTED IF NON-INTERRUPT
|
||
;
|
||
NTDDOD: ;HERE TO CHECK IF THIS IS NON-INTERRUPT DATA
|
||
MOVE T1,PCBPTR(U) ;GET POINTER TO MESSAGE
|
||
;NCT
|
||
ILDB T1,T1 ;GET THE FIRST BYTE OF THE MESSAGE
|
||
TRNE T1,NCT.IT ;INTERRUPT MESSAGE??
|
||
POPJ P, ;YES, DON'T MUNG OUTSTANDING DRQ COUNT
|
||
MOVSI T1,-1 ;INDICATE ONE LESS
|
||
ADDM T1,DEVDRQ(F) ; OUTSTANDING DATA-REQUEST
|
||
POPJ P, ;ALL DONE
|
||
;NTDXDQ SUBROUTINE TO SEND DATA REQUESTS BASED ON EMPTY BUFFERS.
|
||
;CALL MOVEI F,DDB
|
||
; PUSHJ P,NTDXDQ ;TRY TO SEND DATA REQUESTS
|
||
;RETURN CPOPJ ;ALWAYS.
|
||
;
|
||
NTDXDQ:: ;HERE TO SEND DATA REQUESTS
|
||
SETZ T1, ;FIRST COUNT BUFFERS (INITIALIZE COUNT TO ZERO)
|
||
HRRZ T2,DEVIAD(F) ;GET POINTER TO THE FIRST BUFFER
|
||
MOVEI T3,(T2) ;REMEMBER START OF RING INCASE ALL ARE EMPTY
|
||
|
||
NTDXD1: UMOVE T2,(T2) ;GET THE BUFFER USE BITS
|
||
ERJMP NTDXD2 ;PAGED OUT, STOP COUNTING BUFFERS
|
||
JUMPLE T2,NTDXD2 ;IF IT'S NOT FREE, STOP COUNTING BUFFERS
|
||
ANDI T2,-1 ;MASK OFF THE "SIZE" PART OF THE HEADER WORD
|
||
CAIGE T1,MAXODR## ;IF WE HAVE ENOUGH DATA REQUESTS,
|
||
CAIN T2,(T3) ; OR WE HAVE COUNTED ALL THE BUFFERS.
|
||
AOJA T1,NTDXD2 ; THEN TRY TO SEND THE REQUEST
|
||
AOJA T1,NTDXD1 ;OTHER WISE KEEP COUNTING FREE BUFFERS.
|
||
|
||
NTDXD2: ;HERE WITH THE NUMBER OF FREE BUFFERS IN T1
|
||
HLRZ T2,DEVDRQ(F) ;GET THE NUMBER OF OUTSTANDING DRQ'S
|
||
SUBI T1,(T2) ;FIGURE OUT HOW MANY MORE WE CAN SEND
|
||
JUMPLE T1,CPOPJ## ;IF WE CAN'T SEND ANY, THEN RETURN NOW
|
||
|
||
PUSH P,T1 ;SAVE THE NUMBER WE ARE REQUESTING
|
||
PUSHJ P,NCSDRQ ;SEND THE DRQ MESSAGE
|
||
JRST [PUSHJ P,NETSLP ;IF WE CAN'T THEN WAIT (*** SEE FOOTNOTE)
|
||
MOVE T1,(P) ; GET THE COUNT BACK
|
||
JRST .-1] ; AND TRY AGAIN
|
||
POP P,T1 ;GET THE COUNT BACK
|
||
HRLZI T1,(T1) ;GET IT IN THE LEFT HALF
|
||
ADDM T1,DEVDRQ(F) ;AND UPDATE THE COUNT OF OUTSTANDING DRQ'S
|
||
POPJ P, ;ALL DONE
|
||
|
||
|
||
;*** FOOTNOTE ***
|
||
|
||
COMMENT \
|
||
|
||
I don't think that I can return to the user here since if this is his
|
||
first DRQ then he may be stuck waiting for messages that will never come.
|
||
I don't like the idea of making some one wait (he may be doing non-blocking
|
||
I/O) but until someone devizes a way to give the job an input done interrupt
|
||
when free core becomes available, I think this will have to be done.
|
||
Note also that this routine cannot be called from interrupt level. There
|
||
are reasons for this other than the fact that it's a bad idea to put an
|
||
interrupt level to "NETSLP". The other main reason is that if this is running
|
||
on an SMP KL-10 system looking at anything in a users address space at interrupt
|
||
level screws up the cache. (It sets the cache valid bit in the CPU that
|
||
may not be running the user.) The solution to this is to "OUCHE" any words
|
||
that are looked at by interrupt level. Whatta pain.
|
||
|
||
\
|
||
;NTDRDQ ROUTINE TO PROCESS INCOMING DATA REQUESTS (HERE FROM ICMDRQ VIA
|
||
; THE DRQ DISPATCH.
|
||
;CALL MOVEI T4,"DRQ" COUNT
|
||
; PUSHJ P,NTDRDQ
|
||
;RETURN CPOPJ1 ;ALWAYS
|
||
;
|
||
;NOTE THIS ROUTINE WAKES THE JOB ONLY IF THIS WAS THE FIRST DATA REQUEST.
|
||
;
|
||
NTDRDQ:: ;HERE IN RECEIPT OF A DATA REQUEST
|
||
HRRZ T1,DEVDRQ(F) ;GET THE OLD DATA REQUEST COUNT
|
||
ADDM T4,DEVDRQ(F) ;ADD IN THE NEW
|
||
SKIPGE T1 ;SKIP IF THE OLD ONE WAS NON-NEGATIVE
|
||
STOPCD .,STOP,ANFDRQ, ;++ DRQ WENT NEGATIVE
|
||
;*** SKIPG T1 ;SEE IF HE WAS WAITING FOR DATA REQUESTS
|
||
MOVE S,DEVIOS(F) ;SET UP S
|
||
PUSHJ P,NTDOAV ; IF HE WAS. THEN WAKE HIM
|
||
JRST CPOPJ1## ;GIVE GOOD RETURN
|
||
|
||
;*** FOOTNOTE ***
|
||
|
||
COMMENT \
|
||
|
||
For some as yet unknown reason, the "SKIPG" that is commented out
|
||
breaks asynch I/O. Inspite of the fact that everything is interlocked
|
||
via the "NT" INTERLOCK, there appears to be a race. The symptom is that
|
||
the job does not get an output done interrupt, and hence is stuck waiting
|
||
for one, even though he has several data requests.
|
||
|
||
\
|
||
;NTDWTI ;ROUTINE TO WAIT FOR INPUT DATA
|
||
;CALL PUSHJ P,NTDWTI ;
|
||
;RETURN CPOPJ ;IF NON-BLOCKING, OR IF PROG HAS AT LEAST
|
||
; ; ONE BUFFER AVAILABLE FOR READING
|
||
; CPOPJ1 ;IF BLOCKING AND WE NOW HAVE INPUT DATA
|
||
|
||
NTDWTI::HRRZ T2,DEVBUF(F) ;IF THE USER HAS AT LEAST
|
||
JUMPE T2,CPOPJ## ;IF NO BUFFERS, GET OUT NOW
|
||
EXCTUX <HRRZ T2,(T2)> ; ONE BUFFER OF DATA AVAILABLE,
|
||
EXCTUX <SKIPGE (T2)> ; (IE USE BIT IS SET)
|
||
POPJ P, ;THEN RETURN NOW SO HE CAN RUN
|
||
MOVE T2,DEVAIO(F) ;IF USER HAS NO DATA, THEN SEE IF
|
||
TRNE T2,DEPAIO ; NON-BLOCKING I/O. IF SO,
|
||
POPJ P, ; THEN JUST RETURN. (UUOCON WILL UNDERSTAND)
|
||
PUSHJ P,NETHIB ;IF BLOCKING, THEN GO SLEEP TILL SOME COMES
|
||
RETSKP ; (NOTE THAT "W" IS NO LONGER VALID) (NOR "S")
|
||
|
||
;NTDWTO ;ROUTINE TO WAIT FOR OUTPUT DATA REQUESTS
|
||
;CALL PUSHJ P,NTDWTO ;CALL TO SEE IF OUTPUT CAN BE DONE
|
||
;RETURN CPOPJ ;NO DATA-REQUESTS. BUT NON-BLOCKING I/O
|
||
; CPOPJ1 ;THERE ARE DATA REQUESTS. TRY MORE OUTPUT
|
||
|
||
NTDWTO::MOVE T2,DEVAIO(F) ;IF THIS IS NOT NON-BLOCKING
|
||
TRNN T2,DEPAIO ; STYLE I/O, THEN
|
||
JRST [AOS (P) ; GIVE A SKIP (DO MORE OUTPUT RETURN)
|
||
PJRST NETHIB] ; AFTER WE GET MORE DATA.
|
||
; (NOTE THAT "W" IS NO LONGER VAILD)
|
||
; HLRZ T2,DEVBUF(F) ;IF THE USER HAS AT LEAST ONE
|
||
; EXCTUX <HRRZ T2,(T2)> ; EMPTY BUFFER AVAILABLE FOR
|
||
; EXCTUX <SKIPL (T2)> ; FOR FILLING, THEN
|
||
; JRST [TLNN F,OCLOSB ; UNLESS THIS IS FROM THE "CLOSE" UUO
|
||
; POPJ P, ; RETURN TO UUOCON TO LET THE USER CONTINUE.
|
||
; JRST .+1] ;IF IT IS THE CLOSE UUO, BLOCK.
|
||
MOVSI S,IOSTBL ;IF IT IS NONBLOCKING. SET "TROUBLE" SO THAT
|
||
IORB S,DEVIOS(F) ; UUOCON WON'T ADVANCE DEVBUF, AND
|
||
POPJ P, ; LET UUOCON RUN THE USER SOME MORE
|
||
|
||
|
||
;*** FOOTNOTE ***
|
||
|
||
COMMENT \
|
||
|
||
In NTDWTO it would be nice if it could return and let the user run
|
||
if he had any buffers left to fill, but this appears not to work. What
|
||
happens is that the WAIT1 code does a CALOUT trying to empty the last few
|
||
buffers. NTDWTO trying to be clever quickly returns noticing that the
|
||
user has a few buffers left to fill. The situation is clearly out of hand.
|
||
The monitor hangs. One might think that we could do this for async I/O,
|
||
but unfortunatly, under MSGSER, DEVBUF doesn't really mean anything.
|
||
|
||
\
|
||
;NTDIAV ;HERE TO TELL A JOB THAT IT HAS NETWORK INPUT.
|
||
;CALL PUSHJ P,NTDIAV
|
||
;RETURN CPOPJ ;ALWAYS
|
||
;
|
||
;THIS ROUTINE FIGURES OUT HOW THE JOB IS WAITING. (SLEEPING, OR NON-BLOCKING)
|
||
; AND USES AN APPROPRIATE METHOD TO WAKE IT.
|
||
;
|
||
NTDIAV:: ;HERE TO NOTIFY JOB THAT IT HAS NETWORK INPUT.
|
||
MOVE T1,DEVAIO(F) ;FIRST CHECK AND SEE IF THIS JOB
|
||
TRNN T1,DEPAIO ; IS DOING NON-BLOCKING I/O
|
||
PJRST NETWAK ;IF NOT, THEN IT'S SLEEPING, SO WAKE IT.
|
||
PUSH P,DEVIOS(F) ;WE NEED TO SET INPUT IO DONE, SO SAVE DEVIOS.
|
||
MOVSI S,IO!IOSTBL ;AND PRETEND THAT THE DEVICE IS
|
||
ANDCAB S,DEVIOS(F) ; DOING INPUT (SO WE DON'T PSI OUTPUT DONE)
|
||
PUSHJ P,SETIOD## ;SAY THAT IO IS DONE SO UUOCON WILL RUN.
|
||
POP P,DEVIOS(F) ;IF IT'S A TSK, LET IT GO BACK TO OUTPUT.
|
||
POPJ P, ;AND THAT'S ALL
|
||
|
||
|
||
;NTDOAV ;HERE TO TELL A JOB IT HAS DATA REQUESTS
|
||
;CALL PUSHJ P,NTDOAV
|
||
;RETURN CPOPJ
|
||
;
|
||
;THIS ROUTINE FIGURES OUT HOW THE JOB IS WAITING (EW, OR NON-BLOCKING)
|
||
; AND USES THE APPROPRIATE METHOD TO WAKE THE JOB.
|
||
;
|
||
NTDOAV:: ;HERE WHEN DATA REQUESTS ARE AVAILABLE
|
||
TLNE S,IOSREL ;HAS THIS DEVICE BEEN "RELEASED"?
|
||
POPJ P, ; IF SO, THEN DON'T WAKE ANYONE.
|
||
MOVE T1,DEVAIO(F) ;NOW SEE IF THIS DEVICE IS
|
||
TRNN T1,DEPAIO ; OF THE NON-BLOCKING KIND.
|
||
PJRST NETWAK ;IF NOT, THEN GET JOB OUT OF EVENT WAIT.
|
||
PUSH P,DEVIOS(F) ;IF NON-BLOCKING, WE MUST GIVE THE JOB AN
|
||
MOVSI S,IO ; OUTPUT DONE INTERRUPT. SO FIRST WE
|
||
IORB S,DEVIOS(F) ; SAY WE ARE DOING OUTPUT (PSIIOD LOOKS)
|
||
TLZ S,IOSTBL ;CLEAR TROUBLE SO PSIIOD WILL BE CALLED
|
||
PUSHJ P,SETIOD## ;SAY THAT THE OUTPUT IS DONE
|
||
POP P,DEVIOS(F) ;LET THE JOB CONTINUE INPUT IF IT WANTS
|
||
POPJ P, ; AND THAT'S ALL.
|
||
;NTDCNC ROUTINE TO PROCESS THE CONNECT CONFIRM MESSAGE FOR "NORMAL" (LPT, CDR
|
||
; PLT ...) DEVICES.
|
||
;CALL MOVEI F,DDB
|
||
; MOVE P1,"POINTER TO SLA"
|
||
; MOVE P4,"NUMBER OF BYTES LEFT IN MSG"
|
||
; PUSHJ P,NTDCNC
|
||
;RETURN CPOPJ ;IF WE WEREN'T WAITING FOR A CONNECT CONFIRM
|
||
; CPOPJ1 ;AFTER WAKING THE JOB
|
||
|
||
NTDCNC::LDB T1,NETSLA ;GET LOCAL LAT ADDRESS
|
||
LDB T2,LATSTA ;GET THE CURRENT STATE
|
||
CAIE T2,LAT.CC ;WAS IT CONNECT CONFIRM WAIT?
|
||
POPJ P, ;IF NOT, GIVE THE "BAD MESSAGE" RETURN
|
||
|
||
;SLA
|
||
|
||
PUSHJ P,EBI2BI ;FIND OUT WHAT LAT THE REMOTE GAVE US.
|
||
DPB T1,NETDLA ;SAVE THE REMOTE LAT NUMBER.
|
||
|
||
;DPN(OBJ)
|
||
|
||
PUSHJ P,EBI2BI ;WE DON'T REALLY CARE ABOUT THIS FOR NORMAL DEVS
|
||
|
||
;DPN(PID)
|
||
|
||
PUSHJ P,EBI2BI ;WE SENT HIM THIS UNIT NUMBER
|
||
|
||
;SPN(OBJ)
|
||
|
||
PUSHJ P,EBI2BI ;THE PARANOID MIGHT VERIFY THAT THIS IS OUR TYPE
|
||
|
||
;SPN(PID)
|
||
|
||
PUSHJ P,EBI2BI ;READ THE UNIT NUMBER WE GOT.
|
||
ANDI T1,17 ; WE ONLY ALLOW 16. UNITS
|
||
DPB T1,PUNIT## ;STORE THE REMOTE UNIT NUMBER
|
||
CAIG T1,9 ;OUT OF SIMPLE DIGIT RANGE?
|
||
TROA T1,'0' ;NO, EASY TO MAKE SIXBIT
|
||
ADDI T1,'A'-'9'-1 ;YES, MAKE SIXBIT THE HARD WAY
|
||
DPB T1,[POINT 6,DEVNAM(F),35] ;UPDATE THE DEVICE NAME TO REFLECT THE
|
||
; NEW UNIT NUMBER
|
||
;MML AND FEA
|
||
|
||
PUSHJ P,NTDCNF ;PROCESS REST OF CONNECT CONFIRM (MML & FEA)
|
||
POPJ P, ;DUH?
|
||
LDB T1,NETSLA ;GET THIS MESSAGES "DLA" BACK
|
||
MOVEI T2,LAT.OK ;NOW THAT WE'RE CONNECTED, CHANGE OUR
|
||
DPB T2,LATSTA ; TO BE "OK".
|
||
MOVSI S,IOSCON ;ALSO REMEMBER TO SET IOSCON TO
|
||
IORB S,DEVIOS(F) ; TELL THE REST OF THE WORLD
|
||
AOS (P) ;SIGNAL GOOD RETURN
|
||
TLNN S,IOSZAP ;IS THIS DDB STILL IN USE?
|
||
PJRST NETWAK ;YES, WAKE THE WAITING JOB.
|
||
EMRGCY ;USE "EMERGENCY" MEMORY IF NECESSARY
|
||
PUSHJ P,NTDXDS ;NO, SEND A DISCONNECT AND CHANGE STATE
|
||
STOPCD .,STOP,ANFXDS, ;++ SHOULDN'T FAIL. NETSCN DIDN'T CALL PBCHECK?
|
||
POPJ P, ;DDB WILL WAIT FOR DISCONNECT CONFIRM
|
||
;NTDCNF ROUTINE TO PROCESS THE CONNECT CONFIRM'S MML AND FEA FIELDS
|
||
;CALL MOVEI F,DDB
|
||
; MOVE P1,"POINTER TO SLA"
|
||
; MOVE P4,"NUMBER OF BYTES LEFT IN MSG"
|
||
; PUSHJ P,NTDCNF
|
||
;RETURN CPOPJ ;IF ERROR (SHOULDN'T HAPPEN)
|
||
; CPOPJ1 ;MML AND FEA(DCM,RLN,...) READ, DCM IN T1
|
||
|
||
NTDCNF::PUSHJ P,EBI2BI ;START OFF WITH MAX MESSAGE LENGTH
|
||
DPB T1,NETMML ;SAVE IT FOR ANYONE WHO CARES
|
||
;FEA(DCM)
|
||
PUSHJ P,EBI2BI ;EXTRACT THE DATA MODES
|
||
PUSH P,T1 ;SAVE THE DCM FOR CALLER TO PONDER
|
||
;RLN
|
||
PUSHJ P,EBI2BI ;READ AND STORE THE RECORD LENGTH. (ALTHOUGH I
|
||
DPB T1,NETRLN ; DON'T THINK ANYONE USES IT...)
|
||
;DVT
|
||
PUSHJ P,EBI2BI ;GET THE DEVICE ATTRIBUTES AND STORE THEM.
|
||
DPB T1,NETDVT ; (THESE ARE USED...)
|
||
;DVU
|
||
PUSHJ P,EBI2BI ;GET THE DEVICE "UNIT" TYPE
|
||
DPB T1,NETDVU ;STASH IN THE DDB
|
||
;DVV
|
||
PUSHJ P,EBI2BI ;GET THE DEVICE "CONTROLLER" TYPE
|
||
DPB T1,NETDVV ;STASH IN THE DDB TOO
|
||
;DFT
|
||
PUSHJ P,EAS2SX ;GET THE "FORMS TYPE"
|
||
MOVEM T1,DEVDFT(F) ;SAVE IT AWAY
|
||
|
||
POP P,T1 ;RESTORE DCM (IF ANYONE CARES)
|
||
JRST CPOPJ1## ;RETURN
|
||
;NTDDSC ROUTINE TO DO THE "DEFAULT" PROCESSING OF DISCONNECT MESSAGES.
|
||
;CALL MOVEI F,DDB
|
||
; MOVEI P4,LENGTH OF DISCONNECT MESSAGE
|
||
; MOVEI P1,POINTER TO THE "SLA" FIELD OF THE DISCONNECT
|
||
; PUSHJ P,NTDDSC
|
||
;RETURN CPOPJ ;SOMETHING WAS WRONG WITH THE MESSAGE
|
||
; CPOPJ1 ;SUCCESSFUL RETURN.
|
||
|
||
NTDDSC::NTDBUG ;JUST CHECKING ...
|
||
|
||
;SLA
|
||
|
||
PUSHJ P,EBI2BI ;GET THE SLA (AND IGNORE)
|
||
|
||
;RSN
|
||
|
||
PUSHJ P,EBI2BI ;GET THE REASON
|
||
DPB T1,NETRSN ; AND STORE IT IN THE DDB.
|
||
LDB T2,NETSLA ;GET POINTER INTO OUR LAT
|
||
LDB T2,LATST2 ;GET CONNECTION'S CURRENT STATE
|
||
CAIL T2,LAT.CC ; AND MAKE SURE THAT IT'S
|
||
CAILE T2,LAT.DC ; REASONABLE (CC, OK, OR DC)
|
||
POPJ P, ;IF IT'S NOT, THEN GIVE "BAD MSG" RETURN
|
||
AOS (P) ;WE LIKE THE MSG. ACCEPT IT.
|
||
CAIN T2,LAT.OK ;IF DISCONNECT INITIATE
|
||
JRST NTDDS1 ;SEND THE DISCONNECT CONFIRM
|
||
MOVEI T1,IR.DOL ;DEVICE OFFLINE PSI FLAG
|
||
JRST NTDNW2 ;CONTINUE WITH COMMON CODE
|
||
|
||
|
||
; HERE SEND DISCONNECT CONFIRM
|
||
|
||
NTDDS1: MOVEI T1,RSN.OK ;NORMAL RETURN "REASON"
|
||
EMRGCY ;USE "EMERGENCY" FREE CORE IF NECESSARY
|
||
PUSHJ P,NCSDSC ;SEND THE DISCONNECT
|
||
STOPCD .,STOP,ANFDS1, ;++ SHOULDN'T FAIL. NETSCN DIDN'T CALL PCBECK?
|
||
MOVEI T1,IR.IER!IR.OER!IR.DOL ;PSI FLAGS FOR UNEXPECTED DISCONNECT
|
||
MOVEI T2,IONDD% ;REMOTE NETWORK DEVICE DISCONNECTED
|
||
JRST NTDNW1 ;USE COMMON CODE TO WAKE THE OWNING JOB
|
||
;NTDCNT ROUTINE TO PERFORM THE CONNECT FOR "NORMAL" DEVICES.
|
||
;CALL MOVEI F,DDB ;WITH NO LAT ASSIGNED
|
||
; PUSHJ P,NTDCNT ;ASSIGN LAT AND DO CONNECT
|
||
;RETURN CPOPJ ;CONNECT FAILED. LAT FREED. ERROR CODE IN T1.
|
||
; CPOPJ1 ;DEVICE CONNECTED.
|
||
;
|
||
NTDCNT:: ;HERE TO CONNECT "NORMAL" DEVICE.
|
||
|
||
LDB T1,NETSLA ;FIRST A BIT OF PARANOIA.
|
||
SKIPE T1 ;MAKE SURE THAT WE HAVEN'T ASSIGNED THE LAT
|
||
STOPCD .,STOP,ANFLAA, ;++ LAT ALREADY ASSIGNED.
|
||
|
||
MOVEI T1,(F) ;COPY THE DDB POINTER FOR GETSLA
|
||
MOVEI T2,LAT.CC ;WE WILL BE IN CONNECT CONFIRM WAIT
|
||
PUSHJ P,GETSLA ;ALLOCATE A LINK ADDRESS
|
||
POPJ P, ;ERROR RETURN IF THE LAT IS FULL
|
||
DPB T1,NETSLA ;STORE THE LINK ADDRESS IN THE DDB
|
||
MOVE T1,[XWD NTDXSN,NTDXPN] ;ADDRESS OF CODE TO WRITE "SPN" & "DPN"
|
||
PUSHJ P,NCSCNT ;SEND THE CONNECT
|
||
PJRST GIVSLA ;CONNECT FAILED. RETURN LAT. ERROR CODE IN T1.
|
||
NTDCN1: PUSHJ P,NETHIC ;WAIT FOR CONNECT (NTDCNC WILL WAKE US)
|
||
LDB T1,NETSLA ;GET THE SLA BACK.
|
||
JUMPE T1,[MOVEI T1,NRTDNA-NODERT ; CONNECT REJECT IF SLA CLEARED.
|
||
POPJ P,] ; GIVE ERROR RETURN WITH ERROR CODE IN T1
|
||
LDB T1,LATSTA ;GET THE CURRENT "STATE"
|
||
CAIN T1,LAT.OK ;IF IT'S "OK" THEN THE CONNECT SUCCEDED
|
||
JRST CPOPJ1## ; SO GIVE A GOOD RETURN
|
||
|
||
IFN PARANOID&P$LAT,<
|
||
|
||
CAIE T1,LAT.CC ;ARE WE STILL IN CONFIRM WAIT
|
||
STOPCD .,STOP,ANFLCC, ;++ NOT IN CONFIRM WAIT. LAT TABLE SCREWED.
|
||
>
|
||
JRST NTDCN1 ;WE HAD A SPURIOUS WAKE...
|
||
;NTDXPN ROUTINE TO SEND THE "DPN" FIELD OF A NORMAL DEVICE CONNECT. (LPT ETC.)
|
||
;CALLED FROM NCSCNT WHERE IT CALLS THE DEVICE DEPENDANT ROUTINE TO WRITE
|
||
; THE "DPN"
|
||
;RETURN CPOPJ ;ALWAYS
|
||
;
|
||
NTDXPN:: ;HERE TO WRITE A NORMAL "DPN" CONNECT FIELD
|
||
PUSH P,W ;SAVE THE NDB POINTER FOR A BIT
|
||
;DPN(OBJ)
|
||
HLRZ W,DEVNET(F) ;GET THE POINTER TO THE NDT
|
||
LDB T1,NDTOBJ ;GET THE OBJECT TYPE OF THIS DEVICE
|
||
PUSHJ P,BI2EBI ;WRITE THE OBJECT TYPE
|
||
POP P,W ;RESTORE THE NDB POINTER
|
||
;DPN(PID)
|
||
LDB T1,PUNIT## ;GET THE UNIT NUMBER FOR THE PID
|
||
PJRST BI2EBI ;WRITE THE UNIT NUMBER
|
||
|
||
|
||
;NTDXMN ROUTINE TO SEND THE "SPN" FIELD OF A NORMAL DEVICE CONNECT CONFIRM
|
||
;OPERATION (WHERE THERE IS NOT NECESSARILY A RELATED JOB TO USE . . .
|
||
;CALLED FROM NCSCNC WHERE IT CALLS THE DEVICE DEPENDANT ROUTINE TO WRITE
|
||
; THE "SPN"
|
||
;RETURN CPOPJ ;ALWAYS
|
||
|
||
NTDXMN::
|
||
;SPN(OBJ)
|
||
MOVEI T1,OBJ.TK ;OBJECT IS A JOB
|
||
PUSHJ P,BI2EBI ;WELL, THE MONITOR IS SORTA LIKE A JOB, KINDA
|
||
;SPN(PID)
|
||
LDB T1,PJOBN## ;GET DEVICE'S ASSOCIATED JOB, IF ANY
|
||
JUMPE T1,NTDXS3 ;AND USE IT, IF IT HAS A JOB
|
||
MOVEI P1,[ASCIZ\The Big Blue Monitor[1,1]\] ;NO JOB
|
||
PJRST AS2EAS ;SO FAKE UP A PID
|
||
|
||
|
||
;NTDXSN ROUTINE TO SEND THE "SPN" FIELD OF A NORMAL DEVICE CONNECT. (LPT ETC.)
|
||
;CALLED FROM NCSCNT WHERE IT CALLS THE DEVICE DEPENDANT ROUTINE TO WRITE
|
||
; THE "SPN"
|
||
;RETURN CPOPJ ;ALWAYS
|
||
|
||
NTDXSN::
|
||
;SPN(OBJ)
|
||
MOVEI T1,OBJ.TK ;OBJECT IS A JOB
|
||
PUSHJ P,BI2EBI ;OUTPUT
|
||
;SPN(PID)
|
||
MOVE T1,.CPJOB## ;GET OUR JOB NUMBER
|
||
NTDXS3: PUSH P,JBTPPN##(T1) ;SAVE THE JOB'S PPN
|
||
MOVE T1,JBTNAM##(T1) ;GET THE PROCESS NAME
|
||
PUSHJ P,SX2EAS ;OUTPUT
|
||
LDB T1,P2 ;GET THE LAST CHARACTER BACK
|
||
TRO T1,200 ;SET THE CONTINUE BIT
|
||
DPB T1,P2 ;STORE AGAIN
|
||
POP P,T1 ;GET THE PPN
|
||
PJRST PP2EAS ;OUTPUT AS [P,P]
|
||
;NTDXDS ROUTINE TO SEND A DISCONNECT AND SET THE LINK STATUS (LT%STA) TO "DC"
|
||
;CALL MOVEI T1,REASON FOR DISCONNECT
|
||
; MOVEI F,DDB OF DEVICE TO SEND DISCONNECT TO
|
||
; PUSHJ P,NTDXDS
|
||
;RETURN CPOPJ ;NO CORE.
|
||
; CPOPJ1 ;DISCONNECT SENT. LINK STATE SET TO LAT.DC
|
||
; ; (DISCONNECT CONFIRM WAIT)
|
||
;
|
||
NTDXDS:: ;HERE TO SEND A DISCONNECT AND SET LAT STATE
|
||
PUSHJ P,NCSDSC ;ATTEMPT TO SEND THE DISCONNECT
|
||
POPJ P, ; IF NO CORE, GIVE ERROR RETURN
|
||
LDB T2,NETSLA ;GET A POINTER TO THE LAT ENTRY
|
||
MOVEI T3,LAT.DC ;GET THE NEW STATE (DISCONNECT CONFIRM WAIT)
|
||
DPB T3,LATST2 ;UPDATE THE STATE
|
||
RETSKP ;GIVE GOOD RETURN
|
||
;NTDNWD ROUTINE TO PROCESS THE "NODE WENT DOWN" NDP DISPATCH ENTRY FOR
|
||
; "NORMAL" DEVICES.
|
||
;CALL MOVEI P1,NUMBER OF THE NODE THAT CRASHED.
|
||
; MOVE F,LAT-ENTRY THAT POINTS TO THIS DEVICE
|
||
; PUSHJ P,NTDNWD ;CALLED FROM CLNNDB
|
||
;RETURN CPOPJ ;ALWAYS.
|
||
|
||
NTDNWD::MOVEI T1,RSN.XN ;GET A UNDEFINED NODE NUMBER ERROR CODE
|
||
DPB T1,NETRSN ;AND PRETEND THAT A DISCONNECT PUT IT THERE
|
||
HRROS DEVNAM(F) ;ZAP THE NAME SO DDBSRC WON'T MATCH IT.
|
||
MOVEI T1,IOERR!IODEND ;ALL ERROR BITS
|
||
IORM T1,DEVIOS(F) ;LIGHT THEM FOR DOWN DEVICE
|
||
MOVEI T1,IR.IER!IR.OER!IR.DOL ;NODE DOWN PSI FLAGS
|
||
MOVEI T2,IONND% ;NODE DOWN (OR PATH LOST) ERROR CODE
|
||
|
||
;ENTER HERE TO DISCONNECT THE DDB,
|
||
; T1 CONTAINING THE PSI REASON FLAGS, T2 CONTAINING EXTENDED ERROR CODE
|
||
|
||
NTDNW1: DPB T2,PDVESE## ;SET EXTENDED (DEVOP.) ERROR STATUS CODE
|
||
NTDNW2: LDB T2,PJOBN## ;GET OWNING JOB (IF ANY)
|
||
JUMPE T2,NTDNW7 ;NO PSI/NETWAK IF NO JOB
|
||
MOVE T2,DEVMOD(F) ;GET DEVICE ACTIVITY FLAGS
|
||
TRNN T2,ASSCON!ASSPRG;DEVICE DEFINITELY IN USE BY A JOB?
|
||
JRST NTDNW4 ;UNCLEAR, MAKE SURE NOT STUCK IN "EW"
|
||
PUSHJ P,PSIDVB## ;YES, GIVE THE DEVICE OFFLINE/ETC. INTERRUPT
|
||
MOVE S,DEVIOS(F) ;DEVICE STATUS FLAGS
|
||
TLZ S,IOSTBL ;CLEAR TROUBLE SO SETIOD CALLS WAKJOB
|
||
PUSHJ P,SETIOD## ;WAKE UP JOB IF HIBERING ON ASYNC I/O
|
||
NTDNW4: PUSHJ P,NETWAK ;WAKE UP JOB IF IN ANF "EW" STATE
|
||
; NOTE THAT WE MUST CALL NETWAK EVEN IF
|
||
; ASSCON!ASSPRG IS OFF, SINCE A DEVICE IN
|
||
; CONNECT-CONFIRM WAIT HASN'T SET THESE BITS
|
||
; YET (DONE BY UUOCON, NOT NETSER)
|
||
NTDNW7: PUSHJ P,GIVSLA ;RETURN THE NOW USLESS LAT ENTRY
|
||
PUSHJ P,GV2NPD ;NPD'S ARE USELESS NOW.
|
||
SETZM DEVDRQ(F) ;CLEAR STALE TSK DATA REQUESTS
|
||
MOVSI S,IOSCON ;GET AND CLEAR THE
|
||
ANDCAB S,DEVIOS(F) ; "DEVICE IS CONNECTED BIT"
|
||
MOVSI S,IOSERR ;GET THE "NETWORK DEVICE ERROR" BIT
|
||
IORB S,DEVIOS(F) ;AND SET IT TO STOP IO (NTDONL FAILS...)
|
||
TLNE S,IOSZAP ;IF THIS DDB IS MARKED FOR DELETION
|
||
PUSHJ P,UNLDDB ;THEN ZAP THE DDB HERE AND NOW
|
||
POPJ P, ;ELSE WAIT FOR UUO LEVEL (ZAPNET)
|
||
;SUBROUTINE NTDHDR - WRITE A NCS/DEVICE CONTROL HEADER
|
||
;CALL MOVEI F,DDB
|
||
; MOVEI W,NDB
|
||
; MOVEI T1,SIZE OF PCB TO REQUEST (INCLUDING HEADER WORDS)
|
||
; PUSHJ P,NTDHDR
|
||
;RETURN CPOPJ ;NO CORE
|
||
; CPOPJ1 ;HEADER BUILT
|
||
|
||
|
||
|
||
NTDHDR::TDZA T2,T2 ;CLEAR NCS NEADER BYTE
|
||
NTDHDI::MOVEI T2,NCT.IT ;INTERRUPT MESSAGE
|
||
PUSH P,P1 ;SAVE P1 FOR A BIT
|
||
MOVEI P1,(T2) ;PUT THE NCT IN P1
|
||
PUSHJ P,MKNPCB ;MAKE A NUMBERED PCB
|
||
JRST [POP P,P1 ;IF NO CORE, THEN RESTORE P1, AND
|
||
POPJ P,] ; GIVE AN ERROR RETURN
|
||
MOVE P2,PCBPTR(U) ;GET THE BYTE POINTER
|
||
MOVE T1,P1 ;GET THE NCT
|
||
PUSHJ P,NCSWHD ;FILL IN NCT, DNA, SNA, NCA & NCN
|
||
LDB T1,NETDLA ;GET THE DESTINATION LINK ADDRESS
|
||
IFN PARANOID&P$LAT,<
|
||
SKIPN T1 ;JUST A BIT OF PARANOIA AGAIN
|
||
STOPCD .,STOP,ANFMDL, ;++ MUST HAVE A DLA ASSIGNED
|
||
>
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
POP P,P1 ;RESTORE P1 (AREN'T WE NICE...)
|
||
ADDM P3,PCBCTR(U) ;ACCOUNT FOR THE BYTES IN THE HEADER
|
||
SETZ P3, ;SIGNAL NO BYTES IN THE MESSAGE
|
||
JRST CPOPJ1## ;EXIT WITH HEADER WRITTEN
|
||
;SUBROUTINE NTDSST/NTDCST SET AND CLEAR STATUS BITS
|
||
;CALL MOVEI T1,BITS ;TO BE CLEARED OR SET
|
||
; PUSHJ P,NTDSST/NTDCST
|
||
; CPOPJ ;NO CORE
|
||
; CPOPJ1 ;MESSAGE SENT
|
||
|
||
NTDXST::SETZ T2, ;SEND WITH A ZERO STC
|
||
JRST NTDST1 ;ON TO MAIN LINE CODE
|
||
NTDSST::SKIPA T2,[1] ;SET STATUS
|
||
NTDCST::MOVEI T2,2 ;CLEAR STATUS
|
||
NTDST1: PUSHJ P,SAVE3## ;SAVE THE P'S
|
||
PUSH P,T1 ;SAVE STD
|
||
PUSH P,T2 ;SAVE STC
|
||
MOVEI T1,^D16 ;GET THE LENGTH OF A STANDARD SHORT PCB
|
||
PUSHJ P,NTDHDI ;WRITE INTERRUPT HEADER
|
||
JRST [POP P,T2 ;RESTORE THE MESSAGE TYPE
|
||
PJRST TPOPJ##] ;AND EXIT
|
||
;CNT
|
||
IBP P2 ;STEP OVER THE COUNT FIELD
|
||
MOVE P1,P2 ;SAVE THE COUNT POSITION
|
||
MOVEI T1,DC.STS ;GET STATUS MESSAGE CODE
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;STC
|
||
POP P,T1 ;GET THE STC
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;STD
|
||
POP P,T1 ;GET THE STD
|
||
PUSHJ P,BI2EBI ;WRITE
|
||
;CNT
|
||
DPB P3,P1 ;STORE THE COUNT FIELD
|
||
ADDI P3,1 ;UPDATE THE COUNT FIELD
|
||
ADDM P3,PCBCTR(U) ;UPDATE THE MESSAGE LENGTH
|
||
PJRST NETWSR ;WRITE THE MESSAGE
|
||
|
||
|
||
|
||
;SUBROUTINE NTDWRT - WRITE A DATA MESSAGE
|
||
;CALL MOVEI F,DDB
|
||
; MOVEI U,PCB
|
||
; MOVEI T1,CONVERSION CODE
|
||
; PUSHJ P,NTDWRT ;SEND THE PCB
|
||
;RETURN CPOPJ ;WRITTEN
|
||
;
|
||
NTDWRT::DPB T1,PCBPCV ;STORE TYPE
|
||
; MOVSI T1,PCB.UR ;GET THE USER DATA FLAG
|
||
; IORM T1,PCBBLK(U) ;STORE
|
||
PJRST NETWRT ;SEND THE MESSAGE
|
||
SUBTTL LOCKS -- NETSER INTERLOCK MANAGEMENT ROUTINES.
|
||
|
||
COMMENT @
|
||
|
||
The following routines are used to manage the NETSER interlock.
|
||
These routines are called ONLY by macros defined in "S".
|
||
|
||
NTLCLK Lock the NETSER database from UUO-level. The job loops
|
||
waiting for the interlock. (Can only happen on an SMP system
|
||
when the other CPU has the interlock.
|
||
NTUNLK Undo's the effects of a call to NTLCLK.
|
||
NTLCKJ If the job currently owns the interlock this routine does
|
||
nothing, Otherwise it gets the interlock and co-routines back
|
||
to the calling routine (ala SAVE4) and frees the interlock
|
||
when the routine POPJ's.
|
||
NTLCKI This routine locks the NETSER database from interrupt level.
|
||
NTULKI This routine undoes the effects of NTLCKI.
|
||
NTCHCK This routine skips if the calling process owns the interlock.
|
||
NTSAV This routine returns the interlock until the calling routine
|
||
POPJ's at which point it gets it back again. (Like RTNEVM)
|
||
NTLERR This routine gives up the interlock only if the process owns
|
||
it, and never generates an error. (Used by ERRCON and friends
|
||
to return the interlock when the owning process gets an error)
|
||
|
||
Variables of interest are.
|
||
|
||
NTLOCK This is the interlock word. -1 implies interlock if free.
|
||
NTUSER This is the "Process I-D" of the process that owns the
|
||
interlock. Legal values are.
|
||
XWD 0,N N is the job number of the owning job
|
||
XWD -1,n N is the number of the cpu that has the
|
||
interlock at interrupt level
|
||
XWD N,-1 N is the number of the cpu that has the
|
||
interlock at clock (scheduler-comcon) level.
|
||
%NTCNT This is a vector of counters that keep track of various facets
|
||
of the interlock management scheme. Elements of the vector are
|
||
+ 0 Number of attempts to get interlock at interrupt level
|
||
+ 1 Number of times interrupt level succeded in getting lock
|
||
+ 2 Number of times interlock gotten at UUO level
|
||
+ 3 Number of times UUO level has failed. (Tries again
|
||
immediatly. Will hang the machine if gets screwed up)
|
||
+ 4 Number of attempts at command level that failed.
|
||
+ 5 Number of times the interlock given up by error routines
|
||
|
||
|
||
@
|
||
NTLCKI::NTDBUG EITHER,INT ;MAY HAVE IT AT ANOTHER LEVEL
|
||
AOS %NTCNT+0 ;COUNT THE NUMBER OF ATTEMPTS
|
||
AOSE NTLOCK## ;TRY TO GET THE INTERLOCK
|
||
POPJ P, ;RETURN NOW IF FAILED
|
||
IFN FTMP,< ;SET THE "OWNING CPU" WORD
|
||
APRID INONT##
|
||
>
|
||
AOS %NTCNT+1 ;COUNT THE SUCCESSFUL ATTEMPTS
|
||
PUSH P,T1 ;SAVE T1 OVER THE CALL TO NTLPID
|
||
PUSHJ P,NTLPID ;GET A "UNIQUE" IDENTIFIER
|
||
MOVEM T1,NTUSER ;SAVE IT IN CASE WE TRY TO RECURSE
|
||
JRST TPOPJ1## ;AND GIVE A SUCCESSFUL RETURN
|
||
|
||
NTULKI::NTDBUG YES,INT ;BETTER HAVE THE INTERLOCK AT INT LEVEL...
|
||
PJRST NTLFRE ;FREE INTERLOCK AND RETURN
|
||
NTLCLK::NTDBUG NO,UUO ;DON'T HAVE INTERLOCK YET, AND AT UUO LEVEL
|
||
AOSA %NTCNT+2 ;COUNT THE NUMBER OF TIMES GOTTEN AT UUO LEVEL
|
||
AOS %NTCNT+3 ;COUNT THE FAILURE
|
||
SKIPGE NTLOCK## ;GIVE OTHER CPUS A CHANCE
|
||
AOSE NTLOCK## ;TRY TO GET THE INTERLOCK
|
||
JRST .-3 ;WAIT
|
||
IFN FTMP,<
|
||
APRID INONT##
|
||
>
|
||
PUSH P,T1 ;NOW THAT WE'VE GOT THE INTERLOCK, SAVE T1
|
||
PUSHJ P,NTLPID ;GET OUR "PROCESS ID"
|
||
MOVEM T1,NTUSER ;SAVE IT IN CASE WE RECURSE
|
||
JRST TPOPJ## ;RESTORE T1 AND RETURN
|
||
NTUNLK::NTDBUG YES,UUO ;WE BETTER HAVE THE LOCK AT UUO-LEVEL
|
||
PUSHJ P,NTLFRE ;FREE THE INTERLOCK
|
||
SKIPN NTRQST ;DOES NETSCN WANT TO RUN?
|
||
POPJ P, ;IF NOT, RETURN NOW
|
||
PJRST NETQUE ;GO CAUSE AN INTERRUPT FOR NETSER
|
||
|
||
|
||
NTLCKJ::PUSHJ P,NTCHCK ;SEE IF WE OWN THE INTERLOCK
|
||
JRST .+2 ;IF NOT, WE MUST GET IT
|
||
POPJ P, ;IF WE OWN IT, THEN WE CAN RETURN NOW
|
||
SKIPE .CPISF## ;ARE WE AT "COMCON" LEVEL (COMMAND PROCESSING)
|
||
JRST NTLCKC ;IF SO, WE MUST HANDLE THE INTERLOCK SPECIAL
|
||
PUSHJ P,NTLCLK ;GET THE INTERLOCK
|
||
POP P,(P) ;AND GO THROUGH THESE CONTORTIONS TO
|
||
PUSHJ P,@1(P) ; CO-ROUTINE BACK TO OUR CALLER
|
||
JRST .+2 ;RESPECT
|
||
AOS (P) ; SKIP RETURNS
|
||
PJRST NTUNLK ; AND FREE THE INTERLOCK ON CALLERS RETURN
|
||
|
||
NTLCKC: PUSHJ P,NTLCKI ;TRY TO GET THE INTERLOCK (ALA INTERRUPT LEVEL)
|
||
JRST [AOS %NTCNT+4 ;COUNT THE FAILURE
|
||
JRST DLYCM1##] ; AND DELAY THE COMMAND (TRYS AGAIN SOON...)
|
||
POP P,(P) ;CO-ROUTINE BACK
|
||
PUSHJ P,@1(P) ; TO OUR CALLER
|
||
JRST .+2 ;RESPECT
|
||
AOS (P) ; SKIP RETURNS
|
||
PJRST NTULKI ;RETURN THE INTERLOCK
|
||
|
||
NTSAV:: PUSHJ P,NTCHCK ;SEE IF WE OWN THE INTERLOCK
|
||
POPJ P, ;IF WE DON'T, WE CAN'T RETURN IT
|
||
PUSHJ P,NTUNLK ;RETURN THE INTERLOCK
|
||
POP P,(P) ;CO-ROUTINE BACK
|
||
PUSHJ P,@1(P) ; TO OUR CALLER
|
||
JRST .+2 ;RESPECT
|
||
AOS (P) ; SKIP RETURNS
|
||
PJRST NTLCLK ;AND GET THE INTERLOCK BACK AGAIN
|
||
NTCHCK::AOSN NTLOCK## ;SEE IF ANYONE HAS THE INTERLOCK
|
||
JRST [SETOM NTLOCK ; IF NOT, THEN WE CERTAINLY DON'T.
|
||
POPJ P,] ; SO GIVE THE ERROR RETURN
|
||
PUSH P,T1 ;WE NEED "T1" AS A TEMP
|
||
PUSHJ P,NTLPID ;GET OUR "PROCESS ID"
|
||
CAMN T1,NTUSER ;SEE IF IT'S US THAT HAS THE INTERLOCK
|
||
AOS -1(P) ;IF SO, SKIP RETURN
|
||
PJRST TPOPJ## ;RESTORE T1 AND (SKIP) RETURN
|
||
|
||
NTLPID::PUSHJ P,INTLVL## ;IF WE ARE AT UUO LEVEL,
|
||
JRST [MOVE T1,.CPJOB## ;THEN OUR PID IS OUR JOB NUMBER
|
||
POPJ P,] ; SO RETURN THAT TO OUR CALLER
|
||
HRRO T1,.CPCPN## ;ASSUME THAT WE ARE AT INTERRUPT LEVEL
|
||
SKIPE .CPISF## ;CHECK TO SEE IF WE ARE AT SCHEDULER LEVEL,
|
||
MOVS T1,T1 ; AND IF WE ARE, SWAP HALFWORDS
|
||
POPJ P, ;RETURN "PID" TO CALLER
|
||
|
||
NTLERR::PUSHJ P,NTCHCK ;DO WE OWN THE INTERLOCK
|
||
POPJ P, ;IF NOT, THEN RETURN NOW
|
||
AOS %NTCNT+5 ;COUNT NUMBER OF ERRORS WITH LOCK
|
||
NTLFRE: SETZM NTUSER ;CLEAR THE USER.
|
||
IFN FTMP,<
|
||
SETOM INONT## ;CLEAR THE "OWNING CPU" WORD
|
||
>
|
||
SETOM NTLOCK## ;FREE THE LOCK
|
||
POPJ P, ; AND RETURN
|
||
SUBTTL NETWORK SUBROUTINES
|
||
|
||
;HERE ARE THE TWO ENTRIES TO TURN ON NETWORK INTERRUPTS
|
||
|
||
NTONP1::AOS (P) ;GIVE SKIP RETURN
|
||
NTONPJ::NETON ;RE-ENABLE NETWORK INTERRUPTS
|
||
POPJ P, ;RETURN
|
||
|
||
|
||
|
||
;ROUTINES TO INTERFACE CERTIAN ERROR ROUTINES TO NETSER. THESE ARE ROUTINES
|
||
; THAT ARE NOT EXPECTED TO RETURN, AND HENCE MUST NOT BE CALLED WITH THE
|
||
; NETSER INTERLOCK.
|
||
|
||
DEFINE X(A,B),< ;;MACRO TO MAKE THE CORRISPONDENCE MORE OBVIOUS
|
||
A:: NTSAVE ;;FIRST "SAVE" THE INTERLOCK
|
||
PJRST B##> ;;THEN GO TO ROUTINE "B" THAT DOES THE WORK
|
||
|
||
X(NTDILI,ILLINP) ;ILLEGAL INPUT UUO
|
||
X(NTDILO,ILLOUT) ;ILLEGAL OUTPUT UUO
|
||
SUBTTL BYTE POINTERS FOR NETSER
|
||
|
||
|
||
;BYTE POINTERS INTO NETWORK DDB'S (INDEXED BY "F")
|
||
|
||
NETRSN::EXP NT%RSN ;REASON BYTE
|
||
NETSLA::EXP NT%SLA ;SOURCE LINK ADDRESS
|
||
NETDLA::EXP NT%DLA ;DESTINATION LINK ADDRESS
|
||
NETZWD::EXP NT%ZWD ;DDB LENGTH (A LA GETZWD/GIVZWD)
|
||
NETRLN::EXP NT%RLN ;LOGICAL RECORD LENGTH ("RLN" - SEE NETPRM)
|
||
NETMML::EXP NT%MML ;MAXIMUM MESSAGE LENGTH ("MML" - SEE NETPRM)
|
||
NETDVT::EXP NT%DVT ;DEVICE ATTRIBUTE BITS ("DVT" - SEE NETPRM)
|
||
NETDVU::EXP NT%DVU ;DEVICE "UNIT" TYPE ("DVU" - SEE NETPRM)
|
||
NETDVV::EXP NT%DVV ;DEVICE "CONTROLLER" TYPE ("DVV" - SEE NETPRM)
|
||
|
||
|
||
|
||
;BYTE POINTERS INTO PCB'S. INDEXED BY "U"
|
||
|
||
PCBPCV::EXP PC%PCV ;CONVERSION TYPE
|
||
PCBMSN::EXP PC%MSN ;MESSAGE NUMBER
|
||
|
||
|
||
|
||
;BYTE POINTERS INTO NDB'S (GETTAB TABLE .GTNDB==161)
|
||
|
||
$LOW
|
||
NDBTBL::EXP NDBLEN ;(00) LENGTH OF NDB
|
||
EXP NB%NXT ;(01) ADDRESS OF NEXT NDB
|
||
EXP NB%NNM ;(02) NODE NUMBER
|
||
EXP NB%SNM ;(03) ADDRESS OF STATION NAME
|
||
NDBTIM::EXP NB%TIM ;(04) TIMER.
|
||
EXP NB%NGH ;(05) FIRST NEIGHBOR ENTRY
|
||
EXP NB%NGL ;(06) LAST NEIGHBOR ENTRY
|
||
EXP NB%NGN ;(07) NODE NUMBER FROM NB%NGH
|
||
EXP NB%OPR ;(10) ADDRESS OF OPR LDB
|
||
EXP NB%CTJ ;(11) JOB NUMBER OF STATION CTL
|
||
; OUTPUT MESSAGE NUMBERS
|
||
NDBLAR::EXP NB%LAR ;(12) LAST ACK RECEIVED
|
||
NDBLAP::EXP NB%LAP ;(13) LAST OUTPUT MESSAGE# ACK'ED
|
||
NDBLMS::EXP NB%LMS ;(14) LAST MESSAGE SENT
|
||
NDBLMA::EXP NB%LMA ;(15) LAST MESSAGE NUMBER ASSIGNED
|
||
NDBLAS::EXP NB%LAS ;(16) LAST ACK SENT
|
||
; INPUT MESSAGE NUMBERS
|
||
NDBLMR::EXP NB%LMR ;(17) LAST INPUT MESSAGE RECEIVED
|
||
NDBLMP::EXP NB%LMP ;(20) LAST MESSAGE PROCESSED
|
||
EXP NB%SDT ;(21) SYSTEM BUILD DATE ADDRESS
|
||
EXP NB%SID ;(22) SYSTEM ID ADDRESS
|
||
EXP NB%MOM ;(23) MAXIMUM OUTSTANDING MESSAGE COUNT
|
||
EXP NB%DEV ;(24) FIRST DEVICE
|
||
EXP NB%NVR ;(25) NCL VERSION OF REMOTE
|
||
|
||
NDBMXL==:<.-NDBTBL-1>_^D9 ;LENGTH OF NDB POINTERS TABLE (GETTAB)
|
||
$HIGH
|
||
;POINTERS INTO A NETWORK DEVICE TABLE
|
||
|
||
NDTTYP::EXP ND%TYP ;-10 DEVTYP BYTE
|
||
NDTBFZ::EXP ND%BFZ ;-10 BUFFER SIZE
|
||
NDTSPL::EXP ND%SPL ;-10 SPOOL BITS
|
||
NDTDVT::EXP ND%DVT ;-11 DEVICE ATTRIBUTES
|
||
NDTOBJ::EXP ND%OBJ ;-11 DEVICE TYPE CODE
|
||
NDTDCM::EXP ND%DCM ;NETWORK DEVICE MODES
|
||
|
||
|
||
;POINTER TO THE "STATE" FIELD OF A LAT ENTRY (INDEXED BY T1)
|
||
|
||
LATSTA::LT%STA+NETLAT(T1) ;POINT TO THE "STATE" FIELD OF A LAT ENTRY
|
||
LATST2::LT%STA+NETLAT(T2) ;DITTO, INDEX BY T2
|
||
LATSP2::LT%STA+NETLAT(P2) ;DITTO, INDEX BY P2
|
||
LATPTR::LT%PTR+NETLAT(T1) ;POINT TO DDB/LDB ADDRESS
|
||
LATPT2::LT%PTR+NETLAT(T2) ;DITTO, INDEX BY T2
|
||
LATPP2::LT%PTR+NETLAT(P2) ;DITTO, INDEX BY P2
|
||
SUBTTL LOCAL STORAGE FOR NETSER
|
||
$LOW
|
||
|
||
DIALDB::BLOCK 1 ;ADDRESS OF LDB WAITING FOR A DIAL REQUEST
|
||
DIALJB::BLOCK 1 ;JOB NUMBER OWNING C(DIALDB)
|
||
DIALFL::BLOCK 1 ;ASSOCIATED DIAL REQUEST FLAGS
|
||
; 1B0 DIALOUT COMPLETE
|
||
; LRLADR DIALOUT IN PROGRESS (REQ ISSUED)
|
||
; LRLCHR REMOTE PROCESSING DIALOUT REQ
|
||
; LRLDSR DIALOUT SUCCEEDED (IF 1B0)
|
||
DIALNM::BLOCK 2 ;PHONE NUMBER FOR REMOTE DIALER
|
||
|
||
NTUSER::EXP 0 ;LAST (CURRENT) OWNER OF THE NETSER INTERLOCK
|
||
|
||
%NTCNT::BLOCK 10 ;A SET OF COUNTERS REGARDING THE USE OF THE
|
||
; NETSER INTERLOCK
|
||
|
||
NTFLGS: 0 ;FLAGS FROM LAST MESSAGE RECIEVED
|
||
NTFACK: 0 ;NONZERO IF WE RECEIVED A MESSAGE IN
|
||
; THE LAST JIFFY. THIS WILL CAUSE THE JIFFY
|
||
; CODE TO SEE IF ANY ACK'S NEED TO BE SENT
|
||
; TO ANY NODE. THIS IS AN EFFICIENCY HACK
|
||
; THAT ALLOWS US TO CUT-DOWN ON THE NUMBER OF
|
||
; TIMES WE MUST SCAN THE NDB-CHAIN DURING
|
||
; THE JIFFY CYCLE
|
||
NTQRCT: 0 ;NONZERO IF WE NEED TO RECOMPUTE TOPOLOGY
|
||
NTQJIF: 0 ;NONZERO IF NETSCN SHOULD DO JIFFY CHECK
|
||
NTQOUT: 0 ;LIST OF OUTPUT MESSAGES BACK FROM THE FEK'S
|
||
NTQINP: 0 ;LIST OF INPUT MESSAGES TO PROCESS
|
||
NTQNDB: 0 ;CHAIN OF NDB'S THAT NEED SERVICE
|
||
NTQSEC: 0 ;NON-ZERO IF NETSCN SHOULD DO ONCE/SEC
|
||
NTRQST::0 ;NON-ZERO TO REQUEST AN INTERRUPT WHEN THE
|
||
; INTERLOCK IS NEXT FREE'D (NETLKU CHECKS IT)
|
||
|
||
PCBECT: EXP 0 ;COUNT OF "EMERGENCY" PCB'S (GOTTEN BY
|
||
; CALLING "PCBEGT"
|
||
PCBELS: EXP 0 ;LIST OF EMERGENCY PCB'S
|
||
|
||
NTUEFC::EXP 0 ;NeTwork Use Emergency Free Core. THE
|
||
; NEXT CALL TO NCSHDR WILL USE "EMERGENCY"
|
||
; FREE CORE IF NECESSARY.
|
||
|
||
IFN PARANOID&P$EAT,< ;DEBUGGING CODE TO EAT A RANDOM NCL MESSAGE
|
||
%TROLL: EXP 77777777777 ;GOVERNS THE EATING OF MESSAGES.
|
||
;START BIG TO GIVE THINGS A CHANCE
|
||
>
|
||
|
||
IFN PARANOID&P$NTR,< ;CHECKING CODE TO SEE WHO GOT THE INTERLOCK
|
||
%NTUSR: 0 ;PC OF THE LAST OWNER OF THE "NT" INTERLOCK
|
||
>
|
||
|
||
IFN PARANOID&P$COR,< ;ASSEMBLE IF WE ARE LOSING FREE CORE
|
||
%NTMEM: 0 ;A POINTER TO ALL THE NETWORK CORE.
|
||
>
|
||
SUBTTL NETWORK STATISTICS
|
||
|
||
DEFINE SUBTBL(MAX,LOC)<<<MAX>B8+LOC-NETGTT>>
|
||
|
||
;ANF NETWORK STATISTICS
|
||
|
||
NETGTT::
|
||
|
||
%NTCOR: 0 ;# WORDS OF FREE SPACE NOW IN USE
|
||
%NTMAX: 0 ;MAXIMUM %NTCOR HAS GONE
|
||
%NTAVG: 0 ;EXPONENTIAL AVERAGE OF %NTCOR * 10^4
|
||
%NTBAD: 0 ;# BAD MESSAGES RECEIVED AND IGNORED
|
||
|
||
%NTRTP: SUBTBL(NCT.TP,NCLRTP)
|
||
%NTRMT: SUBTBL(NC.MAX,NCLRMT)
|
||
%NTRDL: SUBTBL(NETLNH-1,NCLRDL)
|
||
%NTXTP: SUBTBL(NCT.TP,NCLXTP)
|
||
%NTXMT: SUBTBL(NC.MAX,NCLXMT)
|
||
%NTXDL: SUBTBL(NETLNH-1,NCLXDL)
|
||
|
||
%NTBLC: 0 ;LH - PC OF DETECTION OF BAD MESSAGE
|
||
;RH - PCB ADDRESS OF BAD MESSAGE
|
||
|
||
%NTBYI::BLOCK 1 ;COUNT OF BYTES INPUT BY THE NETWORK
|
||
%NTBYO::BLOCK 1 ;COUNT OF BYTES OUTPUT BY THE NETWORK
|
||
|
||
%NTNIP::EXP ANFNIP## ;ANF NI/ETHERNET PROTOCOL (0 IF NOT SELECTED)
|
||
%NTNIM::EXP 526000040000 ;ANF NI/ETHERNET MULTICAST ADDRESS
|
||
EXP ANFNIM## ; (SECOND HALF) ADDRESS = AB-00-04-00-XX-XX
|
||
%NTNII::EXP ^D64 ;ANF NI/ETHERNET BROADCAST INTERVAL MAXIMA
|
||
%NTNIJ::EXP ^D64*5 + 5 ;ANF NI/ETHERNET FEK KEEP-ALIVE TIMER VALUE
|
||
|
||
|
||
;ADD FIXED-OFFSET ENTRIES ABOVE THIS POINT
|
||
|
||
NCLRTP: BLOCK NCT.TP+1 ;RECEIVED NCL TYPES
|
||
NCLRMT: BLOCK NC.MAX+1 ;RECEIVED NUMBERED TYPES
|
||
NCLRDL: BLOCK NETLNH ;RECEIVED DATA LENGTHS BY POWERS OF 2
|
||
NCLXTP: BLOCK NCT.TP+1 ;TRANSMITTED COUNTER PARTS OF ABOVE
|
||
NCLXMT: BLOCK NC.MAX+1
|
||
NCLXDL: BLOCK NETLNH
|
||
|
||
;ADD SUBTABLE DATA ENTRIES ABOVE THIS POINT
|
||
|
||
.NTMXL==:<.-NETGTT-1>_9
|
||
XLIST ;DON'T LIST THE LITERALS
|
||
$LIT
|
||
LIST
|
||
|
||
NETEND::!END
|
||
|