Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_3_19910112 - mit/monitor/impphy.mac
There are no other files named impphy.mac in the archive.
;<5.ISI.MONITOR>IMPPHY.MAC.5350	 6-Jan-83 17:42:06	Edit by JGOLDBERGER
;#535 Add SKIPE to keep 0 instead of intsec,,0
;[BBNF]<CLYNN.NEW>IMPPHY.MAC.23, 17-Dec-82 17:48:09, Edit by: CLYNN
; Save T1 over IMOSRT in IMPSCK
;<5.ISI.MONITOR>IMPPHY.MAC.5010	22-Oct-82 08:39:46	Edit by JGOLDBERGER
;#501 Version 5 MultiNet
;[BBNF]<TAPPAN.NEW>IMPPHY.MAC.18,  8-Oct-82 12:20:55, Edit by: TAPPAN
; Fix handling of HSTGDM
;<TAPPAN.NEW>IMPPHY.MAC.2, 10-Apr-82 12:59:39, Edit by TAPPAN
; Remove NTBFFL (preparatory for No-NCP mods)
; Added IMPVEC -- Hardware routine vector
;<BBN-4-MONITOR>IMPPHY.MAC.4, 11-Mar-82 10:32:31, Edit by TAPPAN
; Modify IMISRT so IMSCHK is called with PION (so as not to hog
; the machine)
;<BBN-4-MONITOR>IMPPHY.MAC.3, 28-Aug-81 16:01:20, Edit by TAPPAN
; 103: keep PI's off when hacking output Q's to preserve integrity
;<TAPPAN.4>IMPPHY.MAC.3, 22-Aug-80 11:28:13, Edit by TAPPAN
; Removed TELENET 
;<TAPPAN.4>IMPPHY.MAC.2,  1-Jul-80 16:11:30, Edit by TAPPAN
; Conversion to Multinet
;[BBNF]<TCP-BBN-4-MONITOR>IMPBBN.MAC.4011,  9-May-80 16:17:53, Ed: PLUMMER
; Make IMISRT call IMPRBF with arg in T2
;[BBNF]<TCP-BBN-4-MONITOR>IMPBBN.MAC.4010,  9-May-80 10:40:26, Ed: PLUMMER
; Merge with Internet version
;
;   Various changes between here
;
;<CLEMENTS>IMPPHY.MAC.1, 19-Jul-76 16:18:47, EDIT BY CLEMENTS
;SEPARATED PHYSICAL IMP DRIVER FROM IMPDV.MAC

	SEARCH PROLOG,IMPPAR
ND INETN,1
IFG INETN,<SEARCH INPAR>
	SEARCH MNTPAR,MONSYM,MACSYM
ND MLCN,0

	TTITLE (IMPPHY,IMPPHY,< -  PHYSICAL IMP DRIVER FOR IMP10>)

	ASCIZ	/
	IMPPHY
	COPYRIGHT (C) 1980,1981,1982,1983 BOLT BERANEK and NEWMAN INC.
	/


;;; DEVICE DEFINITION FOR BBN-STANDARD IMP10 INTERFACE

;;; Cono-coni bits

I.IRQ==1B32		; Input word ready, CONI
I.ORQ==1B28		; Ready for next output word, CONI
I.ERQ==1B24		; End of input, CONI
I.NRD==1B22		; IMP not ready line. CONI
I.ERR==1B21		; The error flop, Imp has been down. CONI
I.DWN==1B20		; Imp is now down. CONI
I.PWR==1B19		; The interface is powered up. CONI

I.GEB==1B23		; Clear eib, CONO
I.EOM==1B22		; End of output message, CONO
I.STO==1B21		; Stop output, CONO
I.NRL==1B20		; Not Ready-line to IMP, CONO
I.CLR==1B19		; Clear error flop, CONO

I.IOF==10B27+10			; E of cono to clear input pi asmt
I.ION==<10+IMPCHN>B27+<10+IMPCHN> ; E of cono to set input pi asmt
I.OOF==10B31			; E of cono to clear output assmnt
I.OON==<10+IMPCHN>B31		; E of cono to set output pi asmt


;Device-dependent data for leaders

	STY%NP==5		;Number of Padding words, for H2I NOP
	RESCD
;;;
;;; Hardware routine vector
IMPVEC::
	NCTVEC(IMPVEC,IMPKIL,NTHKIL)	; Kill hardware
	NCTVEC(IMPVEC,IMPINI,NTHINI)	; Init hardware
	NCTVEC(IMPVEC,IMPRSS,NTRSRT)	; Restart hardware
	NCTVEC(IMPVEC,IMISRT,NTISRT)	; Start input
	NCTVEC(IMPVEC,IMOSRT,NTOSRT)	; Start output
	NCTVEC(IMPVEC,IMPSCK,NTSCHK)	; Check interface status

