;<134-TENEX>IMPDV.MAC;361     2-DEC-75 10:31:23    EDIT BY TOMLINSON
;<134-TENEX>IMPDV.MAC;360     2-DEC-75 10:22:37    EDIT BY TOMLINSON
;<134-TENEX>IMPDV.MAC;359    10-NOV-75 13:44:21    EDIT BY ALLEN
; INCREASE IMPNLK TO ^D200
;<134-TENEX>IMPDV.MAC;358    26-OCT-75 11:48:06    EDIT BY TOMLINSON
;<134-TENEX>IMPDV.MAC;357    21-OCT-75 12:38:48    EDIT BY TOMLINSON
; MORE RCTE FIXUPS
;<134-TENEX>IMPDV.MAC;355     9-OCT-75 13:15:48    EDIT BY ALLEN
; MAKE SURE IMIB NOT ON FREELIST IN IMPEIN
;<134-TENEX>IMPDV.MAC;353    24-SEP-75 09:46:23    EDIT BY TOMLINSON
; DEFER OKINT IN NVTCOB 'TIL AFTER SENDING DATA MARK
;<134-TENEX>IMPDV.MAC;352    22-SEP-75 11:46:31    EDIT BY CLEMENTS
; On startup, (IMPRC1), only send RST's to hosts in name table.
;<134-TENEX>IMPDV.MAC;351    19-SEP-75 12:28:44    EDIT BY TOMLINSON
; MORE RCTE BUG FIXES
;<134-TENEX>IMPDV.MAC;350    17-SEP-75 14:55:18    EDIT BY TOMLINSON
;<134-TENEX>IMPDV.MAC;348    17-SEP-75 14:41:56    EDIT BY TOMLINSON
; RCTE BUG FIXES
;<134-TENEX>IMPDV.MAC;344    15-SEP-75 17:12:18    EDIT BY ALLEN
;<134-TENEX>IMPDV.MAC;343    15-SEP-75 16:39:45    EDIT BY ALLEN
; TEMPORARILY NOP'ED NVTCIB
;<134-TENEX>IMPDV.MAC;342    12-SEP-75 15:31:45    EDIT BY ALLEN
; ADD CHECKS TO BE SURE THAT WE NEVER LOCK OR UNLOCK A BUFFER ON THE
; FREELIST
;<TOMLINSON>IMPDV.MAC;1    10-SEP-75 08:34:36    EDIT BY TOMLINSON
; RCTE FIXES
;<134-TENEX>IMPDV.MAC;336     5-SEP-75 15:48:23    EDIT BY ALLEN
; RESTORE ORIGINAL ACTIVATION CRITERIA
;<134-TENEX>IMPDV.MAC;335     5-SEP-75 15:38:54    EDIT BY ALLEN
;<134-TENEX>IMPDV.MAC;334     3-SEP-75 22:01:33    EDIT BY ALLEN
; NEW ACTIVATION LOGIC AND FIX INPUT BUFFER FETCH LOGIC
;<134-TENEX>IMPDV.MAC;333    28-AUG-75 16:32:26    EDIT BY ALLEN
; SLIGHT MOD DUE TO CHANGE IN LOCK-UNLOCK MACROS
;<134-TENEX>IMPDV.MAC;332    19-AUG-75 15:40:48    EDIT BY ALLEN
; REPAIR TO PKQOB TO STORE ACTUAL WORDS IN USE IN HEADER SO
; OUTPUT ROUTINES DON'T TRY TO SEND THE WHOLE BUFFER
;<134-TENEX>IMPDV.MAC;331    14-AUG-75 15:18:49    EDIT BY ALLEN
; ELIMINATE LOCKUP DUE TO RUNNING OUT OF BUFFERS
;<134-TENEX>IMPDV.MAC;330    12-AUG-75 17:07:12    EDIT BY ALLEN
; FIX AT PKMS5 TO KEEP PKMSG FROM GOING NUTS WHEN ASNTBF FAILS
;<134-TENEX>DCAIMP.MAC;9     6-AUG-75 11:19:35    EDIT BY ALLEN
; END INPUT ROUTINE RECORDS ACTUAL COUNT IN BUFFER HEADER
;<134-TENEX>DCAIMP.MAC;8     5-AUG-75 13:57:29    EDIT BY ALLEN
; Various bug fixes to new buffer management
;<134-TENEX>DCAIMP.MAC;7     4-AUG-75 10:46:05    EDIT BY ALLEN
; VARIOUS CHANGES FOR NEW BUFFER MANAGEMENT
;<134-TENEX>IMPDV.MAC;328    11-JUL-75 17:17:33    EDIT BY ALLEN
; MINOR FIX
;<134-TENEX>IMPDV.MAC;327    11-JUL-75 16:12:43    EDIT BY ALLEN
; DELETE CALL IMPKO1 AT PKMSD 4
;<134-TENEX>DCAIMP.MAC;3    11-JUL-75 09:59:54    EDIT BY ALLEN
; PKMSG USES REMAINING SPACE IN CURRENT OUTPUT BUFFER UNLESS
; THIS WOULD CAUSE A CONTROL MESSAGE TO CROSS A NET MESSAGE BOUNDARY.
; PKMSG1 ADDED -- SAME AS PKMSG BUT DOESN'T ATTEMPT TO SEND THE
; CURRENT MESSAGE. CALLED BY NETTCS SO THAT SIZE OF NET MESSAGE
; IS NOW LIMITED ONLY BY AVAILABLE CHARACTERS IN TTY BUFFERS, 
; BY ALLOCATION, OR BY SIZE OF OUTPUT BUFFER, NOT BY SIZE
; OF NETTCS' STACK BUFFER.
;<134-TENEX>IMPDV.MAC;326    15-MAY-75 07:51:23    EDIT BY TOMLINSON
; CHANGE REFERENCES TO NLINES TO NVTHI
;<134-TENEX>IMPDV.MAC;325    21-APR-75 11:34:59    EDIT BY TOMLINSON
; Limit special queues on message basis rather than buffer space
;<134-TENEX>IMPDV.MAC;324    14-APR-75 17:08:59    EDIT BY OPERATOR
; CORRECT INITIALIZATION OF IDVLCK
;<134-TENEX>IMPDV.MAC;323    14-APR-75 15:37:09    EDIT BY ALLEN
; AVOID SMASHING AC1 IN PIE-SLICE VERSION OF LCKID1
;<134-TENEX>IMPDV.MAC;322    11-APR-75 17:08:19    EDIT BY ALLEN
; REPAIRS TO NEW LOCKING STUFF
;<134-TENEX>IMPDV.MAC;319    10-APR-75 22:18:40    EDIT BY ALLEN
; MAKE USE OF NEW SCHEDULING FOR LCKERS
;<134-TENEX>IMPDV.MAC;318     4-APR-75 18:00:19    EDIT BY CLEMENTS
; FIX TO PREVENT UNKNOWN LINK IMPBUGS IF REMOTE CLOSES A
;  SEND SOCKET WHICH HAS AN OUTSTANDING RFNM
;<134-TENEX>IMPDV.MAC;317    12-MAR-75 14:08:45    EDIT BY PLUMMER
; CHANGE SIQCHK TO FLUSH ENTIRE Q IF NOT ACTIVE
;<134-TENEX>IMPDV.MAC;316    27-FEB-75 15:50:47    EDIT BY CLEMENTS
; INCREASE NUMBER OF CHARACTERS PROCESSED IN NETTCS FROM 32 TO 64
; INCREASE SIZE OF PI-LEVEL STACK, DUE TO DEBUG ROUTINES
;<134-TENEX>IMPDV.MAC;315    10-JAN-75 10:32:56    EDIT BY ALLEN
; REPLENISH INPUT BUFFERS IF IMPNFI .LT. 8
;<133-TENEX>IMPDV.MAC;314    24-DEC-74 08:32:56    EDIT BY TOMLINSON
; DISABLE RCTE UNTIL DEBUGGED THOROUGHLY
;<133-TENEX>IMPDV.MAC;313    18-DEC-74 15:40:48    EDIT BY TOMLINSON
;<133-TENEX>IMPDV.MAC;312    17-DEC-74 16:17:00    EDIT BY TOMLINSON
; CAUSE INITIAL SB STRING FOR RCTE
;MISC BUG FIXES TO RCTE
;<133-TENEX>IMPDV.MAC;311    16-DEC-74 15:50:14    EDIT BY TOMLINSON
; TAKE OUT CODE TO TURN ON RCTE IN ASNNVT. CAN'T DO IT BECAUSE NCPLCK IS SET.
;<133-TENEX>IMPDV.MAC;309    13-DEC-74 12:41:16    EDIT BY TOMLINSON
; INITITATE TURN ON OF RCTE AND SUPPRESS GA
;<133-TENEX>IMPDV.MAC;308    13-DEC-74 12:32:18    EDIT BY TOMLINSON
; BUG FIXES TO RCTE
; PKBY1: MOVE SOS IMPLT4 TO AFTER ASNTBF CALL
; UPBRB: CHANGE BUG MSG
; IM8RAS:  ACCOUNT FOR BUFFERS IN CONNECTION QUEUE WHEN RESETTING ALLOC
;<133-TENEX>IMPDV.MAC;306     8-DEC-74 18:28:13    EDIT BY CLEMENTS
; FIX MISSING EXTERN ON SKPRET
;<133-TENEX>IMPDV.MAC;303     3-DEC-74 10:25:14    EDIT BY TOMLINSON
; Added RCTE code
;<133-TENEX>IMPDV.MAC;300    29-OCT-74 08:22:03    EDIT BY TOMLINSON
; SET UP STACK FOR BUG(IMP) AT IMIMTL
;<133-TENEX>IMPDV.MAC;299     1-OCT-74 13:16:36    EDIT BY TOMLINSON
; REMOVE SUPERFLUOUS INSTRINCTION AT IMPRAP+2
;<133-TENEX>IMPDV.MAC;298    25-SEP-74 12:47:56    EDIT BY TOMLINSON
; (1) MARK HOST USING NEW PROTOCOL AS UNDERSTANDING SAME.
; (2) RELEASE BOTH HALVES OF AN NVT WHEN RECEIVING NXS/R
; (3) FIX BUGIMH ARG IN BADLKS/R
; (4) BUGCHK IF IMPLT4 IS OVERDECREMENTED IN UPBRB
;<133-TENEX>IMPDV.MAC;297    22-AUG-74 16:28:54    EDIT BY CLEMENTS
;<TENEX-132>IMPDV.MAC;296    22-JUN-74 13:07:40    EDIT BY TOMLINSON
; NOP IMPCHK IF IMPRDY = 0

	SEARCH	PROLOG
IFDEF IMPCHN,<	; This whole file is included only if imp exists
	TITLE	IMPDV
	SEARCH	STENEX

; Accumulators

IMPUN==5		; Ac for 'unit'

; Parameters

IMPNLK==^D200		; Size of link table
IMP8XS==40		; Size of irreg mes buffer
NSQ==8			; Size of special q tables
SIQMAX==6		; Maximum messages allowed on siq
NIMSTK==20		; Pi level stack
IMPLBT==400/^D36+1	; Size of bit tables for host states
CLINK==0		; Control link
FLINK==2		; First link to use
LLINK==^D72		; Last link to use
RFNTMO==^D20000		; Rfnm time-out interval (three of these)
UPROBI==^D300000	; Interval at which to probe every up host
UPROBT==^D60000		; Time to spend probing every down host
SIQTM0==^D30000		; Special queue time-out interval
NEGTM0==^D30000		; Negotiation time-out (between 1 & 2 of these)

; NVT special characters

IACCH==377		; Initiate command
DNTCH==376		; DON'T
DOCH==375		; DO
WNTCH==374		; WON'T
WILCH==373		; WILL
SBCH==372		; SB beginning of sub negotiation
GACH==371		; GA go ahead
ELCH==370		; EL erase line
ECCH==367		; EC erase character
AYTCH==366		; AYT are you there?
AOCH==365		; AO abort output
IPCH==364		; IP interrupt process
BRKCH==363		; BREAK
DMCH==362		; DM data mark
NOPCH==361		; NOP
SECH==360		; SE end of subnegotiation

; Nvt option definitions

BINOPT==0		; Binary
ECHOPT==1		; Echo
RCNOPT==2		; Reconnection
SGAOPT==3		; Suppress ga
NAMOPT==4		; Negotiate message size
STSOPT==5		; Status
TMKOPT==6		; Timing mark option
RCTOPT==7		; RCTE option
WILOPT==10		; Offset for requests
MAXOPT==^D18		; Only 1 half word of option bits

; Bits in ttnetw

NVTCRP==1		; Bit in ttnetw -- last char out was cr
IMPTB2==2		; Bit in ttnetw, last char in was cr
NVTGAB==4		; Bit in ttnetw -- suppress go-ahead
			; Bits 12-14 used for nvtstp
NEGTMO==100		; Negotiation time-out started
NEWNVB==200		; New style nvt
NVTRCS==1000		; RCTE CHAAGE IN STATE
NVTWKS==2000		; RCTE WAKEUP SEEN

; The following nvt states are stored in ttnetw bits 12-14 (nvtstp)

DFRWIL==1		; Deferred will
DFRWNT==2		; Deferred wont
DFRDO==3		; Deferred do
DFRDNT==4		; Deferred dont
DFRIAC==5		; Deferred iac

; Imp message leader bits

IMPHIP==1B0		; Hi priority imp msg leader bit
FRMIMP==1B1		; From imp

; Bits in implt2

RFNMC=3B1		; Rfnm outstanding (2 bit count)
LTDF=1B2		; 'done' flag
HIPFLG=1B3		; High priority connection
ILCKB==1B4		; Connection locked (no transmissions)
RXMTF==1B5		; Retransmission after time-out
RARF==1B6		; Rar expected
RARRF==1B7		; Send ras whe no rfnm's out

; Cono-coni bits

IMP=550

IMPINB==1B32		; Input word ready
IMPOUB==1B28		; Ready for next output word
IMPEIB==1B24		; End of input
IMPGEB==1B23		; Clear eib
IMPEOB==1B22		; End of output
IMPSTO==1B21		; Stop output

IMPIOF==10B27+10		; E of cono to clear input pi asmt
IMPION==<10+IMPCHN>B27+<10+IMPCHN> ; E of cono to set input pi asmt
IMPOOF==10B31			; E of cono to clear output assmnt
IMPOON==<10+IMPCHN>B31		; E of cono to set output pi asmt

; Pointers to various fields

PTNETI:	POINT 9,TTNETW(2),35	; Input unit
PTNETO:	POINT 9,TTNETW(2),26	; Output unit
PTINTC:	POINT 3,TTNETW(2),5	; Count, sync-ins
NVTSTP:	POINT 3,TTNETW(2),14	; Current nvt state
PBRCNT:	POINT 9,TTBRKC(2),8	; OUTSTANDING BREAKS COUNT
MAXBRC==777
IMPLBS:	POINT 8,IMPLT2(1),17	; Connection byte size
LTHOST:	POINT 8,IMPLT1(1),27	; Foreign host
LTLINK:	POINT 8,IMPLT1(1),35	; Link

MAXWPM:	400	; Max wds/input msg = (8000/32) + ovhd + slop =
		; 250 + 3 + 3 = 256 = 400(8)

; Following two are a getab table - don't separate

NLHOST:	LHOSTN	; All references to lhostn should be to this cell,
		; So it can be patched if needed.
NVTPTR:	XWD -NNVTLN,NVTLO	; -number of nvt's,,first nvt

; End of getab group

; Linkage into impdv

INTERN	IMPBEG,IMPNLK,IMPLBT,CHKNET,NVTDOB,NVTCOB,NVTPAR,NTTCSO,NETCAP
INTERN	IMPHLT,NVTRCC
INTERN	NVTCHO,NVTXCR,NVTXGA,NVTMOD
INTERN IMPSV,IMPCHK,IMPOPL,IMPCLL,IMPABL,IMPSYN,IMPRTS,IMPSTR,IMPCLS,IMPALL
INTERN ASNNVT,NVTDET,TTNETW
INTERN	.ASNSQ,.RELSQ,.SNDIM,.RCVIM
INTERN IMPRST,IMPRRP,IMSRST,IMPERR,IMPINR,IMPINS
INTERN HSTDED,IMPBG0,NTTRC3
INTERN IMPSDB,PKBYT,PKCHK,PKULCK,PKMSG,UPBYT,UPMSG,MAXWPM,NLHOST,NVTPTR
INTERN	PTNETI,PTNETO

; Linkage to swpmon

EXTERN	CHKBG1,CHKH1

; Linkage to forks

EXTERN	CAPENB,LSTERR
; Linkage to pisrv

EXTERN	MENTR,CHNSON,BUGCHK,BUGNTE,BUGHLT,MRETN,SKMRTN

; Linkage to ttysrv

EXTERN	TTOCT,TTECT,TTICT,TTCHI,TTYLMD,TTFORK,NVTCOF,TTPSI,TTCOBI,TTCIBF
EXTERN	TTRLOB,TTOOUT,TTEOUT,WRPMSK,TTIMAX,TTOMAX,TCOB,TCOBQ,TTFLGS
EXTERN	TCOTST

; Linkage to scheduler

EXTERN	EDISMS,FORKX,JB0FLG,DISNT,ITRAP,IMPTM2

; Miscellaneous

EXTERN	BHC,BITS,R,RSKP
EXTERN	BYTBLT

EXTERN	NETBUF
EXTERN	MAXBPM
EXTERN RECRTS,RECSTR,RECCLS,DISG,PFHST,PLINK,EOTF,DEDF,NVTCLZ
EXTERN NETSTS,RLNTBF,ASNTBF,MULKMP,RCFRFN,MLKMA
EXTERN	SK2DWN
EXTERN ERRB,NETDWN,NETHDN,NETCHK,HOSTN,NHOSTS,DISGT
EXTERN RECRST,NETBAL,NETRAL,RECINR,RECINS,PLIDX,DISL,SVCINT,SVCRST
EXTERN	LCKNCP,ULKNCP
EXTERN	JOBRTT,TODCLK

; Macros

; Lock imp device lock

DEFINE ILOCK (A)
<	CALL LCKIDV
IFB <A>,<0>
IFNB<A>,<A>
>

; Unlock imp device lock

DEFINE IUNLK
<	CALL ULKIDV>

; Call clock switch code

DEFINE	IMSCLK(CLOCK)<
	MOVEI 1,CLOCK
	CALL IMUCLK>

; Storage

; First impgtn are a getab table - don't separate

LS IMPRDY,1		; 0=down, .gtr. 0 =going down, -1=up
LS NETON,1		; 0=network off
LS NETENT,1		; Flags to drive netser. e.g., don't allow login
LS NCPUPT,1		; Gtad of last time ncp cycled up.
LS IGDMSG,1		; Most recent imp-going-down msg
LS IMPDNT,1		; Time of last imp ready line drop
LS IMPUPT,1		; Time of last imp ready line up
LS IGDTIM,1		; Time of above imp-going-down msg
IMPGTN==:8		;LENGTH OF THIS GETAB TABLE
; End of getab group

LS IMPORD,1		; Output ready. non-zero permits outgoing msgs
LS IMPRDL,1		; Ready line noticed off
LS IMPRDT,1		; Todclk when ready line first went off
LS IMPFLG,1		; Service needed by async process
LS NCPFRK,1		; Forkx of ncp fork
LS TTNOF,1		; Scan of net tty lines requested if non-0
LS IMPNOS,1		; Output scan request flag
LS IDVLCK,1		; Local lock
LS IDVLLK,1		; Last idvlck locker
LS IMPDRQ,1		; Reset cycle requested in non-0
LS NETTCH,1		; State of net has changed if non-0
LS IMPFRI,1		; List of free input buffers
LS IMPNFI,1		; Count of free input buffers
LS IMPNIB,1		; NUMBER OF INPUT BUFFERS TO KEEP ON TAP
LS SIQIBI,NSQ		; Special queue
LS SIQIBO,NSQ
LS SIQTIM,NSQ		; Time of first message on special queue
LS SIQSPC,NSQ		; Space occupied by special input q
LS SQJOB,NSQ		; Job to which special q is assigned
LS SQVAL,NSQ		; Value to compare against for mux special q
LS SQMSK,NSQ		; Mask to use in compare
LS SQLCK,1		; Interlock for assigning special q
LS IMPIBI,1		; In buffers in ptr
LS IMPIBO,1		; In buffers out ptr
LS IMPOBI,1		; Output buffers in pointer
LS IMPOBO,1		; Output buffers out pointer
LS IMPHBI,1		; Hi priority output buffers in pointer
LS IMPHBO,1		; Hi priority output buffers out pointer
LS IMIB,1		; Current in bfr, pi level
LS IMPOB,1		; Buffer now being emptied by pi routine
LS IMPINP,1		; Blki pointer on input
LS IMPOUP,1		; Blko pointer
LS IMIDSP,1		; Input pi dispatch
LS IMODSP,1		; Output pi dispatch
LS IMINFB,1		; Buffers made free by pi routines

; Storage continued

LS IMPNCL,1		; Number of control input conns
LS IMPNOL,1		; Number of control output conns
LS LNKNDL,1		; Number of deletes in link table
LS IMIS32,1		; Input repacking state word
LS IMOS32,1		; Output repacking state word
LS IMPSVX,1		; Pi service return
LS IMPTIM,1		; Time of next clock run down
LS IBPTIM,1		; Time of next impibp run
LS NETTIM,1		; Time of next check of fsm for hangs
LS RFNTIM,1		; Time of next check for lost rfnm's
LS NEGTIM,1		; Negotiation time-out clock
LS IMPCHU,1		; 0 if current control mess host not up
LS IMPCHO,1		; Host number of control msg, must precede i8cal
LS I8CAL,5		; Args of control operation, must follow impcho
LS IMPFLS,1		; Count (neg) of messages to flush
LS NOPCNT,1		; Count of nops left to send
LS IMPGDM,1		; Last imp going down msg
LS HSTGDM,1		; Current host going down message
LS IMPCCH,1		; Index to host number for periodic check

LS IMP8XI,1		; Irreg mes buffer in ptr
LS IMP8XO,1		; .. .. out
LS IMP8XC,1		; .. .. count
LS IMP8XB,IMP8XS	; Irreg mes buffer

LS IMPHRT,IMPLBT	; Host ready bits
LS HSTSTS,200		; Dead host status table (18 bits per host)
LS IMPHCT,IMPLBT	; Recent message sent
IFDEF POLLF,<LS IMPHL1,IMPLBT>	; Hosts which have gone down
IFDEF POLLF,<LS IMPHL2,IMPLBT>	; State of hrt at last log tty report

LS IMPBGC,1		; Impbug count
LS IMPBGH,1		; Host involved in last impbug
LS BADHMS,1		; Message associated with header below
LS BADHDR,2		; Header of last funny message received
LS BUGIMP,1		; Impbug w/o host

LS IMPBHT,IMPLBT	; 'bad' host table
LS NWPBT,IMPLBT	; BIT TABLE OF HOSTS USING RAR/RAS ETC.
LS IMPIAC,5		; Pi level ac storage
LS IMSTK,NIMSTK		; Pi level stack
LS IMINP,1

