Trailing-Edge
-
PDP-10 Archives
-
QT020_T20_4.1_6.1_SWSKIT_851021
-
swskit-hacks/eisrv.mac
There are no other files named eisrv.mac in the archive.
TITLE EISRV - Ethernet server
COMMENT \
EISRV is not meant as a fully functional server. It is a demonstration
piece, written to show how the NI% jsys can be used. In particular, it delivers
packets containing asciz strings, only, and does not guarantee order of
delivery. As it currently stands, it can do the following functions across
systems connected by an Ethernet cable:
Report on the load average of another system.
Determine if <username> is logged in on another system.
Determine if <name> is signed on with EISRV at a remote node, and return
his EISRV number.
Deliver a packet of text to a process that has "signed on" with EISRV.
Signing on is accomplished by senfding an IPCF page containing a unique
name string. It responds with an IPCF message that OKs or rejects the
sign on. Thereafter, IPCFs packets from that process are interpreted as
commands to the server. One such command might be "deliver this text to
EISRV user 12 on system FOOBAR." Another might be "have the server on system
FROBAZ return the load average there."
Transmissions over the Ethernet cable can be "lost." This occurs
when two systems try to use the cable to transmit simultaneously. When this
happens, the sending system can normally determine that a failure occured
and try again, and the NI% jsys implements this. However, if the receiving
process did not "post a buffer" to receive the message, the message will
arrive and immediately be dropped, and the sender is not made aware of this
condition. Hence, in this server, all messages sent cause an acknowledgment
message to be returned. If an acknowledgment is not received ffor any
given message, the original sender retransmits it. If a message is
retransmitted several times and still not acknowledged, the receiving
node is assumed to be dead.
The NI% jsys can work in either interrupt or non-interrupt mode.
This code demonstrates receiving in interrupt mode.
\
SEARCH MONSYM,MACSYM
ftlogf==1 ;Have the server write a log file
F=0
T1==1
T2==2
T3==3
T4==4
T5==5
T6==6
T7==7
P==17
;FLAGS
F.SHUT==1B0 ;SHUTDOWN SOON
F.WAIT==1B1 ;WAITING (WAIT JSYS), OK TO BREAK FROM JSYS
F.SKIP==1B2 ;BREAK FROM WAIT IF WAITING
F.TBPA==1B3 ;ENTRY NEEDS ADDING TO TBP
;FLAGS IN RH SHOULD NOT BE TOUCHED BY INTERRUPT ROUTINES
F.INTE==1B35 ;CALLER OF ROUTINE HAD INTERRUPTS ENABLED
NIRINT==1 ;NI RECEIVED INTERRUPT CHANNEL
NICINT==2 ;NI CHANGE OF STATE INTERRUPT
TIMINT==3 ;TIMER INTERRUPT
IPRINT==4 ;IPCF RECEIVED INTERRUPT
PROTOC=1137 ;ARBITRARIALLY CHOSEN ETHERNET "PORT" NUBER
MSGLEN==1440 ;MAXIMUM LENGTH OF TEXT SENDABLE IN ONE PACKET
MAXUSR==70 ;MAXIMUM NUMBER OF USERS THAT CAN SIGNON
; offsets in the first page of a buffer in freespace. Do not change the
; order here.
NXTBUF==0 ;next buffer (MUST BE IN 0 POSITION)
SIZBUF==1 ;number of pages in this buffer
PNTBUF==2 ;pointer into MAPFRE used by DELPGS
TIMBUF==3 ;time stamp (optional)
ERRBUF==4 ;# times Ack hasn't come
SRCBUF==5 ;source of buffer (0 if from NI, PID if from MRECV)
USRBUF==6 ;user# the buffer is from (0 if not known)
NODBUF==7 ;pointer to node entry this buffer is from
CREBUF==10 ;the caller's PC
DATAST==11 ;first word available for data
;FORMAT OF NODES QUEUE
$NDSAD==0 ;where ethernet address lives (2 words)
$NDNAM==2 ;asciz name of node (2 words)
$NDFLG==4 ;flags, see below
$NDOFF==11 ;last command # entry added at offset
$NDCMD==12 ;list of old command #'s (FINLEN long)
ND%OFF==1B0 ;node seems to have died
;INTERNAL NI-NI MESSAGE FORMAT (NUMBER OF 8 BIT BYTES/FIELD)
$SIZE==0 ;free(2), #bytes data after $CMD(2)
$NUM==1 ;msg#(4)
$SAD==2 ;first four bytes of SAD(4)
$SUSR==3 ;last two bytes of SAD(2), sender user#(2)
$TYP==4 ;dest user#(2), type, flags
$CMD==5 ;CMD, transaction #(3)
$ARGS==6 ;data for the command
MS%NOA==1 ;Message needs/expects no Ack
MS%NEW==2 ;New node message
;USER LIST FORMAT
U$LEN==8 ;LENGTH OF ENTRIES
U$NUM==0 ;FLAGS,,USER#
U$PID==1 ;PID
U$NAM==2 ;USER NAME
U%LAST==1B0 ;BOTTOM ENTRY
;IPCF MSG FORMAT
I$CMD==0 ;COMMAND WORD
I$NUM==1 ;NUMBER OF TRANSACTION
I$ARG==2 ;ARGS
;VARIOUS CONSTANTS
FINLEN==550
TIMWAT=23
IPRPAG==77
FRESPC==IPRPAG+1
NUMPAG==760-FRESPC+1
IPRBUF=IPRPAG*1000
.SCVMX==2 ;Max allowed NI to NI message type
.IPMAX==6 ;Max legal IPCF command number
ifn ftlogf,<
DEFINE CALL(where),<
PUSHJ P,[
SKIPN LOGJFN
JRST where
PUSHJ P,BLAT
[ASCIZ/
/]
PUSH P,T2
AOS T2,DEEP
PUSHJ P,OCTLOG
PUSHJ P,BLAT
[ASCIZ/ CALL 'where', from /]
HRRZ T2,-1(P)
SUBI T2,1
PUSHJ P,OCTLOG
POP P,T2
JRST where] >
DEFINE RET,<
JRST [
SKIPN LOGJFN
POPJ P,
PUSHJ P,BLAT
[ASCIZ/
/]
PUSH P,T2
SOS T2,DEEP
ADDI T2,1
PUSHJ P,OCTLOG
POP P,T2
PUSHJ P,BLAT
[ASCIZ/ returning /]
POPJ P,] >
>
ST: RESET%
SETOM INTLCK# ;INTERRUPT ENABLE/DISABLE FLAG
MOVE P,[-100,,STACK-1] ;GET STACK
CALL SETPGS ;SET UP FREESPACE
SETZB F,ZERO ;CLEAR FLAGS AND VERIABLES
MOVE T1,[ZERO,,ZERO+1]
BLT T1,ENDZER
SETOM USRLST ;NO USERS SIGNED ON YET
MOVX T1,.RCADR ; Get LLMOP function code
MOVX T2,LLMBLK ; Get arg block address
LLMOP% ; Read our local address
OURSAD=LLMBLK+.LMPYA ; WHERE LOCAL ADDRESS CAN BE FOUND
;get nodename, 8bit asciz, 6 bytes, in OURNAM, and 7bit asciz in MYNAME
MOVEI T1,.NDGLN
MOVEI T2,T3
HRROI T3,MYNAME
NODE%
MOVE T1,[POINT 7,MYNAME]
MOVE T2,[POINT 8,OURNAM]
CPYNDM: ILDB T3,T1 ;COPY INTO OURNAM
IDPB T3,T2
JUMPN T3,CPYNDM
;OPEN UP INTERRUPT CHANNELS
MOVX T1,.FHSLF
MOVE T2,[LEVTAB,,CHNTAB]
SIR%
EIR%
MOVX T2,1B<NIRINT>+1B<NICINT>+1B<TIMINT>+1B<IPRINT>
AIC%
;OPEN PORTAL
MOVX T1,.EIOPN
HRRM T1,NIBLOK+.EIFCN
MOVEI T1,NIBLOK
NI% ;OPEN A PORTAL TO TALK THROUGH
ERCAL FATAL ;PROBABLY ALREADY IN USE
HRRZ T1,NIPID
HRRM T1,NIINTB+.EIPID
MOVX T1,.EIEMA ;RECEIVE MULTICASTS
HRRM T1,NIBLOK+.EIFCN
DMOVE T4,MULTI
DMOVEM T4,NIBLOK+.EIAR1
MOVEI T1,NIBLOK
NI%
ERCAL FATAL
HRROI T1,[ASCIZ/
EISRV, job /]
PSOUT% ;TYPE STARTUP BANNER
SETO T1,
HRROI T2,T3
MOVEI T3,.JIJNO
GETJI%
ERJMPS .+1
MOVE T2,T3
CALL DECOUT
IFE ftlogf,<
HRROI T1,[ASCIZ/, detaching...
/]
PSOUT%
BYEBYE: DTACH%
>
SETZM LOGJFN#
IFN ftlogf,<
MOVX T1,GJ%FOU+GJ%SHT
HRROI T2,[ASCIZ/PS:EISRV.LOG/]
GTJFN%
ERJMPS NOLOG
MOVE T2,[7B5+OF%WR]
OPENF%
ERJMPS NOLOG
MOVEM T1,LOGJFN
NOLOG:>
;POST 1ST RECEIVING BUFFERS
MOVX T1,.FHSLF
MOVX T2,1B<NIRINT> ;POST RECEIVE BUFFERS BY FAKING AN..
IIC% ;NI RECEIVED INTERRUPT
;SEND MULTICAST HELLO
RECAST: AOS NI.CST ;TELL OTHER NODES WE ARE ONLINE NOW
MOVEI T1,1
CALL GETPGS ;GET 1 PAGE OF MEMORY
DMOVE T3,OURNAM ;BUILD "HELLO" MESSAGE
DMOVEM T3,DATAST+.BXBMX+$ARGS(T2)
MOVEI T1,6
MOVEI T3,100 ;MULTICAST HELLO COMMAND NUMBER
SETZ T4, ;DEST IS SERVER
CALL SNDSTD
MOVX T1,MS%NOA+MS%NEW ;NO ACK NEEDED, AND NEW NODE MESSAGE
DPB T1,[POINT 8,DATAST+.BXBMX+$TYP(T2),31] ;SO SET FLAGS
SETZM DATAST+.BXBMX+$NUM(T2) ;MSG NUMBER 0
MOVEI T3,NIBLOK
DMOVE T4,MULTI
CALL SNDNIM ;SAY "HELLO, EVERYONE!"
MOVEI T1,^D8*^D1000
DISMS% ;WAIT FOR RESPONSES
SKIPN EADQUE ;IF WE GOT ANY RESPONSES, THEN EVERYONE...
JRST RECAST ;HEARD, OTHERWISE, TRY AGAIN
CALL DIRINT ;TURN OFF INTERRUPTS FOR A MOMENT
MOVEI T1,4
MOVEI T2,IPCFSI
MSEND% ;GET A PID, DECALRE OURSELF TO SYS[INFO]
ERCAL FATAL
MOVE T1,SRVPID
MOVEM T1,MRECVB+.IPCFR
MOVEM T1,MUTBLK+1
MOVX T1,.MUPIC
MOVEM T1,MUTBLK
MOVEI T1,3
MOVEI T2,MUTBLK
MUTIL%
ERCAL FATAL
CALL EIRINT ;HANDLE INTERRUPTS AGAIN
;ENTER THE "DO" LOOP
;ONCE THE WAIT% JSYS IS STARTED, THE INTERRUPT ROTUTINES ARE THE ONLY
; THINGS ACTIVE. IF THEY PUT SOMETHING IN THE TBP QUEUE, THEY WILL
; ABORT THE WAIT% JSYS.
DOLOOP: TXNE F,F.SHUT ;SHUTDOWN REQUESTED SOMEWHERE?
CALL FATAL ;YES, DIE
SKIPE TBPQUE ;ANYTHING IN THE "TO BE PROCESSED" QUEUE?
CALL DOTASK ;YES, DO TASKS
TXO F,F.WAIT ;WE ARE ENTERING A WAIT STATE, OK TO BREAK
TXZN F,F.SKIP ;HAVE WE BEEN ASKED NOT TO WAIT?
WAIT% ;WAIT FOR INTERRUPT
WAITIN: TXZ F,F.SKIP+F.WAIT ;CLEARING WAIT STATE
JRST DOLOOP ;GO LOOP FOR THINGS TO DO
DOTASK: CALL DIRINT ;SO WE CAN MODIFY THE QUEUE SAFELY
MOVE T2,TBPQUE ;PULL THE TOP REQUEST OUT
MOVE T3,NXTBUF(T2)
MOVEM T3,TBPQUE
MOVEM T2,TSKINP# ;STORE REQUEST BLOCK ADDRESS
CALL EIRINT ;ENABLE INTERRUPTS
JUMPE T2,NXTTSK ;IF NO REQUEST HERE, CHECK FOR NEXT REQUEST
SKIPN SRCBUF(T2) ;FROM LOCAL USER OR OVER WIRE?
JRST NITASK ;BUFFER PUT ON QUEUE BY NIRECV
ifn ftlogf,<
PUSHJ P,BLAT
[ASCIZ/
IPCF command begun: /]
PUSH P,T2
MOVE T2,DATAST(T2)
PUSHJ P,OCTLOG
POP P,T2 >
MOVE T3,USRBUF(T2) ;LOAD USER NUMBER OR 0
SKIPL T1,DATAST(T2) ;FETCH COMMAND; LEGAL?
CAILE T1,.IPMAX ;??
JRST NXTTSK
CAIN T3,0 ;FROM A KNOWN USER?
JUMPN T1,WDYTUA ;NO; COMMAND OTHER THAN SIGNON?
JRST @[EXP SIGNON, TEXTOT, LAREQU, DMPNDS, USRFNR, WHOISN, STATS
EXP BLATRQ, FNJOBU](T1)
;LEAP WITH T2/ BUFFER FROM TBP (TSKINP ALSO)
;T3/ USER #
SIGNON: SETZ T1, ;MAKE SURE SIGNON NAME TERMINATES
DPB T1,[POINT 8,DATAST+.BXBMX+I$ARG+5(T2),35]
MOVE T4,SRCBUF(T2)
AOS T1,USRCNT ;DO WE HAVE ROOM FOR ANOTHER?
CAIL T1,MAXUSR ;CHECK...
JRST SNFAL1 ;NO...
MOVEI T6,USRLST ;SET UP TO SCAN
SETZ T3, ;NO FREE ENTRY SEEN YET
SCNNUS: HRRE T5,U$NUM(T6) ;FAKE ENTRY?
JUMPL T5,NXTNUS ;YES, SKIP ON
JUMPN T5,SCNCOL ;NO, FREE ENTRY?
CAIN T3,0 ;YES, DO WE HAVE ONE ALREADY?
MOVEI T3,(T6) ;NO, REMEMBER IT
JRST NXTNUS ;AND CAN'T BE A COLLISION, GO ON
SCNCOL: CAMN T4,U$PID(T6) ;PID ALREADY IN TABLE?
JRST SNFAL3 ;YES, GO AWAY
HRROI T1,U$NAM(T6) ;CHECK FOR NAME
MOVE T2,TSKINP
HRROI T2,DATAST+I$ARG(T2)
STCMP%
JUMPE T1,SNFAL2 ;NAME ALREADY IN?
NXTNUS: ADDI T6,U$LEN ;NO PROBLEM YET, ADVANCE
SKIPL U$NUM-U$LEN(T6) ;WAS LAST ENTRY REALLY LAST?
JRST SCNNUS ;NO, GO ON
CALL DIRINT ;TO PLAY WITH USER QUEUE
CAIN T3,0 ;DID WE FIND A FREE ENTRY?
MOVEI T3,(T6) ;NO, USE END OF LIST
AOS T5,USERNM# ;ASSIGN UNIQUE NUMBER TO USER
TRZ T5,700000 ;15 BITS ONLY
HRRM T5,U$NUM(T6) ;SET
MOVEM T4,U$PID(T6) ;SET PID
MOVE T2,TSKINP
MOVSI T2,DATAST+I$ARG(T2) ;BLT POINTER TO NAME...
HRRI T2,U$NAM(T6) ;DEST POINTER..
BLT T2,U$LEN-1(T6) ;COPY IN
SKIPL U$NUM-U$LEN(T6) ;IS ABOVE ENTRY THE OLD LAST?
JRST USEROK ;NO, DONE
MOVX T2,U%LAST ;YES, MUST CLEAR FOR OLD AND SET FOR NEW
IORM T2,U$NUM(T6) ;SET FOR NEW
ANDCAM T2,U$NUM-U$LEN(T6) ;CLEAR FOR OLD
USEROK: CALL EIRINT ;DONE
PUSH P,T4 ;SAVE USER'S PID
MOVEI T1,2
CALL GETPGS ;NEED TO TELL SYS[INFO]
POP P,1000+.IPCI2(T2) ;WATCH USER'S PID
MOVEI T1,.IPCIK
MOVEM T1,1000+.IPCI0(T2) ;SET FUNCTION
SETZ T1, ;0 IS SYS[INFO]
CALL MSGUSR
SETZM IPSCMD# ;COMMAND TO RETURN
JRST DMPND2 ;RETURN SAME AS DUMP NODES COMMAND
USRFNR: MOVEI T1,4
JRST ASCCMD
BLATRQ: MOVEI T1,7
JRST ASCCMD
FNJOBU: MOVEI T1,10
JRST ASCCMD
TEXTOT: MOVEI T1,1 ;SEND TEXT COMMAND
ASCCMD: MOVEM T1,NISCMD# ;SAVE FOR A MOMENT
GENASN: MOVEI T1,1 ;GET A PAGE TO SEND
CALL GETPGS
MOVEM T2,MSGNIS# ;SAVE LOC
MOVE T1,TSKINP ;GET LOC OF REQUEST
SETZM DATAST+5+^D1500/4(T1) ;MAKE SURE USER STRING TERMINATES
HRROI T1,DATAST+I$ARG+3(T1) ;POINT TO STRING
HRROI T2,DATAST+.BXBMX+$ARGS(T2) ;WILL COPY HERE IN 8 BIT
CALL CPYSTR ;COPY IT, RETURN LEN IN T4
CAILE T4,^D1401 ;ALLOW THIS LENGTH
MOVEI T4,^D1401 ;TOO BAD, TRUNCATE
MOVEI T1,(T4) ;MOVE LENGTH TO T1
MOVE T2,MSGNIS ;BUFFER ADDR IN T2
MOVE T3,NISCMD ;CMD NUMBER IN T3
MOVE T4,TSKINP ;GET USER NUMBER TO SEND TO IN T4
MOVE T4,DATAST+I$ARG+2(T4) ;..
GENMSG: SKIPG CREBUF(T2)
CALL FATAL
MOVEM T2,GENTMP#
CALL SNDSTD ;SET UP MSG BLOCK
MOVE T1,TSKINP
CALL IPRSTD ;SET UP IPCF SENDER'S INFO
MOVEI T3,NIBLOK ;GET BLOCK TO USE FOR SEND
CALL SNDNIM ;AND SEND IT
JRST NXTTSK ;NEXT OP?
LAREQU: MOVEI T1,1
CALL GETPGS
MOVEI T3,2 ;COMMAND: LOAD AVERAGE REQUEST
SETZB T1,T4 ;NO ARGS, NO USER DESTINATION
JRST GENMSG ;FIRE A GENERAL NI MESSAGE
DMPNDS: MOVEI T1,3 ;IPCF RESPONSE: NODELIST
MOVEM T1,IPSCMD ;REMEMBER IT
DMPND2: MOVEI T1,2 ;2 PAGES FOR IPCF SEND (ENTRY FROM SIGNON)
CALL GETPGS
MOVE T1,IPSCMD ;WHAT IPCF RESPONSE NUMBER?
MOVEM T1,1000+I$CMD(T2) ;PUT IN COMMAND SLOT
SETOM 1000+I$NUM(T2) ;NOT A NUMBERED TRANSACTION
MOVEI T4,1000+I$ARG(T2) ;POINTER TO BUILD RESPONSE WITH
SKIPA T3,EADQUE ;PERUSE THE NODES QUEUE
DMPND3: MOVE T3,NXTBUF(T3) ;ADVANCE
JUMPE T3,DMPNDE ;AT END, GO FINISH AND SEND
SKIPGE DATAST+$NDFLG(T3) ;DETELED ENTRY?
JRST DMPND3 ;YES, ADVANCE
MOVSI T1,DATAST+$NDSAD(T3) ;NO, BLT INFO IN
HRRI T1,(T4) ;..
BLT T1,3(T4) ;..
ADDI T4,4 ;ADVANCE DEST POINTER
JRST DMPND3 ;GET NEXT NODE
DMPNDE: MOVE T1,TSKINP
MOVE T1,SRCBUF(T1)
CALL MSGUSR ;T1/PID, T2/BUFFER
JRST NXTTSK
WHOISN: MOVEI T1,1
CALL GETPGS
MOVE T1,TSKINP
MOVE T4,DATAST+I$ARG+2(T1)
MOVEI T3,7
SETZ T1,
CALL SNDSTD
MOVE T1,TSKINP
CALL IPRSTD
MOVEI T3,NIBLOK
CALL SNDNIM
JRST NXTTSK
STATS: MOVEI T1,2
CALL GETPGS
MOVEI T1,5
MOVEM T1,1000+I$CMD(T2)
SETOM T1,1000+I$NUM(T2)
MOVE T1,[NISTL,,REALUS-NI.STA+1]
MOVEM T1,1000+I$ARG(T2)
MOVSI T1,NI.STA
HRRI T1,1000+I$ARG+1(T2)
BLT T1,1000+I$ARG+NI.LEN(T2)
MOVE T1,TSKINP
MOVE T1,SRCBUF(T1)
CALL MSGUSR
JRST NXTTSK
SNFAL1: SETO T1, ;NO ROOM FOR ANOTHER USER
JRST CANTDO
SNFAL2: HRROI T1,-2 ;DUPLICATE NAME
JRST CANTDO
SNFAL3: HRROI T1,-3 ;DUPLICATE PID
JRST CANTDO
WDYTUA: HRROI T1,-4 ;PLEASE SIGNON MSG
CANTDO: MOVEM T1,USRERR#
MOVEI T1,2
CALL GETPGS
MOVE T1,USRERR
MOVEM T1,1000(T2)
MOVE T1,TSKINP
MOVE T1,SRCBUF(T1)
CALL MSGUSR
;JRST NXTTSK
NXTTSK: SKIPE T1,TSKINP
CALL RELPGS
ANOTHE: SKIPN TBPQUE
RET
JRST DOTASK
NITASK: ifn ftlogf,<
PUSHJ P,BLAT
[ASCIZ/
Starting NI task: /]
LDB T2,[POINT 8,DATAST+.BXBMX+$CMD(T2),7]
PUSHJ P,OCTLOG >
MOVE T2,TSKINP
MOVE T1,T2
ADD T1,[POINT 8,DATAST+.BXBMX+$ARGS]
MOVEM T1,TSKDAT# ;POINTER TO ARGS IN TSKDAT
LDB T3,[POINT 16,DATAST+.BXBMX+$SIZE(T2),31] ;# BYTES IN T3
ADJBP T3,T1
SETZ T1,
IDPB T1,T3
LDB T1,[POINT 8,DATAST+.BXBMX+$CMD(T2),7]
CAIL T1,100 ;HELLO/GOODBYE STUFF?
JRST HELLO ;GO HANDLE
CAILE T1,11
JRST BADCMD
MOVE T5,DATAST+.BXBMX+$NUM(T2)
MOVE T6,NODBUF(T2)
AOS T7,DATAST+$NDOFF(T6)
CAIL T7,FINLEN
SETZB T7,DATAST+$NDOFF(T6)
ADDI T6,(T7)
MOVEM T5,DATAST+$NDCMD(T6)
NIJUMP: JRST @[EXP NITNUL, TEXTDL, LAASK, NXTTSK, FNDUSR, FONUSR, NDELI
EXP WHOISQ, BLATTM, JOBIN](T1)
BADCMD: IFN ftlogf,<
PUSHJ P,BLAT
[ASCIZ/
Bad NI cmd received/]
>
JRST NXTTSK
NITNUL: IFN ftlogf,<
PUSHJ P,BLAT
[ASCIZ/
NULL NI CMD received/]
>
JRST NXTTSK
TEXTDL: LDB T2,[POINT 16,DATAST+.BXBMX+$TYP(T2),15] ;GET DEST USER
JUMPE T2,CANTDM ;I DON'T ACCEPT TEXT MESSAGES
CALL FNDUSN ;DO WE HAVE A PID FOR THIS USER?
JUMPE T1,CANTDM ;SAY CANT DELIVER MAIL
MOVEM T1,USRPID#
MOVEI T1,2 ;IPCF OUT
CALL GETPGS
MOVEI T1,1 ;COMMAND TYPE 1
CALL IPSSTD
MOVE T7,[POINT 7,1000+I$ARG+3(T2)]
CPYMGU: ILDB T1,T4
IDPB T1,T7
SOJG T5,CPYMGU
IDPB T5,T7
MOVE T1,USRPID
CALL MSGUSR
JRST NXTTSK
;Call with T2/ IPCF buffer and TSKINP/ NI request buffer, T1/ CMD to return
; Returns T4/ byte pointer to data portion of the NI request buffer
IPSSTD: MOVEM T1,1000+I$CMD(T2)
MOVE T4,TSKINP
LDB T1,[POINT 24,DATAST+.BXBMX+$CMD(T4),31]
MOVEM T1,1000+I$NUM(T2)
DMOVE T5,DATAST+.BXSAD(T4)
DMOVEM T5,1000+I$ARG(T2)
LDB T1,[POINT 16,DATAST+.BXBMX+$SUSR(T4),31]
MOVEM T1,1000+I$ARG+2(T2)
LDB T5,[POINT 16,DATAST+.BXBMX+$SIZE(T4),31]
ADD T4,[POINT 8,DATAST+.BXBMX+$ARGS]
RET
CANTDM: MOVEM T2,GONEUN# ;USER NUMBER THAT IS GONE
MOVEI T1,1
CALL GETPGS
MOVEM T2,TSKOUT#
MOVE T1,TSKINP
MOVE T3,DATAST+.BXBMX+$NUM(T1)
MOVEM T3,DATAST+.BXBMX+$NUM(T2)
MOVE T3,GONEUN
DPB T3,[POINT 16,DATAST+.BXBMX+$SUSR(T2),31] ;SENDER IS DEAD USER
LDB T4,[POINT 16,DATAST+.BXBMX+$SUSR(T1),31] ;GET RECEIVER
SETZ T1,
MOVEI T3,6
CALL SNDSTD
MOVE T6,TSKINP
DMOVE T4,DATAST+.BXSAD(T6) ;GET SOURCE TO SEND BACK TO
MOVEI T3,NIBLOK
CALL SNDNIM
JRST NXTTSK
LAASK: MOVEI T1,1
CALL GETPGS
MOVEM T2,LASTMP#
HRROI T1,[ASCIZ/Node /]
ADD T2,[POINT 8,DATAST+.BXBMX+$ARGS]
CALL CSTRB
HRROI T1,MYNAME
CALL CSTRB
HRROI T1,[ASCIZ/ Load average /]
CALL CSTRB
MOVE T1,[14,,.SYSTA]
GETAB%
SETZ T1,
EXCH T1,T2
MOVE T3,[FL%ONE+FL%PNT+2B17+3B23+2B29]
FLOUT%
ERJMPS .+1
MOVEI T1,100
MOVE T2,LASTMP
MOVEI T3,1
CALL NINI
JRST NXTTSK
FNDUSR: MOVEI T1,1
CALL GETPGS
MOVEM T2,TSKOUT
MOVEI T4,USRLST
MOVE T1,TSKDAT
MOVEM T1,USNMAT# ;WORST CASE, RETURN USER'S STRING
SCNINL: HRROI T1,U$NAM(T4)
MOVE T2,TSKDAT
STCMP%
JUMPE T1,SGNYES
ADDI T4,U$LEN
SKIPL U$NUM-U$LEN(T4)
JRST SCNINL
TDZA T1,T1
SGNYES: HRRZ T1,U$NUM(T4)
QRYRES: MOVE T2,TSKOUT
DPB T1,[POINT 32,DATAST+.BXBMX+$ARGS(T2),31]
HRROI T2,DATAST+.BXBMX+$ARGS+1(T2)
MOVE T1,USNMAT
CALL CPYSTR
MOVEI T1,4(T4)
MOVE T2,TSKOUT
MOVEI T3,5
CALL NINI
JRST NXTTSK
WHOISQ: MOVEI T1,1
CALL GETPGS
MOVEM T2,TSKOUT
LDB T2,[POINT 16,DATAST+.BXBMX+$TYP(T2),15]
CALL FNDUSN
SETZM USNMAT
JUMPE T1,QRYRES
HRROI T3,U$NAM(T3)
MOVEM T3,USNMAT
JRST QRYRES
;Find all jobs owned by username in TSKDAT, store them and count in LCLUSR
FNDLCL: SETZM LCLUSR
;GET JOB MAX FOR SYSTEM
MOVEI T1,^D128*4
MOVEM T1,JOBMAX#
SETZM RCUSRN#
MOVE T2,TSKDAT
MOVX T1,RC%PAR
RCUSR%
ERJMPS NOMATC
TXNE T1,RC%NOM
JRST NOMATC
MOVEM T3,RCUSRN
;GET MIN JOB IN T1
SETZ T1,
ADDLCL: HRROI T2,T4
MOVEI T3,.JIUNO
GETJI%
ERJMPS NXTJOB
CAME T4,RCUSRN
JRST NXTJOB
AOS T2,LCLUSR
MOVEM T1,LCLUSR(T2)
NXTJOB: CAMGE T1,JOBMAX
AOJA T1,ADDLCL
NOMATC: RET
BLATTM: MOVE T1,TSKDAT
FNDTAB: ILDB T2,T1
JUMPE T2,NXTTSK ;NULL BEFORE TAB? BAD OPERATION
CAIE T2,.CHTAB
JRST FNDTAB
MOVEM T1,TEXTIS# ;SAVE POINTER TO REAL TEXT TO SEND
SETZ T2,
DPB T2,T1 ;TERMINATE USER NAME
CALL FNDLCL
SKIPN T7,LCLUSR ;GET ANY JOBS?
JRST NXTTSK ;NO
BLATLP: MOVE T1,LCLUSR(T7) ;GET A JOB NUMBER
HRROI T2,T1 ;SET UP FOR TTY NUMBER IN T1
MOVEI T3,.JITNO
GETJI%
ERJMPS BLATEN ;COULD HAVE LOGGED OUT
JUMPL T1,BLATEN ;DON'T TRY IF DETACHED
TRO T1,400000 ;MAKE A TERMINAL CODE
MOVE T2,TEXTIS
TTMSG% ;FIRE AWAY
ERJMPS BLATEN ;SHN
BLATEN: SOJG T7,BLATLP
JRST NXTTSK
JOBIN: MOVEI T1,1
CALL GETPGS
MOVEM T2,TSKOUT
MOVE T1,TSKDAT
MOVEM T1,USNMAT ;GET POINTER TO USERNAME WHERE IT WILL BE SEEN
CALL FNDLCL ;GET JOBS BELONGING TO USERNAME
SETZ T7, ;FLAGS IN T7 (ASSUME NONE TRUE)
SKIPN RCUSRN ;WAS THERE A USERNUMBER?
JRST RETFLG ;NO, JUST RETURN THE 0
TXO T7,1B<7+4> ;4 OFFSET IS TO STORE 32 BIT VALUE IN 36 BITS
SKIPN T6,LCLUSR ;FIND ANY JOBS?
JRST RETFLG ;NO, CURRENT FLAGS REPRESENT WHOLE TRUTH
TXO T7,1B<15+4> ;LIGHT THE LOGGED IN BIT
SCNJBI: MOVE T1,LCLUSR(T6) ;LOOK AT EACH JOB
HRROI T2,T4
MOVEI T3,.JITNO ;GET TERM NUMBER IN T4
GETJI%
ERJMPS NXTJBI ;GONE
JUMPL T4,NXTJBI ;IF DETACHED, CAN'T MARK REAL TERMINAL
HRROI T2,T4
MOVEI T3,.JIBAT ;MAYBE UNDER BATCH?
GETJI%
ERJMPS NXTJBI
CAIL T4,0 ;-1 IF BATCH
TXO T7,1B<14+4> ;NOT BATCH OR DETACHED, HENCE REAL TERMINAL
NXTJBI: SOJG T6,SCNJBI
RETFLG: MOVE T1,T7 ;COPY FLAGS TO TI
JRST QRYRES
FONUSR: MOVE T2,TSKINP
LDB T2,[POINT 16,DATAST+.BXBMX+$TYP(T2),15]
JUMPE T2,NXTTSK ;*I* DON'T WANT IT
CALL FNDUSN
JUMPE T1,CANTDM ;RECEIVER NOT HERE, RETURN TO SENDER
MOVEM T1,USRPID
MOVEI T1,2
CALL GETPGS
MOVEM T2,TSKOUT
MOVEI T1,4
CALL IPSSTD ;SET UP STANDARD IPCF STUFF
LDB T1,[POINT 16,(T4),15] ;FIRST 2 BYTES IS JOB INFO
MOVEM T1,1000+I$ARG+3(T2)
LDB T1,[POINT 16,(T4),31] ;USER #
MOVEM T1,1000+I$ARG+4(T2)
MOVEI T1,1(T4) ;POINT TO USER NAME RETURNED
HRLI T1,(POINT 8) ;IN 8 BIT BYTES
HRROI T2,1000+I$ARG+5(T2)
CALL CSTR
MOVE T2,TSKOUT
MOVE T1,USRPID
CALL MSGUSR
JRST NXTTSK
NDELI: LDB T2,[POINT 16,DATAST+.BXBMX+$TYP(T2),15]
JUMPE T2,NXTTSK
CALL FNDUSN
JUMPE T1,NXTTSK
MOVEM T1,USRPID
MOVEI T1,2
CALL GETPGS
HRROI T1,-6
CALL IPSSTD
MOVE T1,TSKINP
LDB T1,[POINT 16,DATAST+.BXBMX+$SUSR(T1),31]
MOVEM T1,1000+I$ARG+2(T2)
MOVE T1,USRPID
CALL MSGUSR
JRST NXTTSK
HELLO: SUBI T1,100
CAILE T1,2
JRST BADCMD
JRST @[EXP NEWSRV, IAM..., LATER](T1)
NEWSRV: CALL NEWNDE
TIME% ;GET UPTIME AS A RANDOM NUMBER
MOVS T2,OURNAM+1
XOR T2,OURNAM
IDIVI T2,37
ADDI T1,(T2) ;SCRAMBLE BY NODENAME
ANDI T1,7777 ;CUT TO 0-4 SECONDS (ABOUT)
ADDI T1,100(T3) ;ADD AN OFFSET
MOVEM T1,RANDOM#
DISMS% ;THIS HELPS PREVENT COLLISIONS
MOVEI T1,1
CALL GETPGS
DMOVE T4,OURNAM ;OUR SYSTEM NAME, 6 8BIT BYTES
DMOVEM T4,DATAST+.BXBMX+$ARGS(T2)
MOVEI T1,6
MOVEI T3,101 ;NORMAL HELLO
SETZ T4,
CALL SNDSTD
MOVEI T3,NIBLOK
MOVE T5,TSKINP
DMOVE T4,DATAST+.BXSAD(T5)
CALL SNDNIM
JRST NXTTSK
NEWNDE: AOS NI.HLO ;COUNT HELLOS
DMOVE T4,DATAST+.BXSAD(T2)
SKIPA T1,EADQUE
NDEFND: SKIPE T1,NXTBUF(T1)
JUMPE T1,[CALL FATAL] ;NIRECV SHOULD HAVE PUT IT IN
CAMN T4,DATAST+$NDSAD(T1)
CAME T5,DATAST+$NDSAD+1(T1)
JRST NDEFND
DMOVE T6,DATAST+.BXBMX+$ARGS(T2) ;FETCH 8BIT NODENAME
TDZ T7,[3,,-1] ;CLEAR OUT TRASH
MOVE T4,T1
CALL DIRINT
DMOVEM T6,DATAST+$NDNAM(T4)
SETZM DATAST+$NDFLG(T4) ;NODE IS "ONLINE"
LDB T5,[POINT 8,DATAST+.BXBMX+$TYP(T2),31] ;GET FLAGS
TXNN T5,MS%NEW ;NEW NODE MESSAGE?
JRST NOTRLN ;NO, DON'T CLEAR CMD MEMORY
SETZM DATAST+$NDOFF(T4)
SETZM DATAST+$NDCMD(T4)
MOVEI T3,DATAST+$NDCMD+1(T4)
HRLI T3,-1(T3)
BLT T3,DATAST+$NDCMD+FINLEN(T4)
NOTRLN: CALL EIRINT
RET
IAM...: CALL NEWNDE
JRST NXTTSK
LATER: JRST NXTTSK
STATCH: CIS% ;LOSE INTERRUPTS
JRST ST ;AND RESTART
IPCFRV: MOVEM T1,INT1AC+1
MOVE T1,[2,,INT1AC+2]
BLT T1,INT1AC+17 ;SAVE ALL AC'S
MOVE P,[-50,,STACK1-1]
MOVEI T1,IPCFRV
MOVEM T1,ATINTR#
IFN FTLOGF,<
PUSHJ P,BLAT
[ASCIZ/ <int-IPCFRV> /] >
IPREAD: SETO T1,
MOVE T2,[.FHSLF,,IPRPAG]
SETZ T3,
PMAP% ;MAKE RECEIVING PAGE EMPTY
MOVE T1,SRVPID
MOVEM T1,MRECVB+.IPCFR
MOVE T1,[1000,,IPRPAG]
MOVEM T1,MRECVB+.IPCFP
MOVX T1,IP%CFV
MOVEM T1,MRECVB+.IPCFL ;RECEIVE IN PAGE MODE
MOVEI T1,4
MOVEI T2,MRECVB
RERECV: MRECV% ;READ THE MSG
ERJMPR [CAIE T1,IPCF16 ;CAN'T BECAUSE WRONG MODE?
JRST IN1RET ;TRY TO IGNORE
SETZM MRECVB+.IPCFL ;YES, CLEAR FLAG BITS
MOVE T1,[1000,,IPRBUF]
MOVEM T1,MRECVB+.IPCFP ;TRY WORD MODE
MOVEI T1,4 ;AND TRY AGAIN
JRST RERECV]
MOVEM T1,ASSOCV#
LDB T1,[POINT 3,MRECVB+.IPCFL,32] ;WHO IS THIS FROM?
JUMPE T1,IPRUSR ;FROM SOME USER
;HOPEFULLY FROM SYS[INFO]
SYSINF: LDB T1,[POINT 6,MRECVB+.IPCFL,29]
JUMPE T1,IPCFRF ;NO PROBLEM? LEAVE
CAIE T1,.IPCKM ;TELLING ME "DEAD PID"?
CALL FATAL ;NO, WE IN TROUBLE
MOVE T1,IPRBUF ;YES, WHICH PID LEFT?
CALL FNDPID ;FIND THE ENTRY FOR IT
JRST IPCFRF ;VERY ODD!
SOS USRCNT ;ABOUT TO BE LESS ONE USER
HLLZS T1,U$NUM(T2)
SETZM U$NAM(T2)
JUMPGE T1,IPCFRF ;WAS IT BOTTOM ENTRY IN LIST?
MOVX T1,U%LAST ;YES
IORM T1,U$NUM-U$LEN(T2) ;MAKE NEXT ONE UP BOTTOM
JRST IPCFRF ;SIGNOUT DONE
IPRUSR: MOVE T1,MRECVB+.IPCFS ;WHICH PID SENT THIS?
CALL FNDPID
TDZA T3,T3
HRRZ T3,U$NUM(T2)
PUSH P,T3 ;USER # OR 0
PUSH P,T1 ;PID
MOVEI T1,1 ;GET A PAGE FOR TBP QUEUE
CALL GETPGS
POP P,SRCBUF(T2) ;NONZERO: FROM IPCF (PID)
POP P,USRBUF(T2) ;USER # OR 0
MOVSI T1,IPRBUF ;BLT DATA FROM USER IPCF MESSAGE
HRRI T1,DATAST(T2) ;TO QUEUE ENTRY
BLT T1,777(T2)
MOVE T1,T2 ;GO INSERT INTO QUEUE
CALL INSTBP
IPCFRF: SKIPN ASSOCV
JRST IN1RET
JRST IPREAD
TIMOUT: SKIPN TBAQUE ;ANYTHING TO DO?
DEBRK% ;NO, JUST LEAVE
MOVEM T1,INT1AC+1
MOVE T1,[2,,INT1AC+2]
BLT T1,INT1AC+17 ;SAVE ALL AC'S
MOVE P,[-50,,STACK1-1]
IFN FTLOGF,<
PUSHJ P,BLAT
[ASCIZ/ <int-TIMOUT> /] >
MOVEI T1,TIMOUT
MOVEM T1,ATINTR
TIMAGA: GTAD%
MOVE T6,T1
MOVEI T1,TBAQUE ;SCAN TBA QUEUE
SKIPN T2,TBAQUE
JRST IN1RET ;IF NOTHING TO DO, LEAVE
TIMSCN: CAML T6,TIMBUF(T2) ;IS THIS BUFFER DUE?
JRST OVERDU
NOTYET: MOVE T1,T2
SKIPE T2,NXTBUF(T1)
JRST TIMSCN
JRST IN1RET
OVERDU: MOVEM T2,OVRBUF# ;THIS BUFFER IS OVERDUE
MOVE T3,NXTBUF(T2)
MOVEM T3,NXTBUF(T1) ;REMOVE FROM QUEUE
SETZM NXTBUF(T2)
AOS T5,ERRBUF(T2) ;INCR FAILED COUNT
DMOVE T1,DATAST+.BXDAD(T2) ;WHO WAS THIS TO?
SKIPA T4,EADQUE ;FIND IT IN QUEUE OF NODES
NODSTA: MOVE T4,NXTBUF(T4)
JUMPE T4,LSTNDE ;NEVER FOUND IT
CAMN T1,DATAST+$NDSAD(T4) ;EADDRESS MATCH?
CAME T2,DATAST+$NDSAD+1(T4) ;..?
JRST NODSTA ;NO, ADVANCE THROUGH NODE QUEUE
MOVE T6,DATAST+$NDFLG(T4) ;HAVE WE DECLARED IT DEAD?
TXNE T6,ND%OFF ;..?
JRST LSTNDE ;YES
IMULI T5,TIMWAT ;NO, HOW LONG HAVE WE WAITED?
CAIG T5,^D167 ;OVER 40+ SECS?
JRST RESEND ;NO, TRY AGAIN
IFN ftlogf,<
PUSHJ P,BLAT
[ASCIZ/
Declaring node dead/]
>
AOS NI.DND ;COUNT HOW OFTEN THIS HAPPENS
MOVX T1,ND%OFF ;NODE SILENT FOR TOO LONG
IORM T1,DATAST+$NDFLG(T4) ;DECLARE IT DEAD
LSTNDE: MOVEM T4,NODNOR# ;NODE ENTRY ADDRESS OR 0
MOVE T1,OVRBUF ;MSG THAT WAS NEVER ANSWERED
LDB T6,[POINT 16,DATAST+.BXBMX+$SUSR(T1),31] ;WHO CREATED IT?
JUMPE T6,NOCARE ;I DID, NO ONE NEEDS TO KNOW
MOVEI T1,2 ;GET 2 PAGES FOR IPCF SEND
CALL GETPGS
MOVEM T2,LIRTMP#
HRROI T1,-5 ;IPCF MSG TYPE 5, NODE NOT RESPONDING
MOVEM T1,1000+I$CMD(T2) ;2ND PAGE HAS MESSAGE
MOVE T3,OVRBUF
DMOVE T3,DATAST+.BXDAD(T3)
DMOVEM T3,1000+I$ARG(T2)
SETZM 1000+I$ARG+2(T2)
SKIPE T1,NODNOR ;DO WE KNOW THE NODE?
SKIPN DATAST+$NDNAM(T1) ;DO WE HAVE THE NAME?
JRST NDENNM ;CAN'T GIVE NODENAME
HRROI T1,DATAST+$NDNAM(T1)
HRROI T2,1000+I$ARG+3(T2)
CALL CSTR ;COPY STRING IN
NDENNM: MOVE T2,T6 ;GET PID FOR USER#
CALL FNDUSN ;RET T1/PID OR 0
MOVE T2,LIRTMP ;2 PAGE BUFFER FOR IPCF SENDER
JUMPE T1,NOSNNA
CALL MSGUSR ;SEND IT AND DELETE BUFFER
JRST NOCARE
NOSNNA: MOVE T1,T2
CALL RELPGS
NOCARE: MOVE T1,OVRBUF
CALL RELPGS
JRST TIMAGA ;OK, GO SCAN AGAIN
RESEND: IFN ftlogf,<
PUSHJ P,BLAT
[ASCIZ/
TIMOUT resend --/]
>
AOS NI.SAG
MOVE T2,OVRBUF ;WE NEED TO RESEND
DMOVE T4,DATAST+.BXDAD(T2) ;ADDRESS IN T4,5
MOVEI T3,NIINTB ;BLOCK TO USE IN T3
MOVEM T2,RESTMP#
CALL SNDNIM ;T2 HAS PAGE, SEND NI MSG AGAIN
JRST TIMAGA ;OK, RESTART TBA SCAN
;HERE ON A NI RECEIVED INTERRUPT
; TAKE THE RECEIVED PACKET AND DECIDE WHAT TO DO WITH IT. GENERALLY,
; IT IS EITHER A REQUEST (AND GETS PUT ON THE TBP QUEUE) OR AN ACKNOWLEDGEMENT
; TO A REQUEST (AND CAUSES THE ORIGINAL BUFFER TO BE REMOVED FROM THE TBA QUEUE)
NIRECV: MOVEM T1,INT1AC+1
MOVE T1,[2,,INT1AC+2]
BLT T1,INT1AC+17 ;SAVE ALL AC'S
MOVE P,[-50,,STACK1-1]
IFN FTLOGF,<
PUSHJ P,BLAT
[ASCIZ/ <int-NIRECV> /] >
MOVEI T1,NIRECV
MOVEM T1,ATINTR
MOVX T1,EI%BLK
ANDCAM T1,NIINTB+.EIFLG
NIRECA: MOVE T1,TBRCNT ;MAKE SURE WE HAVE AT LEAST..
POSTBF: CAIL T1,6 ;6 POSTED BUFFERS NOW
JRST FINFIL ;WE DO
MOVEI T1,1 ;WE DONT, POST A NEW RECEIVING BUFFER
POSTIN: CALL GETPGS
MOVEI T3,DATAST(T2)
MOVEI T1,(T3)
HRLI T1,BXBFFR ;SET UP TO COPY BX BLOCK INTO PLACE
BLT T1,.BXBMX-1(T3)
MOVEI T4,.BXBMX(T3) ;POINT TO DATA PORTION
HRLI T4,(POINT 8)
MOVEM T4,.BXBFA(T3)
MOVEM T2,.BXBID(T3) ;BUFFER IDENT IS ADDRESS OF PAGE
MOVEM T3,NIINTB+.EIBCP
MOVX T1,.EIRCV
HRRM T1,NIINTB+.EIFCN
MOVEI T1,NIINTB
NI% ;POST THAT BUFFER
ERCAL FATAL
MOVE T1,TBRQUE ;PUT ON TBR QUEUE
MOVEM T1,NXTBUF(T2)
MOVEM T2,TBRQUE
AOS T1,TBRCNT
JRST POSTBF
FINFIL: AOS T1,RECVCT ;HOW MANY TIMES CALLED?
CAIG T1,1 ;FIRST TIME IS JUST AN INIT RUN..
JRST IN1RET ;TO POST LOTS OF RECEIVE BUFFERS.
MOVE T1,[BXBFFR,,BXREAD] ;OK, TIME TO READ RECEIVED BUFFER
BLT T1,BXREAD+.BXBMX-1
MOVX T3,.EIRRQ
HRRM T3,NIINTB+.EIFCN
MOVEI T3,BXREAD
MOVEM T3,NIINTB+.EIBCP ;SET UP READ RECEIVE QUEUE
MOVEI T1,NIINTB
NI% ;TELL IT WE'LL HANDLE BUFFER NOW
ERCAL FATAL
MOVE T2,BXREAD+.BXBFA
ANDI T2,777000
CAIN T2,0
STOP2: JRST NIRMOR ;GOT NOTHING
MOVEM T2,CURRCV ;STORE FOR LATER USE
HRRZ T1,CREBUF(T2)
CAIE T1,POSTIN
STOP6: CALL FATAL
CAME T2,BXREAD+.BXBID
STOP5: CALL FATAL
AOS NI.RCV ;INCR # RECEIVED
MOVEI T1,TBRQUE
MOVE T3,TBRQUE
REMRCV: CAMN T3,T2
JRST DELPSL
MOVE T1,T3
SKIPE T3,NXTBUF(T3)
JRST REMRCV
CALL FATAL
DELPSL: MOVE T4,NXTBUF(T3)
MOVEM T4,NXTBUF(T1)
SETZM NXTBUF(T2)
SOS TBRCNT
HRRZ T1,BXREAD+.BXSTA ;NOW SEE IF GOOD
JUMPN T1,DMPRCV ;ERROR, DUMP IT
MOVSI T1,BXREAD ;COPY BX INFO INTO PROPER PLACE IN PAGE
HRRI T1,DATAST(T2)
BLT T1,DATAST+.BXBMX-1(T2)
MOVEI T3,DATAST(T2)
MOVE T4,.BXBFA(T3) ;FETCH PROPER POINTER TO DATA
IBP T4
IBP T4 ;SKIP NULL BYTES
ILDB T5,T4
LSH T5,8
ILDB T6,T4
ADDI T5,$ARGS*4(T6)
CAILE T5,^D1500 ;POSSIBLE?
JRST DMPRCV ;NO, DUMP IT
MOVE T1,.BXBFA(T3)
MOVE T7,[POINT 8,.BXBMX(T3)]
FIXRCV: ILDB T6,T1
IDPB T6,T7
SOJG T5,FIXRCV
MOVEI T4,.BXBMX(T3)
LDB T1,[POINT 8,$TYP(T4),23] ;GET MESSAGE TYPE
CAILE T1,.SCVMX ;LEGAL?
JRST DMPRCV ;NO, TOSS
IFN ftlogf,<
PUSHJ P,BLAT
[ASCIZ/
RCV type /]
PUSH P,T3
MOVE T2,T1
PUSHJ P,OCTLOG
PUSHJ P,BLAT
[ASCIZ/, n=/]
MOVE T2,$NUM(T4)
LSH T2,-4
PUSHJ P,OCTLOG
MOVE T2,CURRCV
PUSHJ P,BLAT
[ASCIZ/ @/]
MOVE T2,CURRCV
PUSHJ P,OCTLOG
POP P,T3
>
JRST @[EXP RCVACK, RCVCMD, RCVREQ](T1)
;JUMP WITH T3 POINTING TO BX, T4 TO DATA BLOCK
RCVACK: AOS NI.RAC
MOVEI T2,TBAQUE ;SET UP TO SCAN TBA QUEUE
JRST NOTMTA ;START AT LOOP BOTTOM
SCNTBA: MOVE T5,DATAST+.BXBMX+$NUM(T2) ;FETCH MSG# IN QUEUE
CAME T5,$NUM(T4) ;MATCH?
JRST NOTMTA ;NO, CAN'T BE RIGHT ENTRY
DMOVE T5,DATAST+.BXDAD(T2) ;WHERE WAS THIS ENTRY SENT TO
CAMN T5,.BXSAD(T3) ;SAME AS WHERE THIS CAME FROM?
CAME T6,.BXSAD+1(T3) ;..?
JRST NOTMTA ;NO, FALSE ALARM.
MOVE T5,NXTBUF(T2) ;MATCH! REMOVE THE ENTRY
MOVEM T5,NXTBUF(T1) ;..
MOVE T1,T2 ;AND DELETE IT
CALL RELPGS
JRST DMPRCV ;TOSS MESSAGE TOO
NOTMTA: MOVE T1,T2 ;DIDN'T MATCH, ADVANCE TO NEXT
SKIPE T2,NXTBUF(T2) ;..
JRST SCNTBA ;AND GO AGAIN
;HERE TO TOSS INCOMING MESSAGE IF IT'S SERVED IT'S PURPOSE (LIKE AN ACK)
DMPRCV: MOVE T1,CURRCV ;GET JUST-RECEIVED MSG
CALL RELPGS ;AND FREE IT
NIRMOR: MOVE T1,NIINTB+.EIFLG
TXNN T1,EI%RBA
JRST IN1RET ;AND DONE
JRST NIRECA
RCVREQ: JRST DMPRCV ;FOR NOW
;RECEIVE A REQUEST. ACK IT, AND QUEUE IT IF IT ISN'T A DUP
RCVCMD: MOVE T1,CURRCV
SETZM SRCBUF(T1) ;BUFFER IS FROM NI
LDB T2,[POINT 8,DATAST+.BXBMX+$TYP(T1),31]
TXNE T2,MS%NOA ;NO ACK REQUESTED?
JRST NOACKS ;CORRECT - AND ALWAYS TBP IT
MOVEI T1,1
CALL GETPGS
MOVE T1,CURRCV
DMOVE T4,DATAST+.BXSAD(T1)
MOVSI T1,DATAST+.BXBMX(T1)
HRRI T1,DATAST+.BXBMX(T2)
BLT T1,DATAST+.BXBMX+MSGLEN/4(T2) ;GIVE MESSAGE BACK
SETZ T1,
DPB T1,[POINT 8,DATAST+.BXBMX+$TYP(T2),23] ;CLEAR ACK FIELD
MOVEI T3,NIINTB
CALL SNDNIM
NOACKS: MOVE T3,CURRCV
TXO F,F.TBPA ;ASSUME NOT A DUP FOR THE MOMENT
SKIPN T1,DATAST+.BXBMX+$NUM(T3) ;FETCH MSG#
JRST SCNFIN ;0, THIS IS SERVER SIGNON
SKIPN T2,TBPQUE ;SEARCH ONLY SCAN
JRST SCNFIN
MLTRCS: SKIPE SRCBUF(T2) ;AN NI BUFFER?
JRST NOTMTP ;NO, CANT BE A DUP NI BUFFER
DMOVE T5,DATAST+.BXSAD(T2) ;GET SENDER'S ADDRESS OF Q'D MSG
CAMN T5,DATAST+.BXSAD(T3) ;SAME ADDRESS?
CAME T6,DATAST+.BXSAD+1(T3) ;..?
JRST NOTMTP ;NO, FALSE ALARM
CAME T1,DATAST+.BXBMX+$NUM(T2) ;MATCH?
JRST NOTMTP ;NO, KEEP SCANNING TBP
TXZ F,F.TBPA ;YES - FLAG A DUP
JRST SCNFIN ;AND LOOK FOR NODE
NOTMTP: SKIPE T2,NXTBUF(T2)
JRST MLTRCS
SCNFIN: SKIPA T2,EADQUE
SCNNNT: MOVE T2,NXTBUF(T2)
JUMPE T2,ADDNOD ;NOT A KNOWN NODE. ADD IT IN
SCNNOD: DMOVE T5,DATAST+.BXSAD(T3) ;FETCH MSG SOURCE ADDR
CAMN T5,DATAST+$NDSAD(T2)
CAME T6,DATAST+$NDSAD+1(T2) ;MATCH THIS NODE?
JRST SCNNNT ;NO, CHECK NEXT
SETZM DATAST+$NDFLG(T2) ;NODE IS ONLINE
JUMPE T1,NEWSTT ;IF SIGNON MSG, SKIP THE REST
TXNN F,F.TBPA ;DO WE KNOW IT'S A DUP MSG IN TBP?
JRST TBPSET ;YES, NEEDN'T LOOK HERE
MOVSI T6,-FINLEN
HRRI T6,DATAST+$NDCMD(T2)
SCNFNL: CAMN T1,(T6)
JRST ALRINQ
AOBJN T6,SCNFNL
JRST NEWSTT
ADDNOD: DMOVE T5,DATAST+.BXSAD(T3) ;GET SAD ADDRESS
MOVEI T1,1
CALL GETPGS
DMOVEM T5,DATAST+$NDSAD(T2) ;STORE ADDRESS
MOVE T1,EADQUE
MOVEM T1,NXTBUF(T2)
MOVEM T2,EADQUE ;ADD TO TOP OF QUEUE (EASIEST)
NEWSTT: MOVE T1,CURRCV
MOVEM T2,NODBUF(T1)
ADDTBP: TXOA F,F.TBPA
ALRINQ: TXZ F,F.TBPA
TBPSET: MOVE T1,CURRCV
TXZE F,F.TBPA ;INSERT INTO TBP OR TOSS?
JRST INSCAL
IFN ftlogf,<
PUSHJ P,BLAT
[ASCIZ/
DUP msg toss, n=/]
MOVE T2,DATAST+.BXBMX+$NUM(T1)
LSH T2,-4
PUSHJ P,OCTLOG
PUSHJ P,BLAT
[ASCIZ/ @/]
MOVE T2,CURRCV
PUSHJ P,OCTLOG
>
CALL RELPGS ;IT WAS A DUP, TOSS IT
AOS NI.RDP
JRST NIRMOR ;AND DONE
INSCAL: CALL INSTBP
JRST NIRMOR
INSTBP: MOVEI T2,TBPQUE ;FIND END OF TBP QUEUE
IN2TBP: SKIPN T3,NXTBUF(T2) ;END?
JRST OKADDP ;YES, ADD IT IN
MOVE T2,T3
JRST IN2TBP
OKADDP: MOVEM T1,NXTBUF(T2)
SETZM NXTBUF(T1) ;NEW END
TXO F,F.SKIP
RET
IN1RET: TDZA T1,T1
IN2RET: MOVEI T1,1
IFN FTLOGF,<
PUSHJ P,BLAT
[ASCIZ/ <dbk> /] >
TXNE F,F.WAIT ;WAITING?
TXNN F,F.SKIP ;YES. BREAK OUT
JRST NOBREK ;DON'T BREAK OUT
MOVE T2,@[EXP INT1BK,INT2BK,INT3BK](T1)
TXO T2,PC%USR
MOVEM T2,@[EXP INT1BK,INT2BK,INT3BK](T1)
NOBREK: MOVE T2,[ 3,,INT1AC+3
3,,INT2AC+3
3,,INT3AC+3](T1)
BLT T2,17
DMOVE T1,@[EXP INT1AC+1,INT2AC+1,INT3AC+1](T1)
SETZM ATINTR
DEBRK%
;Support
DIRINT: MOVX T1,.FHSLF
DIR%
AOS INTLCK
RET
EIRINT: SOSL T1,INTLCK
RET
CAME T1,[-1]
CALL FATAL
MOVX T1,.FHSLF
EIR%
RET
NINI: MOVE T4,TSKINP
LDB T4,[POINT 16,DATAST+.BXBMX+$SUSR(T4),31]
CALL SNDSTD
MOVEI T3,NIBLOK
MOVE T6,TSKINP
DMOVE T4,DATAST+.BXSAD(T6)
;JRST SNDNIM
;This sends the message, blocking until sent
;T2/ buffer, with data at DATAST+.BXBMX(T2) set up
;T3/ NI% block to use
;T4,5/ Ethernet address to send to
SNDNIM: MOVEI T1,.BXBMX ;CREATE THE BX BLOCK
MOVEM T1,DATAST+.BXLEN(T2)
DMOVEM T4,DATAST+.BXDAD(T2)
MOVEI T1,DATAST+.BXBMX(T2)
HRLI T1,(POINT 8)
MOVEM T1,DATAST+.BXBFA(T2)
LDB T1,[POINT 16,DATAST+.BXBMX+$SIZE(T2),31] ;GET SIZE
ADDI T1,$ARGS*4
MOVEM T1,DATAST+.BXBSZ(T2)
MOVX T1,.EIXMT ;FUNCTION IS TRANSMIT
HRRM T1,.EIFCN(T3)
MOVX T1,EI%BLK
IORM T1,.EIFLG(T3) ;REQUEST BLOCKING
MOVEI T1,DATAST(T2) ;POINT TO BX BLOCK
MOVEM T1,.EIBCP(T3) ;NI BLOCK POINTS TO BX
CALL DIRINT
SETZM TIMBUF(T2) ;NO TIMESTAMP YET
LDB T1,[POINT 16,DATAST+.BXBMX+$TYP(T2),31] ;GET TYPE AND FLAGS
TXNE T1,MS%NOA ;NO ACK REQUESTED?
JRST NOACKE
TRNN T1,377_8 ;OR IS TYPE "ACK"?
AOSA NI.SAC ;YES, RECORD AN ACK
SKIPA T1,[.INFIN] ;NO, PICK UP FAR-FUTURE DATE AND SKIP
JRST NOACKE ;YES, JUMP OVER ACK EXPECTATION CODE
MOVEM T1,TIMBUF(T2) ;FLAG AS NEEDING TIMESTAMP AND ACK
MOVE T4,TBAQUE ;ADD TO "TO BE ACK'D" QUEUE
MOVEM T4,NXTBUF(T2)
MOVEM T2,TBAQUE
NOACKE: MOVEM T2,SENTMP#
MOVEI T1,(T3)
NI% ;FIRE!
ERCAL FATAL
AOS NI.SND ;COUNT ANOTHER SENT
IFN ftlogf,<
PUSHJ P,BLAT
[ASCIZ/
snd typ /]
PUSH P,T2
LDB T2,[POINT 8,DATAST+.BXBMX+$TYP(T2),23]
PUSHJ P,OCTLOG
PUSHJ P,BLAT
[ASCIZ/, n=/]
MOVE T2,(P)
MOVE T2,DATAST+.BXBMX+$NUM(T2)
LSH T2,-4
PUSHJ P,OCTLOG
PUSHJ P,BLAT
[ASCIZ/ @/]
MOVE T2,(P)
PUSHJ P,OCTLOG
POP P,T2
>
HRRZ T1,DATAST+.BXSTA(T2) ;FETCH RESULT
JUMPE T1,SENDOK ;IS IT OK?
CAIE T1,NIEOPN ;NO. SOME ERRORS ARE FATAL
CAIN T1,NIESHT
JRST CBLDIE ;DEAD CABLE
CAIN T1,NIECCF
JRST CBLDIE
SENDOK: SKIPN TIMBUF(T2) ;EXPECT AN ACK SOMETIME?
JRST GODROP ;NO, GO DROP BUFFER
TIMENT: MOVE T2,SENTMP ;GET BUFFER TO TIMESTAMP
GTAD% ;GET "NOW"
ADDI T1,TIMENT
MOVEM T1,TIMBUF(T2) ;SAY WHEN BUFFER IS DUE
AOS T2,T1 ;ADD A TICK AND MOVE TO T2
MOVEI T3,TIMINT ;CHANNEL TO INTERRUPT ON
MOVE T1,[.FHSLF,,.TIMDT] ;INTERRUPT AT GIVEN TIME
TIMER% ;FIRE
ERJMPR [CAIE T1,TIMX6 ;CLOCK CHANGE OR SLOW SYSTEM??
CALL FATAL ;NO, PROBABLY CANT SET CLOCK
JRST TIMENT] ;TRY AGAIN
JRST UNLOCK
GODROP: MOVE T1,T2
CALL RELPGS ;MSG NEEDS NO ACK, SO DON'T SAVE IT
UNLOCK: CALL EIRINT
RET
CBLDIE: SETOM REASON#
CALL FATAL ;NO RETURN
;T1/# of bytes of data
;T2/buffer
;T3/ CMD
;T4/ dest user #
;This assumes type 1 msg. It helps build the msg block.
SNDSTD: DMOVE T5,OURSAD ;LOAD OUR (SENDER'S) ADDRESS INTO..
DMOVEM T5,DATAST+.BXBMX+$SAD(T2) ;THE MESSAGE
LSH T1,4 ;ADJUST FOR 8 BIT FORMAT
MOVEM T1,DATAST+.BXBMX+$SIZE(T2)
AOS T1,MSGID# ;UNIQUE MSG ID
LSH T1,4
MOVEM T1,DATAST+.BXBMX+$NUM(T2)
LSH T3,8+8+8+4 ;PUT CMD IN RIGHT BYTE
MOVEM T3,DATAST+.BXBMX+$CMD(T2)
LSH T4,8+8+4 ;JUSTIFY DEST USER
ADDI T4,1*400*20 ;ADD IN TYPE CODE (1)
MOVEM T4,DATAST+.BXBMX+$TYP(T2)
RET
;Called when an IPCF message will create a NI request. Copies pertinent
; data into msg block and AC's T4,5
IPRSTD: MOVE T3,USRBUF(T1)
DPB T3,[POINT 16,DATAST+.BXBMX+$SUSR(T2),31] ;SET USER NUMBER
MOVE T3,DATAST+I$NUM(T1)
DPB T3,[POINT 24,DATAST+.BXBMX+$CMD(T2),31] ;AND TRANSACTION NUMBER
DMOVE T4,DATAST+I$ARG(T1) ;LOFT SAD FROM IPCF MESSAGE
RET
;HERE WITH PID IN T1, RETURNS +2 WITH T2 POINTING TO USER BLOCK, OR
; +1 WITH T1 STILL CONTAINING PID
FNDPID: MOVEI T2,USRLST
FN2PID: CAMN T1,U$PID(T2)
JRST CPOPJ1
SKIPGE U$NUM(T2)
RET
ADDI T2,U$LEN
JRST FN2PID
;Call with T2/ user#
;Return with T1/ PID or 0 if none
FNDUSN: MOVEI T3,USRLST
FN2USN: HRRZ T4,U$NUM(T3)
CAIN T4,(T2)
JRST MATNUM
ADDI T3,U$LEN
SKIPL U$NUM-U$LEN(T3)
JRST FN2USN
TDZA T1,T1 ;NO MATCH, RETURN 0
MATNUM: MOVE T1,U$PID(T3)
RET
;T1/ PID
;T2/ ADDR OF 2 PAGE BUFFER, 2ND PAGE HAS MSG, FIRST IS FOR ME
MSGUSR: MOVX T3,IP%CFP+IP%CFV
MOVEM T3,DATAST+.IPCFL(T2)
MOVE T3,SRVPID
MOVEM T3,DATAST+.IPCFS(T2)
MOVSI T3,1000
MOVEI T4,1000(T2)
LSH T4,-9
ADD T3,T4
MOVEM T3,DATAST+.IPCFP(T2)
MOVEI T2,DATAST(T2)
GOTPDS: MOVEM T1,.IPCFR(T2)
MOVEI T1,4
MSEND%
ERJMPS .+1
KILSBF: MOVEI T1,-DATAST(T2)
JRST RELPGS
;T1/ source (default is 7bit)
;T2/ dest (default is 8bit)
;return T4/ count of bytes copied (trailing null not copied or counted)
CPYSTR: TLCE T1,-1
TLCN T1,-1
HRLI T1,(POINT 7)
TLCE T2,-1
TLCN T2,-1
HRLI T2,(POINT 8)
SETZ T4,
CPYST1: ILDB T3,T1
JUMPE T3,CPOPJ
IDPB T3,T2
AOJA T4,CPYST1
BLAT: SKIPN LOGJFN
JRST BLTRET
PUSH P,T4
PUSH P,T3
PUSH P,T2
PUSH P,T1
MOVE T1,LOGJFN
HRRZ T2,-4(P)
MOVE T2,(T2)
TLCE T2,-1
TLCN T2,-1
HRLI T2,(POINT 7)
SETZ T3,
SOUT%
POP P,T1
POP P,T2
POP P,T3
POP P,T4
BLTRET: AOS (P)
POPJ P,
CPOPJ1: AOS (P)
CPOPJ: RET
;Here we set up the values we need to make the memory manager routines run
; quickly. MAPEND is the offset from MAPFRE to the last word in the map.
; LBIINI is the value that last word is set to to indicate what pages are
; available in that last set of 36. The last word always flags at least
; one pair of pages (or it wouldn't be needed).
MAPEND=NUMPAG/^D36 ;OFFSET TO LAST WORD IN MAP
%%C==<NUMPAG-<<NUMPAG/^D36>*^D36>> ;NUMBER OF BITS USED IN LAST WORD -1
LBIINI==1B0 ;BUILD VALUE TO INIT LAST WORD WITH
REPEAT %%C,< LBIINI== <LBIINI_<-1>>!<1B0> > ;..
;Call here to set up the memory manager.
SETPGS: SETOM MAPFRE
MOVE T1,[MAPFRE,,MAPFRE+1]
BLT T1,MAPFRE+MAPEND-1 ;MARK PAGES FREE SANS LAST SET
MOVX T1,LBIINI ;VALUE LAST WORD GETS
MOVEM T1,MAPFRE+MAPEND;INIT LAST SET SPECIALLY
SETO T1,
MOVE T2,[.FHSLF,,FRESPC]
MOVE T3,[PM%CNT!NUMPAG]
PMAP%
ERJMPS .+1
RET
;Here to get a buffer (a set of contiguous pages) for any purpose.
;Enter with T1/ # of pages needed. Return with T2/ address of buffer
GETPGS: MOVE T2,T1
CALL DIRINT
MOVEM T2,GETTMP#
GETPGA: SETZ T1,
GETPG1: SKIPE MAPFRE(T1)
JRST GETSCN
CAIGE T1,MAPEND ;AT END OF MAP?
AOJA T1,GETPG1 ;NO, KEEP LOOKING
JRST NOMEM ;NO PAGES AVAILABLE
GETSCN: MOVE T2,T1 ;GEN. A BIT POINTER TO FIRST WORD..
ADD T2,[POINT 1,MAPFRE];WITH AN AVAILABLE PAGE
IMULI T1,^D36
MOVEI T3,NUMPAG
SUBI T3,(T1) ;THE NUMBER OF BITS TO CHECK
FNDCLU: SOJL T3,NOMEM ;NO MORE BITS TO CHECK, FAILED
ILDB T1,T2 ;IS THIS PAGE AVAILABLE?
JUMPE T1,FNDCLU ;0 MEANS TAKEN
MOVEM T2,GE2TMP# ;SAVE POINTER TO POSSIBLE CANDIDATE
MOVE T4,GETTMP ;GET NUMBER OF PAGES NEEDED
MEACLU: SOJE T4,GOTCLU ;IF GOT ENOUGH, DONE
SOJL T3,NOMEM ;END OF POSSIBILITIES? DONE.
ILDB T1,T2
JUMPN T1,MEACLU ;IF AVAILABLE, KEEP GOING
JRST FNDCLU ;NOT LONG ENOUGH. KEEP LOOKING.
GOTCLU: SETO T1, ;BACK UP POINTER 1 FOR IDPB
ADJBP T1,GE2TMP
MOVEM T1,GE2TMP
MOVE T2,GETTMP ;# OF PAGES WANTED
IDPB T4,T1 ;WRITE 0'S
SOJG T2,.-1 ;..
MOVEI T2,FRESPC+NUMPAG;CAL. WORD ADDRESS
SUBI T2,(T3)
MOVE T3,GETTMP
SUBI T2,(T3)
LSH T2,9
SKIPLE CREBUF(T2)
CALL FATAL ;ALREADY TAKEN AND NOT DELETED??
PUSH P,T1
PUSH P,T3
MOVEI T1,3
GETCKA: MOVE T3,[EXP TBPQUE, TBAQUE, EADQUE,TBRQUE](T1)
GETCHK: SKIPN T3,NXTBUF(T3)
JRST GETCH2
CAMN T2,T3
CALL FATAL
JRST GETCHK
GETCH2: SOJGE T1,GETCKA
POP P,T3
POP P,T1
MOVE T4,GE2TMP ;T3/ SIZE AND T4/ POINTER INTO MAPFRE
DMOVEM T3,SIZBUF(T2) ;STORE INTO SIZBUF AND PNTBUF
SETZM NXTBUF(T2) ;NO NEXT YET
SETZM TIMBUF(T2) ;CLEAR BUFFER OUT TOO
MOVEI T1,TIMBUF(T2) ;POINT TO 1ST WORD
HRLI T1,1(T1) ;AND NEXT WORD WOTH LH
MOVSS T1 ;SWAP TO N,,N+1
LSH T3,9 ;CONVERT PAGES TO WORDS
ADDI T3,-1(T2) ;LAST WORD IN BUFFER
BLT T1,(T3) ;ZERO BUFFER OUT
MOVE T3,(P)
SUBI T3,1
HRRZM T3,CREBUF(T2)
CALL EIRINT
RET
;Enter with word address of buffer to free up in T1
RELPGS:
MOVE T2,T1
MOVE T3,SIZBUF(T1)
RELKIL: SETOM CREBUF(T2)
ADDI T2,1000
SOJG T3,RELKIL
MOVEI T3,3
RELPGN: MOVE T2,[EXP TBRQUE,TBAQUE,EADQUE,TBPQUE](T3)
RELPGX: SKIPN T2,NXTBUF(T2)
JRST RELPGA
CAMN T2,T1
CALL FATAL
JRST RELPGX
RELPGA: SOJGE T3,RELPGN
DMOVE T2,SIZBUF(T1) ;T2/ SIZE AND T3/ POINTER
CAIG T2,0
CALL FATAL
SETOB T1,SIZBUF(T1) ;A SOURCE OF 1'S, AND CLEAR SIZE
RELPGL: IDPB T1,T3
SOJG T2,RELPGL
RET
NOMEM: MOVEI T1,1
MOVEM T1,REASON
FATAL: DMOVEM F,CRSHAC
MOVE F,[2,,CRSHAC+2]
BLT F,CRSHAC+17
MOVE T1,['EISRV?']
SETNM%
SKIPE T1,LOGJFN
CLOSF%
ERJMPS .+1
SETZM LOGJFN
HRROI T1,[ASCIZ/
?EISRV fatal error, PC /]
PSOUT%
POP P,T2
MOVX T1,.PRIOU
MOVEI T2,-1(T2)
CALL OCTOUT
HRROI T1,[ASCIZ/
Shutdown flagged/]
TXNE F,F.SHUT
PSOUT%
HRROI T1,[ASCIZ/
Reason code: /]
PSOUT%
MOVE T2,REASON
CALL DECOUT
HRROI T1,[ASCIZ/
Last Monitor error: /]
PSOUT%
MOVX T1,.PRIOU
HRLOI T2,.FHSLF
SETZ T3,
ERSTR%
JFCL
JFCL
RESET%
HALTF%
JRST ST
OCTOUT: SKIPA T3,[8]
DECOUT: MOVEI T3,^D10
PUSH P,T1
MOVX T1,.PRIOU
NOUT%
ERJMPS .+1
POP P,T1
RET
OCTLOG: SKIPN LOGJFN
POPJ P,
PUSH P,T1
PUSH P,T3
MOVE T1,LOGJFN
MOVEI T3,^D8
NOUT%
ERJMPS .+1
POP P,T3
POP P,T1
POPJ P,
;copy string and back up T2 on exit.
CSTRB: CALL CSTR
SETO T3,
ADJBP T3,T2
MOVE T2,T3
RET
;Back up T2 and do a copy string
APPSTR: SETO T3,
ADJBP T3,T2
MOVE T2,T3 ;DESTINATION BACKED UP BY 1
CSTR: TLCE T1,-1
TLCN T1,-1
HRLI T1,(POINT 7)
TLCE T2,-1
TLCN T2,-1
HRLI T2,(POINT 7)
CSTRA: ILDB T3,T1
IDPB T3,T2
JUMPN T3,CSTRA
RET
MULTI: BYTE(8) 253,"E","I","S","R","V"
MAPFRE: BLOCK NUMPAG/^D36+1 ;MEMORY MANAGEMENT BIT ARRAY
STACK: BLOCK 101
STACK1: BLOCK 51
LEVTAB: INT1BK
INT2BK
INT3BK
CHNTAB: 0
1,,NIRECV
1,,STATCH
1,,TIMOUT
1,,IPCFRV
BLOCK ^D32
INT1BK: BLOCK 2
INT2BK: BLOCK 2
INT3BK: BLOCK 2
INT1AC: BLOCK 20
INT2AC: BLOCK 20
INT3AC: BLOCK 20
CRSHAC: BLOCK 20
NIBLOK: .EIBMX,,.EIOPN
NIPID: EI%PAD ;PADDING
0,,PROTOC ;CHN,,PROTOCOL
BYTE(12) -1,NIRINT,NICINT
0
BXBFFR
BLOCK 2
NIINTB: .EIBMX,,0
EI%PAD
0,,PROTOC
BYTE(12) -1,NIRINT,NICINT
BLOCK 4
BXREAD: .BXBMX
BLOCK .BXBMX
BXBFFR: .BXBMX
0 ;NO NEXT
MSGLEN+6 ;COUNT, BYTES + 6 OVERHEAD
0 ;BP, FILLED IN
0 ;0
0 ;ID
0 ;STATUS
0 ;DEST
0
0 ;SOURCE
0
0
MUTBLK: .MUPIC
0
IPRINT
IPCFSI: IP%CPD+IP%NOA
SRVPID: 0
0
5,,IPSYSI
IPSYSI: .IPCII
0
ASCIZ/EISRV/
BLOCK 2
MRECVB: IP%CFV
BLOCK 2
1000,,IPRPAG
OURNAM: BLOCK 2
MYNAME: BLOCK 2
LLMBLK: BLOCK 30
LCLUSR: BLOCK ^D129
ZERO:
DEEP: 0
RECVCT: 0 ;NUMBER OF CALLS TO NIRECV
CURRCV: 0
TBRQUE: 0 ;QUEUE OF POSTED BUFFERS
TBRCNT: 0 ;COUNT OF POSTED BUFFERS
TBAQUE: 0 ;NO DATAGRAMS TO BE ACK'D
TBPQUE: 0 ;NO TASKS TO BE DONE
EADQUE: 0 ;NODES LIST
USRCNT: 0 ;NO USERS IN
NI.STA:
NI.RCV: 0 ;STATS - messages received
NI.RAC: 0 ;received acks
NI.RDP: 0 ;received duplictaes
NI.SND: 0 ;msgs sent
NI.SAC: 0 ;acks sent
NI.SAG: 0 ;msgs resent
NI.CST: 0 ;times looped waiting for hello response
NI.DND: 0 ;times declared a node dead
NI.HLO: 0 ;number of hellos received
NI.RQN: 0 ;number of times missed a node signon
NISTL=.-NI.STA
ENDZER=.
;KEEP ALL THIS ADJACENT
USRLST: -1
-1
-1
BLOCK U$LEN-3
REALUS: BLOCK U$LEN*MAXUSR
NI.LEN=.-NI.STA+1
IFG NI.LEN-777,<PRINTX ?NI.LEN does not fit on one page>
STRINN: BLOCK 100
TSKTMP: BLOCK 2
MISSED: BLOCK 2
END ST