;;; Pi dispatch

IMPSV::	PUSH P,P1		; Save old AC
	SKIPA P1,NCTVT		; Get first NCT
IMPSV0:	LOAD P1,NTLNK,(P1)	; get next in list
	JUMPE P1,IMPSV1		; No more
	LOAD T1,NTDEV,(P1)	; Get device type
	CAIE T1,NT.BBN		; IMP10?
	 JRST IMPSV0		; No, loop
	CALL NTPOLL(P1)		; Check this one out
	 JRST IMPSV0		; No this one
	POP P,P1		; Restore P1
	UNBRK IMP		; Back from interrupt

;;; Here when no interrupt found
IMPSV1:	POP P,P1		; Restore
	RET			; and return
;;; Start input
;;; called from process level when buffers made available and input is off
;;; and from endin processor if more buffers are available

IMISRT:
	CALL IMPSCK		; Is the IMP up?
	 RET			; No, Can't do anything
	PIOFF
	SKIPE NTIB(P1)		;ALREADY DOING INPUT?
	 SOSA IMPNFI		;Yes, so don't start another
	  SOSGE IMPNFI		;IS THERE A BUFFER TO READ INTO?
	   JRST [AOSG IMPNFI	;IF NOT, CORRECT COUNT AND GIVE UP.
		  SETOM NOIBFS	; Flag (that failed) if no buffers
		PION
		RET]
	MOVE T2,IMPFRI		;THERE ARE SOME, IT SAYS. GRAB ONE.
	CALL CHKBUF		; CHECK OUT BUFFER
	 JSP CX,IMPFLB		; Free list bad
	LOAD T1,NBQUE,(T2)	; Get next free
IFNKA <	SKIPE T1 >		; If there's a successor,
	  SETSEC T1,ANBSEC	; Set section number
	MOVEM T1,IMPFRI
	SETZRO NBQUE,(T2)	; DeQueue it from any others
	MOVEM T2,NTIB(P1)
	SETZM NTIS32(P1)	; Flag reading in 36 bit mode
	MOVEM T2,NTINP(P1)	; That's the 23-bit address
	MOVNI T1,<.NBLD2+1>	; Read thru the IMP leader, and 1 pad word
	MOVEM T1,NTIWC(P1)	; That's the count
	XMOVEI T1,IMIN0		; Prepare to accept first words from IMP
	MOVEM T1,NTIDSP(P1)	; Here on PI level
	PION
	MOVEI T1,I.ION+I.CLR	; CLear error and start input
	MNTXCT NTCONO		; ..
	RET

;;; For subsequent interrupts, a field will steer the packing and counts.
;;; Values are named .IIxxx for Imp Interrupt dispatch. Store in NTITYP(NCT)
;;; and correspondingly in NTOTYP for output side.

.IINC6==0		;This is a 36 bit NCP message
.IINC2==1		;This is a 32 bit NCP message
.IITNT==2		;Telenet link
.IISPQ==3		;Special queue
.IIINT==4		;Internet packing
.IIMLC==5		;MLC (Ptip) format
.IISQ2==6		;False start INT becomes SPQ later
;;; Pi service for input
;;; Dispatched at IMPSV to various routines via NTIDSP(NCT)
;;; IMPIND - handles 'end input' signal

IMIN0:	CALL DOBLKI		; Do extended BLKI
	 JRST IMIN1		; Leaders all read.
	RETSKP			; More to read

;;; Here when all leader and one word of padding have been read.

IMIN1:	MOVE T1,NTIB(P1)	; Get buffer location
	LOAD T2,IHLNK,(T1)	; Get link and host numbers
	LOAD T3,IHHST,(T1)	;  for packing decisions
IFN MLCN,<
	MOVEI T4,(T2)		; Half the link field
	LSH T4,-1
	CAMN T4,MLCHLF		; Match the MLC pair?
	JRST IMI1ML		; Yes.
>
IFN INETN,<
	CAIN T2,INTLNK		; Internet link?
	JRST IMI1IN		; Yes.
>
	CAIG T2,LLINK		; Normal NCP and host?
	 CAIL T2,FKHOST
	  JRST IMI1SQ		; No. pack in 32 bit mode