LS TTNETX,NNVTLN	; Stuff for nvt's
LS TTBRKX,NNVTLN	; BREAK CLASSES FOR NVT'S
TTNETW=<Z TTNETX-NVTLO>	; Relative to 0
TTBRKC=<Z TTBRKX-NVTLO>	; RELATIVE TO 0
			; BITS 0-8: OUTSTANDING BREAK COUNT
			; BITS 9-17: LAST RCTE COMMAND SENT
			; BITS 18-35: LAST BREAK CLASSES SENT
LS NVTOPX,NNVTLN	; Lh -- bit for each option in progress
			; Rh -- bit for result of each option
NVTOPF=<Z NVTOPX-NVTLO>	; Relative to 0

; Time accumulators

LS IMCCLK,1		; Run time of last check
LS IMCLST,1		; Pointer to current clock
LS IMCIDL,1		; Time spent idling
LS IMCNRB,1		; Time spent releasing spent buffers
LS IMCGC,1		; Time spent garbage collecting link tables
LS IMCGIB,1		; Time spent assigning input buffers
LS IMCCNP,1		; Time spent processing control messages
LS IMCP1,1		; Time spent dispatching input messages
LS IMC8XM,1		; Time spent processing irregular messages
LS IMCTS,1		; Time spent scanning for nvt output
LS IMCNVI,1		; Time spent unpacking nvt input
LS IMCOS,1		; Time spent scanning for output to do
LS IMCNCK,1		; Time spent probing network
LS IMCRFN,1		; Time spent checking overdue rfnm's
LS IMCNCC,1		; Time spent in ncp checks
LS IMNIDL,1		; Count of idling
LS IMNNRB,1		; Count of releasing spent buffers
LS IMNGC,1		; Count of garbage collecting link tables
LS IMNGIB,1		; Count of assigning input buffers
LS IMNCNP,1		; Count of processing control messages
LS IMNP1,1		; Count of dispatching input messages
LS IMN8XM,1		; Count of processing irregular messages
LS IMNTS,1		; Count of scanning for nvt output
LS IMNNVI,1		; Count of unpacking nvt input
LS IMNOS,1		; Count of scanning for output to do
LS IMNNCK,1		; Count of probing network
LS IMNRFN,1		; Count of checking overdue rfnm's
LS IMNNCC,1		; Count of ncp checks

; Link tables

LS IMPLT1,IMPNLK	; Lh -- UNIT (INDEX TO NCP TABLES)
			;  OR -1 IF CONTROL LINK
			; B18-19/00 -- receive
			;        10 -- SEND
			;        11 -- FREE
			;        01 -- DELETED
			; B20-27 -- host
			; B28-35 -- link
LS IMPLT2,IMPNLK	; B0-b5 -- flags
			; B5-9 -- unused
			; B10-17 -- byte size
			; Rh -- in bfr ptr
LS IMPLT3,IMPNLK	; Lh -- out bfr ptr
			; Rh -- save message for retransmission
LS IMPLT4,IMPNLK	; Lh -- CURRENT BUFFER
			; Rh -- MSG ALLOCATION

; Pi dispatch

IMPSV:	XWD IMPSVX,.+1
	CONSO IMP,7		; Input turned off?
	JRST IMPSV1		; Yes
	CONSZ IMP,IMPINB
	JRST @IMIDSP		; Word in
	CONSZ IMP,IMPEIB
	 JRST [	CONSO IMP,IMPINB; It can happen that last input came in
		 JRST IMPEIN	; Within the last few instructions
		JRST @IMIDSP]	; If so, handle it first
IMPSV1:	CONSZ IMP,7B31		; Do nothing if no channel assigned
	CONSO IMP,IMPOUB
	JRST @IMPSVX		; N.o.t.a
	SKIPE IMPOB
	JRST @IMODSP		; Word out
	CONO IMP,IMPSTO
	JRST @IMPSVX

IMPCHK:	MOVEI 2,^D1000
	MOVEM 2,IMPTM2		; Call this every second
	SKIPN IMPRDY		; Net on?
	 RET			; NO.
	CONSZ IMP,1B19		; Power not on
	CONSZ IMP,1B21!1B20	; Or error flop on, or host not ready?
	SKIPL IMPRDT		; And not already noticed?
	 RET
	CALL IMIERR		; Be sure it's noticed
	AOS IMPFLG		; No, cause running of ncp fork
	RET

; Called by periodic check routine

	SWAPCD

CHKNET:	IFDEF POLLF,<		; Do this printout only if pollf is dfnd
	MOVSI 5,-IMPLBT		; Setup to scan host bit tables
CHKN2:	MOVE 3,IMPHL1(5)	; Bit set if host has gone down since lst
	JFFO 3,[MOVE 3,BITS(4)	; Found one
		ANDCAM 3,IMPHL1(5) ; Reset bits
		ANDCAM 3,IMPHL2(5)
		HRROI 1,[ASCIZ /HOST /]
		PSOUT		; Report downage
		MOVEI 1,101
		MOVEI 2,0(5)	; Compute host number
		IMULI 2,^D36
		ADDI 2,0(4)
		MOVEI 3,^D8	; Octal for nout
		CVHST		; Type host name if any,
		NOUT		; But if that fails, type number
		JFCL
		HRROI 1,[ASCIZ / DOWN
/]
		PSOUT
		JRST CHKN2]
	MOVE 3,IMPHL2(5)	; State of hosts as reported
	XOR 3,IMPHRT(5)		; Compare with state from ncp
	JFFO 3,[MOVE 3,BITS(4)	; Found a difference
		XORM 3,IMPHL2(5) ; Update logged table
		HRROI 1,[ASCIZ /HOST /]
		PSOUT		; Report change on log tty
		MOVEI 1,101
		MOVEI 2,0(5)	; Compute host number
		IMULI 2,^D36
		ADDI 2,0(4)
		MOVEI 3,^D8	; Octal for nout
		CVHST		; Type host name
		NOUT		; Or host number
		JFCL
		MOVE 3,BITS(4)
		HRROI 1,[ASCIZ / UP
/]
		TDNN 3,IMPHL2(5)
		HRROI 1,[ASCIZ / DOWN
/]
		PSOUT
		JRST CHKN2]
	AOBJN 5,CHKN2		; Scan tables
>				; End of ifdef pollf at chknet
	SKIPE BUGIMP
	 CALL CHKN1		; Yes
	SKIPE NETTCH		; Change of state?
	 CALL CHKN5		; Yes
	SKIPE IMPGDM		; Any "imp going down" messages?
	  CALL CHKN7		; Yes, go print it
	RET

; Log network change of state

CHKN5:	HRROI 1,[ASCIZ /
***** NETWORK /]
	PSOUT
	HRROI 1,[ASCIZ /ON/]
	SKIPN NETON
	HRROI 1,[ASCIZ /OFF/]
	PSOUT
	HRROI 1,[ASCIZ /, IMP /]
	PSOUT
	HRROI 1,[ASCIZ /ON/]
	SKIPN IMPRDY
	HRROI 1,[ASCIZ /OFF/]
	PSOUT
	MOVEI 1," "
	PBOUT
	CONI IMP,2
	SETZM NETTCH
	CALL CHKH1		; Go print coni word and tod
	RET

; Log impbug/imhbug

CHKN1:	HRROI 1,[ASCIZ /
***IMPBUG /]
	PSOUT
	MOVEI 1,101
	MOVEI 3,^D10
	MOVE 2,IMPBGC
	NOUT
	JFCL
	HRRZ 2,IMPBGH		; Host number if any
	JUMPE 2,CHKN4		; None
	HRROI 1,[ASCIZ / HOST /]
	PSOUT
	MOVEI 1,101
	MOVEI 3,^D8
	CVHST			; Type host name or number
	 NOUT
	  JFCL
CHKN4:	HLRZ 2,IMPBGH		; Status if any
	JUMPE 2,CHKN3		; None
	HRROI 1,[ASCIZ \ STS/LINK \]
	PSOUT
	MOVEI 1,101
	MOVEI 3,10
	NOUT			; Print status in octal
	JFCL
CHKN3:	SKIPN 4,BADHMS		; Any header to print
	 JRST CHKN8		; No
	HRROI 1,[ASCIZ / HEADER: /]
	PSOUT
	MOVE 5,[POINT 4,BADHDR]
	MOVEI 1,101
	MOVEI 3,10
CHKN8L:	ILDB 2,5
	ROT 2,4
	ILDB 6,5
	IOR 2,6
	NOUT
	 JFCL
CHKN8:	MOVEI 2," "
	BOUT
	SOJG 4,CHKN8L
	HRROI 1,[ASCIZ /AT /]
	PSOUT
	SOS 2,BUGIMP		; Back pc up to point at jsr
	SETZM BADHMS
	SETZM BUGIMP
	SETZM IMPBGH
	CALL CHKBG1		; Print address and message
	RET

; Broadcast imp going down message

CHKN7:	HRROI 1,1(P)		; Buffer on pdl
	ADD P,[20,,20]
	HRROI 2,[ASCIZ /IMP GOING DOWN FOR /]
	SETZ 3,
	SOUT
	LDB 2,[POINT 10,IMPGDM,31]
	IMULI 2,5
	MOVEI 3,^D10
	NOUT
	 JFCL
	HRROI 2,[ASCIZ / MIN IN /]
	SETZ 3,
	SOUT
	LDB 2,[POINT 4,IMPGDM,21]
	MOVEI 3,^D10
	IMULI 2,5
	NOUT
	 JFCL
	HRROI 2,[ASCIZ / MIN DUE TO /]
	SETZ 3,
	SOUT
	LDB 2,[POINT 2,IMPGDM,17]
	HRRO 2,[[ASCIZ /PANIC
/]
		[ASCIZ /SCHED HDWRE PM
/]
		[ASCIZ /SOFTWRE RELOAD
/]
		[ASCIZ /EMRGNCY RESTRT
/]](2)
	SOUT
	HRROI 2,-17(P)
	SETO 1,
	TTMSG
	SUB P,[20,,20]
	SETZM IMPGDM
	RET

	RESCD

; Routines to make footprints for debugging

; Take imp footprints jsys
; Call:	1	; Jfn of output file
;	2	; Word count (stops at first opportunity past this)
;	3	; Re-init flag (non-zero to reset pointers)

.DBGIM::JSYS MENTR
	HRRZS 1			; Don't allow byte pointers
	MOVEI 4,WHEEL!NETWIZ
	TDNN 4,CAPENB
	 JRST MRETN
	JUMPE 3,DBGIM0		; Skip init stuff
	NOSKED
	SETZM DBGNWD
	SETZM DBGSP
	SETZM DBGFAC
	OKSKED
	SETZM DBGRP
	AOS DBGRP		; Point at first word
DBGIM0:	PUSH P,2		; Save count on stack
	PUSH P,1
DBGDBL:	SKIPG 3,DBGNWD
	 JRST DBGDBW
	MOVEI 4,DBGNBF
	SUB 4,DBGRP		; Space to end of buffer
	CAMGE 3,4
	 MOVEM 3,4		; Keep min
	MOVN 3,4
	MOVE 2,DBGRP
	ADD 2,[POINT 36,DBGBUF]
	SOUT
	MOVN 3,4
	ADDM 3,DBGNWD
	ADDB 4,DBGRP
	CAIL 4,DBGNBF
	 SETZB 4,DBGRP
	ADDB 3,-1(P)		; Count words written
	JUMPG 3,DBGDBL		; Continue if still .gr. 0
	UMOVEM 3,3		; Else return updated count
	SUB P,BHC+2
	JRST SKMRTN

DBGDBW:	MOVEI 1,DBGNWD
	PUSHJ P,DISG
	MOVE 1,0(P)
	JRST DBGDBL

; Variables

DBGNBF==2000

LS(DBGFAC,1)		; Failure counter
LS(DBGSP,1)		; Store pointer
LS(DBGRP,1)		; Read pointer
LS(DBGNWD,1)		; Number of words in buffer
NGS(DBGBUF,DBGNBF)	; Buffer


; Stash input irregular msg

DBGIIM:	PUSH P,2
	MOVEI 2,1
DBGSIM:	PUSHJ P,DBGCKS		; Check for space
	 JRST DBGXIT
	PUSHJ P,DBGS2B
	MOVE 2,1
	PUSHJ P,DBGS1B
DBGXIT:	OKSKED
	POP P,2
	POPJ P,

DBGIM:	PUSH P,2
	MOVE 2,1(1)
	TDNE 2,[377B23]
	 SKIPA 2,[3]
	  HRRZ 2,0(1)
DBGSM:	SOS 2
	PUSHJ P,DBGCKS
	 JRST DBGXIT
	PUSH P,1
	PUSHJ P,DBGS2B
	MOVNI 1,0(2)
	HRLZS 1
	HRR 1,0(P)
DBGSLP:	MOVE 2,1(1)
	PUSHJ P,DBGS1B
	AOBJN 1,DBGSLP
	POP P,1
	JRST DBGXIT


DBGOM:	PUSH P,2
	MOVE 2,1(1)
	TLNE 2,(17B7)
	 JRST [	HRROI 2,2
		JRST DBGSM]
	TDNE 2,[377B23]
	 SKIPA 2,[-1,,3]
	  HRRO 2,0(1)
	JRST DBGSM

; Record impbug

DBGBG1:	PUSH P,2
	MOVEI 2,1
	CALL DBGCKS
	 JRST DBGXIT
	MOVE 2,1
	HRLI 2,3
	CALL DBGS2B
	MOVE 2,0(P)
	CALL DBGS1B
	JRST DBGXIT

; Store header word and time stamp

DBGS2B:	PUSHJ P,DBGS1B
	PUSH P,2
	EXCH 1,2
	GTAD
	EXCH 1,2
	PUSHJ P,DBGS1B
	POP P,2
	POPJ P,

; Store 1 word in debug buffer

DBGS1B:	PUSH P,1
	AOS 1,DBGSP
	CAIL 1,DBGNBF
	 SETZB 1,DBGSP
	MOVEM 2,DBGBUF(1)
	AOS DBGNWD
	POP P,1
	POPJ P,

; Check for sufficient space to make new entry

DBGCKS:	SKIPE DBGFAC		; Any intervening failures?
	 AOJA 2,DBGCK2		; Yes
DBGCK1:	PUSH P,1
	NOSKED
	MOVE 1,DBGNWD
	ADDI 1,2(2)
	CAIG 1,DBGNBF
	 AOSA -1(P)
	  AOS DBGFAC
	POP P,1
DBGCK3:	POPJ P,

DBGCK2:	PUSHJ P,DBGCK1
	 SOJA 2,DBGCK3
	EXCH 2,DBGFAC
	HRLI 2,1
	PUSHJ P,DBGS1B
	SOS 2,DBGFAC
	SETZM DBGFAC
	POPJ P,

; Imp asynchronous process
; Started once, call from rundd