IMI1NC:	MOVX T4,.IINC6		; Seems to be an NCP message.
IMIN1A:	XMOVEI T2,.NBLD2+1(T1)	; Get pointer to next word to read
	MOVEM T2,NTINP(P1)	; For next BLKI pointer
	HLRE T2,II1WCT(T4)	; Count, for this type of message
	MOVEM T2,NTIWC(P1)	; That's the count for next group
	HRRZ T2,II1WCT(T4)	; Build a zero or an AOBJN counter to
	HRLS T2			; see if we want to switch to 32 bit mode
	SKIPE T2		; ...
	 HRRI T2,^D8(T2)	; Counter. Set initial state.
	MOVEM T2,NTIS32(P1)	; Save in core for further interrupts
	XMOVEI T3,IMIN2		; Where to go on next interrupt
	MOVEM T3,NTIDSP(P1)	; Save for next int time
	MOVEM T4,NTITYP(P1)	; Include type code
	RETSKP			; Done this interrupt
IMI1SQ:	MOVX T4,.IISPQ		;Special queues
	JRST IMIN1A		;Join common code

IFN MLCN,<
IMI1ML:	MOVX T4,.IIMLC		;MLC link
	JRST IMIN1A		;Join common code
>
IFN INETN,<
IMI1IN:	MOVX T4,.IIINT		;Internet link
	JRST IMIN1A		;Join common code
>

II1WCT:	XWD -2,0		; TYPE NCP36
	XWD -2,0		; TYPE NCP32
	XWD -2,0		; TYPE TELENET (unused)
	XWD -1,-^D8		; TYPE SPECIAL Q, start 32 bit mode
	XWD -5,-^D8		; TYPE INTERNET, start 32 bit mode
	XWD -2,0		; TYPE MLC
	XWD -1,-^D8		; TYPE SQ2, start 32 bit mode
; Here for BLKI's in second group, after leader.

IMIN2:	SKIPE NTIS32(P1)	; Reading 32 bit mode?
	JRST [	CALL BLKI32	; Yes, read and distribute 36 bits
		 JRST IMIN20	; Finished
		RETSKP]	; More to go
	CALL DOBLKI		; Read another word in 36 bit mode
	 JRST IMIN20		; Done.
	RETSKP			; More to go.

IMIN20:	MOVE T1,NTIB(P1)	; Point to buffer being read into
	MOVE T4,NTITYP(P1)	; Get the type code for this msg
;;; Padding removal isn't needed if message isn't that long, but it's
;;; cheaper to always remove it than to test for needing to.
	DMOVE T2,.NBLD2+2(T1)	; Crunch out the padding
	STOR T2,IHPD1,(T1)	; Partial word in .NBLD2
	MOVEM T3,.NBHHL(T1)	;  and H-H leader to its rightful place
IFN INETN,<
	CAIN T4,.IIINT		; Internet link?
	 CALL INETIN		; Yes. Special routine, may change T4,T1.
>
	LOAD T2,NBBSZ,(T1)	; Set up BLKI pointer for rest of msg
	MOVE T3,II2LDT(T4)	; Amount of buffer we have used so far
	SUBI T2,(T3)
	MOVNS T2		; Negative for BLKI
	MOVEM T2,NTIWC(P1)	; That's the next word count
	MOVNI T2,2		; The two fills just removed
	ADDM T2,NTINP(P1)	; Subtract from read so far
	CAIE T4,.IINC6		; NCP message?
	 JRST IMIN2A		; No
	LOAD T2,HHSIZ,(T1)	; Yes, see if packing 32 or 8
	CAIN T2,^D36		; Word mode?
	 JRST IMIN2A		; Yes, continue that way.
	MOVEI T4,.IINC2		; No, switch to 32 bit mode
	MOVEM T4,NTITYP(P1)	; Update in core
	MOVSI T3,-^D8		; Start reading in 32 bit mode from here
	MOVEM T3,NTIS32(P1)
IMIN2A:	XMOVEI T3,IMIN3		; Dispatch for next interrupts
	MOVEM T3,NTIDSP(P1)
	RETSKP

;Table of next word to read into at IMIN2 time, by message type

II2LDT:	EXP .NBDW0		;Type NCP36
	EXP .NBDW0		;Type NCP32
	EXP .NBDW0		;Type TELENET
	EXP .NBHHL		;Type SPECIAL QUEUES
	EXP .NBDW0+2		;Type Internet
	EXP .NBDW0		;Type MLC
	EXP .NBHHL+3		;Type Special Q - false Internet
IFN INETN,<
; Called from IMIN2 when possible Internet message is coming in.
; This routine does the following:
;	1.	Move the 2 remaining H-H words to the right place
;	2.	Check for right message type and subtype
;	3.	Check for Internet being on
;	4.	Check for a Internet-supplied buffer being available
; If any of those conditions is lacking, input is resumed and the
; message is handled as a normal special queue message.
; If the message is really destined for the gateway (TCP, XNET, ...),
; it gets copied into a Internet-supplied buffer and input resumes.
; IMPEIN will then queue it for the gateway.

;T1/	Pointer to current NCP-supplied buffer
;T4/	.IIINT
;	CALL INETIN
;Ret+1:	Always. T4 set to .IIINT if I.N. msg to be completed, or .IISQ2
;		if it will be given to a special Q


INETIN:	DMOVE T2,.NBDW0+2(T1)	; Pick up the Internet header
	DMOVEM T2,.NBDW0(T1)	; Stash in proper place
	MOVE T2,.NBDW0+4(T1)	; And the twelve bits after it
	MOVEM T2,.NBDW0+2(T1)	; Which have also been read
	LOAD T2,IHFTY,(T1)	; ARPANET message format
	LOAD T3,IHMTY,(T1)	; ARPANET message type
	CAIN T3,.IHREG		; Regular msg?
	 CAIE T2,ITY%LL		; Long leader?
	  JRST INETIC		; No. Let normal code handle it.
	LOAD T2,IHSTY,(T1)	; ARPANET subtype
	LOAD T3,INPVR,(T1)	; Inet pkt version flag (part of 2.5 net)
	CAIE T2,STY%FC		; Normal, flow-controlled?
	CAIN T2,STY%UC		; or uncontrolled?
	CAIE T3,.INTVR		; And right Internet version?
	 JRST INETIC		; No.  Let normal code handle this.
	SKIPG INTNFI		; And there is a Internet buffer around?
	 JRST INETIC		; No.  Let normal special queue have it.

; All is OK for the switch to a Internet buffer.  Do it, return the NCP buf.

	SOSL INTNFI		; Count down number of free Internet bufs
	SKIPN T2,INTFRI		; Get pointer to buffer to use
	 JSP CX,IMPNIT		; Buffer list fouled
IFN MAXLDR-.NBHHL,<
	MOVEI T3,.NBHHL		; real header size
	CALL FIXLDR		; correct it
>
	PUSH P,T2		; Save new pointer
	XMOVEI T3,.NBLD0(T2)	; "To" -- into Internet buffer
	XMOVEI T2,.NBLD0(T1)	; "From" pointer for BLT
	HLRE T1,II1WCT(T4)	; Get size of second transfer
	MOVNS T1
	ADDI T1,.NBHHL-2	; Compute count (-2 for fill crunch)
	CALL XBLTA		; Copy ARPANET and Internet headers
	MOVE T1,NTINP(P1)	; Pointer to last read into NCP buffer
	SUB T1,NTIB(P1)		; Figure out how many words were read
	ADD T1,INTFRI		; Pointer to correspoinding point in Inet pkt
	MOVEM T1,NTINP(P1)	; Set new pointer
	MOVE T2,INTFRI		; Get the Internet buffer again
	LOAD T1,NBQUE,(T2)	; Next Internet free buffer
IFNKA <	SKIPE T1 >		; SETSEC might not create an instruction
	  SETSEC T1,INTSEC
	SETZRO NBQUE,(T2)	; Clear list pointer
	EXCH T1,INTFRI		; Becomes head of list
	POP P,T1		; restore pointer
	EXCH T1,NTIB(P1)	; Old head is now current input bfr
	EXCH T1,IMPFRI		; Old input bfr goes to NCP free list
	MOVE T2,IMPFRI		; Get copy for indexing
	STOR T1,NBQUE,(T2)	; Old list is off of new head
	AOS IMPNFI		; There is now another free input bfr
	MOVE T1,NTIB(P1)	; Now think in terms of Internet buffer
	RET

; Here when current input is to be continued.  Fix to be spec. q. input.
INETIC:
;;;	SETOM NTFLS(P1)		; Flush message when it gets in
	MOVEI T2,.IISPQ		; Mark for special Queue dispatch
	MOVEM T2,NTITYP(P1)
	MOVEI T4,.IISQ2		; Return this to caller
	RET
> ;End cond on INETN
; Input body of message

IMIN3:	SKIPE NTIS32(P1)	; Want 32 bit handling?
	 JRST IMIN32		; Yes.
	CALL DOBLKI		; No, read 36 more bits
	 JRST IMIMTL		; Overflowed buffer
	RETSKP			; Mostly just wait for the end interrupt

IMIN32:	SKIPL NTIWC(P1)		; Room for more?
	 JRST IM32TL		; Nope, too long. Clear interface
	CALL BKI32B		; Read 36 bits into 32 format
	 JFCL			; Any more bits would be error.
	RETSKP			; Ok, wait for more.