IMPBEG:	MOVSI 1,(1B1)		; Create fork of job 0
	CFORK
	BUG(HLT,<CAN'T CREATE IMP FORK>)
	MOVEI 2,IMPBP0
	MSFRK			; Start fork in monitor
	RET

; Init

IMPBP0:	MOVSI 1,UMODF		; Establish usual jsys context
	MOVEM 1,FPC
	JSYS MENTR
	MOVE 1,FORKX
	MOVEM 1,NCPFRK
	MOVE 1,[XWD ITFPC,IMPUXI]
	MOVEM 1,MONBK		; Trap any interrupts
	MOVE 1,CHNSON
	MOVEM 1,MONCHN

	MOVEI 1,NINBFS
	MOVEM 1,IMPNIB	;INIT NUMBER OF BUFFERS TO KEEP ON TAP


IFE PIESLC,<
	MOVEI 1,202
	MOVEM 1,JOBBIT
>

IFN PIESLC,<CALL SETSPQ##>	;NCPFRK GETS SPECIAL QUEUE

	CALL IMPINI
	MOVEI 1,2
	MOVEM 1,IMCLST		; Make last clock be dummy (ac 2)
IMPBP1:	IMSCLK(IMCIDL)		; Start charging time to imcidl
	PUSH P,[IMPBP1]		; Return for following dispatches
	SETZM IMPFLG		; Clear request flag
	CALL IMPSTT		; Check state of net and imp
	JRST IMPBP3		; Down
	SKIPE IMINFB		; Garbage buffers to release?
	JRST IMINRB		; Yes
	MOVE 1,LNKNDL		; Deletes in link table
	CAIL 1,IMPNLK/2		; Time for gc?
	JRST IMPGC		; Yes
	SKIPE IMPNCL		; Control msgs for processing?
	JRST IMPCN0		; Yes
	SKIPE IMPIBO		; Input buffers ready?
	JRST IMIP1		; Yes
	SKIPE IMP8XC		; Irreg msgs for processing?
	JRST IMP8XM		; Yes
	SKIPE TTNOF		; Scan of net ttys requested?
	JRST IMPTS		; Yes
	MOVE 1,IMPNFI
	CAMGE 1,IMPNIB	; NEED INPUT BUFFERS?
	CALL IMPGIB		; Yes
	SKIPE IMPNOS		; Need output scan?
	CALL IMPOS		; Yes
	IMSCLK(IMCIDL)		; Back to imcidl for charging

IMPBP2:	MOVE 1,TODCLK
	CAML 1,IMPTIM		; Time for local checks?
	JRST NETCH0		; Yes
	CAML 1,RFNTIM		; Time for overdue rfnm check?
	JRST RFNCHK		; Yes
	CAML 1,NETTIM		; Time for netwrk checks?
	 JRST [	IMSCLK(IMCNCC)
		JRST NETCHK]	; Yes
	CAML 1,NEGTIM
	 JRST NEGCHK		; Check incomplete negotiations
	PUSHJ P,SIQCHK
	CAMLE 1,IMPTIM
	MOVE 1,IMPTIM		; Compute min clocks as
	CAMLE 1,NETTIM		; Next time to wakeup
	MOVE 1,NETTIM
	CAMLE 1,RFNTIM
	MOVE 1,RFNTIM
	CAMLE 1,NEGTIM
	 MOVE 1,NEGTIM
	MOVEM 1,IBPTIM
	MOVEI 1,IMPBPT
	JSYS EDISMS		; Dismiss until something to do
	RET

IMPBPT:	SKIPE IMPFLG		; Flag set?
	JRST 1(4)		; Yes, wakeup
	MOVE 1,TODCLK		; Check alarm clock
	CAML 1,IBPTIM
	JRST 1(4)
	SKIPGE IDVLCK		; Lock clear and out scan needed?
	SKIPG IMPNOS
	JRST 0(4)
	JRST 1(4)		; Yes, wakeup

IMPBP3:	MOVE 1,TODCLK
	CAML 1,NETTIM
	 CALL NETCHK		; Continue calling netchk if net down
	MOVEI 1,^D10000
	DISMS			; Wait 10 sec
	RET			; Then try again

; Unexpected interrupt

IMPUXI:	BUG(CHK,<IMP JB0 FORK - UNEXPECTED INTERRUPT>)
	MOVSI 1,UMODF		; Reset stack
	MOVEM 1,FPC
	JSYS MENTR
	JRST IMPBP1

; Special raw message routines

; Assign a special message queue

.ASNSQ:	JSYS MENTR
	PUSHJ P,CKNTWZ
	 JRST ERMRTN
	NOINT
	AOSE SQLCK
	 PUSHJ P,SQLWAT
	MOVSI 3,-NSQ
	SETZ 4,
ASNSQL:	SKIPGE SQJOB(3)		; Assigned?
	 JRST [	JUMPL 4,ASNSQN
		MOVE 4,3
		JRST ASNSQN]
	UMOVE 1,1		; Get mask
	AND 1,SQMSK(3)		; Joint mask
	UMOVE 2,2
	XOR 2,SQVAL(3)		; Difference
	TDNN 1,2		; Must be different in joint mask bits
	 JRST ASNSQF		; Else fail
ASNSQN:	AOBJN 3,ASNSQL		; Test all possibilities
	MOVEI 1,ASNSX1
	JUMPGE 4,ASNSF1
	UMOVE 1,1		; Mask
	MOVEM 1,SQMSK(4)	; Store mask in table
	XCTUU [	AND 1,2]	; Mask good bits of value
	MOVEM 1,SQVAL(4)
	MOVE 1,JOBNO
	MOVEM 1,SQJOB(4)
	SETOM SQLCK
	XCTUU [HRRZM 4,1]
	JRST SKMRTN

ASNSQF:	MOVEI 1,ASNSX2
ASNSF1:	UMOVEM 1,1
	SETOM SQLCK
	JRST MRETN

; Release special q

.RELSQ:	JSYS MENTR
	NOINT
	AOSE SQLCK
	 PUSHJ P,SQLWAT
	CAMN 1,[-1]
	 JRST RELASQ
	CAIL 1,0
	CAIL 1,NSQ
	 JRST RELSQ1
	PUSHJ P,REL1SQ
RELSQ1:	SETOM SQLCK
	JRST MRETN

RELASQ:	MOVSI 4,-NSQ
RELAS1:	HRRZ 1,4
	PUSHJ P,REL1SQ
	AOBJN 4,RELAS1
	JRST RELSQ1

REL1SQ:	MOVE 2,JOBNO
	CAME 2,SQJOB(1)
	 POPJ P,
	SETOM SQJOB(1)
REL1S1:	PUSHJ P,SIQGET
	 POPJ P,
	PUSH P,1
	PUSHJ P,RLNTBF
	POP P,1
	JRST REL1S1

; .rcvim receive raw messages

.RCVIM:	JSYS MENTR
RCVIM1:	NOINT
	UMOVE 1,1
	CALL CHKSQ		; Check for accessibility to special q
	 JRST ERMRTN		; No access
	PUSHJ P,SIQGET		; Get the message
	 JRST [	OKINT		; None there
		JSYS EDISMS	; Wait
		JRST RCVIM1]	; Try again
	UMOVE 1,2		; Get user's buffer
	HRL 1,2			; Message location
	MOVE 3,1		; Copy of user's buffer location
	ADD 3,0(2)		; Plus size -- end
	XCTMU [BLT 1,-1(3)]	; Transfer to user
	PUSHJ P,RLNTBF		; Release the buffer
	JRST SKMRTN		; Return

ERMRTN:	UMOVEM 1,1
	JRST MRETN

SIQGET:	MOVE 2,TODCLK
	ADDI 2,SIQTM0
	MOVEM 2,SIQTIM(1)	; Reset time
	NOSKED
	HLRZ 2,SIQIBO(1)
	JUMPE 2,SIQEMT
	HLLZ 3,0(2)
	MOVEM 3,SIQIBO(1)
	JUMPN 3,.+3
	MOVEI 3,SIQIBO(1)
	MOVEM 3,SIQIBI(1)
	SOS SIQSPC(1)		; Credit space used
	OKSKED
	AOS 0(P)
	RET

SIQEMT:	OKSKED
	HRLZI 1,SIQIBO(1)
	HRRI 1,DISNT
	POPJ P,

; .sndim: send special message

.SNDIM:	JSYS MENTR
	CALL CHKSQ		; Check access to special q
	 JRST ERMRTN
	UMOVE 1,2
	UMOVE 2,0(1)		; Get size
	CAIL 2,2
	CAML 2,MAXWPM
	 JRST [	MOVEI 1,SNDIX1
		JRST ERMRTN]	; Bad size
	NOINT
	PUSHJ P,ASNTBF		; Get a buffer
	 JRST [	MOVEI 1,SNDIX2
		JRST ERMRTN]	; No room
	PUSH P,1		; Save it
	XCTUU [HRL 1,2]		; Make blt pointer
	MOVE 2,0(1)		; Size
	ADD 2,1			; End of buffer
	ADD 1,BHC+1		; Don't transfer first word
	XCTUM [BLT 1,-1(2)]	; Transfer message to monitor space
	POP P,2			; The buffer
	MOVE 1,1(2)		; Get header word
	AND 1,[FRMIMP+377B23]
	CAMG 1,[LLINK*1B23]
	 JRST [	PUSHJ P,RLNTBF	; Don't allow messages with ncp links
		MOVEI 1,SNDIX3
		JRST ERMRTN]
	UMOVE 1,1		; Get sq index
	MOVE 3,1(2)		; And header
	XOR 3,SQVAL(1)		; Difference with value
	TDNE 3,SQMSK(1)		; Must be equal in masked bits
	 JRST [	PUSHJ P,RLNTBF
		MOVEI 1,SNDIX4
		JRST ERMRTN]
	NOSKED
	SKIPL IMPRDY		; Last minute check if imp is up
	 JRST [	OKSKED
		PUSHJ P,RLNTBF
		MOVEI 1,SNDIX5
		JRST ERMRTN]
	PUSHJ P,IMPQOA		; Put onto output q
	OKSKED
	JRST SKMRTN

; Check for access to specific special q

CHKSQ:	CAIL 1,0
	CAIL 1,NSQ
	 JRST [	MOVEI 1,SQX1
		POPJ P,]
	MOVE 2,JOBNO
	CAMN 2,SQJOB(1)
	JRST RSKP
	MOVEI 1,SQX2
	POPJ P,

; Check for net wizardry

CKNTWZ:	MOVEI 2,NETWIZ
	TDNE 2,CAPENB
	 JRST RSKP
	MOVEI 1,NTWZX1
	POPJ P,

SQLWAT:	PUSH P,1
	MOVEI 1,SQLTST
	JSYS EDISMS
	POP P,1
	POPJ P,

SQLTST:	AOSE SQLCK
	JRST 0(4)
	JRST 1(4)

; Siqchk: check for unclaimed messages

SIQCHK:	HRLOI 3,377777
	MOVSI 2,-NSQ
SIQCKL:	SKIPGE SQJOB(2)
	 JRST SIQCKE
	CAMG 1,SIQTIM(2)
	 JRST SIQCKX
	PUSH P,1
	PUSH P,2
	PUSH P,3
	HRRZ 1,2
REPEAT 0,<			;CODE TO DELETE JUST ONE BUFFER
	PUSHJ P,SIQGET
	SKIPA
	PUSHJ P,RLNTBF>
REPEAT 1,<			;CODE TO FLUSH THE WHOLE QUEUE
	PUSHJ P,REL1S1>

	POP P,3
	POP P,2
	POP P,1
SIQCKX:	CAML 3,SIQTIM(2)
	 MOVE 3,SIQTIM(2)
SIQCKE:	AOBJN 2,SIQCKL
	MOVE 1,3
	POPJ P,

USE RESPC

; Update imp clocks

IMUCLK:	PUSH P,1
	SUBI 1,IMCIDL
	AOS IMNIDL(1)		; Count entries
	MOVE 1,JOBRTT		; Time since last update of fkrt
	ADD 1,FKRT		; Fork cpu to now
	SUB 1,IMCCLK		; Time since last measurement
	ADDM 1,IMCCLK		; Update to be time of this clock measurement
	ADDM 1,@IMCLST		; Charge to current clock
	POP P,IMCLST		; Set to new clock
	RET

; Set idvlck

IFE PIESLC,<		; Version for non-pie slice scheduler
LCKIDV:	PUSH P,1
	MOVEI 1,1
	CALL STMINQ##		; Prevent dropping below q1 while locked
	LOCK IDVLCK,<JRST LCKID1>,SPQ
LCKID0:	POP P,1
	PUSH P,FORKX
	POP P,IDVLLK
	AOS 0(P)
	RET

LCKID1:	SKIPE @-1(P)		; Wait wanted?
	JRST ULKID0		;NO ,RETURN
	MOVEI 1,IDVTST
	JSYS EDISMS
	JRST LCKID0

> ;END NON-PIE-SLICE CONDITIONAL

IFN PIESLC,<		; Version for pie-slice scheduler
LCKIDV:	LOCK IDVLCK,<JRST LCKID1>,SPQ
LCKID0:	PUSH P,FORKX
	POP P,IDVLLK
	AOS 0(P)
	RET

LCKID1:	SKIPE @0(P)		; Wait wanted?
	 JRST RELSPQ##		;RETURN VIA RELSPQ, NORMAL SCHEDULING
	PUSH P,1
	MOVEI 1,IDVTST
	JSYS EDISMS
	POP P,1
	JRST LCKID0
> ; END OF IFN PIESLC CONDITIONAL

; Unlock idvlck

ULKIDV:	UNLOCK IDVLCK,RESIDENT,SPQ

IFE PIESLC,<
	PUSH P,1
ULKID0:	SETZ 1,
	CALL STMINQ
	POP P,1
>
	RET

IDVTST:	AOSE IDVLCK
	 JRST 0(4)
	JRST 1(4)

; Release buffers left by pi routines

IMINRB:	IMSCLK(IMCNRB)		; Charge time to releasing buffers
	SETZ 4,
	EXCH 4,IMINFB		; Get all garbage buffers
IMINR1:	JUMPE 4,R		; Quit when all released
	MOVEI 2,0(4)
	HLRZ 4,0(4)
	CALL RLNTBF		; Release one
	JRST IMINR1

; Get one buffer for input and lock it in core

IMPGIB:	IMSCLK(IMCGIB)		; Charge to imcgib
IMPGI1:	MOVE 2,MAXWPM		; For max input msg
	CALL ASNTBF		; Assign from pool
	JRST IMPB03
	MOVEI 2,0(1)
	CALL IMPLKB		; Lock buffer
	PIOFF
	EXCH 2,IMPFRI		; Put bfr on input free list
	HRLM 2,@IMPFRI
	AOS 2,IMPNFI		; Count number free, if was 0, then
	PION
	SKIPN IMIB		; Input is off?
	SKIPG IMPNFI		; YES, BUFFERS AVAILABLE?
	 CAIA			; NO
	PUSHJ P,IMISRT		; Yes, restart
	MOVE 2,IMPNFI		; GOT ENOUGH BUFFERS?
	CAMGE 2,IMPNIB
	 JRST IMPGI1		; NO
	RET

; Scan net tty lines

IMPTS:	IMSCLK(IMCTS)		; Charge to imcts
	SETZM TTNOF
	MOVSI 10,-NNVTLN	; Count thru nvt lines
IMPTS1:	MOVEI 2,NVTLO(10)
	SKIPN TTOCT(2)		; Output ready?
	SKIPE TTECT(2)
	CALL NETTCS		; Yes
	AOBJN 10,IMPTS1
	RET

; Scan all connections for output possible
; Called by asynch process

IMPOS:	IMSCLK(IMCOS)		; Charge to imcos
	MOVSI 6,-IMPNLK
	SETZM IMPNOS		; Cancel request
IMPOS2:	HRRZ 2,IMPLT1(6)
	TRNE 2,1B18		; Output connection has bit 18 on
	TRNE 2,1B19		; And bit 19 off
IMPOS1:	AOBJN 6,IMPOS2
	JUMPGE 6,[SUB P,BHC+1	; Flush .+1 return, go back to top
		RET]
	ILOCK(<JRST [AOS IMPNOS	; Try again later
		RET]>)		; Return if can't set lock
	MOVEI 1,0(6)
	CALL IMPKO1		; Check and send if possible
	JRST IMPOS1

; Asynch process to put buffers on proper connection queues

IMIP1:	IMSCLK(IMCP1)		; Charge to imcp1
	HLRZ 2,IMPIBO		; Try to get next buffer
	JUMPE 2,R		; None left
	PIOFF
	HLLZ 3,0(2)
	JUMPN 3,.+3
	MOVEI 4,IMPIBO
	MOVEM 4,IMPIBI
	MOVEM 3,IMPIBO
	PION
	PUSH P,2		; Save bfr address
	MOVEI 1,0(2)
IFDEF DBGBUF,<
	CALL DBGIM>
	NOSKED
	HRRZ 2,0(2)		; GET SIZE FIELD
	CAMLE 2,MAXWPM		; MAKE SURE ITS NOT ON FREELIST
	 BUG (HLT,<IMIP1: ATTEMPT TO UNLOCK BUFFER ON FREELIST>)
	MOVE 2,0(P)		; RESTORE 2
	CALL MULKMP		; Unlock head, tail unlocked at pi lev
	HRRZS 0(2)		; Clear fwd pointer
	MOVE 1,1(2)		; Get header
	AND 1,[FRMIMP+377B23]	; Extract link + frmimp
	CAML 1,[<LLINK>B23]	; Normal link?
	 JRST IMIPSQ		; No, dispatch to special q
	OKSKED
	LDB 1,[POINT 16,1(2),23] ; Get host-link
	ILOCK
	CALL LNKLUK		; See if connection exists
	 JRST [	TRNE 1,377	; Doesn't, control link?
		 JRST IMIBB	; Link non-existant
		MOVEI 3,^D8	; Create connection, byte size is 8
		CALL IMPOP1
		HRROS IMPLT1(1)	; Make unit -1
		MOVEI 3,377777
		HRRM 3,IMPLT4(1) ; Set infinite msg alloc
		AOS IMPNCL	; Count control connections
		JRST .+1]
	POP P,2
	MOVE 3,IMPLT2(1)
	HRLM 2,0(3)		; Put msg on queue for conn
	HRRM 2,IMPLT2(1)
	HLRE IMPUN,IMPLT1(1)
	IUNLK
	JUMPL IMPUN,R		; See if nvt connection
	LDB 2,PNVT
	CAIL 2,NVTLO
	CAILE 2,NVTHI
	RET			; Isn't
	CALL NVTUPI		; Unpack nvt input
	RET

IMIPSQ:	MOVSI 3,-NSQ
IMIPS1:	MOVE 1,1(2)		; Get header
	XOR 1,SQVAL(3)		; Compare to value
	SKIPL SQJOB(3)		; In use?
	TDNE 1,SQMSK(3)		; Yes, equal?
	 AOBJN 3,IMIPS1		; No or no
	JUMPGE 3,IMIPS2		; Found nobody, go throw away
	MOVE 1,SIQSPC(3)	; How much space in use?
	CAIL 1,SIQMAX		; Less than max?
	 JRST IMIPS2		; No, too much, go throw away
	MOVE 1,TODCLK
	ADDI 1,SIQTM0
	SKIPN SIQIBO(3)		; First one (queue empty?)
	 MOVEM 1,SIQTIM(3)	; Record time of arrival
	AOS SIQSPC(3)		; Count messages on queue
	HRLM 2,@SIQIBI(3)
	HRRZM 2,SIQIBI(3)
	OKSKED
	JRST IMIPS3

IMIPS2:	OKSKED
	PUSHJ P,RLNTBF		; Throw message away
IMIPS3:	SUB P,BHC+1 
	RET

; Cause bad msg to be printed

IMIBB:	IUNLK
	LSHC 1,-8	; Host in 1
	ROT 2,8			; Link in 2
	ANDI 1,377
	ANDI 2,377
	CALL IMPNXR		; Send nxr
	JRST IMIPB1

IMIPB:	IUNLK
IMIPB1:	HRLI 2,9
	BUG(IML,<Received msg for unknown link>,X)
IMIPB2:	POP P,2
	JRST RLNTBF

; Send RST to all named hosts on startup

NETCH0:	IMSCLK(IMCNCK)		; Charge to imcnck
	SKIPGE 7,IMPCCH		; Sending rst's?
	 JRST IMPET		; No.
IMPRC1:	CALL IMPRCC		; Check for space in link table
	 JRST [	MOVEI 1,^D50
		JRST IMPET1]
	HRRZ 1,7
	CAMN 1,NLHOST		; Local host?
	 JRST IMPRC2		; Never send reset to local host
	MOVEI 1,377777		; NIL designator for CVHST
	HRRZ 2,7		; Host number
	CVHST			; See if the host has a name
	 JRST IMPRC2		; It doesn't. Don't swamp net with 
				;  resets to nonexistent hosts.
	HRRZ 2,7		; Host exists. See if it's up already
	IDIVI 2,^D36
	MOVE 3,BITS(3)
	TDNN 3,IMPHRT(2)	; No reset if already up
	CALL IMSRST
IMPRC2:	CAIGE 7,377
	AOJA 7,IMPRC1
IMPEET:	SETZM IMPHCT
	MOVE 1,[IMPHCT,,IMPHCT+1]
	BLT 1,IMPHCT+IMPLBT-1
	MOVSI 7,-IMPNLK
	MOVE 1,[UPROBI-UPROBT]
	JRST IMPET1

IMPRCC:	MOVE 1,IMPNOL		; Number of links in use
	CAIG 1,IMPNLK/4-10
	 AOS 0(P)
	RET

; Echo tester

IMPET:	MOVEI 1,^D120000
	SKIPL IMPRDY
	 JRST IMPCC6		; Don't probe if ncp not fully up
	PUSHJ P,IMPRCC		; Check space in link table
	 JRST [	MOVEI 1,^D5000	; Try again in 5 seconds
		JRST IMPCC6]
IMPET3:	MOVE 1,IMPLT1(7)
	TRNE 1,200000		; Active?
	 JRST IMPET4		; No, get next
	LSH 1,-8
	ANDI 1,377		; The host
	MOVE 2,1
	IDIVI 2,^D36		; Compute bit table index
	MOVE 3,BITS(3)
	TDNE 3,IMPHCT(2)	; Recently sent a message
	 JRST [	ANDCAM 3,IMPHCT(2)
		JRST IMPET4]	; Send next time not this
	IORM 3,IMPHCT(2)	; Remember we have sent one
	MOVE 2,1		; If up, data=host
	CALL IMPNOP		; And send nop (echo might be better)
IMPET4:	AOBJP 7,IMPEET
IMPET0:	TRNE 7,7		; Wait every eighth entry
	 JRST IMPET
	MOVEI 1,UPROBT*8/IMPNLK	; Delay for correct interval
IMPET1:	MOVEM 7,IMPCCH		; Save current state
IMPCC6:	ADD 1,TODCLK		; Compute when to do it again
	MOVEM 1,IMPTIM
	RET

; Check for overdue rfnm's
; Count down rfnmc field if non-zero.
; If it reaches 0, then generate impbug cause rfnm seems lost
RFNCHK:	IMSCLK(IMCRFN)		; Charge imcrfn
	MOVSI 10,-IMPNLK	; Set to scan conn table
RFNCK0:	MOVSI 6,(RFNMC)
	MOVEI 5,1B19
RFNCK2:	TDNN 5,IMPLT1(10)	; Connection in use?
	TDNN 6,IMPLT2(10)	; Rfnm set here?
RFNCK1:	AOBJN 10,RFNCK2		; No
	JUMPGE 10,RFNCK4
	LDB 7,[POINT 2,IMPLT2(10),1]
	SOJE 7,RFNCK5		; Decrement count, jump if exhausted
	DPB 7,[POINT 2,IMPLT2(10),1]
	JRST RFNCK1

RFNCK5:	PIOFF			; Prevent confusion if pi stores buffer
	HRRZ 2,IMPLT3(10)	; While we get message to retransmit
	HLLZS IMPLT3(10)	; And clear the pointer
	PION
	JUMPE 2,RFNCK3		; Apparently hasn't made it thru q yet
	HRRZ 3,IMPLT1(10)	; Get host/link
	ROT 3,-8
	ANDI 3,377		; Retain only host
	MOVSI 5,(RXMTF)
	CAME 3,NLHOST		; If local host
	TDNE 5,IMPLT2(10)	; Or retransmission wanted?
	 JRST RFNCK7		; Then retransmit
	CALL RLNTBF		; Else release the buffer
	DPB 7,[POINT 2,IMPLT2(10),1]
	HRRZ 2,IMPLT1(10)	; Yes, rfnm lost. get host-link
	CALL IMP8X1		; Reformat for bug msg
	BUG(IMH,<RFNM OVERDUE>,X)
	AOS IMPNOS		; Cause output scan to restart output
RFNCK6:	AOBJN 10,RFNCK0		; Reset ac5 and 6
RFNCK4:	MOVEI 1,RFNTMO
	ADD 1,TODCLK		; Set next check for rfntmo msec.
	MOVEM 1,RFNTIM
	RET

RFNCK7:	IORM 6,IMPLT2(10)	; Set rfnmc again
	CALL IMPQOA		; Put message back on output queue
	JRST RFNCK6		; Go to next item

RFNCK3:	IORM 6,IMPLT2(10)	; Set rfnmc again
	HRRZ 2,IMPLT1(10)	; Get host/link
	CALL IMP8X1		; Format for bug msg
	BUG(IMH,<MESSAGE STUCK IN OUTPUT QUEUE>,X)
	JRST RFNCK6		; Go on to next item

; Queue irreg msg

IMP8XQ:	AOS 3,IMP8XI		; Increment input index
	CAIL 3,IMP8XS
	SETZB 3,IMP8XI		; Wraparound
	CAMN 3,IMP8XO		; Overflow?
	BUG(NTE,<IRREG MSG BUFFER OVERFLOW>)
	MOVEM 2,IMP8XB(3)
	AOS IMP8XC
	RET

IMP8XM:	IMSCLK(IMC8XM)		; Charge to imc8xm
	AOS 3,IMP8XO		; Retrieve stuff from queue
	CAIL 3,IMP8XS
	 SETZB 3,IMP8XO		; Wraparound
	MOVE 1,IMP8XB(3)
	SOS IMP8XC
IFDEF DBGBUF,<
	CALL DBGIIM>
	LDB 3,[POINT 4,1,7]	; Message type code
	LDB 2,[POINT 16,1,23]	; Host-link
	XCT IMPMTT(3)		; Dispatch to appropriate routine
	RET

XX==JRST IMP8XX			; Unimplemented code

IMPMTT:	BUG(HLT,<IMP - REGULAR MESSAGE ON IRREG QUEUE>)
	JRST IMPEC1		; Error
	JRST IMPDN2		; Imp going down
	XX			; Formerly blocked link
	JFCL			; Nop

	JRST IMRFNM		; Rfnm
	JRST IMPEC6		; Dead host status
	JRST IMPEC7		; Destination dead
	JRST IMPEC8		; Error
	JRST IMPEC9		; Incomplete transmission
	JRST IMPE10		; Imp dropped ready line
	XX			; Cease timeout
	XX			; Cease sent
	XX			; Unassigned
	XX			; "

	XX			; "

; Irregular message processors

; Error in leader (type 1)

IMPEC1:	TRNN 1,377B31		; Sub-type 0?
	 JRST IMPEC8		; Yes, retransmit
	JRST BADIRM		; Go cause it to be printed

; Imp going down (type 2)

IMPDN2:	MOVEM 1,IMPGDM		; Save it for printing
	AOS JB0FLG
	MOVEM 1,IGDMSG
	GTAD
	MOVEM 1,IGDTIM
	RET

; Rfnm (type 5)

IMRFNM:	MOVEI 1,1B18(2)		; Host and link, denote send connection
	ILOCK
	CALL LNKLUK		; Lookup in link table
	 JSP 2,BADIRY		; Not found
	PUSH P,1
	MOVSI 2,(RFNMC)
	PIOFF			;  if rfnm returns before msg out done
	ANDCAM 2,IMPLT2(1)	; Clear rfnm and check flags
	HRRZ 2,IMPLT3(1)	; Get retransmit buffer
	HLLZS IMPLT3(1)
	PION
	SKIPE 2
	 CALL RLNTBF
	POP P,1
	HLRE IMPUN,IMPLT1(1)	; Get impun
	MOVSI 2,(RXMTF)
	TDNN 2,IMPLT2(1)	; Have we been retransmitting?
	 JRST IMPKO1		; No. just send next message
	ANDCAM 2,IMPLT2(1)	; Yes. stop retransmitting
	CALL IMPKO1		; Send next message
	JUMPGE IMPUN,SVCRST	; If not ctrl generate service restored
	RET

; Dead host status (type 6)

IMPEC6:	TLNE 1,(1B1)		; Usual type?
	 RET			; No. ignore it
	ROT 2,-9		; Get host number/2 low bit in b0
	LSH 1,-4		; Get msg id -- subtype
	ANDI 1,177777		; Keep 16 bits
	IORI 1,1B18+1B19	; Mark info valid and dead
	JUMPL 2,[		; Odd host?
		HRRM 1,HSTSTS(2); Yes, store in rh
		JRST .+2]
	HRLM 1,HSTSTS(2)	; No, store in lh
	ANDI 1,17		; Extract sub-type
	CAIE 1,2		; Is it simply tardy?
	CAIN 1,^D10		; Or at a bpt
	 RET			; Yes, no further action
	ROT 2,9			; No. get back host/link
	JRST IMPDD1		; And declare it dead

; Destination dead (type 7)

IMPEC7:	PUSH P,2
	LDB 1,[POINT 8,2,27]	; Extract host
	IDIVI 1,^D36
	MOVE 1,IMPHRT(1)	; Get host up bits
	AND 1,BITS(2)		; Mask in the correct one
	POP P,2
	JUMPE 1,IMPDD1		; If already down, call it down
	MOVE 1,2		; Host/link
	IORI 1,1B18		; Send
	ILOCK
	CALL LNKLUK		; Find the link
	 JSP 2,BADIRY
IMPECC:	MOVSI 2,(RXMTF)
	IORM 2,IMPLT2(1)	; Cause retransmission
	HLRE IMPUN,IMPLT1(1)	; Get "unit"
	IUNLK
	JUMPL IMPUN,R		; Done if control connection
	CALL SVCINT		; Else perform service interruption
	RET

IMPDD1:	LDB 1,[POINT 8,2,27]	; Host number
HSTDED:	MOVEI 3,0(1)
	IDIVI 3,^D36
	MOVE 5,BITS(4)
	TDNE 5,IMPHRT(3)	; Did we already know he was down?
	IFDEF POLLF,<
	IORM 5,IMPHL1(3)>	; Request obituary
	ANDCAM 5,IMPHRT(3)	; Mark him down
	CALL IMPXLT		; Clear link table for dead host
	CALL NETHDN		; Clean up any connections to host
	RET

; Error in data & incomplete transmission (types 8 & 9)

IMPEC8:
IMPEC9:	MOVEI 1,1B18(2)		; Send connection
	ILOCK
	CALL LNKLUK		; Get lt index for this one
	 JSP 2,BADIRY		; Not there, can't retransmit
	PIOFF			; Prevent pi from storing in implt3
	HRRZ 2,IMPLT3(1)	; Get buffer for retransmission
	HLLZS IMPLT3(1)
	PION
	JUMPE 2,IMPECC		; None there now. retransmit later
	IUNLK
	CALL IMPQOA		; Put it back on output queue
	RET

; Interface reset (type 10)

IMPE10:	MOVSI 1,-IMPNLK
IMPRSY:	PUSH P,1
	ILOCK
	MOVE 2,IMPLT1(1)
	TRNE 2,1B19		; In use?
	 JRST IMPZSY		; No
	TRNN 2,377
	 JRST IMPZSY		; Control
	TRNE 2,1B18		; Send?
	 JRST IMPSSY		; Yes
	LDB 2,LTLINK
	LDB 1,LTHOST
	IUNLK
	CALL IMPRAP
	JRST IMPXSY

IMPSSY:	CALL IMPSYN
IMPZSY:	IUNLK
IMPXSY:	POP P,1
	AOBJN 1,IMPRSY
	MOVSI 4,-400
IMPOSY:	HRRZ 1,4
	CALL CHKNWP		; DOES THIS HOST UNDERSTAND?
	 JRST [	PUSH P,4	; NO
		CALL HSTDED
		POP P,4
		JRST .+1]
	AOBJN 4,IMPOSY
	AOS IMPNOS		; Scan for output to pick up rarrf's
	RET

; Check if host for control message knows about new protocol stuff

CHKNWP:	PUSH P,2
	PUSH P,1
	IDIVI 1,^D36
	MOVE 2,BITS(2)
	TDNE 2,NWPBT(1)
	 AOS -2(P)
	POP P,1
	POP P,2
	RET

; MARK NEW PROTOCOL BIT FOR HOST

MRKNWP:	PUSH P,1
	PUSH P,2
	IDIVI 1,^D36
	MOVE 2,BITS(2)
	IORM 2,NWPBT(1)
	POP P,2
	POP P,1
	RET

; Error tail ends for irregular msg processors

BADIRY:	IUNLK
BADIRM:
IMP8XX:	MOVE 2,IMP8XO
	ADD 2,[4,,IMP8XB-1]	; Make pointer to one before message
	BUG(IML,<Received irreg msg with unknown link or type>,X)
	RET

IMP8X1:	DPB 2,[POINT 8,2,9]	; Unpack host-link in b20-35 into
	LSH 2,-^D8		; Xwd link,host
	TRZ 2,777400
	RET


; Scan for input ready on control link connection

IMPCN0:	IMSCLK(IMCCNP)		; Charge to imccnp
	MOVEI 5,1B18+1B19+377	; Connection must be receive, link 0
	PUSH P,BHC		; Put a zero on stack
	MOVSI 6,-IMPNLK
IMPCN4:	TDNE 5,IMPLT1(6)	; Desired connection?
	AOBJN 6,.-1		; No
	JUMPGE 6,IMPCN5		; Done
	AOS 0(P)		; Count number of msgs seen
	MOVEI 1,0(6)		; Conn index
	PUSH P,5		; Save these ac's
	PUSH P,6
	CALL IMPCNP		; Go process this host's control msgs
	POP P,6			; Restore ac's
	POP P,5
	MOVEI 1,0(6)
	CALL IMPCLL		; Close "connection"
	JRST IMPCN4
IMPCN5:	POP P,1			; Done. get count of processed msgs
	JUMPN 1,R		; If any, done.
	BUG(IMP,<IMPNCL TOO HIGH>,X)
	SOS IMPNCL		; Count it down so don't loop.
	RET

; Control table for control opcodes

	DEFINE CTOP (A,C)
<	XWD IM8'A,C>

I8CCM:	CTOP NOP,0
	CTOP RTS,441000
	CTOP STR,441000
	CTOP CLS,440000
	CTOP ALL,124000

	CTOP GVB,111000
	CTOP RET,124000
	CTOP INR,100000
	CTOP INS,100000
	CTOP ECO,100000

	CTOP ERP,100000
	CTOP ERR,144200
	CTOP RST,0
	CTOP RRP,0
	CTOP RAR,100000
	CTOP RAS,100000
	CTOP RAP,100000
	CTOP NXR,100000
	CTOP NXS,100000
I8NCCM==.-I8CCM

; Process control message

IMPCNP:	LDB 2,LTHOST		; Get host
	MOVEM 2,IMPCHO		; And leave it for following commands
	IDIVI 2,^D36		; Compute index to bit tables
	MOVE 3,BITS(3)
	TDNE 3,IMPBHT(2) 	; Bad host?
	 RET			; Yes. let impcll flush it
	SETZM IMPCHU		; Say host not ready (no rst/rrp)
	TDNE 3,IMPHRT(2)	; Unless it is up
	 SETOM IMPCHU		; Then say it's up
IMP8T6:	CALL UPBYT		; Get next op code
	 RET			; None left...done
	CAIL 3,I8NCCM		; Legal code?
	JRST IMP8T4		; No, flush whole message
	MOVEI 6,I8CCM(3)	; Address of table entry for this code
	HRLI 6,220300		; Pntr for 3-bit bytes specifying fields
	HLRZ 7,I8CCM(3)		; Get routine dispatch address
	MOVEI 4,I8CAL		; Args buffer
IMP8T1:	ILDB 5,6		; Number of (8-bit) bytes in next arg
	SETZ 2,			; Clear word to construct arg
	JUMPN 5,IMP8T2		; 0 means no more args
	CAIN 7,IM8NOP		; Check for NOP's at this level
	 JRST IMP8T6
	CAIE 7,IM8RST		; Is rst?
	CAIN 7,IM8RRP		; Or rrp?
	 SETOM IMPCHU		; Yes, consider him up
	SKIPN IMPCHU		; Is he up?
	 MOVEI 7,IMSRST		; No. force call to send rst
	PUSH P,1		; Preserve ac1
	MOVE 6,[XWD IMPCHO,1]	; Move args to acs 1-6
	BLT 6,6			; Ac1 (impcho) always gets host number
	CALL 0(7)		; Do function
	POP P,1			; Restore 1 (lt index)
	JRST IMP8T6		; See if another

IMP8T2:	PUSH P,2		; Preserve ac2
	CALL UPBYT		; Get a byte of argument
	 JRST IMP8T5		; Whoops, short message
	POP P,2
	ROT 3,-8		; And shift it
	LSHC 2,8		; Into the arg being accumulated
	SOJG 5,IMP8T2		; All bytes packed?
	MOVEM 2,0(4)		; Yes, store arg in buffer
	AOJA 4,IMP8T1		; And see if more args

IMP8T5:	SUB P,BHC+1
IMP8T4:	MOVE 2,IMPCHO		; Screwed up control msg
	BUG(IMH,<ILL FMT CTL MSG>,X)
	RET			; Let impcll flush rest of message(s)

; Control routines

; Nop (type 0)

IM8NOP:	RET

; Receiver to sender request for connection (type 1)

IM8RTS=RECRTS		; Code in  netwrk

; Sender to receiver request for connection (type 2)

IM8STR=RECSTR		; Code in netwrk

; Close connection (type 3)

IM8CLS=RECCLS		; Code in netwrk

; Allocate (type 4)

IM8ALL:	LSH 1,^D8		; Concat host and link
	IORI 1,1B18(2)		; Bit for send connection
	ILOCK
	CALL LNKLUK		; Lookup in connect table
	 JSP 2,BADLKS		; Not found
	HLRE IMPUN,IMPLT1(1)	; Get unit
	JUMPL IMPUN,ULKIDV	; Control connection, shouldn't happen
	MOVSI 2,(RARF)		; Waiting for rar?
	TDNE 2,IMPLT2(1)
	 JRST ULKIDV		; Yes, ignore all allocates
	HRRZ 2,IMPLT4(1)	; Get current msg alloc
	ADD 2,3
	CAILE 2,777777		; Bigger than max?
	JRST IMPB06		; Yes
	HRRM 2,IMPLT4(1)
	ADDB 4,NETBAL(IMPUN)	; Update bit allocation
	CAML 4,[1B3]		; Excessive?
	JRST IMPB06
	LDB 2,PNVT
	CAIL 2,NVTLO		; Nvt attached?
	CAILE 2,NVTHI
	JRST IMPKO1		; No, test more output for reg. connet'n
	IUNLK
	CALL NETTCS		; Yes, pack up more characters
	JRST IMPCKO		; And try to send

; Give back (code 5)

IM8GVB:	LSH 1,^D8		; Give back requested
	IORI 1,1B18(2)		; Construct host-link for send socket
	ILOCK
	CALL LNKLUK
	 JSP 2,BADLKS		; Not found
	HLRE IMPUN,IMPLT1(1)	; Get unit
	JUMPL IMPUN,ULKIDV	; Control conn, shouldn't happen
	HRRZ 2,IMPLT4(1)	; Msg alloc
	CAIL 3,200		; All?
	JRST .+3		; Yes
	IMUL 2,3		; No, calc how much
	IDIVI 2,200
	HRRZ 3,IMPLT4(1)
	SUB 3,2			; Reduce current msg alloc
	HRRM 3,IMPLT4(1)
	PUSH P,2
	MOVE 2,NETBAL(IMPUN)	; Bit allocation
	CAIL 4,200		; Return all?
	JRST .+3		; Yes
	MUL 2,4			; No, calc how much
	DIVI 2,200
	MOVN 3,2
	ADDM 3,NETBAL(IMPUN)	; Reduce bit alloc
	MOVE 4,2		; Setup call for ret
	POP P,3
	LDB 2,LTLINK
	LDB 1,LTHOST
	IUNLK
	CALL IMPRET		; Send the ret
	RET

; Return (code 6)

IM8RET:	RET			; Never send gvb/ nver get ret

; Interrupt from receiver (code 7)

IM8INR:	MOVE 3,1
	LSH 1,^D8
	IORI 1,1B18(2)		; We must be a send connection
	ILOCK
	CALL LNKLUK
	 JSP 2,BADLKS		; No such connection
	HLRE IMPUN,IMPLT1(1)	; Unit
	IUNLK
	JUMPL IMPUN,R		; Control connection, shouldn't happen
	MOVE 1,3		; Host
	JRST RECINR		; Not specified for nvt

; Interrupt from sender (code 8)

IM8INS:	MOVE 3,1
	LSH 1,^D8
	IORI 1,0(2)		; Combine host-link
	ILOCK
	CALL LNKLUK
	 JSP 2,BADLKR
	HLRE IMPUN,IMPLT1(1)
	IUNLK
	JUMPL IMPUN,R
	MOVE 1,3
	LDB 3,PNVT		; Get nvt number
	CAIL 3,NVTLO
	CAILE 3,NVTHI
	JRST RECINS		; Isn't nvt, go do regular connection
	MOVE 2,3
	LDB 1,PTINTC
	SUBI 1,1		; Ins counts -1, sync char counts 1
	DPB 1,PTINTC
	LDB IMPUN,PTNETI
	SKIPN NETBAL(IMPUN)
	 CALL NVTRAL		; Send more allocation
	RET


; Echo and echo reply (code 9 & 10)

IM8ECO:	CALL IMPERP		; Send reply
	RET

IM8ERP:	CAME 1,2		; We send echo with data = host
	JFCL			; Not equal ... oh well
	RET

; Error (code 11)

IM8ERR:	MOVSI 2,0(2)		; Arg
	HRRI 2,0(1)		; Host
	BUG(IMH,<RECD NCP ERR>,X)
	RET

; Reset and reset-reply ctrl msg (codes 12 & 13)

IM8RST:	PUSH P,1
	CALL RECRST		; Notify fsm
	POP P,1
IM8RRP:	ROT 1,-1		; Halve
	MOVEI 2,1B18		; Valid info, host up
	JUMPL 1,[		; If od host number
		HRRM 2,HSTSTS(1); Put into rh
		JRST .+2]
	HRLM 2,HSTSTS(1)
	ROT 1,1			; Restore host number
	IDIVI 1,^D36		; Get bit for host tables
	MOVE 5,BITS(2)
	IORM 5,IMPHRT(1)	; Mark host alive
	RET

; Reset allocate by receiver (code 14)

IM8RAR:	CALL MRKNWP		; MARK THIS HOST AS USING NEW PROTOCOL
	LSH 1,^D8
	IORI 1,1B18(2)
	ILOCK
	CALL LNKLUK
	 JSP 2,BADLKS
	HLRE IMPUN,IMPLT1(1)
	JUMPL IMPUN,ULKIDV
	MOVSI 2,(RARF)
	ANDCAM 2,IMPLT2(1)	; Clear resync in progress flag
	JRST ULKIDV

; Reset allocate by sender (code 15)

IM8RAS:	CALL MRKNWP		; MARK THIS HOST AS USING NEW PROTOCOL
	LSH 1,8
	IORI 1,0(2)
	ILOCK
	CALL LNKLUK
	 JSP 2,BADLKR
	HLRE IMPUN,IMPLT1(1)
	JUMPL IMPUN,ULKIDV
	HLLZS IMPLT4(1)
	HLRZ 4,IMPLT4(1)	; ANY CURRENT BUFFER?
	JUMPE 4,IM8RA1		; NO
	MOVE 4,2(4)		; ACCUMULATE BYTES
IM8RA1:	HLRZ 2,IMPLT3(1)	; GET BUFFER
	JUMPE 2,IM8RA3		; NONE
IM8RA2:	LDB 3,[POINT 16,2(2),27]; NUMBER OF BYTES
	ADD 4,3
	AOS IMPLT4(1)		; COUNT MSGS
	HLRZ 2,0(2)		; NEXT BUFFER
	JUMPN 2,IM8RA2
IM8RA3:	LDB 3,IMPLBS		; BYTE SIZE
	IMUL 3,4
	MOVEM 3,NETBAL(IMPUN)
	IUNLK
	LDB 2,LTLINK
	LDB 1,LTHOST
	CALL IMPRAR
	LDB 2,PNVT
	CAIL 2,NVTLO
	CAILE 2,NVTHI
	 JRST NETRAL
	JRST NVTRAL

; Reset allocate please (code 16)

IM8RAP:	CALL MRKNWP		; MARK THIS HOST AS USING NEW PROTOCOL
	LSH 1,8
	IORI 1,1B18(2)
	ILOCK
	CALL LNKLUK
	 JSP 2,BADLKS
	HLRE IMPUN,IMPLT1(1)
	JUMPL IMPUN,ULKIDV
	MOVSI 2,(RARF!RARRF)
	IORM 2,IMPLT2(1)
	JRST IMPKO1

; Non-existent link from receiver and sender (codes 17 & 18)

IM8NXR:	IORI 2,1B18
IM8NXS:	CALL MRKNWP		; MARK THIS HOST AS USING NEW PROTOCOL
	LSH 1,8
	IOR 1,2
	ILOCK
	CALL LNKLUK
	 JRST ULKIDV
	HLRE IMPUN,IMPLT1(1)	; Get impun
	JUMPL IMPUN,ULKIDV	; Ignore if control conn
	IUNLK
	CALL SK2DWN
	RET

; Link lookup failure for receivers and senders

BADLKR:	SKIPA 3,[IMPNXR]
BADLKS:	MOVEI 3,IMPNXS
	IUNLK
	PUSH P,2		; SAVE PC FOR INSPECTION
	MOVE 2,1
	LSH 1,-8
	ANDI 1,377
	ANDI 2,377
	PUSH P,1
	HRLM 2,0(P)
	CALL 0(3)
	POP P,2
	BUG(IMH,<RECD CTL MSG FOR UNKNOWN LINK>,X)
	SUB P,BHC+1		; FLUSH SAVED PC
	RET

; Calls from ncp

; Open link, i.e. associate host-link and unit
; 1/ host
; 2/ link
; 3/ byte size

IMPOPL:	ILOCK
	LSH 1,^D8
	IORI 1,0(2)		; Concat host and link
	CALL LNKLUK		; Now in table?
	 JRST IMPOP0		; No, slot to use returned in 2
	IUNLK
	BUG(IMP,<IMPOPL: Link already exists>,X)
	RET

IMPOP0:	CALL IMPOP1
	IUNLK
	RET

IMPOP1:	EXCH 1,2
	MOVEM 2,IMPLT1(1)
	HRLM IMPUN,IMPLT1(1)
	MOVEI 2,IMPLT3(1)	; Init bfr queue
	MOVEM 2,IMPLT2(1)	; Make in point to out
	SETZM IMPLT3(1)
	SETZM IMPLT4(1)
	DPB 3,IMPLBS		; Set byte size
	RET

; Close link, inverse of above
; 1/	LT INDEX

IMPCLL:	ILOCK
	CALL IMPLL0
	IUNLK
	RET

IMPLL0:	MOVEI 2,1B19
	TDNE 2,IMPLT1(1)	; Was in use?
	RET			; No, do nothing else
	EXCH 2,IMPLT1(1)	; Set entry to deleted
	TRNE 2,377		; Control link?
	 JRST IMPLL9		; No, skip this
	TRNE 2,1B18		; Send?
	 SOSA IMPNOL		; Yes, decrease count of send cl's
	  SOS IMPNCL		; Else decrease count of recv cl's
IMPLL9:	AOS LNKNDL		; Count deletes
	CALL IMPLL1		; Flush messages
	RET

; Set done flag for connection
; 1/ conn index

IMPSDB:	MOVSI 2,(LTDF)
	IORM 2,IMPLT2(1)
	AOS IMPNOS		; Make output be looked at
	RET

; Abort link (called by ncp if transmission aborted)

IMPABL:	ILOCK
	CALL IMPLL3		;CLEAR QUEUES, DON'T CLEAR RFNMC
	IUNLK
	RET

; Clear link table for particular host

IMPXLT:	PUSH P,1
	ILOCK
	MOVSI 1,-IMPNLK		; Set to scan conn table
IMPXLL:	LDB 2,LTHOST		; Get host
	CAIE 2,@0(P)		; Specified one?
	 JRST IMPXLN
	LDB 2,LTLINK		; Get link
	JUMPE 2,[CALL IMPLL0	; If control link, flush all
		JRST IMPXLN]
	CALL IMPLL1		; Else flush queued messages
IMPXLN:	AOBJN 1,IMPXLL
	IUNLK
	POP P,1
	RET

; Resync allocation

IMPSYN:	PUSH P,1
	LDB 1,LTHOST
	CALL CHKNWP		; NEW PROTOCOL?
	 JRST [	POP P,1
		RET]
	POP P,1
	MOVSI 2,(RARF!RARRF)
	IORM 2,IMPLT2(1)
	AOS IMPNOS
	RET

; Flush all messages for a connection

IMPLL3:	TDZA 2,2		;DON'T CLEAR RFNMC
IMPLL1:	MOVSI 2,(RFNMC)		;CLEAR RFNMC
	PUSH P,2		;A BIT LATER ON
	HLRZ 2,IMPLT4(1)
	HRRZS IMPLT4(1)
	PUSH P,1
	CAIE 2,0		; Is current bfr?
	PUSHJ P,RLNTBF
	MOVE 1,0(P)		; Get back lt index
	MOVEI 2,IMPLT3(1)
	HRRM 2,IMPLT2(1)	; Fix tail pointer
	PIOFF
	MOVE 2,-1(P)		;GET BITS TO CLEAR, EITHER 0 OR RFNMC
	ANDCAM 2,IMPLT2(1)	; Cancel outstanding rfnm
	HRRZ 2,IMPLT3(1)	; Get retransmit buffer
	HLLZS IMPLT3(1)
	PION
	SKIPE 2
IMPLL2:	CALL RLNTBF		; Yes, release it
	POP P,1
	HLRZ 2,IMPLT3(1)	; Release any buffers on queue
	JUMPE 2,[POP P,(P)
		POPJ P,0]
	HLLZ 3,0(2)
	HLLM 3,IMPLT3(1)
	PUSH P,1
	JRST IMPLL2

; Control message senders

; Nop, rts, str, cls, all, gvb, ret, inr, ins, eco, erp

IMPNOP:	PUSH P,[XWD 0,0]	; Nop, no args
	JRST IMPSCM

IMPRTS:	PUSH P,[XWD 441000,1]	; Arg descriptor,,opcode
	JRST IMPSCM		; Construct message and output

IMPSTR:	PUSH P,[XWD 441000,2]
	JRST IMPSCM

IMPCLS:	PUSH P,[XWD 440000,3]
	JRST IMPSCM

IMPALL:	CAIGE 3,0		; Don't send neg allocs
	SETZ 3,
	CAIGE 4,0
	SETZ 4,
	PUSH P,1
	LDB 1,PLIDX		; Get conn index
	PUSH P,2
	MOVSI 2,(RARF)		; Waiting for ras?
	TDNE 2,IMPLT2(1)
	 JRST [	POP P,2		; Yes. do nothing
		POP P,1
		RET]
	POP P,2			; No, get back ac2
	ADDM 3,IMPLT4(1)	; Update msg alloc
	POP P,1
	ADDM 4,NETBAL(IMPUN)	; Bits
	PUSH P,[XWD 124000,4]
	JRST IMPSCM

IMPGVB:	PUSH P,[XWD 111000,5]
	JRST IMPSCM

IMPRET:	PUSH P,[XWD 124000,6]
	JRST IMPSCM

IMPINR:	PUSH P,[XWD 100000,^D7]
	JRST IMPSCM

IMPINS:	PUSH P,[XWD 100000,^D8]
	JRST IMPSCM

IMPECO:	PUSH P,[XWD 100000,^D9]
	JRST IMPSCM

IMPERP:	PUSH P,[XWD 100000,^D10]
	JRST IMPSCM

; Control message senders (continued)

; Err, rst, rrp, rar, ras, rap, nxr, nxs

IMPERR:	PUSH P,[XWD 144200,^D11]
	JRST IMPSCM

IMSRST:	PUSH P,[XWD 0,^D12]
	JRST IMPSCM

IMPRRP:	PUSH P,[XWD 0,^D13]
	JRST IMPSCM

IMPRAR:	CALL CHKNWP
	 RET
	PUSH P,[100000,,^D14]
	JRST IMPSCM

IMPRAS:	CALL CHKNWP
	 JRST IM8RAR		; Resync not implemented -- sim rar
	PUSH P,[100000,,^D15]
	JRST IMPSCM

IMPRAP:	CALL CHKNWP
	 RET			; DOES NOT UNDERSTAND NEW PROTOCOL
	PUSH P,[100000,,^D16]
	JRST IMPSCM

IMPNXR:	CALL CHKNWP
	 RET
	PUSH P,[100000,,^D17]
	JRST IMPSCM

IMPNXS:	CALL CHKNWP
	 RET
	PUSH P,[100000,,^D18]
	JRST IMPSCM

; Send control message
; 1/ dest host
; 0(p) arg descriptor,,opcode

IMPSCM:	EXCH 13,0(P)
	PUSH P,6
	PUSH P,7
	PUSH P,10
	PUSH P,11
	PUSH P,12
	PUSH P,14
	MOVEI 10,0(P)		; Use 3 words on stack as buffer
	ADD P,BHC+3
	HRLI 10,1000		; Construct byte pointer, 8-bits
	PUSH P,10		; Save it for later use
	IDPB 13,10		; Store opcode as first byte of message
	MOVEI 11,1		; Init message byte count
	MOVEI 14,2		; Index to args
IMPSC4:	SETZ 12,
	LSHC 12,3		; Next arg descriptor byte
	JUMPN 12,IMPSC3		; 0 means done
	LSH 1,^D8
	IORI 1,1B18
	ILOCK
	CALL LNKLUK		; See if connection now exists
	 JRST [	MOVEI 3,^D8	; Doesn't, create it
		CALL IMPOP1
		AOS IMPNOL	; Count open output links
		HRROS IMPLT1(1)	; Set unit neg
		MOVEI 3,377777	; Set infinite msg alloc
		HRRM 3,IMPLT4(1)
		MOVSI 3,(HIPFLG)
		IORM 3,IMPLT2(1)	; Set high priority flag
		JRST .+1]
	POP P,3			; Byte ptr
	MOVEI 4,0(11)		; Count
	CALL PKMSG0		; Does iunlk
	SUB P,BHC+3
	POP P,14
	POP P,12
	POP P,11
	POP P,10
	POP P,7
	POP P,6
	POP P,13
	RET

IMPSC3:	ADDI 11,0(12)		; Accumulate byte count of message
	MOVNI 6,0(12)		; Compute number of bits to left of arg
	IMULI 6,^D8		; Number bytes times bits per byte
	ADDI 6,^D36		; Subtracted from size of word
	MOVE 7,0(14)		; Get next arg
	LSH 7,0(6)		; Shift out unused bits
	ROT 7,^D8		; Shift next byte into place
	IDPB 7,10		; Store it in message buffer
	SOJG 12,.-2		; For all bytes
	AOJA 14,IMPSC4		; Index arg pointer

; Network tty logic
; For connection driven via the tty service routines

; Assign a pseudo (network) tty
; 1/ receive unit
; 2/ send unit
; Returns 1/ line number

ASNNVT:	MOVEI 3,NVTLO		; Nvt's start after scanner ttys
	NOSKED
ASNPT1:	SKIPGE TTNETW(3)	; Free?
	JRST ASNPT3		; Yes
ASNPT2:	CAIGE 3,NVTHI	; Looked at all nvt's?
	AOJA 3,ASNPT1		; No
	OKSKED			; Yes,
	RET			; Return bad

ASNPT3:	SKIPL TTFORK(3)		; Tty already attached?
	JRST ASNPT2		; Yes, don't use
	TLNN 1,(1B2)		; New nvt protocol request?
	 TLZA 3,-1		; No, make zeroes
	  HRLI 3,NEWNVB		; Yes, make new nvb bit
	HLLZM 3,TTNETW(3)	; Clear ttnetw except for newnvb
	SETZM NVTOPF(3)		; Clear option status
	OKSKED
	EXCH 2,3
	DPB 1,PTNETI		; Remeber units
	DPB 3,PTNETO
	CALL TTCOBI
	CALL TTCIBF		; Clear buffers
	MOVEI 1,3
	DPB 1,[POINT 2,TTFLGS(2),33]
	MOVEI 1,1
	DPB 1,[POINT 2,TTFLGS(2),29]
	MOVEI 1,0(2)		; Return line number
	AOS 0(P)		; Return good
	RET

; Close a full duplex net tty connection

NVTDET:	PUSH P,2
	SKIPL TTFORK(2)		; Line attached?
	CALL NVTCOF		; Yes, initiate carrier off psi
	MOVE 2,0(P)
	SKIPG TTNETW(2)		; Reasonable units?
	JRST NVTDT1		; No
	LDB IMPUN,PTNETI	; Input unit
	CALL NVTCLZ		; Close it
	MOVE 2,0(P)
	LDB IMPUN,PTNETO	; Output unit
	CALL NVTCLZ		; Close it
NVTDT1:	POP P,2
	SETZM NVTOPF(2)
	SETOM TTNETW(2)
	SETZM TTPSI(2)
	CALL TTCOBI
	CALL TTCIBF
	RET

PNVT:	POINT 18,NETBUF(IMPUN),35	; Used to get nvt line number

; Called from tci

NVTCAP:				; Alternate name
NETCAP:	SKIPGE TTNETW(2)	; Still connected?
	RET			; No
	PUSH P,IMPUN
	PUSH P,2
	NOINT			; Protect any possible ilocks
	CALL CKNNVT		; If not new nvt
	 JRST NETCA1		; Skip sending ga
	CALL NVTXGA		; SEND GA IF NEEDED
NETCA1:	LDB IMPUN,PTNETI
	SKIPN NETBAL(IMPUN)
	 CALL NVTRAL		; Probably only 1st time, or after cfibf
	OKINT
	POP P,2
	POP P,IMPUN
	RET

; Check if this nvt is using new protocol

CKNNVT:	PUSH P,1
	MOVSI 1,NEWNVB
	TDNE 1,TTNETW(2)
	 AOS -1(P)
	POP P,1
	RET

; Check for special nvt output processing
; Called from tcoutx for nvt's

NVTCHO:	PUSHJ P,CKNNVT		; Check if new nvt
	 RET			; Not. no special processing
	PUSH P,1		; Save character
	MOVSI 3,NVTCRP
	TDNE 3,TTNETW(2)	; Was previous char cr?
	 JRST [	ANDCAM 3,TTNETW(2)	; Yes, clear it
		CAIE 1,12	; Must be followed by lf
		CAIN 1,0	; Or null
		 JRST .+1
		SETZ 1,		; If not follow it with null
		PUSHJ P,TCOBQ
		MOVE 1,0(P)	
		JRST .+1]
	CAIN 1,IACCH		; Iac?
	PUSHJ P,TCOBQ		; Yes. double the special character
	POP P,1
	RET

; Set NVTCRP called from TTYSRV

NVTXCR:	CALL CKNNVT
	 RET
	MOVSI 3,NVTCRP
	IORM 3,TTNETW(2)
	RET

; Called from tcout

NTTCSO:	AOS TTNOF		; Request tty scan
	AOS IMPFLG
	RET

; CHECK FOR ECHOS DONE BY RCTE
; RETURNS
;	+1	; NO RCTE ACTION
;	+2	; CHARACTER NOT A BREAK CHARACTER
;	+3	; CHARACTER IS A RCTE BREAK
; THE 400 BIT IS SET IN THE CHARACTER IN AC1 IF RCTE DID THE ECHO.

NVTRCC::CAIL 2,NVTLO
	CAILE 2,NVTHI
	 JRST RSKP
	PUSH P,3		; STASH AC3
	MOVEI 3,(1B<RCTOPT+WILOPT>)
	TDNN 3,NVTOPF(2)
	 JRST NVTRC1		; RCTE NOT ON
	MOVEI 3,0(1)		; THE CHARACTER
	ANDI 3,177		; RETAIN LOW BITS
	LSH 3,-2		; DIVIDE BY 4 BYTES PER WORD
	TRNE 1,2		; IF SECOND TWO BYTES WANTED
	 SKIPA 3,CHWTB(3)	; GET THEM
	  MOVS 3,CHWTB(3)	; ELSE GET FIRST TWO BYTES
	TRNN 1,1		; IF BYTE 0 OR 2
	LSH 3,-9		; SHIFT OVER
	HRROS 3
	AND 3,TTBRKC(2)		; RETAIN BITS SPECIFIED AS BREAKS
	TRNN 3,777		; IS THIS CHAR ONE OF THEM?
	 LSH 3,-1		; YES, SHIFT BIT 15 INTO BIT 16
	TLNE 3,2		; WAS ECHO SUPPRESSED?
NVTRC1:	 AOSA -1(P)		; YES, INDICATE RCTE HAS DONE NOUGHT
	  IORI 1,400		; ELSE INDICATE ECHO GENERATED
	POP P,3			; RESTORE AC3
	RET

; Send ga

NVTXGA:	CAIL 2,NVTLO
	CAILE 2,NVTHI
	 RET
	MOVSI 1,NVTGAB
	TDNN 1,TTNETW(2)	; GA SUPPRESSED
	CALL CKNNVT		; OR NOT NEW PROTOCOL?
	 JRST NVTXG1
	MOVEI 1,GACH
	CALL NVTSSP
NVTXG1:	MOVEI 3,(1B<RCTOPT+WILOPT>)
	TDNN 3,NVTOPF(2)	; IS RCTE TURNED ON?
	 RET			; NO. RETURN
	LDB 1,PBRCNT
	ADDI 1,1
	CAILE 1,MAXBRC
	 BUG(CHK, <NVTXG1: TOO MANY BREAKS OUTSTANDING>)
	DPB 1,PBRCNT
	MOVSI 3,NVTWKS
	ANDCAM 3,TTNETW(2)	; CANCEL WAKEUP SEEN
NVTRRR:	PUSH P,BHC+0		; ASSUME ZERO COMMAND
	MOVSI 3,NVTRCS
	TDNN 3,TTNETW(2)	; UNLESS ANY CHANGE IN STATE?
	 JRST NVTRR1		; NO, BYPASS THIS NONSENSE.
	CALL GTBRKC		; GET BREAK CLASSES
	MOVEM 1,0(P)		; SAVE THAT
	CALL GTSPCC
	IORM 1,0(P)		; MUST BREAK ON ALL OF THEM
	SKIPE 1			; ANY SPECIAL BREAKS?
	 MOVEI 1,2		; YES, SUPPRESS ECHO OF BREAKS
	MOVE 3,TTFLGS(2)
	TRNN 3,3B25		; NO ECHO WANTED?
	 IORI 1,6		; SUPPRESS ALL ECHOES
	TRC 3,3B25
	TRCN 3,3B25		; SUPPRESS ECHOES OF BREAKS?
	 IORI 1,2		; YES, ...
	IORI 1,11		; CAUSE BREAK CLASS TO CHANGE
	HRLM 1,(P)		; SAVE THE COMMAND
	SKIPA 1,[^D10]		; NEED 4 CHARS FOR BREAK CLASSES
NVTRR1:	MOVEI 1,6		; NEED 6 FOR SB ETC
	CALL NVTRSV		; RESERVE SPACE
	 JRST [	SUB P,BHC+1
		RET]
	MOVEI 1,SBCH
	CALL NVTSSP		; SEND IAC-SB
	MOVEI 1,RCTOPT
	CALL TCOBQ		; SAY WHICH OPTION WE ARE CHANGING
	HLRZ 1,0(P)		; GET COMMAND
	CALL TCOB		; SEND THE COMMAND
	 JUMPE 1,NVTRR3		; NO CHANGE, SKIP THE FOLLOWING
	HRRZ 1,0(P)		; GET NEW BREAK CLASSES
	LSH 1,-8		; GET HIGH ORDER BYTE
	CALL TCOB		; SEND IT
	HRRZ 1,0(P)		; AND LOW ORDER TOO.
	ANDI 1,377
	CALL TCOB		; SEND LOW ORDER BYTE
NVTRR3:	MOVEI 1,SECH
	CALL NVTSSP		; SEND SE
	LDB 1,PBRCNT		; GET OUTSTANDING BREAKS
	POP P,3
	SKIPE 3
	MOVEM 3,TTBRKC(2)	; SET NEW CURRENT BREAK CLASSES
	SOS 1			; DECREMENT OUTSTANDING BRKS
	DPB 1,PBRCNT		; STORE BACK
	MOVSI 3,NVTRCS
	ANDCAM 3,TTNETW(2)	; CANCEL STATE CHANGE
	OKSKED
	JUMPN 1,NVTRRR		; REPEAT IF BREAKS STILL OUTSTANDING
	RET

; TABLE OF BREAK CLASS FOR EACH CHARACTER

U==1
L==2
N==4
FC==10
CC==20
P6==40
P7==100
P8==200
P9==400

CHWTB:	BYTE(9)CC,CC,CC,CC,CC,CC,CC,CC	; ^@ - ^G
	BYTE(9)FC,FC,FC,FC,FC,FC,CC,CC	; ^H - ^O
	BYTE(9)CC,CC,CC,CC,CC,CC,CC,CC	; ^P - ^W
	BYTE(9)CC,CC,CC,CC,CC,CC,CC,FC	; ^X - EOL
	BYTE(9)P9,P6,P8,P8,P8,P8,P8,P8	; SPACE - '
	BYTE(9)P7,P7,P8,P8,P6,P8,P6,P8	; ( - /
	BYTE(9)N,N,N,N,N,N,N,N		; DIGITS
	BYTE(9)N,N,P6,P6,P7,P8,P7,P6	; 8, 9 - ?
	BYTE(9)P8,U,U,U,U,U,U,U		; @ - G
	BYTE(9)U,U,U,U,U,U,U,U		; H - O
	BYTE(9)U,U,U,U,U,U,U,U		; P - W
	BYTE(9)U,U,U,P7,P8,P7,P8,P8	; X - _
        BYTE(9)P8,L,L,L,L,L,L,L		; ' - g
	BYTE(9)L,L,L,L,L,L,L,L		; h - o
	BYTE(9)L,L,L,L,L,L,L,L		; p - w
	BYTE(9)L,L,L,P7,P7,P7,P8,CC	; x - RUBOUT

; GET TERMINAL BREAK CLASSES

GTBRKC:	SETZ 1,
	MOVE 3,TTFLGS(2)
	TRNE 3,1B23		; BREAK ON ALPHANUMERICS
	 TRO 1,7		; UPPER AND LOWER CASE AND NUMBERS
	TRNE 3,1B22		; PUNCTUATION
	 TRO 1,740
	TRNE 3,1B21		; NON-FORMATTING CONTROLS
	 TRO 1,20
	TRNE 3,1B20		; FORMATTERS
	 TRO 1,10
	RET

; GET BREAK CLASS FOR CHARACTERS NEEDING SPECIAL ECHOES

GTSPCC:	CALL TTYGPI##		; GET PI CHARACTERS AS COCFORMAT
	PUSH P,1		; SAVE
	PUSH P,3
	CALL TTRCOC##		; GET CONTROL CHAR OUTPUT MODES
	ANDCMI 3,377		; ONLY CONTROL CHARACTERS
	IORI 3,2B<40*2-^D36+1>	; FAKE A NORMAL ECHO FOR SPACE
	ANDCM 3,0(P)		; FORCE ZEROES FOR INT CHARS
	ANDCM 1,-1(P)
	XOR 1,NVTNMD		; COMPARE TO ASSUMED ECHO MODE
	XOR 3,NVTNMD+1
	PUSH P,[FC]		; ASSUME NEED FORMATTERS
	TDZN 1,[BYTE (2)0,0,0,0,0,0,0,0,3,3,3,3,3,3]
	TDNE 3,[BYTE (2)0,0,0,0,0,0,0,0,0,0,0,0,0,3]
	 SKIPA
	 SETZM 0(P)		; NOT NEEDED AFTER ALL
	TDZN 1,[BYTE (2)3,3,3,3,3,3,3,3,0,0,0,0,0,0,3,3,3,3]
	TDNE 3,[BYTE (2)3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3]
	 MOVEI 1,CC		; NEED SPECIAL ECHO FOR NON-FORMATTERS
	IOR 1,0(P)
	TRNE 3,<BYTE (2)0,0,0,0,0,0,0,0,0,0,0,0,0,0,3>	; SPACE?
	 IORI 1,P9		; NEED SPECIAL ECHO FOR SPACE
	SUB P,BHC+3
	RET

; NORMAL MODES FOR ECHO (MUST AGREE WITH THAT IN USER TELNET)

NVTNMD:	BYTE (2)0,0,0,0,0,0,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2

; RCTE SET NVTWKS

NVTXWW::CAIL 2,NVTLO
	CAILE 2,NVTHI
	 RET
	PUSH P,3
	MOVSI 3,NVTWKS
	IORM 3,TTNETW(2)
	POP P,3
	RET

; RCTE CHECK FOR READING BREAK CHARACTERS AND SEND RCTRST IF NEEDED

NVTXWK::CAIL 2,NVTLO		; IS THIS AN NVT?
	CAILE 2,NVTHI
	 RET			; NO
	SKIPL TTNETW(2)		; THAT IS STILL CONNECTED
	CALL CKNNVT		; AND USING NEW PROTOCOL
	 RET			; NO, RETURN
	PUSH P,3		; PRESERVE AC3
	MOVEI 3,(1B<RCTOPT+WILOPT>)
	TDNN 3,NVTOPF(2)		; RCTE OPTION TURNED ON?
	 JRST NVTXWX		; NO, GET OUT
	MOVSI 3,NVTWKS
	TDNN 3,TTNETW(2)	; JUST SAW WAKEUP?
	 JRST NVTXW1		; SEND A RCTE RESET
	PUSH P,1
	CALL NVTXGA		; NOW SEND THIS ONE
	POP P,1			; RESTORE AC1
NVTXW1:	CALL WAKCHK##		; IS THIS A WAKEUP CHAR?
	 JRST NVTXWX		; NO
	MOVSI 3,NVTWKS		; YES
	IORM 3,TTNETW(2)	; REMEMBER WE SAW IT
NVTXWX:	POP P,3
	RET

; NVT CLEAR INPUT BUFFER
; NEEDS NEW PROTOCOL FEATURE TO WORK PROPERLY

NVTCIB::CAIL 2,NVTLO
	CAILE 2,NVTHI
	 RET
	SKIPL TTNETW(2)		; STILL CONNECTED TO NETWORK?
	CALL CKNNVT		; AND NEW STYLE NVT?
	 RET			; NO. DONE
	MOVEI 1,RCTOPT		; USE RCTE OPTION IN REVERSE
	SKIPN NSKED
	 CALL NVTNGT		; TO CLEAR INPUT BUFFER
	SETZ 1,
	DPB 1,PBRCNT
	RET

; NOTE CHANGE IN PSI SET

NVTXPI::CAIL 2,NVTLO
	CAILE 2,NVTHI
	 RET
	CALL CKNNVT
	 RET
	PUSH P,3
	MOVE 3,NVTOPF(2)	; GET CURRENTLY ON OPTIONS
	TRNN 3,(1B<RCTOPT+WILOPT>)
	 JRST NVTXP1
	MOVSI 3,NVTRCS
	IORM 3,TTNETW(2)	; NOTE STATE CHANGE
NVTXP1:	POP P,3
	RET

; Called from ttcobf

NVTCOB:	SKIPG TTNETW(2)
	 RET
	NOINT			; Protect possible ilocks
	PUSH P,IMPUN
	PUSH P,2
	LDB IMPUN,PTNETO
	LDB 1,PLIDX
	LDB 2,LTLINK
	LDB 1,LTHOST
	CALL IMPINS
	POP P,2
	POP P,IMPUN
	CALL CKNNVT		; New style nvt?
	 JRST NVTCO1		; Old style
	MOVEI 1,DMCH
	CALL NVTSSP		; Send new dm
	OKINT
	RET

NVTCO1:	MOVEI 1,200
	CALL TCOB
	OKINT
	RET

; Perform dobe sequence called from ttdobe

NVTDOB:	CALL CKNNVT		; New nvt?
	 RET			; No. just return
	MOVEI 1,TMKOPT		; Timing mark option
	PUSHJ P,NVTNGT		; Go negotiate option
	 JFCL			; Ignore failure
	RET

; Check stpar argument and negotiate any needed options

NVTPAR:	CAIL 2,NVTLO
	CAILE 2,NVTHI
	 RET			; Return if not nvt
	CALL CKNNVT		; New nvt?
	 JRST [	PUSH P,1
		XOR 1,TTFLGS(2)
		TRNN 1,14
		 JRST NVTPAX
		MOVE 1,0(P)
		TRNE 1,14	; Is new full?
		 SKIPA 1,[204]	; No. send "you echo"
		  MOVEI 1,203	; Yes. send "i echo"
		CALL TCOB
		JRST NVTPAX]
	MOVE 3,1		; Copy new state
	PUSH P,1		; Save
	XOR 1,TTFLGS(2)		; Get difference
	TRNN 1,14		; Change in echo?
	 JRST NVTPA1		; No, try next
	PUSH P,1		; Save difference
	TRNN 3,14		; Negotiate on?
	SKIPA 3,[NVTNGT]	; Yes
	MOVEI 3,NVTNGF		; No
	MOVEI 1,ECHOPT+WILOPT
	CALL @3
	 JRST [	MOVEI 1,14
		IORM 1,-1(P)
		JRST .+1]
	POP P,1
NVTPA1:					; Other checks go here if any
NVTPAX:	POP P,1
	RET

; Check sfmod argument and negotiate any options needed

NVTMOD:	CAIL 2,NVTLO
	CAILE 2,NVTHI
	 RET			; Return if not nvt
	CALL CKNNVT		; New nvt?
	 RET			; No. do nothing
	MOVE 3,1		; Copy of argument
	PUSH P,1		; Save it
	XOR 1,TTFLGS(2)		; Get bit difference
	PUSH P,1
	TRNN 1,100		; Change in binary?
	 JRST NVTMO1
	MOVE 3,0(P)
	TRNN 3,100
	SKIPA 3,[NVTNGT]
	MOVEI 3,NVTNGF
	PUSH P,3
	MOVEI 1,BINOPT
	CALL @3
	 JRST [	MOVEI 1,100
		IORM 1,-1(P)
		SUB P,BHC+1
		JRST NVTMO1]
	MOVEI 1,BINOPT+WILOPT
	POP P,3
	CALL @3
	 JRST [	MOVEI 1,BINOPT
		CALL NVTNGF
		 JFCL
		MOVEI 1,100
		IORM 1,0(P)
		JRST NVTMO1]
NVTMO1:	MOVE 3,0(P)		; GET BIT DIFFERENCE
	MOVEI 1,(1B<RCTOPT+WILOPT>)
	TDNE 1,NVTOPF(2)	; NO RCTE ON?
	TRNN 3,77B23+3B25	; OR NO CHANGE IN WAKEUP SET
	 JRST NVTMO2		; NO,, SKIP FOLLOWING
	MOVSI 3,NVTRCS
	IORM 3,TTNETW(2)	; NOTE CHANGE IN RCTE SETTINGS
NVTMO2:	POP P,1			; GET BACK DIFFERENCE
	POP P,1			; AND ARGUMENT
	RET

; Negotiate an option

NVTNGT:	MOVE 3,[NVTXWL,,NVTXDO]
	CALL NVTNGC
	 AOS 0(P)
	RET

NVTNGF:	MOVE 3,[NVTXWN,,NVTXDN]
NVTNGC:	CAIL 1,MAXOPT
	 RET
	PUSH P,1
	PUSH P,3
	MOVE 3,BITS(1)
	IORM 3,NVTOPF(2)	; Set option negotiation in progress bit
	TRZE 1,WILOPT
	MOVSS 0(P)
	POP P,3
	CALL 0(3)		; Say "do, wil, dont, wont"
	MOVE 1,0(P)
	ROT 1,-9		; Into top 9 bits
	TLO 1,(2)		; Line number in 9-17
	HRRI 1,NVTNTT		; Activation test
	JSYS EDISMS
	MOVSI 1,NEGTMO
	ANDCAM 1,TTNETW(2)	; Cancel any time-out in progress
	POP P,1
	MOVS 3,BITS(1)
	TDNN 3,NVTOPF(2)
	 AOS 0(P)		; Skip if successful
	RET

NVTNTT:	LDB 3,[POINT 9,1,26]	; Get option number
	MOVE 3,BITS(3)
	ANDI 1,777		; Line number
	SKIPL TTNETW(1)		; Satisfied if disconnected
	TDNN 3,NVTOPF(1)
	 JRST 1(4)		; Negotiation complete
	JRST 0(4)

; Check overdue negotiations

NEGCHK:	MOVE 2,NVTPTR		; Pointer to nvts
NEGCKL:	SKIPGE TTNETW(2)	; Attached?
	 JRST NEGCKE		; No, skip it
	MOVSI 3,NEGTMO
	HLLZ 1,NVTOPF(2)	; Get outstanding options
	 JUMPE 1,[ANDCAM 3,TTNETW(2)	; None, cancel time-out if any
		JRST NEGCKE]
	XORB 3,TTNETW(2)	; Yes, count counter
	TLNN 3,NEGTMO		; Count from 1 to 0?
	 HRRZS NVTOPF(2)	; Yes, cancel outstanding option
NEGCKE:	AOBJN 2,NEGCKL
	MOVE 1,TODCLK
	ADDI 1,NEGTM0
	MOVEM 1,NEGTIM
	RET

; Move tty output to net buffers

NETTCS:	MOVEI 3,(1B<RCTOPT+WILOPT>)
	TDNE 3,NVTOPF(2)
	CALL CKNNVT
	 JRST NETTC8		; NO RCTE
	LDB 3,PBRCNT		; NEED TO SEND RESET?
	SKIPE 3
	 CALL NVTRRR		; YES, TRY TO SEND
NETTC8:	SKIPGE TTNETW(2)	; Still connected?
	 JRST NETTCF		; No, just clear buffer
	SETZ 4,			; Init char count
	MOVEI 6,0(P)		; Use stack as local buffer
	HRLI 6,1000		; Construct 8-bit byte ptr
	LDB IMPUN,PTNETO	; Get unit index
	MOVE 7,NETSTS(IMPUN)
	TLNN 7,EOTF
	TLNE 7,DEDF
	 JRST NETTCF		; Yes, don't send any more
	PUSH P,2		; Preserve line number
	LDB 1,PLIDX		; Get link index
	PUSHJ P,PKCHK		; Check how many bits can be sent now
	MOVE 7,2
	POP P,2
	JUMPLE 7,PKULCK		; If none, give up
	CAILE 7,100		; But limit to 100 (20 wds on stack)
	MOVEI 7,100
	ADD P,[20,,20]		; Reserve space on stack
	MOVE 3,6		; Save byte ptr
NETTC2:	SOJL 7,NETTC4		; Count down limit
	NOSKED
	SKIPE TTECT(2)		; Chars from echo buffer?
	JRST [	CALL NETTEO	; Yes, get one
		JRST NETTC1]
	SKIPE TTOCT(2)		; Chars from output buffer?
	JRST [	CALL NETTOO	; Yes, get one
		JRST NETTC1]
	PUSH P,3		; Preserve ac3
	CALL TTRLOB		; Buffers empty, release them
	POP P,3
	OKSKED
NETTC4:	JUMPE 4,[SUB P,[20,,20]	; No chars to send, clear stack
		JRST PKULCK]
	MOVNI 1,^D8
	IMUL 1,4		; Adjust allocation
	ADDM 1,NETBAL(IMPUN)
	LDB 1,PLIDX		; Get conn index
	PUSH P,2
	CALL PKMSG1
	POP P,2
	SUB P,[20,,20]		; Clear stack
	JRST NETTC8		; See if any more

NETTCF:	CALL TTCOBI		; FLUSH OUTPUT BUFFER
	LDB 1,PLIDX
	RET

NETTC1:	OKSKED
	IDPB 1,6		; Put char on stack buffer
	AOJA 4,NETTC2

; Get chars for output from echo buffer

NETTOO:	SKIPN 1,TTOOUT(2)
	RET			; Stuff vanished, return 0
	TDNN 1,WRPMSK
	HRR 1,1-TTSIZ(1)
	MOVEM 1,TTOOUT(2)
	ILDB 1,TTOOUT(2)
	SOS TTOCT(2)
	RET

; Get chars for output from echo buffer

NETTEO:	SKIPN 1,TTEOUT(2)
	RET			; Stuff vanished, return 0
	TDNN 1,WRPMSK
	HRR 1,1-TTSIZ(1)
	MOVEM 1,TTEOUT(2)
	ILDB 1,TTEOUT(2)
	SOS TTECT(2)
	RET

; Unpack message into tty buffers
; Impun/socket table index (unit)
; 1/	LT INDEX

NVTUPI:	PUSH P,1		; Preserve ac1
	IMSCLK(IMCNVI)		; Charge to imcnvi
	PUSH P,[0]		; Count bytes unpacked
NVTUPL:	MOVE 1,-1(P)		; Get link table index
	CALL UPBYT		; Get  byte
	 JRST NVTUPD
	AOS 0(P)		; Count bytes
	LDB 2,PNVT		; Get line number
	MOVE 1,3
	LDB 3,NVTSTP		; Get the current command state of this
	SETZ 4,
	DPB 4,NVTSTP
	CALL @NVTSTD(3)		; Dispatch on it
	JRST NVTUPL

NVTSTD:	NVTNRM			; Nothing deferred
	NVTWIL			; Deferred will
	NVTWNT			; Deferred wont
	NVTDO			; Deferred do
	NVTDNT			; Deferred dont
	NVTIAC			; Deferred iac
	NVTNRM			; Not used
	NVTNRM			; Not used

NVTNRM:	CAIL 1,200
	 JRST NVTCTL		; Process possible nvt control character
NVTDCH:	LDB 3,TTYLMD
	JUMPE 3,NVTUPB		; Binary, skip special checks
	MOVSI 3,IMPTB2
	TDNN 3,TTNETW(2)	; Was last ch cr?
	 JRST [	CAIE 1,15	; NO. IS THIS ONE?
		 JRST NVTUPB	; NO, PROCEED NORMALLY
		IORM 3,TTNETW(2)	; YES, REMEMBER IT
		RET]		; AND IGNORE FOR NOW
	ANDCAM 3,TTNETW(2)	; YES, FORGET THAT
	MOVEI 1,15		; AND PROCESS AS CR NOW
NVTUPB:	SETZ 6,			; No special flags
	PUSH P,IMPUN
	NOSKED			; Ttchi expects to be called nosked
	CALL TTCHI		; Stuff it in tty buffer
	OKSKED
	POP P,IMPUN
	RET

NVTUPD:	POP P,4			; Bytes unpacked
	POP P,1			; Restore lt index
	IMUL 4,[-8]
	ADDB 4,NETBAL(IMPUN)
	JUMPGE 4,NVTRAL		; Reallocate
	LDB 2,LTHOST		; Get host
	BUG(IMH,<NVT RECEIVED BYTES EXCEEDING ALLOCATION>,X)
	SETZM NETBAL(IMPUN)
	JRST NVTRAL

; Telnet control codes received
; 1/ code
; 2/ line

NVTCTL:	SKIPGE TTNETW(2)	; If no sockets attached,
	 JRST NVTDCH			; Ignore char
	PUSHJ P,CKNNVT		; New style nvt?
	 JRST NVTCT0		; No, look for old style commands
	CAIE 1,IACCH		; Yes, is iac
	 JRST NVTDCH		; No, continue processing
	JRST NVTCL4		; Yes. take care of it

NVTCT0:	CAIN 1,202		; Nop
	 RET
	CAIN 1,200		; Sync char?
	 JRST NVTCL1
	CAIN 1,203		; Echo off?
	 JRST NVTCL2
	CAIN 1,204		; Echo on?
	 JRST NVTCL3
	JRST NVTDCH

NVTCL1:	LDB 1,PTINTC
	ADDI 1,1		; Sync counts 1, ins counts -1
	DPB 1,PTINTC
	RET

NVTCL3:	TDZA 1,1		; Zero ac and skip
NVTCL2:	MOVEI 1,3
	DPB 1,[POINT 2,TTFLGS(2),33] ; Set duplex mode full/half
	RET

; Process iac

NVTCL4:	MOVEI 3,DFRIAC
	DPB 3,NVTSTP
	RET

; Process byte after iac

NVTIAC:	CAIGE 1,SECH
	 RET			; Not a valid command
	MOVSI 3,NEWNVB
	IORM 3,TTNETW(2)	; Mark this new protocol
	SETZ 3,			; Next state if any
	XCT NVTDTB-SECH(1)	; Dispatch on the character
	 JRST NVTDCH		; Special function character
	DPB 3,NVTSTP		; Next state
	RET

NVTDTB:	RET			; (360) end of subnegotiation
	RET			; (361) nop -- ignore
	JRST NVTCL1		; (362) new data mark
	RET			; (363) break -- ignore
	MOVEI 1,3		; (364) ip -- convert to ^c
	MOVEI 1,"O"-100		; (365) ao -- convert to ^o
	MOVEI 1,"T"-100		; (366) ayt -- convert to ^t
	MOVEI 1,"A"-100		; (367) ec -- convert to ^a
	MOVEI 1,"Q"-100		; (370) el -- convert to ^q
	RET			; (371) ga -- ignore
	RET			; (372) sb -- shouldn't get this
	TROA 3,DFRWIL		; (373) defer will
	TROA 3,DFRWNT		; (374) defer wont
	TROA 3,DFRDO		; (375) defer do
	TROA 3,DFRDNT		; (376) defer dont
	JFCL			; (377) iac iac -- iac

; Send special character

NVTSSP:	PUSH P,1
	MOVEI 1,2
	PUSHJ P,NVTRSV		; Reserve space in buffer (nosked)
	 JRST [	POP P,1
		RET]
	HRROI 1,IACCH		; SAME AS 377, BUT PREVENT ITS DOUBLING
	CALL TCOB		; CALL TCOB TO GET CR-NULL IF NEEDED
	POP P,1
	CALL TCOBQ
	OKSKED
	RET

; Reserve space in buffer for characters specified in 1

NVTRSV:	NOSKED			; Make sure space doesn't disappear
	LDB 3,TTOMAX
	SUB 3,TTOCT(2)		; Space in output buffers
	CAML 3,1
	 JRST RSKP		; Enough room, return skip
	OKSKED
	MOVE 3,FORKX
	CAMN 3,NCPFRK		; Is this the ncp fork?
	 JRST NVTRV1		; Yes, attempt to send the buffer
	PUSH P,1		; No. wait for space
	MOVEI 1,TCOTST
	HRL 1,2
	JSYS EDISMS		; Wait for space
	POP P,1
	JRST NVTRSV

NVTRV1:	LDB IMPUN,PTNETO	;@GET UNIT NUMBER
	PUSH P,1
	LDB 1,PLIDX		; Get lt index
	HRRZ 3,IMPLT4(1)	; Get msg alloc
	SKIPE 3
	 MOVE 3,NETBAL(IMPUN)	; Get bit alloc if non-zero msg alloc
	LSH 3,-3		; Convert to bytes
	CAMGE 3,0(P)		; At least what we need?
	 JRST [	POP P,1		; No. give up
		RET]
	PUSH P,2		; P@PRESERVE LINE NUMBER
	CALL NETTC8		; s, send as much as possible
	POP P,2			; RESTORE LINE NUMBER
	POP P,1
	JRST NVTRSV		; And try again

; Send wont (refuse)

NVTRFU:	MOVEI 1,WNTCH

; Send reply in 1 for option on stack

NVTSRP:	PUSH P,1
	MOVEI 1,3
	CALL NVTRSV		; Reserve space for three characters
	 JRST [	SUB P,BHC+2
		RET]
	HRROI 1,IACCH		; SAME AS 377 BUT PREVENT DOUBLING
	PUSHJ P,TCOB		; USE TCOB TO GET CR-NULL IF NEEDED
	POP P,1
	PUSHJ P,TCOBQ
	POP P,1
	PUSHJ P,TCOBQ
	OKSKED
	RET

; Send will

NVTXWL:	PUSH P,1		; Save option
NVTSWL:	MOVEI 1,WILCH		; Enter here when option is on stack
	JRST NVTSRP		; Send reply

; Send no reply

NVTSNR:	SUB P,BHC+1		; No reply necessary or possible
	RET

; Send wont

NVTXWN:	PUSH P,1		; Save option
NVTSWN:	MOVEI 1,WNTCH		; Enter here when option already pushed
	JRST NVTSRP

; Send "do"

NVTXDO:	PUSH P,1		; Save option
NVTSDO:	MOVEI 1,DOCH		; Enter here when option already pushed
	JRST NVTSRP

; Send "dont"

NVTXDN:	PUSH P,1		; Save option
NVTSDN:	MOVEI 1,DNTCH		; Enter here when option already pushed
	JRST NVTSRP

; Process "do"

NVTDO:	CAIL A,WILOPT
	 JRST NVTDO1
	MOVE 3,BITS+WILOPT(1)
	TDNE 3,NVTOPF(2)
	 JRST NVTWI2
NVTDO1:	PUSH P,1		; Remember the option
	MOVSS 3			; Put bit in "options on" half
	TDNE 3,NVTOPF(2)	; Is the option on?
	 JRST NVTSNR		; Yes, send no reply
	CAIGE 1,NVTLOP		; Do we know about this option
	 CALL @NVTDOD(1)	; Yes. attempt execution
	  JRST NVTRFU		; Can't do it -- refuse
	IORM 3,NVTOPF(2)	; Set option on
	JRST NVTSWL		; And send "will"

NVTDOD:	R			; Binary xmit -- refuse for now
	NVTECN			; Turn echos on
	R			; Reconnect -- refuse for now
	NVTSGA			; Suppress ga -- wonderful news
	R			; Message size -- refuse
	R			; Status -- refuse
	NVTDTM			; Timing mark -- try to do it
	NVTDRC			; Remote controlled trans & echo
NVTLOP=.-NVTDOD

; Action routines for "do"
; Turn echoes on

NVTECN:	MOVEI 1,3B33
	ANDCAM 1,TTFLGS(2)	; Set to full duplex
	JRST RSKP

; Set suppress ga bit

NVTSGA:	MOVSI 1,NVTGAB
	IORM 1,TTNETW(2)
	JRST RSKP

; Do timing mark protocol

NVTDTM:	JRST RSKP

; TURN ON RCTE

NVTDRC:	MOVSI 1,NVTRCS		; SEND CURRENT STATE INFO WITH FIRST CMD
	IORM 1,TTNETW(2)
	SETZM TTBRKC(2)		; CLEAR BREAK STATUS INFO
	MOVEI 1,1
	DPB 1,PBRCNT		; SEND ONE RCTE COMMAND TO START
	JRST RSKP		; We are happy to do RCTE


; Process "dont"

NVTDNT:	CAIL A,WILOPT
	 JRST NVTDN1
	MOVE 3,BITS+WILOPT(1)
	TDNE 3,NVTOPF(2)
	 JRST NVTWN2
NVTDN1:	PUSH P,1
	MOVSS 3			; Put bit in "option on" half
	TDNN 3,NVTOPF(2)	; Option already off?
	 JRST NVTSNR		; Yes. send no reply
	CAIGE 1,NVTLOP		; Do we know about this option?
	 CALL @NVTDND(1)	; Yes. perform action
	ANDCAM 3,NVTOPF(2)	; Clear the option
	JRST NVTSWN		; And send "won't"

NVTDND:	R			; Dilemma -- he wants off, but we can't
	NVTECF			; Echo off
	R			; Option not on, no reply
	NVTAGA			; He wont suppress ga -- nuts
	R			; Message size option
	R			; Status option
	R			; Timing mark -- huh?
	R			; Turn off RCTE

; "dont" action routines
; Turn echos off

NVTECF:	MOVEI 1,3B32
	IORM 1,TTFLGS(2)
	RET

; Turn off suppress ga bit

NVTAGA:	MOVSI 1,NVTGAB
	ANDCAM 1,TTNETW(2)
	RET

; Process "will"

NVTWIL:	CAIL A,WILOPT		; Only wilopt options
	 JRST NVTWI1		; Others cannot be outstanding
	MOVE 3,BITS(1)		; Get the bit for the option
	TDNN 3,NVTOPF(2)	; Is this option outstanding?
	 JRST NVTWI1		; No.
NVTWI2:	MOVS 1,3
	IORM 1,NVTOPF(2)	; Set will bit
	ANDCAM 3,NVTOPF(2)	; And clear outstanding bit
	RET

NVTWI1:	PUSH P,1		; save the option
	MOVSS 3			; Put bit in "optons on" half
	TDNE 3,NVTOPF(2)	; Is option already on?
	 JRST NVTSNR		; Yes. send no reply
	CAIGE 1,NVTLOP
	 CALL @NVTWID(1)	; Call action routine
	  JRST NVTSDN		; Unimplemented option or can't comply
	IORM 3,NVTOPF(2)	; Done. set option "on"
	JRST NVTSDO		; And send "do"

NVTWID:	R			; Will binary -- dont
	R			; Will echo -- dont
	R			; Reconnect -- dont
	RSKP			; Suppress ga -- do, do, do , do!
	R			; Message size -- dont
	R			; Status -- dont
	R			; Timing mark -- huh?
	R			; What's he trying to do?

; Process "wont"

NVTWNT:	CAIL 1,MAXOPT
	 JRST NVTWN1		; Option not handled
	MOVE 3,BITS(1)		; Get bit for option
	TDNN 3,NVTOPF(2)	; Is this option outstanding
	 JRST NVTWN1		; No. request
NVTWN2:	HLR 3,3			; Yes. neg acknowledge
	ANDCAM 3,NVTOPF(2)	; Clear both outstand and will flags
	RET

NVTWN1:	PUSH P,1
	MOVSS 3			; Put bit in "options on" half
	TDNN 3,NVTOPF(2)	; Option already off?
	 JRST NVTSNR		; Yes. send no rply
	ANDCAM 3,NVTOPF(2)	; Strangely enough, the user end
	JRST NVTSDN		; Never has any options to turn off

; Re-allocate if needed to bring allocation up to operating level
; Impun/socket table index (unit)

NTTRC3:				; Known to ncp by this tag
NVTRAL:	CALL LCKNCP		; Prevent ncp changes
	MOVSI 1,DEDF
	TLO 1,EOTF
	TDNE 1,NETSTS(IMPUN)
	 JRST ULKNCP		; Connection dead or done
	LDB 2,PNVT		; Pick up line number
	LDB 3,TTIMAX		; Capacity of line
	SUB 3,TTICT(2)		; Gives space now in line buffer
	JUMPE 3,[LDB 1,PTINTC	; If full, check for ins received
		TRNE 1,4	; Count is sync-ins, 3 bit field
		MOVEI 3,1	; Ins requested, allocate 1 byte
		JRST .+1]
	LSH 3,3			; Imuli 3,8 (byte size)
	SUB 3,NETBAL(IMPUN)	; Desired all less all now out
	MOVE 4,3
	LDB 1,PLIDX		; Get conn index
	HRRZ 3,IMPLT4(1)	; Current msg alloc
	MOVN 3,3
	ADDI 3,^D6		; Raise it to 6
	LDB 1,TTIMAX		; Max space in buffer
	ASH 1,-1		; One-half
	CAMGE 4,1		; Re-allocate if more than half a buffer
	CAIL 3,4		; Or if more than 3 msgs
	SKIPA
	 JRST ULKNCP
	LDB 1,PFHST
	LDB 2,PLINK
	CALL IMPALL
	JRST ULKNCP


; Lookup host-link
; 1/ b20-27, host; b28-35, link; b18, direction (1=send)

LNKLUK:	PUSH P,3
	MOVSI 3,(1B1)		; Bit says no deleted entry found
LNKL6:	PUSH P,4
	PUSH P,1		; Save arg
	IMUL 1,[5654123]	; Compute hash
	LSH 1,-^D9
	IDIVI 1,IMPNLK		; Remainder gives initial index
	POP P,1
	PUSH P,2
	HRLI 2,-IMPNLK(2)	; Setup ptr for remainder of table
LNKL2:	HRRZ 4,IMPLT1(2)
	CAIN 4,0(1)		; Desired entry?
	JRST [	AOS -3(P)	; Yes, return good
		MOVEI 1,0(2)
		JRST LNKL1]	; With table index in 1
	TRNE 4,1B19		; Special? i.e. free or deleted?
	JRST [	TLNE 3,(1B2)	; Yes, called by rehash or pi level?
		JRST LNKL4	; Yes
		TRNE 4,1B18	; This a free entry?
		JRST LNKL3	; Yes, search done, not found
		TLZE 3,(1B1)	; This first deleted entry encountered?
		HRRI 3,0(2)	; Yes, save its position
		JRST .+1]
LNKL5:	AOBJN 2,LNKL2
	JUMPL 3,[TLNN 3,(1B1)	; Table full, was delete seen?
		JRST LNKL3	; Yes, use it
		JRST IMPB01]	; No, lossage
	MOVN 2,0(P)		; Wraparound ptr, setup count
	MOVSI 2,0(2)		; To look up to initial index
	TLO 3,(1B0)		; Remember wraparound
	JRST LNKL2

LNKL3:	TLNN 3,(1B1)		; Not found, delete encountered?
	MOVEI 2,0(3)		; Yes, use that for new entry
LNKL1:	SUB P,BHC+1		; Flush temp
	POP P,4
	POP P,3
	RET

LNKL4:	TLNE 3,(1B3)		; Pi level call?
	 JRST LNKL5		; Yes. ignore deleted/free entries
	MOVEI 4,1B19		; Make deleted
	MOVEM 4,IMPLT1(2)
	JRST LNKL5

; Special entry used only by rehash routine
; It assumes item will be found, and it sets any 'free' entries
; Encountered to be 'deleted'

IMPHFL:	PUSH P,3
	MOVSI 3,(1B2)		; Controls action on special entries
	JRST LNKL6

; Special entry from imodn2 to find entry to store retransmit buffer
; Searches entire table for entry regardless of deletes and frees

IMPPIL:	PUSH P,3
	MOVSI 3,(1B2+1B3)
	JRST LNKL6

; Routine to garbage collect hash table.
; Sets all deleted entries to free then calls lookup
; routine to mark all needed entris deleted to enable all entries
; to be found.
; Lookup routine will change any 'free' entries passed over during
; a search to 'deleted'.  thus all 'deleted' entries not currently
; Necessary will be flushed.

IMPGC:	IMSCLK(IMCGC)		; Charge time to imcgc
	ILOCK
	SETZM LNKNDL		; Clear delete count
	MOVSI 7,-IMPNLK		; Prepare to scan link table
	MOVEI 1,1B19
	MOVEI 2,1B19!1B18
IMPGC1:	TDNE 1,IMPLT1(7)	; Free or deleted?
	 MOVEM 2,IMPLT1(7)	; Yes, set it to free
	AOBJN 7,IMPGC1
	MOVSI 7,-IMPNLK		; Prepare to scan again
IMPGC2:	HRRZ 1,IMPLT1(7)	; For every entry
	TRNE 1,1B19		; That is not
	 JRST IMPGC3		; Deleted or free
	CALL IMPHFL		; Marked necessary deleted entries
	 BUG(CHK,<IMPGC-IMPOSSIBLE FAILURE OF IMPHFL>)
IMPGC3:	AOBJN 7,IMPGC2
	IUNLK
	RET

; Unpack byte from current msg for a connection
; 1/ connection index
; Returns byte in 3

UPBYT:	ILOCK
	HLRZ 2,IMPLT4(1)	; Get current buffer
	JUMPN 2,UPBYT1
	CALL UPBGNB		; No buffer, try to get one
	RET			; Failed, return noskip
UPBYT1:	ILDB 3,1(2)		; Get byte, byte ptr in bfr header
	SOSG 2(2)		; Count down bytes in bfr
	CALL UPBRB		; Now empty, release bfr
	IUNLK
	AOS 0(P)
	RET

; Unpack message
; 1/	LT INDEX
; 3/	STORE BYTE POINTER
; 4/	MAX BYTE COUNT

UPMSG:	ILOCK
	PUSH P,3		; Save store pointer
	HLRZ 2,IMPLT4(1)	; Get current buffer
	JUMPN 2,.+3
	CALL UPBGNB		; None, try to get one
	JRST UPMSG5		; Failed, return bad
	MOVE 3,2(2)		; Get buffer count
	CAML 3,4
	 MOVE 3,4		; Use minimum count
	SUB 4,3			; Update count
	PUSH P,4		; Save updated count
	MOVN 4,3
	ADDM 4,2(2)		; Update buffer count
	PUSH P,1		; Save lt index
	MOVE 1,1(2)		; Get buffer pointer
	EXCH 2,-2(P)		; Save buffer location, get tgt
	MOVEI 4,0		; Transfer monitor to monitor
	PUSHJ P,BYTBLT		; Transfer the bytes
	EXCH 2,-2(P)		; Save updated tgt, get buffer loc
	MOVEM 1,1(2)		; Store update buffer pointer
	POP P,1			; Restore lt index
UPMSG4:	POP P,4
	SKIPG 2(2)		; Imp bfr now exhausted?
	CALL UPBRB		; Yes, release it
UPMSG2:	AOS -1(P)
	IUNLK
UPMSG5:	POP P,3
	RET

; Try to get next input bfr

UPBGNB:	HLRZ 2,IMPLT3(1)	; Check queue of in bfrs
	JUMPE 2,UPBG1		; None
	PUSH P,4
	HLLZ 3,0(2)		; Unqueue this buffer
	JUMPN 3,.+3
	MOVEI 4,IMPLT3(1)
	HRRM 4,IMPLT2(1)	; Make input buffer list empty
	HLLM 3,IMPLT3(1)	; Output buffer pointer
	HRLM 2,IMPLT4(1)	; Save current bfr adr
	PUSH P,1(2)		; Save header in case of error
	PUSH P,2(2)
	HRRZ 4,0(2)		; Number words in buffer
	CAIGE 4,3		; At least overhead words present?
	JRST UPBGNE		; No, msg too short
	LDB 3,[POINT 16,2(2),27] ; Byte count for this buffer
	JUMPE 3,UPBGNE		; 0 is illegal, but in case...
	LDB 4,[POINT 8,2(2),11]	; Get byte size
	MOVEM 3,2(2)		; Leave byte count in full word
	LDB 3,IMPLBS		; Byte size for connection
	CAME 3,4		; Same?
	JRST UPBGNE		; No
	LSH 3,^D24		; Shift to s field of byte ptr
	HRRI 3,2(2)
	MOVEM 3,1(2)
	MOVEI 3,^D36		; Compute max bytes which could be
	IDIV 3,4		; As words*(bytes/wd)
	HRRZ 4,0(2)		; Number of words
	IMULI 3,-3(4)		; But not counting overhead
	CAMGE 3,2(2)		; Actual greater than max?
	JRST UPBGNE		; Yes, lossage
	SUB P,BHC+2
	POP P,4
	AOS 0(P)
	RET

UPBGNE:	CALL UPBRB
	PUSH P,2
	MOVEI 2,-3(P)		; Pntr to 1 before saved hdr on stack
	HRLI 2,9
	BUG(IML,<Message has bad size or count>,X)
	POP P,2
	SUB P,BHC+2
	POP P,4
	JRST UPBGNB

UPBGNX:	SUB P,BHC+2
	POP P,4
	JRST UPBGNB

; No input ready, return activation test

UPBG1:	MOVSI 1,0(1)		; Connection index
	HRRI 1,UPBGT		; Wait for input or closed conn
	IUNLK
	RET

; Activation test

UPBGT:	MOVSI 3,777777
	MOVSI 2,(LTDF)		; Check done flag
	TDNN 2,IMPLT2(1)	; If set, or
	TDNE 3,IMPLT3(1)		; If bfr(s) appeared
	JRST 1(4)		; Wakeup
	JRST 0(4)

; Release input buffer

UPBRB:	HLRZ 2,IMPLT4(1)	; Get current buffer
	HRRZS IMPLT4(1)		; Clear field
	PUSH P,1
	CALL RLNTBF		; Release bfr back to pool
	POP P,1
	SOSL IMPLT4(1)		; Count msgs processed
	RET
	BUG(CHK,<UPBRB: Received excessive messages>)
	SETZM IMPLT4(1)
	RET

; Check connection for output possible
; Called on receipt of rfnm, allocation, etc.
; 1/ connection index
; Do output if rfnm clear, msg alloc non-0, and output exists

IMPCKO:	ILOCK (JRST IMPROS)	; If can't check now, set request flag
IMPKO1:	MOVSI 3,(RFNMC!ILCKB)
	TDNE 3,IMPLT2(1)	; Rfnm out or connection locked?
	JRST IMPKO2		; Yes, will try again later
	HLRZ 2,IMPLT3(1)
	JUMPN 2,[
		CALL IMPQO1	; If completed bfrs on output queue,
		JRST IMPKO1]	; Give one to imp to send
	HLRZ 2,IMPLT4(1)	; See if partial bfr exists
	JUMPN 2,[
		CALL PKQOB	; Complete it and send
		JRST IMPKO1]
	LDB 2,LTLINK		; Nothing to do here
	JUMPE 2,[CALL IMPLL0
		JRST IMPKO2]	; Flush conn if ctl link
	MOVSI 2,(RARRF)
	TDNN 2,IMPLT2(1)	; Ras requested?
	 JRST IMPKO4		; No
	PUSH P,1		; Yes
	ANDCAM 2,IMPLT2(1)
	HLRZ IMPUN,IMPLT1(1)
	SETZM NETBAL(IMPUN)
	HLLZS IMPLT4(1)
	IUNLK
	LDB 2,LTLINK
	LDB 1,LTHOST
	CALL IMPRAS
	POP P,1
	JRST IMPKO3

IMPKO4:	IUNLK
IMPKO3:	HLRZ IMPUN,IMPLT1(1)	; Pick up pseudo-unit
	MOVSI 2,(LTDF)
	TDNN 2,IMPLT2(1)	; Done flag set?
	 RET			; No. done
	ANDCAM 2,IMPLT2(1)	; Only see it once
	PUSH P,6		; Preserve ac6
	CALL RCFRFN		; Yes, notify ncp
	POP P,6
	RET

IMPKO2:	IUNLK			; Always returns with lock clear
	RET

IMPROS:	AOS IMPNOS
	RET

; Pack byte for output
; 1/	CONNECTION INDEX
; 3/	BYTE

PKBYT:	ILOCK
	HLRZ 2,IMPLT4(1)
	JUMPN 2,PKBY2
	CALL PKBY1		; No current buffer, get a new one
	 JRST PKBY5		; No buffers
PKBY2:	IDPB 3,1(2)
	MOVSI 3,(ILCKB)
	ANDCAM 3,IMPLT2(1)	; Clear lock
	SOSG 2(2)		; Or if bfr now full
	CALL PKQOB		; Put bfr on output queue
	CALL IMPKO1		; Send if possible (does iunlk)
	AOS 0(P)
	RET

PKBY5:	IUNLK
	CALL IMPB03
	JRST PKBYT

; Check maximum bytes that can be sent due to msg alloc restriction
; and partial msg already constructed.  Leave connection locked.

PKCHK:	ILOCK
PKCHK0:	PUSH P,3
	SETZ 2,
	MOVSI 3,(ILCKB)
	TDNE 3,IMPLT2(1)	; There should only be one fork trying
	 JRST PKCHK2		; at a time since files are interlocked
				; by fillck, nvt transmission is done by
				; Ncp fork and control links have no
				; flow control.
	IORM 3,IMPLT2(1)	; Lock connection so state can't change
	LDB 3,IMPLBS		; Get byte size
	HLRZ 2,IMPLT4(1)	; get current buffer
	JUMPE 2,PKCHK1		; If none, contribution is zero
	MOVE 2,2(2)		; Get bytes left
	IMUL 2,3		; Times byte size is bits

PKCHK1:	PUSH P,3
	HRRZ 3,IMPLT4(1)	; GET MSG ALLOCATION
	JUMPG 3,[IMUL 3,MAXBPM	; TIMES BITS PER MESSAGE
		ADD 2,3		; ADD TO CURRENT BUFFER RESIDUE
		JRST .+1]	; AND CHECK AGAINST BIT ALLOCATION
	POP P,3			; NO MSG ALLOC., JUST RESTORE 3
	CAMLE 2,NETBAL(IMPUN)	; More than bit allocation
	 MOVE 2,NETBAL(IMPUN)	; Yes. limit is that
	IDIV 2,3		; Convert to bytes
PKCHK2:	POP P,3
	IUNLK
	RET

; Unlock connection

PKULCK:	MOVSI 2,(ILCKB)
	ANDCAM 2,IMPLT2(1)
	MOVE 2,IMPLT3(1)	; Any buffers to be sent
	IOR 2,IMPLT4(1)
	TLNE 2,-1
	 JRST IMPCKO		; Yes
	RET			; No

; Pack msg
; 1/ connection index
; 3/ byte ptr
; 4/ byte count

PKMSG:	ILOCK
PKMSG0:	CALL PKMSG2		; GET THE MESSAGE PACKED UP
	PUSH P,3
	CALL IMPKO1		; SEND IF POSSIBLE (DOES IUNLK)
	POP P,3
	RET

; SAME AS PKMSG, BUT DOESN'T ATTEMPT TO SEND THE MSG 
PKMSG1:	ILOCK
	CALL PKMSG2		; PACK IT UP
	IUNLK
	RET


; ROUTINE TO MOVE BYTES FROM SOURCE BUFFER TO NETWORK OUTPUT BUFFER
; 1/ CONNECTION INDEX
; 2/ SOURCE BYTE PTR
; 4/ BYTE COUNT
PKMSG2:	MOVSI 2,(ILCKB)		; LOCK CONNECTION
	IORM 2,IMPLT2(1)
	PUSH P,4		; SAVE BYTE COUNT
	HLRZ 2,IMPLT4(1)	; Get current bfr
	JUMPN 2,PKMS2
	PUSH P,4		; Wasn't one, get a new one
PKMS4:	CALL PKBY1
	 JRST PKMS5
	POP P,4
	CAMLE 4,2(2)		; New buffer big enough?
	 JRST PKMSL		; Message too long
PKMS3:	PUSH P,1		; Save connection index
	MOVE 1,3		; Source pointer
	MOVE 3,4		; Count to 3
	MOVNS 4
	ADDM 4,2(2)		; Update buffer count
	ADDM 4,-1(P)		; MAINTAIN RESIDUAL COUNT
	PUSH P,2		; Save buffer loc
	MOVE 2,1(2)		; Target to 2
	MOVEI 4,0		; Mode is monitor to monitor
	PUSHJ P,BYTBLT		; Transfer bytes
	EXCH 2,0(P)		; Get buffer location, save updated ptr
	POP P,1(2)		; Store updated pointer
	MOVEM 3,4		; Updated count
	EXCH 1,0(P)		; Save update source and get lt index
PKMSD:	MOVSI 3,(ILCKB)
	ANDCAM 3,IMPLT2(1)
	SKIPG 2(2)		; Bfr now full?
	CALL PKQOB		; Yes
	POP P,3
	POP P,4			; GET BACK RESIDUAL COUNT
	JUMPG 4,PKMSG2		; GO BACK IF ANYTHING LEFT
	SKIPE 4			; MAKE SURE WE HAVEN'T SCREWED UP
	BUG (HLT,<PKMSG: NEGATIVE RESIDUAL BYTE COUNT>)
	RET

PKMSL:	BUG(CHK,<PKMSG - MSG TOO LARGE>)
	MOVE 4,2(2)
	JRST PKMS3

PKMS2:	CAMG 4,2(2)		; Enough room in current bfr?
	JRST PKMS3		; Yes
	PUSH P,4
	HLRZ 4,IMPLT1(1)
	CAIN 4,-1		; CONTROL LINK?
	 JRST PKMS6		; YES, CONTROL MESSAGE CAN'T CROSS 
				; NET MESSAGE BOUNDARY
	SUB P,BHC+1		; USE REST OF CURRENT BUFFER
	MOVE 4,2(2)		; GET RESIDUAL BYTE COUNT OF BUFFER
	JRST PKMS3		; GO DO IT
PKMS6:	PUSH P,3
	CALL PKQOB		; No, finish current bfr
	POP P,3
	JRST PKMS4		; Start a new one

PKMS5:	IUNLK
	SUB P,BHC+1
	POP P,4
	CALL  IMPB03
	ILOCK
	JRST PKMSG2

; Assign and init a bfr for output use

PKBY1:	PUSH P,3
	HRRZ 3,IMPLT4(1)	; Get msg allocation
	JUMPG 3,PKBY4		; Ok
	BUG(CHK,<PKBY1: NO MSG ALLOCATION>)
	AOS IMPLT4(1)
PKBY4:	MOVEI 2,^D36		; Compute number of bits per output wd
	LDB 4,IMPLBS		; As (36/bs)*bs
	IDIVI 2,0(4)
	IMULI 2,0(4)
	MOVEI 4,0(2)
	MOVE 2,IMPLT1(1)	; Get proper size for output msg
	TRNE 2,377		; For link 0?
	SKIPA 2,MAXBPM		; No, usual regular max
	MOVEI 2,^D<120*8>	; For ctrl link, max is 120 bytes
	IDIVI 2,0(4)		; Wds = bits / (bits/wd)
	ADDI 2,3		; Plus overhead
	PUSH P,1
	CALL ASNTBF		; Assign bfr
	JRST [	POP P,1
		POP P,3
		RET]
	MOVEI 2,0(1)
	POP P,1
	HRLM 2,IMPLT4(1)	; Set as current buffer
	SOS IMPLT4(1)		; Consume allocate
	MOVEI 3,^D36		; Compute number of bytes
	LDB 4,IMPLBS		; Which will fit in buffer.
	IDIVI 3,0(4)		; I.e. words*(36/bytesize)
	HRRZ 4,0(2)		; Number of words in bfr
	IMULI 3,-3(4)		; Less header overhead
	MOVEM 3,2(2)		; Setup counter
	HRLM 3,0(2)		; Remember original count
	LDB 3,IMPLBS		; Byte size
	LSH 3,^D24		; Construct byte ptr
	HRRI 3,2(2)
	MOVEM 3,1(2)
	POP P,3
	AOS 0(P)
	RET

; Put output buffer on queue

PKQOB:	HLRZ 2,IMPLT4(1)	; Get current buffer
	HRRZS IMPLT4(1)		; Clear ptr
	HRRZ 4,1(2)		; ADDRESS OF LAST WORD CONTAINING DATA
	SUBI 4,-1(2)		; LESS ADDRESS-1 OF BUFFER
	HRRM 4,0(2)		; GIVES ACTUAL WORDS IN USE
	HLRZ 3,0(2)		; Get original byte count
	SUB 3,2(2)		; Minus current count gives bytes in bfr
	LSH 3,^D8		; Shift to proper position for header
	MOVEM 3,2(2)
	LDB 3,IMPLBS		; Byte size
	DPB 3,[POINT 8,2(2),11]	; Put in header
	SETZM 1(2)		; Clear imp header
	MOVE 3,IMPLT1(1)	; Get host-link
	DPB 3,[POINT 16,1(2),23] ; Put in imp header
	MOVE 3,IMPLT2(1)
	MOVSI 4,(IMPHIP)
	TLNE 3,(HIPFLG)	; If high priority connection,
	 IORM 4,1(2)		; Set priority bit in leader
	HRRZS 0(2)		; Put bfr on queue
	HRLM 2,0(3)
	HRRM 2,IMPLT2(1)
				; Fall into output check

; Put bfr on imp output queue if no rfnm outstanding

IMPQOB:	MOVSI 3,(RFNMC!ILCKB)
	TDNE 3,IMPLT2(1)	; Rfnm now out?
	RET			; Yes, don't send
	HLRZ 2,IMPLT3(1)
	JUMPE 2,R		; Return if no bfrs to go
IMPQO1:	MOVSI 3,(RFNMC)
	IORM 3,IMPLT2(1)	; Set rfnm flag
	HLLZ 3,0(2)		; Get bfr off queue
	JUMPN 3,.+3
	MOVEI 4,IMPLT3(1)
	HRRM 4,IMPLT2(1)
	HLLM 3,IMPLT3(1)
	CALL IMPQOA		; Actually put it on output queue
	RET

; Entry here for queueing host-imp messages

IMPQOA:	SKIPN IMPORD		; is output on?
	 JRST RLNTBF		; No. don't queue it up
	PUSH P,1		; Save ac1
	CALL IMPLKB		; Lock bfr for pi service routine
IFDEF DBGBUF,<
	MOVE 1,2
	CALL DBGOM>
	MOVSI 1,(IMPHIP)
	PIOFF
	HRRZS 0(2)		; Put bfr on imp out queue
	TDNN 1, 1(2)		; Is priority bit set in message
	 JRST IMPQOL		; No, lo priority queue
	HRLM 2,@IMPHBI
	HRRZM 2,IMPHBI
	JRST IMPQOC

IMPQOL:	HRLM 2,@IMPOBI
	HRRZM 2,IMPOBI
IMPQOC:	PION
	SKIPN IMPOB		; Output now in progress?
	JSP 4,IMPXOU		; No, start it
	POP P,1
	RET

; Lock imp bfr. must lock beginning and end in case crosses page bndry

IMPLKB:	PUSH P,1		; Save 1 and 2
	PUSH P,2
	HRRZ 1,0(2)		; GET SIZE FIELD
	CAMLE 1,MAXWPM		; MAKE SURE NOT ON FREELIST
	 BUG (HLT,<IMPLKB: ATTEMPT TO LOCK BUFFER ON FREELIST>)
	MOVEI 1,0(2)
	CALL MLKMA		; Lock beginning
	MOVE 1,0(P)
	ADD 1,0(1)		; Compute end
	MOVEI 1,-1(1)
	CALL MLKMA		; LOCK END
	POP P,2
	POP P,1
	RET

; Clear imp queues

IMPCLQ:	NOSKED			; Prevent confusion
	SKIPLE 1,IMPOB		; Anything here?
	 CALL IMPCQ5		; Unlock and release
	SETZB 2,IMPOB
	EXCH 2,IMPHBO
	MOVEI 1,IMPHBO
	MOVEM 1,IMPHBI
	CALL IMPCQ2		; Dequeue everything
	SETZ 2,
	EXCH 2,IMPOBO
	MOVEI 1,IMPOBO
	MOVEM 1,IMPOBI
	CALL IMPCQ2
	SKIPE 1,IMIB		; Anything here?
	 CALL IMPCQ5		; Yes, clear it
	SETZB 2,IMIB
	EXCH 2,IMPIBO		; Get things on input queue
	MOVEI 1,IMPIBO
	MOVEM 1,IMPIBI
	CALL IMPCQ3		; Clear 1 locked things
	SETZB 2,IMPIBO
	EXCH 2,IMPFRI		; Clear input free list
	HRLZS 2
	CALL IMPCQ2		; Clear 2 locked things
	SETZB 2,IMPNFI
	EXCH 2,IMINFB		; Get release queue
	HRLZS 2
	CALL IMPCQ4		; Release 0 locked things
	OKSKED
	RET

; Unlock buffers on a queue twice

IMPCQ2:	MOVEI 3,2
	JRST IMPCQ0

; Unlock buffers on a queue 0 or 1 times

IMPCQ4:	TDZA 3,3		; Zero times
IMPCQ3:	MOVEI 3,1		; Once
IMPCQ0:	JUMPE 2,R		; Common code. 0 -- no buffers left
	HLRZ 1,2
	HLLZ 2,0(1)
	CALL IMPCQ1		; Unlock and release
	JRST IMPCQ0		; Continue with next in chain

; Release individual buffer

IMPCQ5:	MOVEI 3,2		; Entry for twice locked buffer
IMPCQ1:	PUSH P,3		; Common routine
	PUSH P,2		; Transparent to 2
	PUSH P,1
	HRRZ 1,0(1)		; GET COUNT FIELD
	CAMLE 1,MAXWPM		; MAKE SURE NOT ON FREELIST
	 BUG (HLT,<IMPCQ: ATTEMPT TO UNLOCK BUFFER ON FREELIST>)
	MOVE 1,0(P)		;RESTORE AC1
	CALL @[	R
		MULKMP
		IMULKB](3)	; Call appropriate routine
	POP P,2
	CALL RLNTBF		; And release
	POP P,2
	POP P,3
	RET

; Unlock imp buffer at pi level

IMULKB:	PUSH P,1
	HRRZ 1,0(1)		; GET SIZE FIELD
	CAMLE 1,MAXWPM		; MAKE SURE NOT ON FREELIST
	 BUG (HLT,<IMULKB: ATTEMPT TO UNLOCK BUFFER ON FREELIST>)
	MOVE 1,0(P)
	CALL MULKMP		; Unlock first adr in bfr
	POP P,1
	ADD 1,0(1)		; COMPUTE END OF BFR
	MOVEI 1,-1(1)
	CALL MULKMP		;UNLOCK END OF BFR IN CASE PAGE BDRY
	RET

; Start input
; called from process level when buffers made available and input is off
; and from endin processor if more buffers are available

IMISRT:	CONSZ IMP,1B19		; Power on
	CONSZ IMP,1B22		; And imp up?
	 RET			; No do nothing
	SOSL IMPNFI
	SKIPN 1,IMPFRI
	 BUG(HLT,<NO IMP INPUT BUFFERS>)
	HLRZ 2,0(1)		; Get next free
	MOVEM 2,IMPFRI
	MOVEM 1,IMIB
	MOVN 2,0(1)		; Get count
	HRLI 1,2(2)		; Blki ptr
	MOVEM 1,IMPINP
	MOVEI 1,IMIN0
	MOVEM 1,IMIDSP
	CONSZ IMP,1B21		; If error flop is set
	 CALL IMIERR		; Be sure it gets noticed
	CONO IMP,IMPION+1B19	; Clear error and start input
	POPJ P,

; Pi service for input
; Dispatched at impsv to one of the following:
; Imin1: first word of msg
; Imis1: second word of msg
; Imi36:  36-bit msg in
; Imi32: 32-bit msg in
; Imin00: flush rest of msg in
; Impein - handles 'end input' signal

IMIN0:	BLKI IMP,IMPINP		; Read in first word
	BUG(HLT,<IMPIN-BFR NOT SETUP>)
	MOVEM 1,IMIDSP
	MOVEI 1,IMIS1
	EXCH 1,IMIDSP
	UNBRK IMP

; Second word in

IMIS1:	BLKI IMP,IMPINP
	BUG(HLT,<IMPIN-BFR NOT SETUP>)
	MOVEM 1,IMIDSP		; Save an ac
	MOVSI 1,-^D8		; Init 36-32 bit state word
	MOVEM 1,IMIS32
	MOVE 1,IMIB		; Get buffer location
	MOVE 1,1(1)		; Header
	AND 1,[FRMIMP + 17B7 + 377B23]
	CAMLE 1,[<LLINK>B23]
	 JRST IMIS1A		; Special link/irreg msg do in 36 bit
	MOVE 1,IMIB
	LDB 1,[POINT 8,2(1),11]
	CAIE 1,^D36		; 36-bit?
	SKIPA 1,[IMI32]		; No, assume 32 (or 8)
IMIS1A:	MOVEI 1,IMI36		; Yes
	EXCH 1,IMIDSP		; Setup dispatch for rest of msg
	UNBRK IMP

; 36-bit input

IMI36:	BLKI IMP,IMPINP
	JRST .+2		; Overflowed buffer
	UNBRK IMP
	MOVEM 4,IMPIAC+4
	MOVEI 4,IMPIAC
	BLT 4,IMPIAC+3
IMIMTL:	MOVEM P,IMINP
	MOVE P,PIMSTK
	BUG(IMP,<MSG TOO LONG>,X)
	MOVE P,IMINP
	MOVEI 1,IMIN00
	MOVEM 1,IMIDSP
IMPUB:	MOVSI 4,IMPIAC		; Restore ac's
	BLT 4,4
	UNBRK IMP

IMIN00:	DATAI IMP,IMIS32
	UNBRK IMP

PIMSTK:	IOWD NIMSTK,IMSTK

; 32-bit input

IMI32:	MOVEM 4,IMPIAC+4
	MOVEI 4,IMPIAC
	BLT 4,IMPIAC+3		; Save ac's
	DATAI IMP,1
	SKIPL 4,IMPINP		; Get ptr to input buffer
	JRST IMIMTL		; Bfr full, msg too long
	MOVE 3,IMIS32		; Get unpacking state word
	AOBJP 4,IMIMTL		; Seq bfr ptr
	TRNN 3,777777		; Is this the zero'th state?
	 AOBJP 4,IMIMTL		; Yes point to partial word
	LSHC 1,@IMISHT(3)	; Align input bytes with destination
	DPB 1,IMIPT1(3)		; High order byte for n-1st word
	MOVEM 2,0(4)		; Low order byte for nth word
	AOBJN 3,IMI32A		; Step state
	MOVSI 3,-^D8		; Reinit state word
IMI32A:	MOVEM 3,IMIS32		; Save state
	MOVEM 4,IMPINP		; Save bfr ptr
	JRST IMPUB

; Tables for 36-32 bit conversion, indexed by state word

IMISHT:	XX==4
	REPEAT ^D8,<Z -XX
		XX=XX+4>

IMIPT1:	XX==^D32
	REPEAT ^D8,<POINT XX,-1(4),31
		XX=XX-4>

; Here when end msg recd from imp

IMPEIN:	MOVEM 4,IMPIAC+4
	MOVEI 4,IMPIAC
	BLT 4,IMPIAC+3		; Save ac's
	MOVEM P,IMINP
	MOVE P,PIMSTK		; Setup local stack
	CONSZ IMP,1B21		; Error ff set?
	 PUSHJ P,IMIERR		; Take care of it
	CONO IMP,IMPGEB!IMPIOF
	SKIPG 1,IMIB		; Bfr address
	JRST IMPEI2		; Wasn't one
	AOSG IMPFLS		; Flushing msgs?
	 JRST IMPEI3		; Yes, return to free list
	HRRZ 2,IMIDSP
	CAIE 2,IMIN0		; No msg started? or
	CAIN 2,IMIN00		; Were flushing msg?
	JRST IMPEI2		; Yes, skip usual finish up stuff
	MOVE 2,1(1)		; Get header
	LDB 3,[POINT 4,2,7]	; And msg type
	AND 2,[FRMIMP + 377B23]
	CAIN 3,6		; Dead host status
	 JRST IMPEI4		; Yes. has no message id
	CAIE 3,2		; Going down?
	CAMG 2,[<LLINK>B23]
	JUMPN 3,IMPEI4		; Irregular msg not special link
	HRRZS 0(1)		; Clear fwd ptr of this bfr
	HRLM 1,@IMPIBI		; Add bfr to in queue
	HRRZM 1,IMPIBI
	HRRZ 3,0(1)		; GET SIZE FIELD
	CAMLE 3,MAXWPM		; MAKE SURE NOT RELEASED
	 BUG (HLT,<IMPEIN: ATTEMPT TO UNLOCK BUFFER ON FREELIST>)
	ADD 1,0(1)		; Compute tail of bfr
	MOVEI 1,-1(1)
	CALL MULKMP		; Unlock it
	HRRZ 3,IMPINP	; GET LAST LOC WITH DATA
	HRRZ 4,IMIB		; START ADDRESS OF BUFFER
	SUBI 3,-1(4)		; 3=END-(START-1)=ACTUAL COUNT
	HRRM 3,@IMIB		; RECORD ACTUAL COUNT IN BUFFER HEADER
	AOS IMPFLG		; Request job 0 service
IMPEI2:	SETZM IMIB
	SKIPLE IMPNFI		; More buffers available?
	 PUSHJ P,IMISRT		; Yes, start new input
IMPUB1:	MOVE P,IMINP
	JRST IMPUB

IMPEI4:	MOVE 2,1(1)		; Get header
	CALL IMP8XQ		; Put on irreg msg q
	AOS IMPFLG
IMPEI3:	EXCH 1,IMPFRI
	HRLM 1,@IMPFRI
	AOS IMPNFI
	JRST IMPEI2

IMIERR:	PUSH P,1
	SETOM IMPRDL		; Be sure this flap gets noticed
	MOVNI 1,2
	MOVEM 1,IMPFLS
	MOVNM 1,NOPCNT		; Send some nops
	CONO IMP,1B19		; Clear error flop
	POP P,1
	POPJ P,

; Pi service for output
; Dispatched from impsv to one of the following:
; Imo36: doing 36 bit output
; Imo32: doing 32 bit output (second word only)
; Imo321: doing 32 bit output (rest of msg)
; Impdn2: final phase of end-of-msg cleanup

IMODN0:	MOVEM 4,IMPIAC+4
	MOVEI 4,IMPIAC
	BLT 4,IMPIAC+3		; Save ac's
IMODN1:	MOVEM P,IMINP
	MOVE P,PIMSTK
	CONO IMP,IMPEOB		; Sent last word, now send end bit
	MOVE 1,IMPOB		; Get buffer location
	MOVE 2,1(1)		; Get header
	AND 2,[FRMIMP+377B23]
	CAMLE 2,[<LLINK>B23]	; Regular link?
	 JRST IMODN4		; No. just flush the message
	LDB 1,[POINT 16,1(1),23]; Extract host-link
	IORI 1,1B18
	CALL IMPPIL		; Get lt index for this
	 JRST IMODN6		; Not there
	MOVSI 2,(RFNMC)		; Be sure rfnm has not returned already
	TDNN 2,IMPLT2(1)
	 JRST IMODN4		; Well what do you know!
	HRRZ 2,IMPLT3(1)	; Be sure nothing is there
	JUMPN 2,IMODN6		; Anomalous, but what can you do?
	MOVE 2,IMPOB
	HRRM 2,IMPLT3(1)
	JRST IMODN5

IMODN6:	BUG(NTE,<Can't find LT entry for output message>)
IMODN4:	MOVE 1,IMPOB
	EXCH 1,IMINFB		; Put bfr back on free list
	HRLM 1,@IMINFB
	AOS IMPFLG		; Request job 0 service
IMODN5:	MOVE 1,IMPOB
	CALL IMULKB		; Unlock bfr
	MOVEI 1,IMODN2		; Setup dispatch for final step
	MOVEM 1,IMODSP
	JRST IMPUB1

IMOIRG:	CONO IMP,IMPEOB
	MOVEM 1,IMODSP
	MOVEI 1,IMODN2
	EXCH 1,IMODSP
	UNBRK(IMP)

IMODN2:	MOVEM 4,IMPIAC+4
	MOVEI 4,IMPIAC
	BLT 4,IMPIAC+3		; Save ac's
	JSP 4,IMPIOU		; Start next msg if any
	JRST IMPUB

; Routine to start msg going out. called at pi level, and at
; Main level if no output in progress

IMPXOU:	PIOFF
	SKIPN IMPOB		; ANY OUTPUT IN PROGRESS?
	 JRST IMPXO1		; NO
	PION			; YES, TURN PI BACK ON
	JRST (4)		; AND RETURN

IMPXO1:	HRROS IMPOB		; MARK OUTPUT IN PROGRESS
	PION			; NO IT'S OK TO TURN PI BACK ON
IMPIOU:	SKIPLE NOPCNT		; Any nop's to send?
	 JRST IOUNOP		; Yes, go send them
	HLRZ 1,IMPHBO		; Hi priority msg waiting?
	JUMPE 1,IMPIOL		; No, check lo priority
	HLLZ 2,0(1)		; Get buffer
	JUMPN 2,.+3
	MOVEI 3,IMPHBO
	MOVEM 3,IMPHBI
	MOVEM 2,IMPHBO
	JRST IMPIOC

IMPIOL:	HLRZ 1,IMPOBO		; Msg waiting to go out?
	JUMPE 1,[SKIPE 2,HSTGDM
		 JRST IOUIRG	; Send the host going down msg
		CONO IMP,IMPSTO	; No, turn of imp pi req
		SETZM IMPOB
		JRST 0(4)]
	HLLZ 2,0(1)		; Get bfr
	JUMPN 2,.+3
	MOVEI 3,IMPOBO
	MOVEM 3,IMPOBI
	MOVEM 2,IMPOBO
IMPIOC:	MOVEM 1,IMPOB
	MOVN 2,0(1)		; Count of data words
	HRLI 1,1(2)		; Construct blko ptr
	MOVEM 1,IMPOUP
	MOVE 2,1(1)		; Get header
	AND 2,[FRMIMP + 377B23]
	CAMLE 2,[LLINK*1B23]	; Special message?
	 SKIPA 2,[^D36]		; Yes, assume 36-bit mode
	LDB 2,[POINT 8,2(1),11]	; Byte size
	MOVEI 1,IMO36
	CAIE 2,^D36		; 36-bit connection?
	MOVEI 1,IMO32		; No, transmit in 32-bit
	MOVEM 1,IMODSP		; Setup dispatch
	BLKO IMP,IMPOUP		; Send first word (always 36-bit)
	JFCL
	JRST 0(4)

IOUNOP:	SOS NOPCNT
	MOVE 2,[BYTE (8)4,0,0,0]
IOUIRG:	HRROS IMPOB		; Make non-zero so checks work
	MOVEI 1,IMOIRG
	MOVEM 1,IMODSP
	DATAO IMP,2
	JRST (4)

; 36-bit output

IMO36:	SKIPL IMPOUP		; Data left?
	JRST IMODN0		; No
	BLKO IMP,IMPOUP
	JFCL
	UNBRK IMP

; 32-bit output (second word)

IMO32:	BLKO IMP,IMPOUP		; Send second word (extended hdr)
	JFCL
	MOVEM 1,IMODSP		; Save an ac
	MOVSI 1,-^D8		; Init 36-32 bit translation state word
	MOVEM 1,IMOS32
	MOVEI 1,IMO321		; Setup dispatch for rest of msg
	EXCH 1,IMODSP
	UNBRK IMP

; 32-bit output (rest of msg)

IMO321:	MOVEM 4,IMPIAC+4
	MOVEI 4,IMPIAC
	BLT 4,IMPIAC+3		; Save ac's
	SKIPL 4,IMPOUP		; Data left?
	JRST IMODN1		; No
	MOVE 3,IMOS32		; Get state word
	AOBJP 4,.+2		; Inc bfr ptr
	MOVE 2,1(4)		; Get n+1th word
	MOVE 1,0(4)		; Get nth word
	LSH 1,-4		; Align high-order byte
	LSHC 1,@IMOSHT(3)	; Shift bytes into output word
	DATAO IMP,1
	AOBJN 3,IMO32A		; Step state
	AOBJN 4,.+1		; Extra inc of bfr each cycle
	MOVSI 3,-^D8		; Reinit state word
IMO32A:	MOVEM 3,IMOS32		; Save state word
	MOVEM 4,IMPOUP		; Save bfr ptr
	JRST IMPUB

; Table for 32-36 bit conversion, indexed by state word

IMOSHT:	XX==4
	REPEAT ^D8,<Z XX
		XX=XX+4>

; Various impbug's from above

IMPB01:	BUG(IMP,<IMPLT FULL>,X)
	JRST LNKL1

IMPB03:	SKIPN IMINFB		; ANY BUFFERS RELEASE BY PI ROUTINES?
	 JRST IMPB04		; NO
	PUSH P,1
	PUSH P,2
	PUSH P,4
	CALL IMINRB
	POP P,4
	POP P,2
	POP P,1
	RET

IMPB04:	PUSH P,1
	BUG(IMP,<ASNTBF FAILED>,X)
	MOVEI 1,^D5000
	DISMS			; Wait for 5 sec, then try again
	POP P,1
	RET

IMPB06:	IUNLK
	MOVE 2,1
	CALL IMP8X1
	BUG(IMH,<RECD EXCESS ALL>,X)
	RET

; Bug or untreated net error

BGRIML:	PUSH P,1
	PUSH P,2
	MOVE 1,2
	SETZ 2,
	JRST BGRIM0

IMPBG0:
BGRIMH:	PUSH P,1
	PUSH P,2
	SETZ 1,			; No header
	JRST BGRIM0

BGRIMP:	PUSH P,1
	PUSH P,2
	SETZB 1,2
BGRIM0:	IFDEF DBGBUF,<
	EXCH 1,-2(P)
	CALL DBGBG1		; Store bug info
	EXCH 1,-2(P)>
	AOS IMPBGC		; Count bugs
	SKIPE BUGIMP
	 JRST BGRIM1
	MOVEM 2,IMPBGH		; Save host/link
	HLRZM 1,BADHMS
	MOVE 2,1(1)		; First word ofheader
	MOVEM 2,BADHDR
	MOVE 2,2(1)
	MOVEM 2,BADHDR+1
	HRRZ 2,-2(P)		; Pc of the bug
	MOVEM 2,BUGIMP
BGRIM1:	POP P,2
	POP P,1
	AOS JB0FLG		; Get job 0 started
	RET

; Imp and ncp status check

IMPSTT:	AOSE IMPRDL		; Was error flop noticed set?
	CONSZ IMP,1B22		; Or is ready line off?
	 JRST IMPSTA		; Yes, mark down
	SKIPGE IMPRDT		; Was it down?
	 JRST IMPSTB		; No, continue
	SETOM IMPRDT		; Yes, reset flag
	GTAD
	MOVEM 1,IMPUPT		; Record time back up
	JRST IMPSTB		; Continue

; Imp is or was down.  record time thereof

IMPSTA:	SKIPN IMPRDY
	 JRST IMPSTB		; Don't record imp down if ncp is off
	SKIPL 1,IMPRDT		; Was it down?
	 JRST IMPSTC		; Yes, check how long
	MOVE 1,TODCLK
	MOVEM 1,IMPRDT		; No, record when in went off
	GTAD
	MOVEM 1,IMPDNT
	JRST IMPSTB

IMPSTC:	ADDI 1,^D10000
	CAMG 1,TODCLK		; Down for more than 10 sec?
	 SETOM IMPDRQ		; Yes, declare imp down & recycle ncp
	JRST IMPSTB

; Bring state of ncp into agreement with state of imp and neton/impdrq

IMPSTB:	SKIPLE 1,IMPRDY		; Down cycle in progress?
	 JRST IMPNO1		; Yes. complete it.
	JUMPL 1,IMPSTU		; No. jump if we think imp is up
	SKIPE NETON		; Ncp is shut off.  do we want it off?
	SKIPLE NETTCH		; No. but if state change unreported,
	 RET			;  then wait. do nothing if all agrees.
	JRST IMPRSS		; Else bring ncp back up.

IMPSTU:	SKIPLE NOPCNT		; ARE ANY NOPS NEEDED
	 JSP 4,IMPXOU		; YES, BE SURE OUTPUT IS GOING
	SKIPN IMPDRQ		; We think it's up, want it down
	SKIPN NETON
	 JRST IMPNOF		; Yes, take it down
	SETZM HSTGDM		; Else it's up. be sure to cancel
	JRST RSKP		;  host going down msg and skip

; Shut down ncp

IMPNOF:	SKIPLE NETTCH
	 JRST RSKP		; But not until state change reported
IMPNF1:	MOVEI 1,^D30000		; Begin down sequence
	ADD 1,TODCLK
	MOVEM 1,IMPRDY		; When to give up and turn ncp off.
	CALL NETDWN		; Start clear of ncp
	CALL CLRHRT		; Clear host ready table
	SETZM IMPCCH		; Send rst's to everyone
	SETZM IMPTIM		; Now.
	AOS NETTCH
	AOS JB0FLG
	JRST IMPSTT

; Down sequence in progress

IMPNO1:	CONSO IMP,1B22		; If imp is dead
	CAMG 1,TODCLK		; or time has run out?
	 JRST IMPNF3		; Yes. just pull the plug.
	SKIPG NETTCH		; Else if change unreported
	SKIPL IMPCCH		;  or rst's not all sent
	 JRST RSKP		;  then wait.
	SETZM IMPORD		; Shut off output
	SKIPN IMPOBO		; Check if both output queues are empty.
	SKIPE IMPHBO
	 JRST RSKP		; If not, then wait.
	SKIPLE IMPOB		; If last message not completely sent
	 JRST RSKP		;  then wait.
	SETZM HSTGDM		; Now stop sending host going down.
	SKIPE IMPOB		; Are all messages sent?
	 JRST RSKP		; No. wait.
IMPNF3:	SETZM IMPRDY		; Now say totally down
	CONO IMP,IMPSTO!IMPIOF!IMPOOF!1B20
				; Stop output, in&out off, drop rdy
	AOS NETTCH		; Report final state change
	AOS JB0FLG
	MOVEI 2,NVTLO		; Finish clean up
IMPNO2:	SKIPGE TTFORK(2)	; Nvt in use
	SKIPL TTNETW(2)
	 CALL TTCOBI		; Yes, flush output
	CAIGE 2,NVTHI		; Check all net nvt lines
	 AOJA 2,IMPNO2
	MOVSI 1,-IMPNLK
	CALL IMPCLL		; Clear all entries from link table
	AOBJN 1,.-1
	CALL IMPCLQ		; Clear queues
	RET			; Not up - nonskip return

; Initialization

IMPINI:	MOVEI 1,IMPIBO		; Init buffer lists
	MOVEM 1,IMPIBI
	MOVEI 1,IMPOBO
	MOVEM 1,IMPOBI
	MOVEI 1,IMPHBO
	MOVEM 1,IMPHBI
	MOVSI 2,-NSQ
	MOVEI 1,SIQIBO(2)
	MOVEM 1,SIQIBI(2)
	SETOM SQJOB(2)
	AOBJN 2,.-3
	SETOM SQLCK
	MOVEI 2,1B18+1B19	; Free entry for implt1
	MOVSI 1,-IMPNLK
	MOVEM 2,IMPLT1(1)	; Make all links unused
	AOBJN 1,.-1
	MOVSI 1,-NNVTLN		; Count through nvt lines
	SETOM TTNETX(1)		; Init all net lines to free
	AOBJN 1,.-1
	SETOM IDVLCK		; INIT IDVLCK
IMPRSN:	SETZM IMPNCL		; Clear irreg msg q variables
	SETZM IMP8XI
	SETZM IMP8XO
	SETZM IMP8XC
	MOVEI 1,IMIN00		; Setup pi dispatches
	MOVEM 1,IMIDSP
	MOVEI 1,IMODN2
	MOVEM 1,IMODSP
	MOVEI 1,^D120000	; Start timers
	ADD 1,TODCLK		; In two minutes
	MOVEM 1,NETTIM		; Set alarm clocks to infinity
	MOVEM 1,RFNTIM
	SETZM IMPTIM
	SETZM IGDTIM		; Clear time of last imp-going-down msg
	SETZM HSTGDM		; Cancel any residual host going down
	SETZM IMPCCH		; Cause send of rst to all hosts
CLRHRT:	SETZM IMPHRT		; Clear ready table
	MOVE 1,[XWD IMPHRT,IMPHRT+1]
	BLT 1,IMPHRT+IMPLBT-1
	RET

; Bring up ncp

IMPRSS:	CONSZ IMP,1B19		; Power on
	CONSZ IMP,1B22		; And ready line on
	 RET			; No, stop here
	CALL IMPRSN		; Reset variables
	CONO IMP,1B19		; Set host ready line, clear imp error
	SETZM IMPRDL		; And notices of b21
	SETZM IMPDRQ		; Forget any intervening down requests
	MOVNI 1,2
	MOVEM 1,IMPFLS		; Init flush count
	MOVEI 1,3
	MOVEM 1,NOPCNT
	MOVEI 1,^D1000
	DISMS			; Allow time for ready line to settle
	AOS NETTCH		; Cause change in state to be noted
	AOS JB0FLG
	GTAD			; Yes
	MOVEM 1,NCPUPT		; Save time whe it came up
	DATAI IMP,1		; Helps to clear interface
	CONO IMP,IMPSTO+IMPGEB
	CONO IMP,IMPOON		; Give output pi asmt
	SKIPLE IMPNFI		; If input bfrs available,
	 CALL IMISRT		; Start input
	SETOM IMPRDY
	SETOM IMPORD		; Allow output
	MOVE 1,NLHOST		; Local host
	CALL IMPRRP		; Send ourselves an rrp
	RET

; Take network down
; Accepts in
;	1	; Reason for going down (a la 1822)
;	2	; Time when back up (TENEX standard)

IMPHLT:	SKIPN NETON		; IS IT ON?
	 RET			; NO. DO NOTHING
	PUSH P,1
	GTAD			; GET NOW
	CAMG 2,1		; IS SHUTDOWN LATER THAN NOW?
	 JRST [	MOVEI 1,177776
		JRST IMPHL1]	; TIME BACK UP NOT KNOWN
	ADD 1,[6,,0]
	CAMG 1,2		; MORE THAN 6 DAYS AWAY?
	 JRST [	MOVEI 1,177777
		JRST IMPHL1]
	MOVSI 4,(1B0+1B2+0B17)	; USE GMT STANDARD TIME
	ODCNV			; SEPARATE INTO DAY, SECOND ETC
	HRRZ 1,3		; DAY OF WEEK
	HRRZ 2,4
	IDIVI 2,^D300		; CONVERT SECONDS TO 5 MIN
	IDIVI 2,^D12		; SEPARATE INTO HOUR AN 5 MIN
	LSH 1,5
	IOR 1,2			; INSERT HOUR OF DAY
	LSH 1,4
	IOR 1,3			; AND 5 MIN PART OF HOUR
IMPHL1:	LSH 1,4
	IOR 1,0(P)
	LSH 1,4
	TLO 1,(2B7)
	PIOFF
	SETZM NETON		; START NET DOWN
	MOVEM 1,HSTGDM
	PION
	JSP 4,IMPXOU
	SUB P,BHC+1
	RET

; Restart code. called by sysrst

IMPRST:	SETOM IMPDRQ		; Request down cycle
	MOVEI 1,1
	SKIPLE IMPRDY		; Going down already?
	 MOVEM 1,IMPRDY		; Shorten delay
	RET

>			; End of idfef impchn on page 1
	END