IM32TL:	MNTXCT NTDATI		; Disgard the bits
IMIMTL:	MOVE T4,NTITYP(P1)	; If Internet, this can happen legally
	CAIE T4,.IIINT		; Because buffers are shorter.
	 MNTBUG(INF,IMPML2,<MSG TOO LONG>)
	XMOVEI T1,IMIN00
	MOVEM T1,NTIDSP(P1)
	SETOM NTFLS(P1)		; Flag input overflow
	RETSKP

;;; Here when message has been found to be a loser. Just throw it away
;;; until the end input interrupt comes along.

IMIN00:	MNTXCT NTDATI		; Just disgard all wds until end input
	RETSKP

;;; Routine to do a BLKI in extended address environment. We have two
;;;  words, NTINP for the 23 bit address, and NTIWC as a negative count.

DOBLKI: MNTXCT NTDATI		; Get a word
	AOS T2,NTINP(P1)	; Count the pointer
	MOVEM T1,0(T2)		; Read the bits into core
	AOSGE NTIWC(P1)		; Count up the count
	 AOS 0(P)		; Skip unless overflowed count
	RET			; And return from DOBLKI
;;; Routine called if IMIS32 is non-zero. Pack 36 bits into
;;;  two words, 32 bits in each.
;;; Two versions. BLKI32 for all but body of message, BKI32B for body.
;;; This is because body may go to last word of 1/2 page buffer, and
;;;  in that case you can't do the MOVEM of the last partial word.

BKI32B:	TDZA T4,T4		; Remember entry point
BLKI32:	SETO T4,0		; Remember entry point
	PUSH P,T4		; Save on stack
	MNTXCT NTDATI		; DATAI to T1
	MOVE T3,NTIS32(P1)	; Get unpacking state word
	AOS NTINP(P1)		; Step the data address
	AOSGE T4,NTIWC(P1)	; And the word count
	 AOS -1(P)		; Do skip return if no overflow
	TRNN T3,777777		; Is this the zero'th state?
	 JRST [	AOS NTINP(P1)	; Yes, step pointers one more
		AOS T4,NTIWC(P1)
		JRST .+1]
	IORM T4,0(P)		; Make stack negative unless overflowed.
	MOVEI T2,0		; Any pad bits should be zero
	MOVE T4,NTINP(P1)	; Now point to the data
	LSHC T1,@IMISHT(T3)	; Align input bytes with destination
	DPB T1,IMIPT1(T3)	; High order byte for n-1st word
	SKIPL 0(P)		; Don't overwrite if last word of body.
	 JRST [	SOS NTINP(P1)	; And don't make a 401 size!
		SOS NTIWC(P1)
		JRST BKI32C]	; Skip the MOVEM
	MOVEM T2,0(T4)		; Low order byte for nth word
BKI32C:	POP P,(P)		; Remove flag from stack
	AOBJN T3,BKI32A		; Step state
	MOVSI T3,-^D8		; Reinit state word
BKI32A:	MOVEM T3,NTIS32(P1)	; Save state
	RET			; Return

;;; 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(T4),31
		XX=XX-4>
;;; Here when end msg recd from imp

IMPIND::MOVEI T1,I.GEB!I.IOF	; We got the end bit, turn input off
	MNTXCT NTCONO		; ...
	AOS NTINP(P1)		; Incremnt pointer to 1 past last word read
	MNTCALL NTIDUN		; Do Input done stuff
	RETSKP			; Done successfully
;;; Routine to start msg going out. Called  at PI
;;;  level, and at main level if no output in progress

IMOSRT:	PIOFF 
	SKIPN NTOB(P1)		; ANY OUTPUT IN PROGRESS?
	 JRST IMPXO1		; NO
	PION			; YES, TURN PI BACK ON
	RET			; AND RETURN

IMPXO1:	SETOM NTOB(P1)		; MARK OUTPUT IN PROGRESS
	PION			; NOW IT'S OK TO TURN PI BACK ON
	SKIPLE NTNOP(P1)	; Any nop's to send?
	 JRST IOUNOP		; Yes, go send them
	CALL NCPUNQ		; Get next buffer to go out
	 JRST [	SKIPLE T2,HSTGDM(P1)
		  JRST IOUHGD	; Send the host going down msg
		MOVEI T1,I.STO	; No turn off PI req
		MNTXCT NTCONO	; ...
		SETZM NTOB(P1)
		RET]
	MOVEM T1,NTOB(P1)
	MOVMS HSTGDM(P1)	; may need another host going down message
	SETZRO NBQUE,(T1)	; Remove from any queue
;;;	SETZRO IHNET,(T1)	; And network number
;;; Now decide on packing via message type
	LOAD T2,IHHST,(T1)	;Check host and link for NCP range
	LOAD T3,IHLNK,(T1)
IFN MLCN,<
	MOVEI T4,(T3)		;Get link
	LSH T4,-1
	CAMN T4,MLCHLF		;PTIP link?
	 JRST [	MOVEI T3,.IIMLC	;Yes. pack in 36 bit mode
		JRST IMPIOD]
>
IFN INETN,<
	CAIN T3,INTLNK		; Internet?
	 JRST [MOVEI T3,.IIINT	; Internet.  Set packing mode
		JRST IMPIOD]
>
	CAIGE T2,FKHOST		;Special to-imp group?
	CAILE T3,LLINK		;Or link out of range?
	JRST [	MOVEI T3,.IISPQ	;Yes, special queue formatting.
		JRST IMPIOD]
	LOAD T2,HHSIZ,(T1)	;NCP will have set up packing mode
	CAIE T2,^D36		;Is it 36 bit mode?
	SKIPA T3,[.IINC2]	;No, it is 8 or 32.
	MOVEI T3,.IINC6		;Select 36 bit mode
IMPIOD:	MOVEM T1,NTOUP(P1)
	MOVNI T1,<.NBLD2+1>	; Send up thru first fill wd in 36-bit
	MOVEM T1,NTOWC(P1)	; Here's the count
	XMOVEI T1,IMOLDR	; Where to go in out-done int level
	MOVEM T1,NTODSP(P1)	; Setup dispatch
	MOVEM T3,NTOTYP(P1)	; Here's the dispatch type
	SETZM NTOS32(P1)	; Flag to send in 36 bit mode
	MOVE T1,TODCLK		; Get time now
	ADDI T1,^D60*^D1000	; One minute timeout
	MOVEM T1,NTTOUT(P1)	; Set it
	CALL DOBLKO		; Send first word (always 36-bit)
	 JFCL
	RET
;;; Pi service for output

IMOLDR:	SKIPL NTOWC(P1)	; All done?
	 JRST IMOLD1		; Yes, send some padding
IMO36B:	CALL DOBLKO		; Send another word
	 JFCL
	RETSKP

IMOLD1:	MOVE T1,NTOB(P1)	; Point to buffer
	XMOVEI T2,.NBHHL-1-1(T1) ; Get address of buffer, resend a word
				; as padding
	MOVE T4,NTOTYP(P1)	; Get the packing procedure
	MOVEM T2,NTOUP(P1)	; Now send these words
	HLRE T2,IO1WCT(T4)	; And select a word count for output
	MOVEM T2,NTOWC(P1)	; This is the count
	HRRZ T2,IO1WCT(T4)	; See if should switch to 32 bit mode
	HRLS T2
	SKIPE T2		; Skip if staying in 36 bit mode
	HRRI T2,^D8(T2)		; In 32 bits, make AOBJN counter
	MOVEM T2,NTOS32(P1)	; Set packing state word
	XMOVEI T2,IMOLD3	; Here on next interrupt
	MOVEM T2,NTODSP(P1)
	JRST IMO362		; Send the first one, 36 or 32 bits

IMOLD3:	SKIPGE NTOWC(P1)	; Send all the second group?
	 JRST IMO362		; No, send some more.
	MOVE T1,NTOB(P1)	; Point to data buffer
	MOVE T4,NTOTYP(P1)	; Get packing procedure
	LOAD T2,NBBSZ,(T1)	; Set up BLKO pointer
	MOVE T3,IOLDT(T4)	; How many sent already?
	SUBI T2,(T3)		; Allow for sent words in count
	MOVNM T2,NTOWC(P1)	; Count is negative for BLKO
	MOVSI T3,-^D8		; May need to set packing state
	CAIN T4,.IINC2		; If NCP 32 bit message,
	MOVEM T3,NTOS32(P1)	; Switch to 32 bit mode here.
	XMOVEI T3,IMOBDY	; For next interrupts, go here.
	MOVEM T3,NTODSP(P1)	; Set in core dispatch
	JRST IMO362		; Now go send a word in 36 or 32 mode.

IO1WCT:	XWD -2,0		; TYPE NCP36
	XWD -2,0		; TYPE NCP32
	XWD -2,0		; TYPE TELENET
	XWD -1,-^D8		; TYPE SPECIAL Q, start 32 bit mode
	XWD -1,-^D8		; TYPE INTERNET, start 32 bit mode
	XWD -2,0		; TYPE MLC
	XWD -1,-^D8		; TYPE SQ2, start 32 bit mode

;Table of number of words already sent, at IMOLD3 time

IOLDT:	EXP .NBDW0		;Type NCP36
	EXP .NBDW0		;Type NCP32
	EXP .NBDW0		;Type TELENET
	EXP .NBHHL		;Type SPECIAL QUEUES
	EXP .NBHHL		;Type Internet
	EXP .NBDW0		;Type MLC
	EXP .NBHHL		;Type SQ2
; Output body of message, in 32 or 36 bit mode

IMOBDY:	SKIPL NTOWC(P1)		; Data left?
	 JRST IMODN1		; No
	TDZA T1,T1		; Flag this is last part of buffer
IMO362:	 SETO T1,0		; Flag this isn't last part of buffer
	SKIPN T3,NTOS32(P1)	; In 32 bit mode?
	JRST IMO36B		; No, send 36 bits.
IMO32:	AOS T4,NTOUP(P1)	; Get pointer to data, step it
	MOVE T3,NTOS32(P1)	; Get state word
	AOSL NTOWC(P1)		; Count the count. Check end.
	JRST [	MOVEI T2,0	;Pad bits are zero, if from BDY
		JUMPE T1,IMO32B	; If from BDY, don't load T2
		JRST .+1]	; If in leaders, load T2
	MOVE T2,1(T4)		; Get n+1th word
IMO32B:	MOVE T1,0(T4)		; Get nth word
	LSH T1,-4		; Align high-order byte
	LSHC T1,@IMOSHT(T3)	; Shift bytes into output word
	MNTXCT NTDATO		; DATAO T1
	AOBJN T3,IMO32A		; Step state
	AOS NTOUP(P1)		; Extra inc of bfr each cycle
	AOS NTOWC(P1)		; The count, too.
	MOVSI T3,-^D8		; Reinit state word
IMO32A:	MOVEM T3,NTOS32(P1)	; Save state word
	RETSKP

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

IMOSHT:	XX==4
	REPEAT ^D8,<Z XX
		XX=XX+4>
IMODN1:	MNTCALL NTODUN		; Do output done stuff

IMOIR2:	MOVEI T1,I.EOM		; Tell IMP thats all
	MNTXCT NTCONO		; Send it out
	XMOVEI T1,IMODN2	; Setup dispatch for final step
	MOVEM T1,NTODSP(P1)
	RETSKP

IMODN2:	SETZM NTTOUT(P1)	; Clear output hung timeout
	SETZM NTOB(P1)
	CALL IMOSRT		; Start next msg if any
	RETSKP
;
; Here to make a HOST GOING DOWN message
; HSTGDM is 0 if not going down, +N if needs to be sent
; -N if doesn't

IOUHGD:	MOVEI T3,0		; Set up 2 words of data
	LSHC T2,-^D8		; From down-time and reason
	DMOVEM T2,IIMBUF+1	; In a scratch buffer
	MOVE T1,H2IHGD		; Proto Host-Going-Down msg
	MOVEM T1,IIMBUF		; To the scratch buffer
	XMOVEI T2,IIMBUF-1	; Point to this msg
	MOVNS HSTGDM(P1)	; down message sent
	JRST IOUIRG		; And go send it.

IOUNOP:	SOS NTNOP(P1)		; Decrement count of NOP's to send
	XMOVEI T2,H2INOP-1	 ; Prototype of a NOP/padding request
IOUIRG:	MOVEM T2,NTOUP(P1)	; Set for further BLKO's
	MOVNI T2,3		; And the count for each
	MOVEM T2,NTOWC(P1)
	MOVE T1,TODCLK		; Get time
	ADDI T1,^D1000		; Timeout in one second
	MOVEM T1,NTTOUT(P1)	; get timeout
	XMOVEI T1,IMOIRG
	MOVEM T1,NTODSP(P1)
	CALL DOBLKO		; Now send first word of irreg msg
	 JFCL
	RET			; and done

IMOIRG:	SKIPL NTOWC(P1)		; Any more words?
	 JRST IMOIR2		; No. Send end-of msg
	JRST IMO36B		; Same as during leader. Send a word.

;;; Prototype Host-to-Imp NOP msg, with padding control.
H2INOP:	BYTE (4)0,ITY%LL (16)0 (8).IHNOP (4)0
	EXP 0
	BYTE (4)0,STY%NP	; Desired padding amount

;;; Prototype Host-to-IMP Host-going-down message.

H2IHGD:	BYTE (4)0,ITY%LL (16)0 (8).IHHGD (4)0	;1-36
;	BYTE (4)0 (24)0 (3)DAY-OF-WK (5)HOUR	;37-72
;	BYTE (4)5MIN, REASON
;;; DOBLKO routine to do BLKO-ish stuff in multi-section environment

DOBLKO:	PUSH P,T1		; Save an AC
	AOS T1,NTOUP(P1)	; Step the address pointer
	MOVE T1,0(T1)		; Get word
	MNTXCT NTDATO		; Send it out
	AOSGE NTOWC(P1)		; Count the word count
	AOS -1(P)		; Skip return if not overflowed
	POP P,T1		; Restore the AC
	RET

;STATUS CHECK SUBROUTINES

IMPSCK:	SKIPN NTRDY(P1)		; Hardware on?
	 RET			; no, error
	PUSH P,T1		; Save T1
	MOVEI T1,I.PWR		; Power on?
	MNTXCT NTCNSO		; ?
	 SETOM NTERRF(P1)	; No
	MOVEI T1,<I.DWN+I.NRD+I.ERR> ;OK, IMP DOWN NOW OR RECENTLY?
	MNTXCT NTCNSZ		; ?
	 SETOM NTERRF(P1)	; FLAG ERROR
	SKIPL NTERRF(P1)	; DID ERROR HAPPEN NOW OR BEFORE?
	 JRST [	POP P,T1
		RETSKP]			;NO, IT'S UP. SKIP RETURN
	MOVNI T1,2
	MOVEM T1,NTFLS(P1)
	MOVEI T1,10
	MOVEM T1,NTNOP(P1)	; Send some nops
	MOVEI T1,I.CLR		; Clear error flop
	MNTXCT NTCONO		; ...
	CALL MNTWAK		; Wake up hardware fork
	CALL IMOSRT		; Start NOP's going
	POP P,T1
	RET

;;; HERE FROM DOWN-SEQUENCE PROCESSING IN MAINTENANCE TO COMPLETELY
;;; SHUT OFF THE HARDWARE DEVICE

IMPKIL:	MOVEI T1,I.STO!I.IOF!I.OOF!I.NRL
	MNTXCT NTCONO		;STOP OUTPUT, TURN OFF INPUT AND
				; OUTPUT SECTIONS, DROP READY LINE.
	RET

;;; CALL HERE FROM IMPIN0 (ONLY FROM MAINTENANCE) AT INITIALIZATION OF
;;; BACKGROUND FORK - NOT ON EVERY RECYCLE OF READY LINE.

IMPINI:	XMOVEI T1,IMIN00		;RESET DISPATCHES
	MOVEM T1,NTIDSP(P1)	;INPUT PI DISPATCH TO DISCARD DATA
	XMOVEI T1,IMODN2	;OUTPUT PI DISPATCH TO START NEW MSG
	MOVEM T1,NTODSP(P1)
	RET
;;; CALL HERE FROM MAINTENANCE, PROCESS LEVEL, WHEN IMP IS WANTED UP
;;; BUT NET IS CURRENTLY DOWN.

IMPRSS:	SETZM NTTOUT(P1)	; Clear timout counter
	MOVEI T1,I.PWR		; Power on?
	MNTXCT NTCNSO		; ?
	 RET
	MOVEI T1,I.NRD
	MNTXCT NTCNSZ		; OK, IMP DOWN NOW OR RECENTLY?
	 RET			; No, stop here
	MOVEI T1,I.CLR		; Clear 
	MNTXCT NTCONO
	SETZM NTERRF(P1)	; And notices of errors
	SETZM HSTGDM(P1)	; and down messages
	HRRES NETON(P1)		; Forget any intervening down requests
	MOVNI T1,2
	MOVEM T1,NTFLS(P1)	; Init flush count
	MOVEI T1,10
	MOVEM T1,NTNOP(P1)
	MOVEI T1,^D1000
	DISMS			; Allow time for ready line to settle
	AOS NTSTCH(P1)		; Cause change in state to be noted
	CALL MNTWAK		; Wake up hardware fork
	GTAD			; Yes
	MOVEM 1,NTXUPT(P1)	; Save time whe it came up
	MNTXCT NTDATI		; Helps to clear interface
	MOVEI T1,I.STO+I.GEB
	MNTXCT NTCONO
	MOVEI T1,I.OON
	MNTXCT NTCONO
	SETOM NTRDY(P1)
	SETOM NTORDY(P1)	; Allow output
	CALL IMOSRT		; Start output if needed
	CALLRET IMISRT		; And input

	TNXEND
	END			; OF IMPPHY