Google
 

Trailing-Edge - PDP-10 Archives - tops20v41_monsrc - monitor-sources/kdpsrv.mac
There are 20 other files named kdpsrv.mac in the archive. Click here to see a list.
;<4-1-FIELD-IMAGE.MONITOR>KDPSRV.MAC.2, 25-Feb-82 20:26:08, EDIT BY DONAHUE
;UPDATE COPYRIGHT DATE
;<4.MONITOR>KDPSRV.MAC.23,  3-Jan-80 08:09:16, EDIT BY R.ACE
;UPDATE COPYRIGHT DATE
;<4.MONITOR>KDPSRV.MAC.22,  2-Jan-80 10:05:34, EDIT BY PLATUKIS
;Restructure routine RCVAK3 to continue processing message, even if
; bad ACK field.  Corrected NAK reason codes. Restructured PGDSTS
; word of station table.
;<4.MONITOR>KDPSRV.MAC.21,  8-Oct-79 10:55:34, EDIT BY GRANT
;TCO 4.2515 - Fix DUP maintenance mode bit definitions for loopback
;<4.MONITOR>KDPSRV.MAC.20, 27-Sep-79 12:15:39, EDIT BY WEISBACH
;TCO 4.2491 - Fix range checking of DUP number on BOOT JSYS calls in routines
;BTGPRT and BTIDC0.
;<OSMAN.MON>KDPSRV.MAC.1, 10-Sep-79 15:40:25, EDIT BY OSMAN
;TCO 4.2412 - Move definition of BUGHLTs, BUGCHKs, and BUGINFs to BUGS.MAC
;<4.MONITOR>KDPSRV.MAC.18, 24-Aug-79 13:50:43, EDIT BY WEISBACH
; Return updated byte pointer to user on a DDCMP read.
;<4.MONITOR>KDPSRV.MAC.17,  9-Jul-79 10:01:48, EDIT BY R.ACE
; Redefine PGLSTS word in line table and correct polling algorithm
; for stations in start state.
;<4.MONITOR>KDPSRV.MAC.16, 13-May-79 12:41:21, EDIT BY WEISBACH
; Make the read and write DDCMP message functions understand byte pointers.
; Correct problem of ^Cing a program during the execution of the BTINI
; function resulting in a RESBAZ bugchk.
;<4.MONITOR>KDPSRV.MAC.15,  1-Apr-79 10:43:03, EDIT BY WEISBACH
; Ensure that resident buffer released when an error is encountered while
; sending a DDCMP message (@BTSDD).
;<4.MONITOR>KDPSRV.MAC.13, 25-Mar-79 12:45:29, EDIT BY WEISBACH
; Fix potential races caused by RELRES's turning the PI system back on.
;<4.MONITOR>KDPSRV.MAC.12, 21-MAR-79 edit by MBEGUN
;Don't try to send implicit acks for multidrop lines at XMTAK3
;<4.MONITOR>KDPSRV.MAC.11, 18-Mar-79 11:48:00, EDIT BY WEISBACH
; Read MOP and DDCMP return one word too many to user.
;<4.MONITOR>KDPSRV.MAC.10, 11-Mar-79 13:51:43, EDIT BY WEISBACH
; Make timeout work properly for MOP protocol
; Also remove outdated table of contents
;<4.monitor>kdpsrv.mac.9 6-mar-79 edit mbegun - remove race at
;kdpchk  - turn pioff for scheduler tests
;<4.MONITOR>KDPSRV.MAC.8,  4-Mar-79 17:45:42, Edit by KONEN
;UPDATE COPYRIGHT FOR RELEASE 4
;<4.MONITOR>KDPSRV.MAC.7,  4-Mar-79 11:12:12, EDIT BY WEISBACH
; Correct password code for ENTER-MOP-MODE messages and set line server
; to default to NSP at protocol termination
;<4.MONITOR>KDPSRV.MAC.6, 13-Feb-79 16:54:03, EDIT BY WEISBACH
; Zero PGLINQ after reading a MOP message.
;<4.MONITOR>KDPSRV.MAC.5, 29-Jan-79 08:33:10, EDIT BY WEISBACH
;<4.MONITOR>KDPSRV.MAC.4,  4-Jan-79 11:00:15, EDIT BY WEISBACH
; Add support for MOP protocol
;<4.MONITOR>KDPSRV.MAC.29, 5-DEC-78 12:00:00, Edit by MBEGUN
; Restructure data base and add support for full duplex multi-drop stations

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1976,1977,1978,1979,1980,1981,1982 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.

	SEARCH PROLOG,PROKS
	TTITLE KDPSRV

	EXTN <DEDMCB>
	EXTN <KDPLIM,KDPNLN,KDPN,KDPPAG,KDPTIM,KDPXPC>
	EXTN <KMCACS,KMCINQ,KMCIPL,KDPFLG,KMCPAG,KMCQLN>
	EXTN <NODINI,NSPQ,NSPSPC>

;THIS MODULE PROVIDES SUPPORT FOR DUP11'S WITH A KMC11 FOR NSPSRV ON A 2020

;THINGS TO CHECK
; 1) ERROR COUNTERS - SYSERR
; 2) COLLAPSE PAGES
	IFNDEF FTRACE,<FTRACE==-1>	;NONZERO TO TURN ON TRACE
; P1 FOR LINE SPECIFIC CODE WILL CONTAIN THE ADDRESS OF THE LINES PAGE
; P4 FOR STATION SPECIFIC CODE WILL CONTAIN THE ADDRESS OF STATION TABLE

; MESSAGE BLOCKS LIVE IN BLOCKS OF RESIDENT SPACE
	BLKSIZ=<MBKFRE*10>+1		;SIZE OF BLOCKS IN RESIDENT SPACE
;FORMAT OF EACH MESSAGE BLOCK
	MBKLNK==0	;LH = ADR OF NEXT MESSAGE BLOCK
			; RH = ADR OF MESSAGE
	MBKCOD==1	;DRIVER UNIQUE CODE
	MBKLEN==2	;LH IS DRIVER INT LOC
			; RH IS LENGTH OF MESSAGE IN BYTES
	;FOLLOWING VALID ONLY FOR LAST MSG BLOCK IN BLOCK
	MBKFRE==3	;LH = NUMBER OF FREE WORDS LEFT IN BLOCK
			; RH = ADR OF BLOCK

;KMCINQ - QUEUE OF MESSAGE TO BE GIVEN TO THE KMC11
; FIRST WORD IS USED TO PUT THINGS INTO THE QUEUE
; 2ND WORD IS USED TO TAKE ENTRIES FROM QUEUE
; QUEUE ENTRIES ARE 2 WORDS LONG
; RH OF 1ST WORD GOES TO BSEL2
; LH OF 2ND WORD GOES TO BSEL4
; RH OF 2ND WORD GOES TO BSEL6
	SUBTTL	DEFINITIONS -- STG

DEFINE X (A,B)<
A==Z
Z=Z+B
>
Z=0

;PAGE OFFSETS FOR LINE PAGE
X PGUBAD,1	;LH IS UNIBUS ADR OF PAGE
X PGSTAL,1	;STATION LIST -- DDCMP LINE TABLE
    DEFSTR (DDSTT,PGSTAL(P1),35,18) ;TOP OF STATION LIST
    DEFSTR (DDSTB,PGSTAL(P1),17,18) ;BOTTOM OF STATION LIST
X PGCSTA,1	;POINTER TO CURRENT STATION
X PGLINQ,1	;INPUT MESSAGE QUEUE
X PGLOUQ,1	;OUTPUT MESSAGE STATION QUEUE
X PGLSTS,1	;LINE STATUS
  DUPDSR==1B13	;DATA SET READY
  DEFSTR(LINSR,PGLSTS(P1),35,2)  ;SERVER
	NSPL==0	;NSP LINE
	DCPL==1	;DCP LINE
  DEFSTR(DDINP,PGLSTS(P1),33,5)  ;# OF QUEUED INPUT BUFFERS
  DEFSTR(DDINT,PGLSTS(P1),28,1)	;PSI FLAG
  DEFSTR(DDSSP,PGLSTS(P1),17,4)	;STARTUP PRESET COUNTER
X PGLINT,1	;FORK #,,INTERRUPT CHANNEL ASSIGNMENT
X PGKDPN,1	;DUP11 LINE NUMBER
X PGUBAM,1	;ADR OF UBA MAPPING REGISTER FOR PAGE
X PGZTIM,1	;TIME LAST ZEROED COUNTERS, TICKED ONCE PER SECOND
X PGSTCC,1	;STARTUP COUNTER
    DDSTIC==2	;INITIAL STARTUP COUNT
X PGCOCN,10	;CONTROL OUT COUNTS AS FOLLOWS
		;10 = INVALID DDCMP HEADER
		;12 = BAD CRC
		;14 = BUFFER NOT AVAILABLE
		;16 = DATASET READY TRANSITION
		;20 = NXM
		;22 = TRANSMIT UNDERRUN
		;24 = RECEIVER UNDERRUN
		;26 = KILL COMPLETE
X PGCOXX,1	;OTHER
X PGXMCN,1	;COUNT OF DDCMP MESSAGES TRANSMITTED
X PGNRNK,10	;COUNT OF RECEIVED NAKS
		; FIRST IS MISC NAKS, NEXT 7 ARE BY NAK CODE
		;catch all
		;1= header bcc error
		;2= data bcc error
		;3= rep response
		;8= buffer unavailable
		;9= receiver overrun
		;16= message too long
		;17= header format error
X PGRMCN,1	;COUNT OF DDCMP MESSAGES RECEIVED
X PGNXNK,10	;COUNT OF TRNASMITTED NAKS
		; FIRST IS MISC NAKS, NEXT 7 ARE BY NAK CODE (see PGNRNK)
X PGKMCR,2	;KMC11 REGISTERS WHEN KMC11 LAST HALTED
		; BSEL0,,BSEL2
		; BSEL4,,BSEL6
X PGLACK,2	;LAST DDCMP ACK,NAK OR DATA MESSAGE TO UPDATE ACKED MESSAGE
X PGXBD1,4	;1ST TRANSMIT BUFFER DESCRIPTOR LIST
X PGXMS1,140	;1ST XMIT MESSAGE BUFFER
X PGXBD2,4	;2ND TRANSMIT BUFFER DESCRIPTOR LIST
X PGXMS2,140	;2ND XMIT MESSAGE BUFFER
X PGRBD1,4	;1ST RECEIVE BUFFER DESCRIPTOR LIST
X PGRMS1,140	;1ST INPUT MESSAGE BUFFER
X PGRBD2,4	;2ND RECEIVE BUFFER DESCRIPTOR LIST
X PGRMS2,140	;2ND INPUT MESSAGE BUFFER
; DATA BASE NEEDED FOR MOP PROTOCOL
X PGMSTS,1			;MOP STATUS WORD
	DEFSTR	(MOPSTS,PGMSTS(P1),35,2) ;MOP STATUS
		MPPRI==1	;PRIMARY MODE
		MPSEC==2	;SECONDARY MODE
		MPERR=400000	;ERROR IN MOP MSG EXCHANGE(MUST BE SIGN BIT)
	DEFSTR	(MOPTMR,PGMSTS(P1),17,12) ;MOP TIMEOUT COUNTER
		PRITMO==^D15	;SPECIAL TIMEOUT WHEN STILL IN PRIMARY MODE
		MOPTMO==3	;TIME-OUT
X PGMPSW,1			;PASSWORD TO ENTER MOP MODE
X PGMXHD,3			;MOP XMIT MESSAGE HEADER
	DEFSTR	(MPBPTR,PGMXHD(P1),35,36) ;POINTER TO THE MOP MSG XMITTED
	DEFSTR	(MPBADR,PGMXHD(P1),35,18) ;ADDRESS OF THE MOP BUFFER
	DEFSTR	(MPPOST,PGMXHD+1(P1),35,18)	;MOP POST ADDRESS
	DEFSTR	(MPFLGS,PGMXHD+1(P1),17,18) ;FLAGS
		MPSHRT=1	;MOP BUFFER IS A SHORT BUFFER
		MPXSEC=2	;SENDING SECONDARY BOOTSTRAP
	DEFSTR	(MPBLEN,PGMXHD+2(P1),35,18)	;LENGTH OF MOP BUFFER
X PGMXBF,2			;BUFFER FOR SHORT MOP MESSAGES
X PGMRHD,2			;MOP RECEIVE MESSAGE HEADER
	DEFSTR	(MPRPTR,PGMRHD(P1),35,36) ;POINTER TO THE MOP MSG RECVD
	DEFSTR	(MPRADR,PGMRHD(P1),35,18) ;ADDRESS OF THE MOP BUFFER
	DEFSTR	(MPRLEN,PGMRHD+1(P1),35,18) ;LENGTH OF THE BUFFER (BYTES)
IFN FTRACE,<
X PGTPTR,1	;TRACE PUTTER
	Z=<Z+1>&<-2>	;TRACE MUST BEGIN ON AN EVEN WORD
X PGTRCE,1	;TRACE
>;IFN FTRACE
;OFFSETS FOR STATION TABLE ENTRIES

Z=0
X PGDLNK,1	;LINE TABLE THREAD
    DEFSTR (DDLNK,PGDLNK(P4),35,18)  ; FORWARD THREAD
    DEFSTR (DDBAK,PGDLNK(P4),17,18)	; BACK LINK
X PGDADR,1	;STATION ID
    DEFSTR (DDDRP,PGDADR(P4),17,8)   ;DROP# OF STATION
    DEFSTR (DDLMX,PGDADR(P4),35,8)   ;LAST MESSAGE XMTED PREVIOUS INTERVAL
X PGDSTS,1	;DDCMP STATUS
    DEFSTR (DDSTA,PGDSTS(P4),35,3) ;DDCMP STATE
	STADWN==0		;KMC11 NOT RUNNING
	STAMAI==1		;MAINT MODE
	STASTR==2		;SENDING STARTS
	STASTK==3		;SENT STACK
	STARUN==4		;RUNNING
    DEFSTR (DDTIM,PGDSTS(P4),32,7)	;TIMER
	TIMSTR==5	;5 SECONDS BETWEEN STARTS
	TIMREP==3	;3 SECONDS BETWEEN REPS
	REPMAX==10	;MAXIMUM NUMBER OF REPS BEFORE DECLARING LINE DOWN
    DEFSTR (DDXAK,PGDSTS(P4),17,1)	;want to send an ack
    DEFSTR (DDNCD,PGDSTS(P4),15,6)	;nak code to send
    DEFSTR (DDXRP,PGDSTS(P4),9,1)	;WANT TO SEND A REP
    DEFSTR (DCHNG,PGDSTS(P4),8,3)	;INFORMATION FOR NSPSRV (SWAPPABLE)
    DEFSTR (DDSEL,PGDSTS(P4),5,1)	;SEND SELECT
    DEFSTR (DDACI,PGDSTS(P4),4,1)	;ACTIVE/IDLE INDICATOR FOR SLAVES
    DEFSTR (DDSFC,PGDSTS(P4),3,4)	;STARTUP FAILURE COUNTER
	MAXSTR==10	;MAXIMUM STARTUPS TO TRY BEFORE GIVING UP
	DDUP==1		;DDCMP NOW UP
	DDOWN==2	;DDCMP DOWN
	DDPT==3		;INDICATOR FOR XMIT COMPLETE
	DDSF==4		;INDICATOR FOR STARTUP FAILURE
X PGDOMQ,1	;DDCMP OUTPUT MESSAGE QUEUE
		; LH IS ADR OF FIRST OUTPUT MESSAGE BLOCK
		; RH IS ADR OF LAST OUTPUT MESSAGE BLOCK
X PGOLST,1	;THREAD FOR OUTPUT MESSAGE STATION QUEUE
		;LH IS BACK POINTER ,, RH IS FORWARD POINTER
X PGDLMX,1	;RH IS ADR OF MESSAGE BLOCK FOR LAST MESSAGE TRANSMITTED
X PGFCOR,1	;RH & LH ARE ADR OF CORE BLOCKS FOR MESSAGE QUEUE
		;LH ASSIGNED FIRST, RH USED FIRST
X PGDMNM,1	;DDCMP MESSAGE NUMBERS
    DEFSTR (DDRMN,PGDMNM(P4),7,8)	;RECEIVED MESSAGE NUMBER (HIGHEST)
    DEFSTR (DDHXM,PGDMNM(P4),15,8)	;HIGHEST MESSAGE NUMBER TRANSMITTED
    DEFSTR (DDHMA,PGDMNM(P4),23,8)	;HIGHEST MESSAGE NUMBER ACKED
    DEFSTR (DDREPC,PGDMNM(P4),35,12)	;COUNTER FOR REPS
X PGDPRI,1	;STATION POLLING PRIORITY
    DEFSTR (DDSPC,PGDPRI(P4),35,18)	;STATION PRIORITY COUNTER
    DEFSTR (DDIPC,PGDPRI(P4),17,18)	;INITIAL PRIORITY COUNT
X PGLTIM,1	;TIME LAST ZEROED COUNTERS
X PGLCOC,10	;CONTROL OUT COUNTS - AS FOR DUP
X PGLRNK,10	;COUNT OF RECEIVED NAKS
X PGLXNK,10	;COUNT OF XMIT NAKS
DDLSZ==Z
	PURGE	Z,X
	SUBTTL	DEFINITIONS -- KMC11

;KMC11 REGISTER BIT DEFINITIONS

BSEL0==0
BSEL1==1
	KMCRUN==100000	;RUN FLOP
	KMCMCL==040000	;MASTER CLEAR
	KMCCWR==020000	;CRAM WRITE
	KMCSLU==010000	;STEP LINE UNIT
	KMCLUL==004000	;LINE UNIT LOOP
	KMCRMO==002000	;ROM OUTPUT
	KMCRMI==001000	;ROM INPUT
	KMCSUP==000400	;STEP u-PROCESSOR
	KMCRQI==000200	;REQUEST INPUT
	KMCIEO==000020	;INTERRUPT ENABLE OUTPUT
	KMCIEI==000001	;INTERRUPT ENABLE INPUT
BSEL2==2
BSEL3==3		;CONTAINS LINE NUMBER
	KMCRDO==000200	;READY FOR OUTPUT
	KMCRDI==000020	;READY FOR INPUT
	KMCIOT==000004	;SET FOR RECEIVE CLEARED FOR TRANSMIT
	KMCTYP==000003	;COMMAND TYPE
	 BASEIN==000003	;BASE IN
	 CNTLIN==000001	;CONTROL IN
	 BFADIN==000000	;BUFFER ADDRESS IN
	 CNTLOU==000001	;CONTROL OUT
	 BFADOU==000000	;BUFFER ADDRESS OUT
BSEL4==4
BSEL5==5
			;BUFFER DESCRIPTOR LIST ADDRESS (BUFFER ADR IN & OUT & CONTROL OUT)
BSEL6==6
BSEL7==7
		;140000	;ADR BITS 17 & 16 (BUFFER ADR IN & OUT & CONTROL OUT)
	BFREOM==010000	;END OF MESSAGE (BUFFER ADR OUT)
	BFRENB==020000	;BUFFER ENABLE (BUFFER ADR IN)
	BFRKIL==010000	;BUFFER KILL (BUFFER ADR IN)
	CSRMSK==017770	;MASK FOR DUP11 CSR ADR (BASE IN)
	CDDCMP==100000	;FLAG THIS A DDCMP LINE (CONTROL IN)
	CHALFD==020000	;FLAG THIS IS HALF DUPLEX (CONTROL IN)
		;010000	;ENABLE SECONDARY STATION (CONTROL IN)
		;001000	;CRC INHIBIT (CONTROL IN)
	CENABL==000400	;FLAG TO ENABLE LINE (CONTROL IN)
	COUERR==000377	;ERROR CODE (CONTROL OUT)

CRAMSZ==2000	;SIZE OF KMC11 CRAM
DRAMSZ==2000	;SIZE OF KMC11 DRAM
;BUFFER DESCRIPTOR LISTS ARE STRINGS OF 3 16 BIT WORDS
; 1ST WORD 16 BITS OF BUFFER ADDRESS
; 2ND WORD 16 BIT BYTE COUNT
; 3RD WORD
	BDLLDS==100000	;LAST DESCRIPTOR
	BDLRSY==010000	;RESYNC TRANSMITTER
	;==006000	;BUFFER ADDRESS 17 & 16
	BDLEOM==001000	;END OF MESSAGE
	BDLSOM==000400	;START OF MESSAGE

;MESSAGES TO THE KMC11
; BASEIN:	BSEL2/	<LINE #>*400+3
;		BSEL6/	<DUP11 ADR>&017770
; CONTROL IN:	BSEL2/	<LINE #*400+1
;		BSEL6/	FLAGS
; BF AD IN:	BSEL2/	<LINE NU>*400+0+<4 IF INPUT>
;		BSEL4/	BUFFER DESCRIPTOR LIST ADR
;		BSEL6/	FLAGS
; BF AD OUT:	BSEL2/	<LINE NU>*400+0+<4 IF RECEIVE>
;		BSEL4/	BUFFER DESCRIPTOR LIST ADR
;		BSEL6/	FLAGS
; CONTROL OUT:	BSEL2/	<LINE NU>*400+1+<4 IF RECEIVE>
;		BSEL4/	BUFFER DESCRIPTOR LIST ADR
;		BSEL6/	ERROR CODE
;INPUT DATA BUFFERS FOR VT62
;QUEUE HEADER IS PGLINQ(P1)
;LH IS TAIL
;RH IS HEAD
;EACH DATA BUFFER CONTAINS A TWO WORD HEADER
	MSHDR==2
	INDLNK==0	;LH SYSTEM LINE #, RH LINK TO NEXT BUFFER OR ZERO
	INDCNT==1	;BYTE COUNT OF DATA
	MAXIN==^D40	;MAXIMUM NUMBER OF INPUT BUFFERS KDPSRV WILL MAINTAIN
	SUBTTL	DEFINITIONS -- DUP11

	DUPADR==3760300	;ADDRESS OF 1ST DUP11
	DUPUBN==3	;UNIBUS ADAPTER NUMBER FOR DUP11

	DPRCSR==0	;RECEIVER CSR
		DPDTR==000002	;DATA TERMINAL READY
	DPRDBF==2	;(RO)RECEIVER DATA BUFFER
	DPPCSR==2	;(WO)PARAMETER CONTROL AND STATUS REGISTER
	DPTCSR==4	;TRANSMIT CONTROL AND STATUS REGISTER
		DPCBLP==004000	;EXTERNAL MAINTENCE MODE (CABLE LOOPBACK)
		DPCNLP==010000	;SYSTEMS TEST MODE (CONTROLLER LOOPBACK)
		DPMAIN==014000	;MAINTAINENCE MODE BITS
	DPTDBF==6	;TRANSMIT DATA BUFFER
	SUBTTL	DEFINITIONS -- DDCMP

	SYN==226
	IDLE==SYN	;NO SPECIAL IDLE CHARACTER
	ENQ==005	;1ST CHAR IN UNNUMBERED MESSAGES
	DLE==220	;1ST CHAR IN BOOTSTRAP MESSAGES
	SOH==201	;1ST CHAR IN NUMBERED MESSAGES

	MAXOUT==10	;MAXIMUM NUMBER OF DATA MESSAGES TO PUT IN PIPE

;NUMBERED MESSAGES
;	SOH CC1 CC2 QSYNC SELECT R N A0 BCC1 DATA BCC2
;	CC1&CC2 ARE TOTAL LENGTH OF DATA(BCC1 THRU BCC2 EXCLUSIVE)
;	CC1 IS LOWORDER 8BITS OF LENGTH
;	CC2 IS HIGH ORDER 6 BITS OF LENGTH
	QSYNC==100	;QSYNC BIT
	SELECT==200	;SELECT BIT
;	R IS # OF LAST GOOD MESSAGE RECEIVED
;	N IS THIS MESSAGE NUMBER
	A0==1	;A0 IS THE DESTINATION STATION ADR(ALWAYS 1)
;	BCC1 IS THE 16 BIT CRC ON SOH THROUGH A0 INCLUSIVE
;	DATA IS PASSED TO NCL
;	BCC2 IS THE 16BIT CRC OF DATA
;UNNUMBERED MESSAGES
	FILL==000		;FILL CHARACTER

;ACK:	ENQ	ACK	QSYNC SELECT FILL	MSG#	FILL	A0	BCC1	BCC2
	ACK==001
;	MSG# IS LAST GOOD MSG RECEIVED

;NAK:	ENQ	NAK	QSYNC SELECT RNAK	MSG#	FILL	A0	BCC1	BCC2
	NAK==002		;NETIVE ACKNOWLEDGE
;	RNAK IS NAK REASON AS FOLLOWS
	NCDHBC==1	;HEADER BCC ERROR
	NCDBCC==2	;DATA BCC ERROR
	NCDREP==3	;REP RESPONSE
	NCDBTU==^D8	;BUFFER TEMPORARILY UNAVAILABLE		(rjp)
	NCDROV==^D9	;RECEIVER OVERRUN			(rjp)
	NCDMTL==^D16	;MESSAGE TOO LONG			(rjp)
	NCDHFE==^D17	;HEADER FORMAT ERROR			(rjp)
;	MSG# IS LAST GOOD MSG RECEIVED

;REP:	ENQ	REP	QSYNC SELECT FILL	FILL	N	A0	BCC1	BCC2
	REP==003		;REPLY TYPE
;	N IS THE LAST MESSAGE# SENT

;RESET:	ENQ	RESET	QSYNC SELECT FILL	FILL	N	A0	BCC1	BCC2
;	RESET==4		;DC72 WILL NOT SEND THIS TYPE;WILL RESPOND WITH START

;RESAK:	ENQ	RESAK	QSYNC SELECT FILL	R	FILL	A0	BCC1	BCC2
	RESAK==5		;DC72 WILL NOT SEND THIS TYPE;WILL RESPOND WITH START

;START:	ENQ	STRT	QSYNC SELECT FILL	FILL	N	A0	BCC1	BCC2
	STRT==006		;START TYPE
;	N IS NEXT NUMBERED MESSAGE TO BE SENT

;STACK:	ENQ	STACK	QSYNC SELECT FILL	R	N	A0	BCC1	BCC2
	STACK==007		;START ACKNOWLEDGE
;	R IS NEXT EXPECTED MESSAGE # FOR RECPTION
;	N IS NEXT MESSAGE # FOR TRANSMISSION


MSNMAX==377		;MAXIMUM MESSAGE NUMBER

;WHEN A MSG IS RECEIVED CORRECTLY AN ACK IS SENT BACK;
; AN ACK IMPLIES ACK OF ALL LOWER NUMBERED MESSAGES
;WHEN A MSG IS RECEIVED INCORRECTLY A NAK MSG IS SENT BACK;
; A NAK IMPLIES ACK OF ALL LOWER NUMBERED MSGS.
	SUBTTL	DEFINITIONS -- MOP

	.MPLDT==0		;MEMORY LOAD WITH TRANSFER ADDRESS
	.MPRQD==4		;REQUEST MEMORY DUMP
	.MPMOP==6		;ENTER MOP MODE
	.MPRQP==8		;PROGRAM REQUEST
	.MPDMC==^D12		;DMC DEV CODE
	MPSPRQ==0		;PROGRAM REQUEST FOR SECONDARY BOOTSTRAP
	.BTPSW==1		;PASSWORD IN BOOT BLOCK
	SUBTTL	PROTOTYPE MESSAGES

	RESCD
ACKMSG:	BYTE(18)ENQ+400*ACK,FILL+400*FILL,FILL+400*A0,FILL+400*FILL

NAKMSG:	BYTE(18)ENQ+400*NAK,FILL+400*FILL,FILL+400*A0,FILL+400*FILL

REPMSG:	BYTE(18)ENQ+400*REP,FILL+400*FILL,FILL+400*A0,FILL+400*FILL

STRTMS:	BYTE(18)ENQ+400*STRT,QSYNC+SELECT+FILL+400*FILL,FILL+400*A0,FILL+400*FILL

STCKMS:	BYTE(18)ENQ+400*STACK,QSYNC+SELECT+FILL+400*FILL,FILL+400*A0,FILL+400*FILL
	;table of legal NAK reason codes. used to offset into line table
	;PGNRNK and PGNXNK...

naktbl:	0		
	1			;offset NAK reason 1
	2			;offset NAK reason 2
	3			;offset NAK reason 3
	0
	0
	0
	0
	4			;offset NAK reason 8
	5			;offset NAK reason 9
	0
	0
	0
	0
	0
	0
	6			;offset NAK reason 16
	7			;offset NAK reason 17
	SUBTTL	DUP11 COMIOP CODE FOR KMC11

	SWAPCD
COMIOP:	BYTE(18)61220,61222,63234,63233,63224,16400,123600,60400
	BYTE(18)103412,100405,440,63225,74524,63220,60365,101427
	BYTE(18)63064,2777,4457,70000,76613,62614,114707,4003
	BYTE(18)10375,16451,16517,2777,123620,103163,10375,4003
	BYTE(18)140620,120440,103501,120440,103434,400,61222,2511
	BYTE(18)100434,2511,10377,50220,101434,55223,55224,55225
	BYTE(18)55226,55227,55222,10376,57221,43220,2517,767
	BYTE(18)60360,101474,406,62400,40361,101477,100500,2777

	BYTE(18)10375,123400,103105,2441,100434,2443,700,61231
	BYTE(18)100434,120400,103514,100451,3020,61202,102121,2524
	BYTE(18)100434,2531,600,100507,120440,103127,100533,120400
	BYTE(18)102121,120440,103034,2451,457,63225,123072,60532
	BYTE(18)70005,57233,47234,70213,14414,75231,56226,56227
	BYTE(18)70213,120440,102555,102272,100764,102254,400,61222
	BYTE(18)123620,116353,100434,521,61271,400,63232,73233
	BYTE(18)67234,100607,123620,116353,63072,420,60372,101436

	BYTE(18)4457,63220,60532,70000,57233,47234,70213,54620
	BYTE(18)43220,101572,62560,101172,76620,56224,56225,415
	BYTE(18)61230,43231,120600,102222,23421,60731,106750,23100
	BYTE(18)23417,103637,1400,106441,60617,107576,100572,402
	BYTE(18)62004,415,61230,120600,102243,23007,23030,60617
	BYTE(18)100632,110740,110470,110545,137140,14770,62660,56226
	BYTE(18)123160,740,62700,42227,401,62223,556,63236
	BYTE(18)405,114643,120560,102277,17400,76560,100702,136500

	BYTE(18)136500,422,76222,134560,2401,103707,2400,42223
	BYTE(18)421,61230,120600,102312,123560,103724,122142,2600
	BYTE(18)102722,2400,422,100732,2626,42222,2444,103331
	BYTE(18)2440,600,62263,736,63236,114645,120560,1400
	BYTE(18)103343,400,100746,410,63220,42700,76222,2633
	BYTE(18)120560,103753,2605,400,76223,136540,454,70013
	BYTE(18)2400,556,63236,114645,22144,22165,415,61230
	BYTE(18)120440,1400,102775,432,100776,411,60413,63226

	BYTE(18)120600,106000,23017,120560,113002,417,70006,43625
	BYTE(18)1400,107033,2440,70206,136500,136520,123160,700
	BYTE(18)60660,1400,1400,1400,1400,62620,60525,103556
	BYTE(18)434,63235,114450,500,62705,43225,403,70006
	BYTE(18)104414,60601,1400,107045,100634,404,62004,415
	BYTE(18)61230,120600,106051,20400,107456,100634,22106,22127
	BYTE(18)123220,501,63260,414,61311,454,70013,43620
	BYTE(18)113105,451,70013,40620,1400,107107,106100,100634

	BYTE(18)23140,770,62266,773,63677,62222,110520,20400
	BYTE(18)107116,20420,102634,3020,110515,103634,43620,106164
	BYTE(18)463,63236,445,114632,43621,76461,106152,62224
	BYTE(18)56225,414,63260,61070,400,62223,120600,106136
	BYTE(18)36002,22420,23140,402,62006,421,61230,120600
	BYTE(18)106147,100634,105155,14400,104561,560,63236,114743
	BYTE(18)400,76223,42222,104542,113040,20420,107573,62560
	BYTE(18)60611,1400,107120,401,62223,104542,404,70013

	BYTE(18)64214,57231,60610,117550,144620,2611,572,77236
	BYTE(18)104620,2615,572,77236,104620,106627,653,77236
	BYTE(18)74611,113545,43220,76607,43227,62600,160616,2605
	BYTE(18)435,63235,110635,2656,404,70013,456,62671
	BYTE(18)43231,601,60367,105653,405,60367,111545,620
	BYTE(18)60367,105653,114567,401,62711,110545,2663,407
	BYTE(18)70013,62607,110545,2677,410,70013,477,62667
	BYTE(18)63271,404,70013,700,60667,62711,110545,2701

	BYTE(18)110545,2703,110545,2717,74611,1400,106710,110545
	BYTE(18)40367,111545,404,70013,420,62711,110545,2721
	BYTE(18)100572,2727,107324,114555,60611,102172,104756,437
	BYTE(18)63236,114627,105334,104737,60611,103172,110545,405
	BYTE(18)70013,2743,100572,107356,114557,120600,106345,100572
	BYTE(18)3002,42722,706,63236,416,110722,2633,60611
	BYTE(18)107364,400,63235,110635,417,70013,57224,57223
	BYTE(18)57222,57221,57220,76604,76603,76602,76601,76600

	BYTE(18)60531,114762,120440,1400,112414,454,70013,43220
	BYTE(18)423,62700,601,110420,417,63235,114571,605
	BYTE(18)63222,426,63223,426,63235,110663,417,70006
	BYTE(18)2602,120560,1400,107005,100556,100572,114567,104732
	BYTE(18)60611,1400,113051,400,62222,2003,757,62660
	BYTE(18)104542,626,76222,401,76223,43221,62561,105142
	BYTE(18)451,70013,110446,105124,20420,113533,60600,112522
	BYTE(18)473,63235,110731,774,23140,62266,451,70013

	BYTE(18)43620,61620,107115,112127,100634,112541,2400,451
	BYTE(18)70013,40620,1400,107107,3000,410,60671,62302
	BYTE(18)621,104546,402,62223,652,63236,114645,454
	BYTE(18)70013,2423,100634,422,63223,473,63235,601
	BYTE(18)110734,62560,404,62223,104542,430,70013,43622
	BYTE(18)1400,113160,435,63235,571,63236,414,110722
	BYTE(18)563,63236,114631,111204,43622,112167,110577,572
	BYTE(18)63236,114615,60562,62226,14621,42222,61230,545

	BYTE(18)63235,120600,112201,110714,40620,112213,14000,14776
	BYTE(18)76662,62607,110627,616,63236,114615,74607,62223
	BYTE(18)42222,60602,112225,421,110626,621,61230,426
	BYTE(18)70013,745,63236,401,114741,426,70013,43622
	BYTE(18)112242,110654,645,63236,114615,74562,62226,42222
	BYTE(18)621,61230,120600,112252,420,63223,604,63222
	BYTE(18)411,60413,63226,70206,56226,56227,123220,501
	BYTE(18)63260,43221,414,60661,61311,406,70006,57220

	BYTE(18)43221,413,70006,56342,54441,76223,651,77236
	BYTE(18)40620,1400,117245,110740,400,63223,604,63222
	BYTE(18)411,110736,63223,3400,63221,63224,601,63222
	BYTE(18)110746,400,63223,600,63222,432,60413,63226
	BYTE(18)416,63236,70206,57220,57221,43224,10376,4003
	BYTE(18)50220,76612,76600,76601,62603,60602,112361,2400
	BYTE(18)110763,400,63223,77124,63124,63124,63524,76703
	BYTE(18)76602,10376,57220,40620,115410,60360,115412,10376

	BYTE(18)767,60360,115406,406,62400,174616,2517,174616
	BYTE(18)62600,110777,70200,3200,42700,174616,417,70006
	BYTE(18)64214,43620,117430,70206,432,63236,406,114741
	BYTE(18)60520,117435,737,62660,170615,677,62660,403
	BYTE(18)70006,57220,57221,57222,70206,76600,76601,62602
	BYTE(18)70206,56224,56225,401,63220,55310,120600,116056
	BYTE(18)37004,37025,465,63236,114721,37002,23023,36400
	BYTE(18)36420,76604,76605,476,63236,114721,23020,36420

	BYTE(18)76602,76603,76604,76605,43222,540,60662,62700
	BYTE(18)411,60413,60366,115543,74564,116126,62224,60605
	BYTE(18)62225,414,63260,61070,120600,116124,36420,16407
	BYTE(18)60617,1400,116542,2400,404,63717,62222,542
	BYTE(18)63236,114672,170615,754,43220,63260,62460,170615
	BYTE(18)117157,60530,117561,406,114562,410,114562,412
	BYTE(18)114562,424,63223,436,63235,605,110657,435
	BYTE(18)63235,64214,757,63677,62222,600,63236,114672

	BYTE(18)420,63717,62222,621,61230,54620,2633,1400
	BYTE(18)117212,2605,120600,116212,170615,56226,56227,123220
	BYTE(18)501,63260,414,63221,40661,61311,170616,407
	BYTE(18)114632,424,70013,43221,76561,115640,14000,170616
	BYTE(18)43221,76561,170616,3221,114647,402,3021,23140
	BYTE(18)62006,23160,62107,115255,114662,123220,404,63000
	BYTE(18)515,61271,123200,555,60660,60701,61230,120600
	BYTE(18)116267,160616,402,70013,56226,56227,123220,501

	BYTE(18)63260,414,61311,621,61230,114733,100572,460
	BYTE(18)73013,60013,115315,64214,100414,67114,400,73233
	BYTE(18)100414,402,23100,62004,23120,62105,123200,115336
	BYTE(18)416,63260,61070,120600,116333,174616,404,63000
	BYTE(18)114730,63220,56400,43220,76500,115347,164616,43220
	BYTE(18)404,62400,164616,500,61271,761,63236,420
	BYTE(18)110722,100434,117567,100572,0,0,0,0
	BYTE(18)0,0,0,0,0,0,0,0

COMIOE:	;END OF COMIOP CODE
	SUBTTL	BOOT JSYS -- PERFORM BOOTSTRAP FUNCTIONS FOR KMC11

;BOOT JSYS IS USED TO LOAD AND DUMP KMC11
; CALL	MOVEI AC1,<FUNCTION CODE>
;	MOVEI AC2,<ADR OF ARGUMENT BLOCK>
;	BOOT
;
;REG STRING IS BSEL0,BSEL2,BSEL4,BSEL6,MISC+NPR,INDATA,OUTDATA,INBA,OUTBA


; TABLE OF DISPATCH ADDRESSES

BOOTTB:	EXP BTINI		;(0) = ENTER MOP MODE
	EXP BTLSB		;(1) = LOAD SECONDARY BOOTSTRAP
	EXP BTSMP		;(2) = SEND MOP MESSAGE
	EXP BTERR		;(3) = DUMP MEMORY
	EXP BTIPR		;(4) = INITIALIZE PROTOCOL
	EXP BTTPR		;(5) = TERMINATE PROTOCOL
	EXP BTSTS		;(6) = RETURN STATUS
	EXP RSKP		;(7) = WAIT FOR TO-10 DOORBELL
	EXP BTRMP		;(10) = READ MOP MESSAGE
	EXP BTKML		;(11) = LOAD KMC11
	EXP BTKMD		;(12) = DUMP KMC11
	EXP BTRLC		;(13) = RETURN LINE COUNTS
	EXP BTCLI		;(14) = CONVERT LINE-ID TO PORT NUMBER
	EXP BTCPN		;(15) = CONVERT PORT NUMBER TO LINE-ID
	EXP BTSTA		;(16) = SET TERMINAL STATE (ACTIVE/IDLE)
	EXP BTSSP		;(17) = SET START PRIORITY
	EXP BTSTP		;(20) = SET TERMINAL PRIORITY
	EXP BTSDD		;(21) = SEND DDCMP MESSAGE
	EXP BTRDD		;(22) = RECEIVE DDCMP
	EXP BTCHN		;(23) = ASSIGN SOFTWARE INTERRUPT CHANNEL
	EXP BTSLS		;(24) = SET LINE SERVICE TYPE
	BOOTLN==.-BOOTTB
;HERE ON A BOOT JSYS
.BOOT::	MCENT			;MONITOR CONTEXT ENTRY
	MOVE T1,CAPENB		;GET ENABLED CAPABILITIES
	TXNN T1,SC%WHL!SC%OPR!SC%MNT ;WHEEL, OPERATOR, OR MAINTENANCE ?
	ITERR (CAPX2)		;WHEEL, OPERATOR, or MAINTENANCE capability required
	UMOVE Q3,1		;GET FUNCTION CODE FROM USER
	CAIL Q3,.BTROM		;CHECK RANGE OF GIVEN
	CAIL Q3,.BTROM+BOOTLN	; FUNCTION CODE
BTERR:	ITERR (ARGX02)		;Invalid function

; VALIDATE KMC11 ADDRESS

	UMOVE Q1,2		;GET ADDRESS OF USER'S ARGUMENT BLOCK

; DISPATCH TO PROCESSING ROUTINE BASED ON REQUESTED FUNCTION

	CALL @BOOTTB-.BTROM(Q3)	;DISPATCH TO APPROPRIATE ROUTINE
	 ITERR ()		;FAILED, RETURN ERROR TO USER
	MRETNG			;SUCCESS, RETURN TO USER

;HERE TO GET KMC11 ADDRESS FROM ARGUMENT BLOCK
BTGKMA:	UMOVE Q2,.BTKMC(Q1)	;GET KMC11 ADDRESS FROM USER
	TRNE Q2,7		;BE SURE FIRST KMC11 ADR
	JRST BTDVX5		;GIVE USER ERROR
	MOVE T1,Q2		;COPY KMC11 ADR FOR UBGOOD
	LDB T2,[POINT 9,T1,22]	;GET UBA NUMBER & 5 BITS OF UNIBUS ADR
	CAIE T2,77		;1,,76#### ?
	CAIN T2,177		;OR 3,,76#### ?
	CALL UBGOOD		;SEE IF THAT ADDRESS EXISTS
BTDVX5:	ITERR (DEVX5)		;No such device
	RET

;HERE TO GET A PORT NUMBER ARGUMENT
; RETURN:	P1/ LINES PAGE
;		T4/ DUP11 HDW ADR
BTGPRT:	UMOVE T1,.BTPRT(Q1)	;GET PORT NUMBER FROM ARGUMENT BLOCK
	HRRZ T4,T1		;COPY DUP#
	CAML T4,KDPNLN		;IS ARGUMENT IN RANGE ?
	ITERR (ARGX19)		;Invalid unit number
	LSH T4,3		; *10
	ADD T4,[DUPADR]		;MAKES THIS DUP11'S ADR
	HRR P1,T1		;GET DUP #
	HRR P1,KDPPAG(P1)	;GET ADR OF LINES PAGE
	LOAD P4,DDSTT		;GET TOP OF STATION LIST
	JUMPE P4,[ HRR P4,PGCSTA(P1)  ;POINT TO POINT?
	           RET ]	;ALL SET
	HLRZS T1		;GET DROP FROM USER
	SKIPN T1		;DID USER GIVE A DROP#
	RET			;NO, USE THIS ONE
	LOAD T3,DDSTB		;REMEMBER FOR END OF SEARCH
BTGPR1: LOAD T2,DDDRP		;GET THIS DROP #
	CAMN T2,T1		;IS THIS THE ONE
	RET			;GOT IT
	CAMN P4,T3		;END OF LIST??
	ITERR (ARGX19)		;INVALID DROP
	LOAD P4,DDLNK		;GET NEXT LINE TABLE
	JRST BTGPR1		;LOOP THROUGH LINE TABLES
SUBTTL	BOOT JSYS --MOP -- INITIALIZE A NEIGHBORING COMPUTER

BTINI:
	CALL BTGPRT		; GET THE DUP HDW ADDR (T4) & LINE PAGE (P1)
	CALL BTIMOP		; PUT LINE IN MAINTENANCE MODE
; may want to do this first when successful, i.e. answer is back
	 JFCL			; THERE IS NO ERROR RETURN
	MOVE	Q2,PGMPSW(P1)	; GET THE BOOT PASSWORD
	MOVEI	T1,MPPRI	;WE ARE NO IN PRIMARY MODE
	STOR	T1,MOPSTS	;STORE IN MOP STATUS WORD
	HRRI	T1,PGMXBF(P1)	; THIS WILL BE A SHORT MESSAGE
	MOVEI	T2,MPSHRT	; REMEMBER THIS
	STOR	T2,MPFLGS	; FOR LATER
	HRLI	T1,(<POINT 8,0,17>)	; MAKE A BYTE POINTER
	PUSH	P,T1		; SAVE IT FOR BELOW
	MOVEM	Q2,(T1)		;PUT PASSWORD INTO MESSAGE
	MOVEM	Q2,1(T1)	;NEED IT FOUR TIMES
	MOVEI	T2,.MPMOP	; ENTER MOP MODE CODE
	DPB	T2,T1		; PUT INTO MESSAGE
	MOVEI	T3,5		; LENGTH OF MESSAGE
	POP	P,T2		; GET BACK POINTER TO MESSAGE BUFFER
	MOVE T1,PGKDPN(P1)	;SET LINE #
	MOVEI	F,0		;NO SPECIAL POST ROUTINE
	CALL XMTMOP		; go transmitt the MOP msg
	RET			;DIDN'T MAKE IT???
	MOVEI	T1,MPRTST	;DISMISS UNTIL A MESSAGE RETURNED FROM SATELLITE
	HRL	T1,P1		;SO SCHEDULER TEST KNOWS WHERE TO LOOK
	MDISMS			;DISMISS UNTIL ANSWER COMES FROM SATELITE
	MOVE	T1,PGMSTS(P1)	;GET THE MOP STATUS WORD
	TLNE	T1,MPERR	;ERROR?
	RET			;YES


;RESUME HERE WHENT THE SATELLITE HASE RESPONDED TO THE
; ENTER-MOP-MODE MESSAGE

	MOVE	T3,PGMRHD(P1)	;GET THE RECEIVED BUFFER BYTE PTR
	ILDB	T1,T3			
	CAIE	T1,.MPRQP	; PROGRAM REQUEST?
	 JRST	[CALL RELMOP	;RELEASE BUFFER
		 RET	]	;RETURN BAD
	ILDB	T1,T3		; DEVTYPE FIELD
	CAIE	T1,.MPDMC	; ON A DMC11?
	 JRST	[CALL RELMOP	;RELEASE BUFFER
		 RET	]	;RETURN BAD
	ILDB	T1,T3		; SKIP MOP VERSION FIELD
	LOAD	T1,MPRLEN	; GET RECEIVED MSG LENGTH
	CAIG	T1,3		; ANY MORE?
	JRST	BTEMOK		; NO, ALL OKAY
	ILDB	T1,T3		; GET PGM TYPE FIELD
	CAIE	T1,MPSPRQ	; REQUESTING SECONDARY BOOTSTRAP
	 JRST	[CALL RELMOP	;RELEASE BUFFER
		 RET	]	;RETURN BAD
BTEMOK:	CALL RELMOP		;RELEASE RECEIVE BUFFER
	MOVEI	T1,MPSEC	;WE ARE NOW IN SECONDARY MODE
	STOR	T1,MOPSTS	;STORE THIS FACT IN MOP STATUS WORD
	RETSKP			;RETURN OKAY
SUBTTL	BOOT JSYS --MOP--  LOAD SECONDARY BOOTSTRAP LOADER.

BTLSB:
	CALL	BTGPRT		;GET DUP HDW ADDR AND LINE PAGE
	LOAD	T1,DDSTA	; GET LINE STATUS
	CAIE	T1,STAMAI	; IN MAINTENANCE MODE?
	 RET			; NO, THAT'S AN ERROR
	MOVE	T1,[.RESP1,,200] ; GET BUFFER FOR MOP MESSAGE HEADER + DATA
	MOVE	T2,[RS%SE0+.RESNP] ; SET BUFFER SPACE
	CALL ASGRES		;
	 RET			; CAN'T
	MOVE	T2,[<.MPLDT>_12]	; MOP LOAD WITH TRANSFER CODE
	MOVEM	T2,(T1)		; STORE IN MESSAGE
	MOVE	P3,T1		; MESSAGE STARTING ADDRESS
	MOVEI	P3,177(P3)	; LAST WORD IN BUFFER
	MOVX	T2,6B7		; LOAD ADDRESS IS 6
	MOVEM	T2,1(T1)	; STORE IN MESSAGE
	MOVEM	T2,(P3)		; TRANSFER ADDRESS  IS ALSO 6
	MOVE	T2,[POINT 8,0,15]	; POINTER TO START OF MOP MSG.
	HRR	T2,T1			; ...
	HRRI	T1,2(T1)	;PUT  USER MSG AT 2ND WORD
	XCTU [HRL T1,.BTSEC(Q1)] ;GET ADDR OF USER DATA
	XBLTUM [BLT T1,-1(P3)]	;MOVE THE DATA
	LOAD	T1,MPFLGS	;GET MOP XMIT FLAGS
	TXO	T1,MPXSEC	;INDICATE WE ARE SENDING SECONDARY BOOTSTRAP
	TXZ	T1,MPSHRT	;NOT A SHORT MESSAGE
	STOR	T1,MPFLGS
	MOVEI	T3,772		;MESSAGE LENGTH
	CALL	SECSHF		;POSITION FOR KMC
	MOVE	T1,PGKDPN(P1)	;SET LINE #
	MOVEI	F,MOPQ		;ON RETURN QUEUE TO USER
	CALL XMTMOP		; go transmitt the MOP msg
	RET			;DIDN'T MAKE IT???
	RETSKP
SUBTTL	BOOT JSYS --MOP--  REQUEST UPLINE DUMP

BTDMP:	;NOT YET IMPLEMENTED.
 SUBTTL	BOOT JSYS --MOP--  SEND MOP MESSAGE

BTSMP:
	CALL BTGPRT		;GET PORT NUMBER(t4=dup hdw addr,p1=line page)
	LOAD	T1,DDSTA	;GET LINE STATUS
	CAIE	T1,STAMAI	;IN MAINTENANCE MODE?
	 RET			;NO, ERROR
	MOVEI	T1,0		;NOW IN LOAD MODE
	STOR	T1,MOPSTS	;SHOW SO IN MOP STATUS WORD
	UMOVE P2,.BTCNT(Q1)	;GET LENGTH OF DATA
	MOVEI T1,3(P2)		;PREPARE TO ROUND
	LSH T1,-2		;# OF WORDS
	MOVE P3,T1		;TAKE A COPY FOR LATER
	HRLI T1,.RESP1		;PRIORITY 1
	MOVE T2,[RS%SE0+.RESNP]	;GET SPACE FROM NET POOL
	CALL ASGRES
	  RET			;%% ADD ERROR CODE
	MOVE T2,T1		;COPY ADDR OF BUFFER
	HRLI T2,(<POINT 8,>)	;MAKE THE BYTE POINTER
	ADD P3,T1		;COMPUTE END OF BUFFER FOR BLT
BTSMP0:	XCTU [HRL T1,.BTLPT(Q1)] ;GET ADDR OF USER DATA
	XBLTUM [BLT T1,-1(P3)]	;MOVE THE DATA
	LOAD	T1,MPFLGS	;GET MOP XMIT FLAGS
	TXZ	T1,MPXSEC	;THIS IS NOT SECONDARY BOOTSTRAP
	TXZ	T1,MPSHRT	;NOT A SHORT MESSAGE
	STOR	T1,MPFLGS
	MOVE	T3,P2		;XMTMOP NEEDS IT THIS WAY
	CALL	SHFFLE		;POSITION FOR KMC
	MOVE T1,PGKDPN(P1)	;SET LINE #
	MOVEI	F,MOPQ		;PUT RESULTING MOP ANSWER ON USER QUEUE
	CALL XMTMOP		;go transmitt the MOP msg
	RET			;DIDN'T MAKE IT???
	RETSKP
SUBTTL	BOOT JSYS --MOP--  RECEIVE MOP MESSAGE

BTRMP:
	CALL BTGPRT		;GET PORT NUMBER
	LOAD	T1,DDSTA	;GET LINE STATUS
	CAIE	T1,STAMAI	;IN MAINTENANCE MODE?
	 RET			;NO, ERROR
BTRMP0:	SKIPGE	PGMSTS(P1)	;DID OTHER SIDE EVER ANSWER?
	 RET			;NO,ERROR
	SKIPN T1,PGMRHD(P1)	;IS QUEUE EMPTY
	JRST [MOVEI T1,MPRTST		;WAIT FOR SOME INPUT TO COME
		HRL	T1,P1		;SAVE ADDRESS
		MDISMS			;DISMISS UNTIL INPUT
		JRST	BTRMP0		;TRY AGAIN
		]
	SKIPN	PGLINQ(P1)	;IS IT FOR THE USER?
	 JRST	[CALL RELMOP	;ERROR, RELEASE BUFFER AND RETURN
		 RET	]	;ERROR CODE
	LOAD	T3,MPRLEN	;LENGTH OF RECEIVED BUFFER
	XCTU [HRRZ T2,.BTCNT(Q1)] ;GET LENGTH OF USERS BUFFER
	CAMLE T3,T2		;ENOUGH ROOM?
	 RET	 		;NO
	UMOVEM T3,.BTCNT(Q1)	;RETURN ACTUAL SIZE OF BUFFER
	ADDI T3,3		;ROUND TO WORDS
	LSH T3,-2
	XCTU [HRRZ T2,.BTMPT(Q1)] ;ADDR OF USER DATA
	ADD T3,T2		;END ADDR OF BLT
	HRRZ T1,PGMRHD(P1)	;ADDR OF DATA BUFFER
	HRL	T2,T1		;FOR THE BLT
	XBLTMU [BLT T2,-1(T3)]	;GIVE DATA TO USER
	PIOFF
	SETZM	PGMRHD(P1)	;SAY NO BUFFER ANYMORE
	SETZM	PGLINQ(P1)	;ZERO THIS TOO
	CALL RELRES		;RELEASE THE BLOCK
	PION
	RETSKP
	SUBTTL	BOOT JSYS -- SEND A DDCMP MESSAGE


;ARGUMENT BLOCK
;	.BTPRT/	DROP#,,LINE#
;	.BTMSG/ ADDR OF DATA
;	.BTLEN/ BYTE COUNT OF MESSAGE
;ERROR RETURN TAKEN IF MESSAGE QUEUE IS FULL


BTSDD:	CALL BTGPRT		;GET PORT NUMBER
	UMOVE P2,.BTLEN(Q1)	;GET LENGTH OF DATA
	MOVEI T1,3(P2)		;PREPARE TO ROUND
	LSH T1,-2		;# OF WORDS
	MOVE P3,T1		;TAKE A COPY FOR LATER
	HRLI T1,.RESP1		;PRIORITY 1
	MOVE T2,[RS%SE0+.RESNP]	;GET SPACE FROM NET POOL
	CALL ASGRES
	  RET			; ERROR
	MOVE T2,T1		;COPY ADDR OF BUFFER
	UMOVE	T3,.BTMSG(Q1)	;GET USER'S DATA POINTER
	TLNN	T3,-1		;IF LH ALL ZERO
	JRST	BTSDD1		;THE DO WORD BLTs
	HLRZ	T4,T3		;STANDARD ASCII POINTER?
	CAIN	T4,-1
	HRLI	T3,440700	;YES
	HRLI	T1,(<POINT 8,>) ;DESTINATION BYTE POINTER
	PUSH	P,P2		;WILL NEED THIS LATER
BTSDD0:	XCTBU	[ILDB T4,T3]	;GET A BYTE FROM USER
	IDPB	T4,T1		;STORE IN RESIDENT BUFFER
	SOJG	P2,BTSDD0	;REPEAT UNTIL DONE
	UMOVEM	T3,.BTMSG(Q1)	;RETURN UPDATED POINTER TO USER
	POP	P,P2		;PUT BYTE LENGTH BACK FOR BELOW
	JRST	BTSDD2
BTSDD1:	ADD P3,T1		;COMPUTE END OF BUFFER FOR BLT
	HRL	T1,T3		;USER DATA ADDRESS FOR BLT
	XBLTUM [BLT T1,-1(P3)]	;MOVE THE DATA
BTSDD2:	HRLI T2,(<POINT 8,>)	;MAKE THE BYTE POINTER
	MOVE T1,PGKDPN(P1)	;SET LINE #
	HRLI T1,DCPPST		;ADDR FOR COMPLETION
	MOVE T3,P2		;GET LENGTH OF DATA
	HRRZ F,T2		;BUFFER ADDR FOR COMPLETION POSTING
	TXO T3,1B1		;MARK THIS MESSAGE FROM DCP
	CALL DCNMSO		;QUEUE THE MESSAGE TO KMC
	 JRST	[MOVE T1,F	;GET BACK THE RESIDENT BUFFER ADDRESS
		 CALLRET RELRES]	;FREE THE BUFFER
	RETSKP			;SUCCESS
	SUBTTL	BOOT JSYS -- INITIATE PROTOCOL

BTIPR:	CALL BTIDC0		;INSURE STATION TABLE EXITS
	CALL BTGPRT		;GET PORT NUMBER
	MOVE T1,[EXP KMCADR]	;GET ADDRESS OF KMC11
	RDIO T1,(T1)		;GET STATUS FROM KMC11
	TRNN T1,KMCRUN		;IS KMC11 RUNNING ?
	RETBAD (KDPX01)		;KMC11 not running
	LOAD T1,DDSTA		;GET CURRENT LINE STATE
	UMOVE T2,.BTPRV(Q1)	;GET PROTOCOL VERSION NUMBER
	RDIO T3,DPTCSR(T4)	;GET CURRENT MAINTENANCE MODE BITS
	ANDI T3,DPMAIN		;LEAVE ONLY THE MAINTAINENCE MODE BITS
	CAIN T2,.VNDDC		;STARTING DDCMP ?
	JRST BTIDDC		;STARTING DDCMP
	CAIN T2,.VNCNL		;INITIATING CONTROLLER LOOPBACK ?
	 JRST BTICNL		;YES
	CAIN T2,.VNCBL		;INITIATING CABLE LOOPBACK ?
	 JRST BTICBL		;YES
	CAIE T2,.VNMOP		;STARTING DDCMP MAINTENANCE MODE ?
	JRST BTERR		;CAN'T DO THAT

;HERE TO INITIATE MAINTENANCE MODE ON LINE
BTIMOP:	SETZM	PGMSTS(P1)	;INITIALIZE MOP STATUS
	MOVEI	T1,DPMAIN	;DUP11 MAINTENANCE MODE BITS
	BCIO T1,DPTCSR(T4)	;CLEAR MAINTENANCE MODE
	MOVEI T1,STAMAI		;NOW AM IN MAINTENANCE MODE
	CALL DEDLIN		;DROP LINE
	RETSKP

;HERE TO INITIATE DDCMP ON LINE
BTIDDC:	JUMPN P3,BTIDC4		;MULTI-DROP??
	SETZ T2,		;NO MAINTENANCE MODE BITS
	CAIE T1,STADWN		;IS THE LINE DOWN ?
	CAIN T1,STAMAI		;OR IS LINE IN MOP MODE ?
	 JRST BTIDC4		;GO TRY TO DDCMP START IT
	JUMPN T3,BTERR		;IF HDW LOOPED BACK LOSE
	RETSKP			;ALREADY RUNNING SO WIN
BTIDC4:	MOVEI T1,DPMAIN		;DUP11 MAINTENANCE MODE BITS
	BCIO T1,DPTCSR(T4)	;CLEAR MAINTENANCE MODE
	BSIO T2,DPTCSR(T4)	;SET NEW FORM OF MAINTAINENCE MODE
	MOVEI T1,DPDTR		;WANT DATA TERMINAL READY SET
	BSIO T1,DPRCSR(T4)	;SET IT
	SETZRO DDACI		;SET POLLING STATUS ACTIVE
	MOVEI T1,STASTR		;NOW WANT TO SEND STARTS
	CALL DEDLIN		;DROP LINE
	RETSKP

;HERE TO INITIATE CONTROLLER LOOPBACK
BTICNL:	MOVEI T2,DPCNLP		;BIT FOR CONTROLLER LOOPBACK
	JRST BTILPB		;SET LOOPBACK
;HERE TO INSURE STATION TABLE EXIST FOR A POTENTIALLY NEW STATION

BTIDC0:	UMOVE T1,.BTPRT(Q1)	;GET TERMINAL ID
	HRR P1,T1		;GET LINE NUMBER
	CAML P1,KDPNLN		;IS IT IN RANGE
	ITERR(ARGX19)		;NO
	HRR P1,KDPPAG(P1)	;GET LINES PAGE
	HLRZ P3,T1		;REMEBER DROP
	SKIPN P3		;POINT TO POINT?
	RET			;ALL DONE
	HRR P4,PGCSTA(P1)	;GET A STATION TABLE
	SKIPN PGSTAL(P1)	;IS THIS FIRST STATION TO START
	JRST DDINI0		;YES, LINK A STATION TABLE AND CONTINUE
BTIDC1:	SETZM P4		;INIT STATION SCAN
BTIDC2:	CALL NXTSTA		;GET THE NEXT STATION
	JRST DDINI		;CREATE A NEW STATION
	LOAD T1,DDDRP		;GET DROP OF THIS STATION
	CAMN T1,P3		;IS THIS IT?
	RET			;YES, ALL SET
	JRST BTIDC2		;SCAN THE STATION LIST

;HERE TO INITIATE CABLE LOOPBACK
BTICBL:	MOVEI T2,DPCBLP		;BIT FOR FOR CABLE LOOPBACK
BTILPB:	CAIE T1,STADWN		;IS THE LINE DOWN ?
	CAIN T1,STAMAI		;OR IS LINE IN MOP MODE ?
	 JRST BTIDC4
	CAMN T2,T3		;ALREADY THIS WAY ?
	 RETSKP			;ALREADY LOOPED BACK
	JRST BTERR		;LOSE
	SUBTTL	BOOT JSYS -- TERMINATE PROTOCOL

BTTPR:	CALL BTGPRT		;GET PORT NUMBER
	MOVEI T1,DPMAIN		;MAINTAINENCE MODE BITS
	BCIO T1,DPTCSR(T4)	;CLEAR MAINTAINENCE MODE BITS
	MOVEI T1,DPDTR		;NO LONGER TRYING
	BCIO T1,DPRCSR(T4)	;CLEAR DAT TERMINAL READY
	MOVEI	T1,NSPL		;SET DEFAULT LINE SERVER TO NSP
	STOR	T1,LINSR
	NOINT
	MOVEI T1,STADWN		;CODE FOR STOPPED
	CALL DEDLIN		;CLEAN UP LINE
	OKINT
	CALL RELMOP		;RELEASE ANY MOP MESSAGES
	MOVE	T1,PGLINQ(P1)	;CHECK IN ANY MSGS IN Q ARE MOP MSGS
	TLNN	T1,-1		;IF SO, HAS ZERO IN LH
	SETZM	PGLINQ(P1)	;YES, ZERO Q POINTER. BUFFER ALREADY RELEASED
	RETSKP

;HERE FOR BOOT JSYS FUNCTIONS TO SET SLAVE STATION PARAMETERS

;SET POLLING STATUS ACTIVE/IDLE
BTSTA:	CALL BTGPRT		;GET STATION 
	UMOVE T1,.BTCOD(Q1)	;GET ACTIVE/IDLE INDICATOR
	STOR T1,DDACI		;SET IT
	RETSKP

;SET RELETIVE STARTUP FREQUENCY COUNTER 
;THIS WILL DETERMINE HOW MANY CYCLES THRU THE ACTIVE POLLING LIST MUST
;BE DONE BETWEEN SENDING DDCMP STARTS 
BTSSP:	CALL BTGPRT		;GET STATION
	UMOVE T1,.BTPRI(Q1)	;GET STARTUP COUNTER
	STOR T1,DDSSP		;SET IT
	RETSKP

;SET A STATIONS RELETIVE POLLING PRIORITY (1 IS HIGH)
BTSTP:	CALL BTGPRT		;GET STATION
	UMOVE T1,.BTPRI(Q1)	;GET TERMINAL PRIORITY
	STOR T1,DDSPC		;SET IT
	RETSKP

;SET INTERRUPT CHANNEL FOR INDICATION OF INPUT AVAILABLE FOR USER
BTCHN:	CALL BTGPRT		;SET UP P1
	UMOVE T1,.BTCOD(Q1)	;GET INTERRUPT CHANNEL
	AOS T1			;INDEX BY 1
	HRL T1,FORKX		;GET USER'S FORK#
	MOVEM T1,PGLINT(P1)	;SAVE IT
	RETSKP

;SET LINE TYPE OF LINE SERVICE (DDCMP OR NSP)
BTSLS:	CALL BTGPRT		;SET UP P1
	UMOVE	T1,.BTCOD(Q1)	;GET LINE SERVICE FLAG
	CAIE	T1,DCPL		;RUNNING LINE AS DDCMP ONLY?
	CAIN	T1,NSPL		;OR AS NSP?
	SKIPA
	 RET			;NOT IT RANGE
	STOR	T1,LINSR	;SET THE VALUE
	RETSKP			;RETURN OKAY
	SUBTTL	BOOT JSYS -- RETURN PROTOCOL STATUS

BTSTS:	CALL BTGPRT		;GET PORT NUMBER
	LOAD T1,DDSTA		;GET LINE STATE
	MOVEI T3,.VNMOP		;CALL IT MOP MODE
	CAIN T1,STAMAI		;MAINTENANCE MODE ?
	 JRST BTSTS9		;LINE IS IN MAINTAINENCE MODE
	SETOM T3		;ASSUME NOT RUNNING
	CAIN T1,STADWN		;IS THE LINE STOPPED
	 JRST BTSTS9		;LINE IS DOWN
	MOVEI T3,.VNDDC		;ASSUME RUNNING DDCMP
	RDIO T2,DPTCSR(T4)	;GET MAINTAINENCE MODE STATUS
	ANDI T2,DPMAIN		;STRIP EXTRA BITS
	JUMPE T2,BTSTS9		;IF NOT MAINTAINENCE THEN RUNNING
	SETOM T3		;IN CASE INTERNAL MAINTENANCE MODE
	CAIN T2,DPCNLP		;CONTROLLER LOOPBACK ?
	MOVEI T3,.VNCNL		;YES
	CAIN T2,DPCBLP		;CABLE LOOPBACK ?
	MOVEI T3,.VNCBL		;YES
BTSTS9:	UMOVEM T3,.BTPRV(Q1)	;GIVE STATE TO USER
	RETSKP
	SUBTTL 	BOOT JSYS -- RECEIVE A DDCMP MESSAGE 

;HERE TO RECEIVE A DATA MESSAGE OR A COMPLETION POSTING
;COMPLETION POSTINGS AND DATA MESSAGES RESIDE ON THE SAME QUEUE
;ARGUMENT BLOCK
;	.BTPRT/ LINE#
;	.BTMSG/ ADDR OF BUFFER TO RECEIVE MESSAGE
;	.BTLEN/ SIZE OF BUFFER (8 BIT BYTES)
;RETURNS
;	.BTPRT/ DROP#,,LINE#
;	.BTMSG/ DATA
;	.BTLEN/ ACTUAL BYTE COUNT OF DATA RETURNED
;		OR COMPLETION POSTING CODE
;		STATION CAME UP = 400000,,1
;		STATION DIED	= 400000,,2
;		XMIT COMPLETE	= 400000,,3
;ERROR RETURN IF BUFFER TOO SMALL

BTRDD:		CALL BTGPRT		;GET PORT NUMBER
	SKIPN T1,PGLINQ(P1)	;IS QUEUE EMPTY
	JRST [ XCTU [SETZM .BTLEN(Q1)]		;YES
	       RETSKP]
	SKIPG P3,INDCNT(T1)	;DATA??
	JRST [UMOVEM P3,.BTLEN(Q1) ;NO, GIVE IT TO USER
	      JRST BTRDD1 ]     ;CONTINUE
	HRRZ P3,INDCNT(T1)	;GET SIZE OF MESSAGE
	XCTU [HRRZ T2,.BTLEN(Q1)] ;GET LENGTH OF USERS BUFFER
	CAMLE P3,T2		;ENOUGH ROOM?
	ITERR() 		;NO
;%% ADD CODE
	UMOVEM P3,.BTLEN(Q1)	;RETURN ACTUAL SIZE OF BUFFER
	UMOVE	T2,.BTMSG(Q1)	;GET USER'S BUFFER POINTER
	TLNN	T2,-1		;IF LH 0 THEN USER
	JRST	BTRDD0		;WORD BLTs
	HLRZ	T4,T2		;STANDARD ASCII POINTER?
	CAIN	T4,-1
	HRLI	T2,440700	;YES
	MOVE	T4,[POINT 8,MSHDR(T1)] ;BYTE POINTER TO RECEIVE DATA
BTRDD2:	ILDB	T3,T4		;GET A BYTE FOR USER
	XCTBU	[IDPB T3,T2]	;DEPOSIT IN USER SPACE
	SOJG	P3,BTRDD2	;LOOP TIL DONE
	UMOVEM	T2,.BTMSG(Q1)	;RETURN UPDATED BYTE POINTER
	JRST	BTRDD1
BTRDD0:	ADDI P3,3		;ROUND TO WORDS
	LSH P3,-2
	ADD P3,T2		;END ADDR OF BLT
	HRLI T2,MSHDR(T1)	;ADDR OF DATA BUFFER
	XBLTMU [BLT T2,-1(P3)]	;GIVE DATA TO USER
BTRDD1:	MOVE T2,INDLNK(T1)	;GET TERMINAL #
	XCTU [HLLM T2,.BTPRT(Q1)] ;GIVE IT TO USER
	PIOFF
	LOAD T4,DDINP		;COUNT OF RCV MSGS QUEUED
	SOS T4			;GOT RID OF ONE
	STOR T4,DDINP		;SAVE IT
	HRRZS T1		;CLEAR LEFT HALF FOR RELRES
	HRRZ P2,INDLNK(T1)	;GET ADDR OF NEXT MESSAGE
	JUMPE P2,[ SETZM PGLINQ(P1) ;QUEUE EMPTY
 		   JRST BTRDD3 ]	;YES
	HRRM P2,PGLINQ(P1)	;POINT AT NEXT ENTRY
BTRDD3:	CALL RELRES		;RELEASE THE BLOCK
	PION
	RETSKP
	SUBTTL	BOOT JSYS -- LOAD KMC11

BTKML:	CALL BTGKMA		;GET KMC11 ADR FROM ARGUMENT BLOCK
	CALL BTSTOP		;STOP THE KMC11 IF RUNNING
	MOVEI T1,KMCMCL		;TO CLEAR THE KMC11
	WRIO T1,BSEL0(Q2)	;RESET THE KMC11

;QUICK CHECK OF KMC11 INTEGRITY
	MOVEI T2,200		;BIT PATERN FOR FIRST REGISTER
	MOVE T4,Q2		;COPY KMC11 ADR
BTCHK0:	WRIO T2,@T4		;WRITE THE REGISTER
	RDIO T1,@T4		;THEN READ IT BACK
	CAME T2,T1		;DO THE BITS MATCH ?
	 JRST [	TXO T1,BT%RVE	;REGISTER VERIFY ERROR
		JRST KMCILL ]	;REPORT PROBLEM THEN QUIT,Q2
	JUMPE T2,BTCHK2		;DONE WITH REGISTER
	LSH T2,-1		;NEXT MASK TO TRY
	JRST BTCHK0		;TRY NEXT MASK
BTCHK2:	MOVEI T2,100000		;BIT PATERN FOR NEXT BSEL
	ADDI T4,2		;NEXT BSEL
	TRNE T4,7		;DONE ALL REGS YET ?
	JRST BTCHK0		;LOOP BACK FOR REST OF REGISTERS

;VERIFY DRAM IS OK
	CALL MARCLR		;INITIALIZE THE MAR
	MOVEI T4,DRAMSZ		;SIZE OF THE DRAM
	MOVEI T1,041222		;MOVE <MEM><BSEL2>
	CALL KMCXCT		;READ DRAM (TO RESTORE LATER)
	RDIO Q3,BSEL2(Q2)	;GET OLD CONTENTS
BTCKD0:	MOVEI T3,200		;PATERN FOR DRAM
BTCKD1:	WRIO T3,BSEL2(Q2)	;SO WE WRITE INTO DRAM
	MOVEI T1,122440		;MOVE <BSEL2><MEM>
	CALL KMCXCT		;WRITE DRAM
	SETZ T2,
	WRIO T2,BSEL2(Q2)	;CLEAR BSEL2
	MOVEI T1,041222		;MOVE <MEM><BSEL2>
	CALL KMCXCT
	RDIO T1,BSEL2(Q2)	;READ MEMORY
	CAME T1,T3		;RIGHT DATA ?
	 JRST [	TXO T1,BT%DVE	;DRAM VERIFY ERROR
		JRST KMCILL ]	;REPORT ERROR THEN QUIT
	JUMPE T3,BTCKD2
	LSH T3,-1		;NEXT PATERN FOR DRAM
	JRST BTCKD1		;TRY THAT ONE
BTCKD2:	WRIO Q3,BSEL2(Q2)	;OLD CONTENTS OF DRAM
	MOVEI T1,136440		;MOVE <BSEL2><MEM><MARINC>
	CALL KMCXCT		;RESTORE DRAM LOCATION
	SOJG T4,BTCKD0		;ON TO NEXT DRAM LOCATION
;HERE TO LOAD THE CRAM
BTKLC0:	UMOVE T4,.BTKCC(Q1)	;GET COUNT FOR CRAM BYTES
	UMOVE Q3,.BTKCP(Q1)	;GET POINTER FOR CRAM BYTES
	JUMPLE T4,BTKLC9	;IN CASE NOT LOADING CRAM
	SETZ T3,		;FIRST ADDRESS TO LOAD
BTKLC2:	WRIO T3,BSEL4(Q2)	;PUT ADR IN REGISTER
	AOS T3			;NEXT CRAM ADR
	XCTBU [ILDB T1,Q3]	;GET NEXT BYTE FOR CRAM
	WRIO T1,BSEL6(Q2)	;PUT DATA IN RIGHT PLACE
	MOVEI T1,KMCRMO		;SELECT ROM OUTPUT
	WRIO T1,BSEL0(Q2)	;SET IT
	MOVEI T1,KMCRMO!KMCCWR	;NOW DO CRAM WRITE
	WRIO T1,BSEL0(Q2)
	SETZ T1,
	WRIO T1,BSEL0(Q2)	;CLEAR UP THE KMC11
	SOJG T4,BTKLC2		;ON FOR REST OF DATA
;NOW VERIFY CRAM LOAD
	UMOVE T4,.BTKCC(Q1)	;GET COUNT FOR CRAM BYTES
	UMOVE Q3,.BTKCP(Q1)	;GET POINTER FOR CRAM BYTES
	SETZ T3,		;FIRST ADR TO VERIFY
BTKLC4:	WRIO T3,BSEL4(Q2)	;PUT ADR IN KMC11
	MOVEI T1,KMCRMO		;FLAG FOR ROM OUTPUT
	WRIO T1,BSEL0(Q2)	;TELL IT TO READ CRAM
	RDIO T1,BSEL6(Q2)	;GET CRAM DATA
	XCTBU [ILDB T2,Q3]	;GET NEXT BYTE FROM USER
	UMOVEM Q3,.BTKCP(Q1)	;SAVE UPDATED CRAM POINTER
	CAME T1,T2		;IS CRAM RIGHT ?
	JRST [	TXO T1,BT%CVE	;FLAG FOR CRAM VERIFY ERROR
		JRST KMCILL ]	;REPORT ERROR THEN QUIT
	AOS T3			;NEXT CRAM ADR
	SOJG T4,BTKLC4		;ON TO NEXT CRAM LOCATION
BTKLC9:	UMOVEM T4,.BTKCC(Q1)	;SAVE UPDATED COUNT
;HERE TO LOAD THE DRAM
BTKLD0:	UMOVE T4,.BTKDC(Q1)	;GET COUNT FOR DRAM BYTES
	UMOVE Q3,.BTKDP(Q1)	;GET POINTER FOR DRAM BYTES
	JUMPLE T4,BTKLD9	;IN CASE NOT LOADING DRAM
	CALL MARCLR		;INITIALIZE THE MAR
	MOVEI T1,136440		;MOVE <BSEL2><MEM><MARINC>
BTKLD2:	XCTBU [ILDB T2,Q3]	;GIVE NEXT BYTE TO USER
	WRIO T2,BSEL2(Q2)	;PUT DATA IN BSEL2 FOR KMC11
	CALL KMCXCT		;HAVE KMC11 PUT DATA INTO MEM
	SOJG T4,BTKLD2		;COUNT BYTE AND THEN DO NEXT
	UMOVE T4,.BTKDC(Q1)	;GET COUNT FOR DRAM BYTES
	UMOVE Q3,.BTKDP(Q1)	;GET POINTER FOR DRAM BYTES
	CALL MARCLR		;INITIALIZE THE MAR
	MOVEI T1,055222		;MOVE <MEM><BSEL2><MARINC>
BTKLD4:	CALL KMCXCT		;GET NEXT BYTE FROM DRAM
	RDIO T2,BSEL2(Q2)	;GET DATA
	XCTBU [ILDB T3,Q3]	;GET WHAT USER WANTED
	UMOVEM Q3,.BTKDP(Q1)	;SAVE UPDATED DRAM POINTER
	CAME T2,T3		;DO THEY MATCH ?
	JRST [	TXO T2,BT%DVE	;DRAM VERIFY ERROR
		MOVE T1,T2	;PUT IN RIGHT REGISTER
		JRST KMCILL ]	;DONE WITH JSYS
	SOJG T4,BTKLD4		;LOOP BACK FOR REST OF VERIFY
BTKLD9:	UMOVEM T4,.BTKDC(Q1)	;SAVE UPDATED DRAM COUNT
;HERE TO LOAD THE REGISTERS
	MOVEI T1,KMCMCL		;DO A MASTER CLEAR AGAIN
	WRIO T1,BSEL0(Q2)
	SETZ T1,		;TO FINISH IT
	WRIO T1,BSEL0(Q2)
	WRIO T1,BSEL2(Q2)	;CLEAR BSEL2
	WRIO T1,BSEL4(Q2)	;CLEAR BSEL4
	WRIO T1,BSEL6(Q2)	;CLEAR BSEL6
	UMOVE T1,.BTKSA(Q1)	;GET STARTING ADDRESS
	SETZ T3,		;DEFAULT IS DON'T START
	JUMPGE T1,BTKLR0	;IN CASE NO STARTING ADDRESS
	TRO T3,KMCRUN		;IF GAVE A STARTING ADR ASSUME WANTS TO RUN
	LSHC T1,-^D8		;LEAVE ONLY BRANCH ADR BITS 9,8
	ANDI T1,3		;STRIP ANY EXTRANEOUS BITS
	LSH T1,^D3
	LSHC T1,^D8
	IORI T1,100400		;MAKES AN UNCONDITIONAL BRANCH
	CALL KMCXCT		;EXECUTE THE BRANCH
BTKLR0:	UMOVE T4,.BTKRC(Q1)	;GET COUNT FOR REGISTER BYTES
	UMOVE Q3,.BTKRP(Q1)	;GET POINTER FOR REGISTER BYTES
	JUMPLE T4,BTKLR9	;IN CASE NOT LOADING REGISTER
	XCTBU [ILDB T1,Q3]	;GET CONTENTS FOR BSEL0
	IOR T3,T1		;INCLUDE WITH RUN BIT
	MOVE T2,Q2		;COPY KMC11 ADR
	JRST BTKLR4
BTKLR2:	XCTBU [ILDB T1,Q3]	;GET NEXT BYTE FROM USER
	WRIO T1,(T2)		;LOAD REGISTER
BTKLR4:	ADDI T2,2		;READY FOR NEXT REGISTER
	TRNE T2,7		;LOADED ALL FOUR ?
	SOJG T4,BTKLR2		;ON TO NEXT
BTKLR9:	WRIO T3,BSEL0(Q2)	;NOW SET BSEL0 (I.E. RUN FLOP)
	UMOVEM T4,.BTKRC(Q1)	;SAVE UPDATED REGISTER COUNT
	UMOVEM Q3,.BTKRP(Q1)	;SAVE UPDATED REGISTER POINTER
	CAMN Q2,[KMCADR]	;IS THIS OUR KMC11 ?
	CALL COMINI		;INITIALIZE THE COMIOP
	RETSKP

KMCILL:	MOVEM T1,.BTKER(Q1)	;GIVE USER ERROR CODE
	BUG (KMCBRK,<<Q2,D>>)
	MOVEI T1,IOX5		;Device or data error
	RET			;REPORT PROBLEM THEN QUIT
;HERE TO INITIALIZE THE COMIOP

COMINI:	SKIPL P1,KDPLIM		;GET NUMBER OF DUP11'S
	RET			;NONE SO DONE
	MOVEI T1,KMCINQ+3	;START PUTTING ENTRIES HERE
	MOVEM T1,KMCINQ		;INITIALIZE THE PUTTER
	MOVEM T1,KMCINQ+1	;INITIALIZE THE TAKER
KMBT.8:	HRR P1,KDPPAG(P1)	;GET ADR OF LINES PAGE
	HRR P4,PGCSTA(P1)	;GET ADR OF DDCMP LINE TABLE
	SETZM PGXBD1(P1)	;FIRST TRANSMIT BUFFER IS FREE
	SETZM PGXBD2(P1)	;SECOND TRANSMIT BUFFER IS FREE
	SETZM PGRBD1(P1)	;FIRST RECEIVE BUFFER IS FREE
	SETZM PGRBD2(P1)	;SECOND RECEIVE BUFFER IS FREE
    IFN FTRACE,<
	MOVEI T1,PGTRCE(P1)	;GET ADR OF TRACE
	MOVEM T1,PGTPTR(P1)	;SAVE PUTTER
    >;IFN FTRACE
	MOVEI T1,STASTR		;TRYING TO START LINE
	STOR T1,DDSTA		;REMEMBER NEW STATE
	MOVEI T1,1		;QUICK TIMER
	STOR T1,DDTIM		;SO WE SEND A START SOON
	HRRZ T2,PGKDPN(P1)	;GET LINE NUMBER
	LSH T2,3		;MULTIPLY BY 8
	ADD T2,[DUPADR]		;MAKES THIS LINES ADR
	SETZ T1,
	WRIO T1,(T2)		;CLEAR FIRST DUP11 REGISTER
	WRIO T1,2(T2)		;CLEAR 2ND DUP11 REGISTER
	WRIO T1,4(T2)		;CLEAR 3RD DUP11 REGISTER
	WRIO T1,6(T2)		;CLEAR 4TH DUP11 REGISTER
	HRRZ T1,PGKDPN(P1)	;THIS IS LINE NUMBER
	LSH T1,^D8		;POSITION FOR LH UNIBUS BYTE
	IORI T1,BASEIN		;COMMAND TYPE
	ANDI T2,CSRMSK		;STRIP EXTRA BITS
	CALL KMCINP		;GIVE MSG TO KMC11
	HRRZ T1,PGKDPN(P1)	;LINE NUMBER
	LSH T1,^D8		;POSITION FOR LH UNIBUS BYTE
	IORI T1,CNTLIN		;WILL BE A CONTROL IN MESSAGE
	MOVEI T2,CDDCMP!CENABL	;DDCMP AND ENABLE LINE
	CALL KMCINP		;GIVE MSG TO KMC11
	MOVEI T3,PGRBD1(P1)	;FIRST RECEIVER BUFFER
	CALL RCVENB		;START THE RECEIVER ... BUFFER 1
	MOVEI T3,PGRBD2(P1)	;2ND RECEIVER BUFFER
	CALL RCVENB		;START THE RECEIVER ... BUFFER 2
	HRR P1,PGKDPN(P1)	;GET LINE NUMBER AGAIN
	AOBJN P1,KMBT.8		;LOOP BACK FOR REST OF DUP11 LINES
	RET
	SUBTTL	BOOT JSYS -- DUMP THE KMC11

BTKMD:	CALL BTGKMA		;GET KMC11 ADR FROM ARGUMENT BLOCK
	UMOVE T4,.BTKRC(Q1)	;GET COUNT FOR SAVING REGISTERS
	UMOVE Q3,.BTKRP(Q1)	;POINTER FOR STORING REGISTERS
	JUMPLE T4,BTKDR9	;IN CASE DOESN'T WANT REGISTERS
	MOVE T3,Q2		;COPY KMC11 ADR
BTKDR2:	RDIO T1,(T3)		;GET DATA FROM BSEL#
	XCTBU [IDPB T1,Q3]	;SAVE NEXT BYTE FOR USER
	SOJLE T4,BTKDR9		;IF NO ROOM DONE
	ADDI T3,2		;ON TO NEXT REGISTER
	TRNE T3,7		;DONE ALL FOUR ?
	JRST BTKDR2		;ON FOR NEXT
	CALL BTSTOP		;STOP THE KMC11 IF RUNNING
	MOVEI T1,121202		;MOVE <NPR>,<BSEL2>
	CALL BTKDR6
	MOVEI T1,021002		;MOVE <IBUS 0>,<BSEL2>
	CALL BTKDR6
	CALL BTKDR6
	CALL BTKDR6
	CALL BTKDR6
BTKDR9:	CALL BTSTOP		;STOP THE KMC11 IF RUNNING
	UMOVEM T4,.BTKRC(Q1)	;SAVE UPDATED REG COUNTER
	UMOVEM Q3,.BTKRP(Q1)	;SAVE UPDATED POINTER

;HERE TO DUMP THE KMC11 CRAM
BTKDC0:	UMOVE T4,.BTKCC(Q1)	;GET COUNTER FOR CRAM DATA
	UMOVE Q3,.BTKCP(Q1)	;GET POINTER FOR CRAM DATA
	JUMPLE T4,BTKDC9	;IN CASE DOESN'T WANT TO DUMP CRAM
	SETZ T2,		;CRAM ADR TO DUMP NEXT
BTKDC2:	WRIO T2,BSEL4(Q2)	;SELECT ADR TO DUMP
	MOVEI T1,KMCRMO		;FLAG TO DUMP CRAM
	WRIO T1,BSEL0(Q2)	;TELL IT TO DUMP CRAM
	RDIO T1,BSEL6(Q2)	;GET LOCATION FROM CRAM
	XCTBU [IDPB T1,Q3]	;PUT BYTE IN USER CORE
	SOJLE T4,BTKDC9		;COUNT BYTE
	AOJA T2,BTKDC2		;ON FOR NEXT BYTE
BTKDC9:	UMOVEM T4,.BTKCC(Q1)	;SAVE UPDATED CRAM COUNTER
	UMOVEM Q3,.BTKCP(Q1)	;SAVE UPDATED POINTER

;HERE TO DUMP THE KMC11 DRAM
BTKDD0:	UMOVE T4,.BTKDC(Q1)	;GET COUNTER FOR DRAM DATA
	UMOVE Q3,.BTKDP(Q1)	;GET POINTER FOR DRAM DATA
	JUMPLE T4,BTKDD9	;IN CASE DOESN'T WANT TO DUMP THE DRAM
	CALL MARCLR		;INITIALIZE THE MAR
BTKDD2:	MOVEI T1,055222		;MOVE <MEM>,<BSEL2>,<MARINC>
	CALL KMCXCT		;GET NEXT DRAM BYTE
	RDIO T2,BSEL2(Q2)	;GET BYTE WE JUST PUT IN BSEL2
	XCTBU [IDPB T2,Q3]	;GIVE BYTE TO USER
	SOJG T4,BTKDD2		;ON FOR NEXT BYTE
BTKDD9:	UMOVEM T4,.BTKDC(Q1)	;SAVE UPDATED DRAM COUNTER
	UMOVEM Q3,.BTKDP(Q1)	;SAVE UPDATED DRAM POINTER
	RETSKP
;HERE TO FORCE KMC11 TO GIVE US INTERNAL INFORMATION
BTKDR6:	JUMPLE T4,R		;IN CASE COUNT ALREADY EXHAUSTED
	CALL KMCXCT		;XCT FIRST INSTRUCTION
	ADDI T1,21		;NEXT SOURCE & DEST
	CALL KMCXCT		;EXECUTE NEXT INSTRUCTION
	ADDI T1,17		;INCREMENT SOURCE,DECREMENT DESTINATION
	RDIO T2,BSEL2(Q2)	;GET DATA WE JUST FORCED TO BSEL2 & BSEL3
	XCTBU [IDPB T2,Q3]	;SAVE THIS REGISTER
	SOJA T4,R		;COUNT BYTE GIVEN TO USER

;HERE TO CLEAR THE MAR
MARCLR:	MOVEI T1,004000		;CLEAR MAR LOW
	CALL KMCXCT		;DO IT
	MOVEI T1,010000		;CLEAR MAR HI
	;CALL KMCXCT		;DO IT
	;RET

;HERE TO EXECUTE A KMC11 INSTRUCTION
; CALL WITH KMC11 INSTRUCTION IN T1
KMCXCT:	MOVEI T2,KMCRMI
	WRIO T2,BSEL0(Q2)	;PUT BSEL1 IN KNOWN STATE
	WRIO T1,BSEL6(Q2)	;LOAD BSEL6 & BSEL7
	MOVEI T2,KMCRMI!KMCSUP
	WRIO T2,BSEL0(Q2)	;DO ONE INSTRUCTION
	SETZ T2,		;TO CLEAN UP BSEL0
	WRIO T2,BSEL0(Q2)	;CLEAN OUT BSEL0
	RET

;HERE TO STOP THE KMC11 AS PART OF BOOT JSYS
BTSTOP:	NOINT			;PREVENT INTERRUPTS
	CAMN Q2,[KMCADR]	;IS THIS OUR KMC11 ?
	CALL KMCHLT		;YES SO CLEAN UP FIRST
	SETZ T1,		;TO CLEAR BSEL0
	WRIO T1,BSEL0(Q2)	;STOP THE KMC11
	OKINT
	RET
	SUBTTL	BOOT JSYS -- RETURN LINE COUNTERS

BTRLC:	CALL BTGPRT		;GET PORT NUMBER
	MOVE T1,PGZTIM(P1)	;GET TIME SINCE ZEROED COUNTERS
	UMOVEM T1,.BTZTM(Q1)	;GIVE NUMBER TO USER
	HRLI T4,-11		;NUMBER OF STATUS COUNTERS
	HRRI T4,PGCOCN(P1)	;POINT TO STATUS COUNTERS
	MOVEI T3,.BTSCC(Q1)	;ADR OF USERS COUNT FOR STATUS COUNTERS
	CALL BTRLCS		;GIVE STATUS COUNTERS TO USER
	HRLI T4,-11		;NUMBER OF RECEIVE COUNTERS
	HRRI T4,PGRMCN(P1)	;POINT TO RECEIVE COUNTERS
	MOVEI T3,.BTRCC(Q1)	;ADR OF USERS COUNT FOR RECEIVER COUNTERS
	CALL BTRLCS		;GIVE RECEIVE COUNTERS TO USER
	HRLI T4,-11		;NUMBER OF TRANSMIT COUNTERS
	HRRI T4,PGXMCN(P1)	;POINT TO TRANSMIT COUNTERS
	MOVEI T3,.BTTCC(Q1)	;ADR OF USERS COUNT FOR TRANSMITTER COUNTERS
	CALL BTRLCS		;GIVE TRANSMIT COUNTERS TO USER
	SKIPG P1		;DID WE ZERO COUNTERS ?
	SETZM PGZTIM(P1)	;START ZERO TIMER AGAIN
	RETSKP

BTRLCS:	UMOVE T2,1(T3)		;GET USERS BYTE POINTER
BRLCS2:	UMOVE T1,(T3)		;GET COUNT USER GAVE
	SOJL T1,BRLCS8		;CHECK FOR USER HAS ENOUGH
	UMOVEM T1,(T3)		;GIVE USER UPDATED COUNTER
	;PIOFF
	MOVE T1,(T4)		;GET NEXT COUNTER
	SKIPG P1		;WANT TO ZERO COUNTER ?
	SETZM (T4)		;CLEAR COUNTER
	;PION
	XCTBU [IDPB T1,T2]	;GIVE COUNTER TO USER
	AOBJN T4,BRLCS2		;LOOP BACK FOR NEXT COUNTER
BRLCS8:	UMOVEM T2,1(T3)		;GIVE UPDATED POINTER TO USER
	RET
	SUBTTL	BOOT JSYS -- CONVERT LINE-ID TO PORT NUMBER

BTCLI:	CALL BTGPLX		;SETUP T4 WITH USER POINTER
				; AND T3 TO POINT TO ASCIZ \KDP_0_\
BTCLI2:	ILDB T1,T3		;GET NEXT BYTE FROM OUR STRING
	XCTBU [ILDB T2,T4]	;GET NEXT BYTE FROM USER STRING
	JUMPE T1,BTCLI5		;IF DONE WITH OUR STRING
	CAMN T1,T2		;DO TWO BYTES MATCH
	JRST BTCLI2		;ON FOR REST OF STRING
BTCLI5:	TRC T2,60		;STRIP EXTRA BITS
	CAML T2,KDPNLN		;IS NUMBER IN RANGE ?
	JRST BTERR		;LOSE
	UMOVEM T2,.BTPRT(Q1)	;RETURN PORT NUMBER TO USER
	XCTBU [ILDB T1,T4]	;GET 0 BYTE FROM USER STRINT
	RETSKP
	SUBTTL	BOOT JSYS -- CONVERT PORT NUMBER TO LINE-ID

BTCPN:	CALL BTGPLI		;GET PORT NUMBER AND POINTERS TO LINEID
	ILDB T1,T3		;GET NEXT BYTE FOR USER
	XCTBU [IDPB T1,T4]	;GIVE BYTE TO USER
	JUMPN T1,.-2		;LOOP ON FOR REST OF NAME
	HRRZ T2,PGKDPN(P1)	;GET DUP11 LINE NUMBER
	IORI T2,"0"		;MAKE IT ASCII
	XCTBU [DPB T2,T4]	;FINISH NAME
	XCTBU [IDPB T1,T4]	;MAKE IT ASCIZ
	UMOVEM T4,.BTLID(Q1)	;GIVE POINTER BACK TO USER
	RETSKP

;HERE TO GET PORT NUMBER AND POINTER TO LINEID FOR BTCLI & BTCPN
BTGPLI:	CALL BTGPRT		;GET PORT NUMBER
BTGPLX:	UMOVE T4,.BTLID(Q1)	;GET USERS POINTER
	HLRZ T1,T4		;GET PART OF BYTE POINTER
	CAIN T1,777777		;SPECIAL CASE ?
	HRLI T4,440700		;MAKE IT ASCII POINTER
	MOVE T3,[POINT 7,[ASCIZ \KDP_0_\]]
	RET
	SUBTTL	HERE TO INITIALIZE THE KMC11

KDPINI::MOVE T1,[KMCADR]	;ADR OF KMC11
	CALL UBGOOD		;CHECK TO SEE IF INSTALLED
	RET			;NO KMC11
	MOVSI P2,-KDPN		;NUMBER OF DUP11'S ASSEMBLED FOR
	MOVEI P1,KMCPAG		;POINT TO FIRST DUP11 PAGE
DPINI2:	HRRZM P1,KDPPAG(P2)	;SAVE ADR OF PAGE FOR LINE
	;HRL T1,P1		;BUILD BLT POINTER
	;HRRI T1,1(P1)		; TO CLEAR
	;SETZM (P1)		; THE LINES
	;BLT T1,777(P1)		; PAGE
	HRRZM P2,PGKDPN(P1)	;SAVE LINE NUMBER IN LINES PAGE
	HRRZ T1,P2		;COPY DUP11 NUMBER
	LSH T1,3		;OFFSET FROM BASE ADDRESS
	ADD T1,[DUPADR]		;MAKE ADDRESS OF THIS DUP11
	CALL UBGOOD		;SEE IF IT EXISTS
	JRST DPINI3		;DON'T HAVE THE DUP11
	MOVEI T1,KMCUBN		;UBA UNIT NUMBER
	MOVEI T2,1		;ONLY NEED ONE PAGE
	CALL ALUBWA		;GET A UBA ADR FOR PAGE
	BUG (DUPUBA)
	HRLZM T2,PGUBAD(P1)	;SAVE UNIBUS ADR OF PAGE
	HRLM T2,KDPPAG(P2)	;SAVE UNIBUS ADR OF PAGE
	MOVEM T1,PGUBAM(P1)	;SAVE ADR OF UBA MAPPING REGISTER
	HRRZ T2,KDPPAG(P2)	;GET ADR OF PAGE
	LSH T2,-^D9		;CONVERT TO PAGE NUMBER
	IORI T2,UNBVBT		;FLAG VALID
	WRIO T2,@T1		;SET MAPPING REGISTER
	SETZ P3,		;INDICATE POINT TO POINT
	CALL DDINI		;SET DDCMP LINE TABLE
	MOVEI	T1,50521	;BOOT PASSWORD FOR ENTER-MOP-MODE
	HRLS	T1		;IS CURRENTLY
	MOVEM	T1,PGMPSW(P1)	;CANNED
	ADDI P1,1000		;ON TO NEXT LINES PAGE
	AOBJN P2,DPINI2		;LOOP BACK FOR OTHER DUP11'S
DPINI3:	HRRZM P2,KDPNLN		;SAVE NUMBER OF DUP11'S
	HRLZS P2		;PUT NUMBER OF EXISTING DUP11'S IN LH
	MOVNM P2,KDPLIM		;REMEMBER HOW MANY THERE ARE
	SKIPL P1,KDPLIM		;GET NUMBER OF DUP11'S
	RET			;NONE

	MOVSI T1,(<XPCW>)	;INTERRUPT INSTRUCTION
	HRRI T1,KDPXPC		;XPCW ADR FOR VECTOR A (INPUT) INTERRUPTS
	SETZM 2(T1)		;CLEAR INTERRUPT FLAGS
	MOVEI T3,KMCVCA		;INTERRUPT ROUTINE FOR VECTOR A
	MOVEM T3,3(T1)		;SET INTERRUPT ROUTINE ADR
	MOVEI T2,KMCVEC/4	;OFFSET FOR VECTOR
	ADD T2,SMTEPT+KMCUBN	;GET ADR OF VECTOR TABLE
	MOVEM T1,(T2)		;SET VECTOR
	ADDI T1,4		;XPCW ADR FOR VECTOR B (OUTPUT) INTERRUPTS
	SETZM 2(T1)		;FLAGS FOR VECTOR B
	MOVEI T3,KMCVCB
	MOVEM T3,3(T1)		;INTERRUPT ROUTINE FOR VECTOR B
	MOVEM T1,1(T2)		;SET VECTOR B
	SKIPN PROFLG		;WANT TO START THE KMC11 ?
	RET			;DON'T START IT

;NOW BOOT THE KMC11
	MOVEI T2,KMCPAG+PGXMS1	;USE THIS FOR ARG BLOCK FOR BOOT JSYS
	SETZM (T2)		;CLEAR ARG BLOCK
	HRL T1,T2
	HRRI T1,1(T2)
	BLT T1,.BTKSA(T2)	;CLEAR ARGUMENT BLOCK
	MOVE T1,[KMCADR]	;ADDRESS OF KMC11 HDW
	MOVEM T1,.BTKMC(T2)	;SAVE IN ARGUMENT BLOCK
	MOVEI T1,<COMIOE-COMIOP>*2 ;SIZE OF COMIOP CODE
	MOVEM T1,.BTKCC(T2)	;SAVE IN ARGUMENT BLOCK
	MOVE T1,[POINT 18,COMIOP] ;POINTER TO COMIOP CODE
	MOVEM T1,.BTKCP(T2)	;SAVE IN ARGUMENT BLOCK
	MOVSI T1,400000		;WANT TO START AT 0
	MOVEM T1,.BTKSA(T2)	;SAVE IT IN ARGUMENT BLOCK
	MOVEI T1,.BTKML		;CODE FOR LOAD FUNCTION
	BOOT			;LOAD THE KMC11
	ERJMP [	BUG (KMCLOD)
		RET ]
	RET
	SUBTTL	HERE TO INIT DDCMP LINE TABLE 

; P3/ DROP OF STATION OR ZERO FOR POINT TO POINT
DDINI:		MOVE T1,[.RESP1,,DDLSZ]	;GET A CORE BLOCK
	MOVX T2,RS%SE0+.RESNP	;FROM THE NET POOL
	CALL ASGRES		;FOR THE LINE TABLE
	BUG (DDLCOR)
	MOVE P4,T1		;COPY ADDRESS
	MOVE T1,[.RESP1,,BLKSIZ] ;PRIORITY AND SIZE OF BLOCK TO GET
	MOVX T2,RS%SE0+.RESNP	;GET IT FROM THE NETWORK POOL
	CALL ASGRES		;GET THE BLOCK
	BUG (DUPCOR)
	CALL SAVBLK		;SAVE ADR OF BLOCK
	MOVEI T1,STASTR		;GET START STATE
	STOR T1,DDSTA		;MARK ELIGABLE FOR STARTS
	JUMPN P3,DDINI0		;POINT TO POINT?
	MOVEI T1,1		;ASSUME POINT TO POINT
	STOR T1,DDDRP
	JRST DDINI2		;ALL SET
DDINI0:	STOR P3,DDDRP		;SAVE DROP #
	MOVEI T1,1		;GET A ONE
	STOR T1,DDSPC		;INIT STATION PRIORITY COUNTER
	STOR T1,DDIPC		;INIT PRESET COUNT
	MOVEI T1,DCPL		;MARK DCP ONLY
	STOR T1,LINSR		;IN LINE PAGE
	CALL INSTA		;THREAD THIS STATION
DDINI2: HRRM P4,PGCSTA(P1)	;MARK LAST STATION AS SELECTED
	RET

;INSERT A LINE TABLE IN A STATION LIST
;INPUT 	/P1 LINE PAGE FOR DUP
;	/P4 DDCMP LINE TABLE
;LINE TABLE IS LINKED AND STATION LIST IN LINE PAGE IS UPDATED

	RESCD
INSTA:	PIOFF
	LOAD T1,DDSTB		;GET END OF STATION LIST
	JUMPE T1,INSTA1		;FIRST ENTRY??
	HRRM P4,(T1)		;UPDATE PREVIOUS LIST TAIL
	STOR P4,DDSTB		;UPDATE POINTER IN STATION LIST
	STOR T1,DDBAK		;SET BACK LINK
	LOAD T1,DDSTT		;GET TOP OF LIST
	STOR T1,DDLNK		;LINK NEW ENTRY
	HRLM P4,(T1)		;UPDATE BACK POINTER OF FORWARD LINK
	PION
	RET

;INITIALIZE NEW STATION LIST
INSTA1:	STOR P4,DDSTT		;TOP OF LIST
	STOR P4,DDSTB		;LIST TAIL
	STOR P4,DDLNK		;LINK FIRST ENTRY TO ITSELF
	STOR P4,DDBAK
	PION
	RET

;REMOVE A STATION FROM THE STATION LIST

REMSTA:	PIOFF
	LOAD T1,DDLNK		;GET FORWARD LINK
	LOAD T2,DDBAK		;GET BACK LINK
	CAMN T1,T2		;IS THIS LAST STATION ON LIST?
	CAME T1,P4
	JRST REM1		;NO, CONTINUE
	SETZM PGDLNK(P4)	;UNLINK STATION
	SETZM PGSTAL(P1)	;STATION LIST EMPTY
	PION
	RET

REM1:	HRRM T1,PGDLNK(T2)	;UPDATE BACK LINK
	HRLM T2,PGDLNK(T1)	;UPDATE FORWARD LINK
	LOAD T2,DDSTT		;GET TOP OF STATION LIST
	CAMN T2,P4		;WAS IT THIS ONE
	STOR T1,DDSTT		;YES, UPDATE IT
	LOAD T1,DDBAK		;GET BACK BACK LINK
	LOAD T2,DDSTB		;GET TAIL OF STATION LIST
	CAMN T2,P4		;WAS IT THIS ONE
	STOR T1,DDSTB		;YES UPDAT IT
	PION
	RET
;HERE TO STOP THE KMC11 uPROCESSOR
	RESCD
KMCHLT::SAVEP			;SAVE THE P'S
	MOVEI P1,KMCPAG		;DUMP INTO FIRST LINES BLOCK
	MOVE P2,[KMCADR]	;ADDRESS OF THE KMC11
	MOVE P3,[POINT 18,PGKMCR(P1)] ;POINT TO REG DUMP AREA
KMHLT2:	RDIO T1,BSEL0(P2)	;GET NEXT REGISTER FROM THE KMC11
	IDPB T1,P3		;SAVE IT
	ADDI P2,2		;POINT TO NEXT REGISTER
	TRNE P2,7		;DONE ALL REGS YET ?
	JRST KMHLT2		;LOOP BACK FOR REST
	SUBI P2,^D8		;FIX UP KMC11 ADR
	MOVEI T1,KMCRUN		;RUN FLOP
	BCIO T1,BSEL0(P2)	;STOP THE uPROCESSOR
	MOVE P1,KDPLIM		;LINE NUMBER
KMHLT3:	HRR P1,KDPPAG(P1)	;GET ADR OF LINES PAGE
	HRR P4,PGCSTA(P1)	;GET ADR OF DDCMPLINE TABLE
	MOVEI T1,STADWN		;KMC11 IS NOT RUNNING
	CALL DEDLIN		;MOURN THE DEAD LINE
	HRR P1,PGKDPN(P1)	;GET THE LINE NUMBER AGAIN
	AOBJN P1,KMHLT3		;LOOP FOR REST OF DUP11 LINES
	RET
;HERE FROM NSPSRV TO CHECK FOR THINGS TO DO
; USED TO TELL NSPSRV IF LINE COMES UP OR DOWN

	SWAPCD
KDPTSK::SETZM KDPFLG		;HAVE CHECKED NOW
	SKIPL P1,KDPLIM		;GET NUMBER OF DUP11'S
	RET			;NONE
KMCTK0:	SETZ P4,			;CLEAR STATION TABLE
	HRR P1,KDPPAG(P1)	;GET LINES PAGE
KMCTK1:	CALL NXTSTA		;GET STATION TABLE ADDR
	JRST KMCTK9		;ALL DONE WITH THIS LINE
	PIOFF			;DISABLE INTERRUPTS
	LOAD T3,DCHNG		;GET CODE FOR READY TO BEGIN
	SETZRO DCHNG		;HAVE DONE IT NOW
	JUMPE T3,KMCTK8		;CHECK FOR NOTHING
	HRRZ T1,PGKDPN(P1)	;COPY LINE NUMBER FOR NSPSRV
	CAIE T3,DDUP		;DID LINE COME UP ?
	JRST [	PION		;REENABLE INTERRUPTS
		LOAD T2,LINSR		;GET LINE SERVER
		CALL DEDDSP(T2)	;TELL SERVER IT DIED
		JRST KMCTK9 ]	;DONE
	LOAD T2,DDSTA		;GET DDCMP STATUS
	CAIE T2,STASTK		;HAVE WE SENT STACK ?
	JRST KMCTK8		;STRANGE - LOST RACE
	MOVEI T2,STARUN		;LINE IS NOW RUNNING
	STOR T2,DDSTA
	SETZRO DDSFC		;CLEAR STARTUP FAILURE COUNTER
	PION			;REENABLE INTERRUPTS
	HRRZ T1,PGKDPN(P1)	;GET LINE NUMBER AGAIN
	LOAD T2,LINSR		;GET LINE SERVER
	CALL INIDSP(T2)		;LET SERVER LINE CAME ON
KMCTK8:	PION			;REENABLE INTERRUPTS
	SKIPE PGSTAL(P1)	;POINT TO POINT
	JRST KMCTK1		;NO, LOOP THRU STATION LIST
KMCTK9:	HRR P1,PGKDPN(P1)	;GET LINE NUMBER AGAIN
	AOBJN P1,KMCTK0
	RET
DEDDSP:	JRST DEDMCB
	JRST DEDDCP		;POST STATION DOWN
INIDSP:	JRST NODINI		;TELL NSPSRV LINE CAME UP
	JRST DCPINI		;POST STATION ON LINE

;HERE TO FIND NEXT STATION IN STATION LIST
;P4/ ADDR OF PREVIOUS STATION OR ZERO TO INITIATE SCAN
;
;RETURNS
; +2 WITH ADDR OF NEXT STATION IN P4
;         OR
; +1 IF CALLED WITH P4 POINTING AT LAST STATION (END OF SCAN)
	RESCD		;CALLED FROM ALL LEVELS
NXTSTA:	SKIPN T1,PGSTAL(P1)	;POINT TO POINT
	JRST [ HRR P4,PGCSTA(P1)	;GET ADR OF DDCMP LINE TABLE
	       RETSKP ]
	HLRZS T1		;GET END OF STATION LIST
	CAMN T1,P4		;IS THIS IT
	RET			;FINISHED ALL STATIONS
	SKIPN P4		;FIRST TIME THRU
	MOVE P4,T1		;YES GET END OF LIST
	LOAD P4,DDLNK		;GET NEXT STATION
	RETSKP			;PROCESS THIS STATION
;HERE TO GIVE "INPUT" TO THE KMC11
; CALL	MOVE T1,(0,,LINE NUMBER*400+TYPE)
;	MOVE T2,(BSEL4 DATA,,BSEL6 DATA)
;	CALL KMCINP
	RESCD			;CALLED FROM ALL LEVELS
KMCINP:	TLNN T2,777		;%% DEBUG %%
	JFCL			;%%%%%%%%%%%
	MOVEI T3,KMCRQI!KMCIEI!KMCIEO	;WANT TO GIVE INPUT
	PIOFF			;DISABLE RACE WITH INT LEVEL
	BSIO T3,@[BSEL0+KMCADR]	;REQUEST INPUT
	MOVE T3,KMCINQ		;GET PUTTER FOR INPUT QUEUE
	CAIN T3,KMCINQ+KMCQLN-1	;READY TO WRAP AROUND ?
	MOVEI T3,KMCINQ+1	;WRAPPING AROUND
	ADDI T3,2		;MAKE ADR OF QUEUE ENTRY
	CAMN T3,KMCINQ+1	;WILL THIS OVERFLOW THE QUEUE ?
	BUG (KMCNTI)
	MOVEM T1,-1(T3)		;PUT 1ST HALF IN QUEUE
	MOVEM T2,(T3)		;PUT 2ND HALF IN QUEUE
	MOVEM T3,KMCINQ		;SAVE UPDATED PUTTER
	PION
	RET
	SUBTTL	KMC11 INTERRUPT LEVEL SERVICE

;HERE FOR INPUT INTERRUPTS
KMCVCA:	MOVEM 17,KMCACS+17	;SAVE REG
	MOVEI 17,KMCACS		;BUILD BLT POINTER
	BLT 17,KMCACS+16	;SAVE REST OF REGS
	MOVE P,[-40,,KMCIPL]	;SET UP STACK
	MOVE T4,[KMCADR]	;GET ADDRESS OF THE KMC11 HDW
	RDIO T2,BSEL2(T4)	;GET RDI FLAG
	MOVE T1,KMCINQ+1	;GET INPUT QUEUE TAKER
	CAME T1,KMCINQ		;ARE PUTTER AND TAKE DIFFERENT ?
	TRNN T2,KMCRDI		;AND IS IT READY ?
	BUG (KMCIII,<<T1,D>,<T2,D>>)
	CAIN T1,KMCINQ+KMCQLN-1	;TIME TO WRAP AROUND AGAIN ?
	MOVEI T1,KMCINQ+1	;YES SO POINT TO BEGINING OF QUEUE
	ADDI T1,2		;ADVANCE POINTER FOR THIS ENTRY
	MOVEM T1,KMCINQ+1	;SAVE UPDATED TAKER
	MOVEI T2,KMCRQI		;WANT TO CLEAR RQUEST INPUT FLAG
	CAMN T1,KMCINQ		;IS QUEUE EMPTY NOW ?
	BCIO T2,BSEL0(T4)	;THIS IS LAST OF DATA
	MOVE T2,(T1)		;GET 2ND WORD IN QUEUE ENTRY
	MOVE T1,-1(T1)		;GET 1ST WORD IN QUEUE ENTRY
    IFN FTRACE,<
	LDB P1,[POINT 8,T1,27]	;GET LINE NUMBER
	HRRZ P1,KDPPAG(P1)	;GET LINES PAGE
	MOVE T3,PGTPTR(P1)	;GET TRACE POINTER
	HRROM T1,(T3)		;SAVE SEL2
	MOVEM T2,1(T3)		;SAVE SEL4 & SEL6
	ADDI T3,2
	CAIN T3,1000(P1)	;TIME TO WRAP AROUND ?
	MOVEI T3,PGTRCE(P1)	;YES
	MOVEM T3,PGTPTR(P1)	;SAVE UPDATED TRACE POINTER
    >;IFN FTRACE
	WRIO T2,BSEL6(T4)	;GIVE HALF OF DATA
	MOVSS T2		;GET OTHER HALF
	WRIO T2,BSEL4(T4)	;GIVE OTHER HALF
	WRIO T1,BSEL2(T4)	;TELL KMC11 WHAT THIS IS AND LINE #
	MOVSI 17,KMCACS		;BLT POINTER TO RESTORE REGS
	BLT 17,17		;RESTORE ALL REGS
	XJEN KDPXPC		;DISMISS INTERRUPT
;HERE FOR KMC11 OUTPUT INTERRUPTS
KMCVCB:	MOVEM 17,KMCACS+17	;SAVE REG
	MOVEI 17,KMCACS		;BUILD BLT POINTER
	BLT 17,KMCACS+16	;SAVE REST OF REGS
	MOVE P,[-40,,KMCIPL]	;SET UP STACK
	MOVE P1,[KMCADR]	;ADDRESS OF THE KMC11 HARDWARE
	RDIO T1,BSEL2(P1)	;GET 1ST 1/3 OF DATA (LINE NUMBER)
	TRNN T1,KMCRDO		;IS RDYO SET ?
	JRST KMVCB9		;DONE WITH INTERRUPT
	RDIO T2,BSEL4(P1)	;GET 2ND 1/3 OF DATA
	ANDI T2,177777		;CLEAR LH
	RDIO T3,BSEL6(P1)	;GET 3RD 1/3 OF DATA
	SETZ T4,		;PREPARE TO LET KMC11 KNOW WE READ IT
	WRIO T4,BSEL2(P1)	;LET KMC11 KNOW WE READ IT
	TRNE T1,100000		;CHECK FOR OUTPUT OVERFLOW
	JRST [	CALL KMCHLT	;STOP THE KMC11
		BUG (KMCFST) ;INFORMATION HAS BEEN LOST
		JRST KMVCB9 ]	;DISMISS THE INTERRUPT
	LDB P1,[POINT 8,T1,27]	;GET THE LINE NUMBER
	HRR P1,KDPPAG(P1)	;GET PAGE ADDRESSES FOR LINE
	HRR P4,PGCSTA(P1)	;GET ADR FOR DDCMP LINE TABLE
    IFN FTRACE,<
	MOVE T4,PGTPTR(P1)	;GET TRACE POINTER
	HRRZM T1,(T4)		;SAVE SEL2
	HRLM T2,1(T4)		;SAVE SEL2
	HRRM T3,1(T4)		;SAVE SEL6
	ADDI T4,2
	CAIN T4,1000(P1)	;TIME TO WRAP AROUND ?
	MOVEI T4,PGTRCE(P1)	;YES
	MOVEM T4,PGTPTR(P1)	;SAVE UPDATED TRACE POINTER
    >;IFN FTRACE
	TRNE T1,3		;IS THIS BUFFER ADR OUT ?
	JRST CNTRLO		;THIS IS A CONTROL OUT
	ANDI T2,3777		;STRIP PAGE NUMBER
	ROT T2,-2		;CONVERT BYTES TO PDP10 WORDS
	ADDI T2,(P1)		;MAKE ADR
	HRRZM T2,P2		;SAVE ADR OF BUFFER DESCRIPTOR LIST
	HRLM T2,P1		;SAVE ADR OF BUFFER DESCRIPTOR LIST
	TRNN T1,KMCIOT		;TRANSMIT OR RECEIVE ?
	JRST XMTDNE		;TRANSMIT

;HERE WHEN RECEIVE DATA
	LOAD T1,DCHNG		;IN CASE JUST RESTARTED
	JUMPN T1,RCVFLU		;IGNORE IT UNTIL NSPSRV FGOING
	HRRZ T1,P1		;COPY PAGE ADDRESS
	LSH T1,-^D9		;CONVERT TO PAGE NUMBER
	CALL MONCLR		;INVALIDATE CACHE FOR THIS PAGE
	SKIPL PGRMS1-PGRBD1(P2)
	SKIPGE PGRMS1+1-PGRBD1(P2)
	JRST BUMHDR
	LDB T1,[POINT 8,PGRMS1+1-PGRBD1(P2),9] ;GET A0
	LOAD T2,DDDRP		;GET DROP OF SELECTED STATION
	CAME T1,T2		;MATCH?
	JRST RCVFLU		;NO, IGNORE
	HLRZ T1,PGRMS1-PGRBD1(P2) ;GET 1ST TWO BYTES OF HEADER
	ANDI T1,377		;LEAVE ONLY LEAD CHARACTER
	LOAD T2,DDSTA		;GET LINE STATUS
	CAIN T1,SOH		;WAS THIS A DATA MESSAGE ?
	JRST RCVDAT		;THIS WAS A DATA MESSAGE
	CAIN T1,ENQ		;WAS THIS A CONTROL MESSAGE ?
	JRST RCVCTL		;WE GOT A CONTROL MESSAGE
	CAIE T1,DLE		;WAS THIS A MAINTENANCE MODE MESSAGE ?
	JRST BUMHDR		;GARBAGE MESSAGE
	JRST	RCVMOP		;THIS IS POSSIBLY A MOP MESSAGE

;HERE WHEN MESSAGE IS DETECTED AS BAD
; I.E. A0.NE.1, NOT STARTED WITH SOH, DLE, OR ENQ
BUMHDR:	DMOVE T1,PGRMS1-PGRBD1(P2) ;GET MSG HEADER
	BUG (BADHDR,<<T1,D>,<T2,D>>)
	MOVEI T1,STADWN		;DON'T TRY TO USE LINE
;	CALL DEDLIN		;DECLARE LINE DOWN
	AOS PGLCOC(P4)		;%%% KMC SHOULD NOT GET HERE %%%
	JRST RCVFLU		;DISCARD MESSAGE
	SUBTTL	DDCMP RECEIVER -- DATA MESSAGE
;HERE WHEN RECEIVE A DATA MESSAGE
RCVDAT:	CAIN T2,STARUN		;ARE WE RUNNING ?
	CALL RCVAK3		;CHECK RESPONSE FIELD
	 JRST RCVFLU		;NOT RUNNING OR ERROR RETURN
	HLRZ T1,PGRMS1+1-PGRBD1(P2) ;GET MESSAGE NUMBER
	SOS T1			;MAKE PREVIOUS MESSAGE NUMBER
	ANDI T1,377		;LEAVE ONLY MESSAGE NUMBER
	LOAD T2,DDRMN		;GET LAST MESSAGE WE RECEIVED CORRECTLY
	CAME T1,T2		;IS THIS WHAT WE EXPECTED ?
	JRST RCVFLU		;NO SO IGNORE IT
;LOOP TO COPY DATA INTO BUFFER FOR NSPSRV
	MOVE T1,PGRMS1-PGRBD1(P2) ;GET DDCMP HEADER AGAIN
	ROT T1,^D8+2		;PUT LOW ORDER 8 BITS OF COUNT IN RH
	MOVE T2,T1		;COPY HIGH ORDER BITS
	ANDI T1,377		;LEAVE ONLY LOW ORDER BITS
	LSH T2,-2		;POSITION HIGH ORDER BITS
	ANDI T2,77*400		;STRIP EXTRA BITS
	IORB T1,T2		;LEAVES COUNT IN RH OF T1 & T2
	MOVNI P3,(T1)		;MAKE NEGATIVE COUNT AND PREPARE TO ROUND
	LSH P3,^D16		;ROUND TO NUMBER OF WORDS
	HRRZ T1,PGKDPN(P1)	;COPY LINE NUMBER
	LOAD T4,LINSR		;GET LINE SERVICE INDICATOR
	CALL @KDPSPC(T4)	;GET SPACE FOR MESSAGE
	JRST [	MOVEI T1,NCDBTU	;BUFFER TEMPORARILY UNAVAILABLE
		CALL XMTNAK	;SEND NAK MSG
		JRST RCVFLU ]
	PUSH P,T1		;SAVE ADR OF DATA BLOCK
	HRRI P3,PGRMS1+1-PGRBD1(P2) ;FINISH AOBJN POINTER TO INPUT
	HRRZI P5,-1(T1)		;COPY DEST ADR
RCVDT3:	HRLZ T1,(P3)		;GET NEXT 16 BITS TO COPY
	HLRZ T2,1(P3)		;GET NEXT 16 BITS TO COPY
	DMOVE T3,T1		;GET ANOTHER COPY OF EACH
	LSH T1,2+^D8		;LEAVE ONLY FIRST BYTE
	TLZ T3,600377		;STRIP BITS FROM 2ND BYTE
	LSH T3,2-^D8		;POSITION BYTE
	IOR T1,T3		;INCLUDE WITH FIRST
	ANDI T2,377		;STRIP EXTRA BITS FROM FIRST BYTE
	LSH T2,4+^D8		;POSITION
	IOR T1,T2		;INCLUDE 3RD BYTE WITH 1ST AND 2ND
	ANDI T4,377*400		;STRIP EXTRA BITS FROM 4TH BYTE
	LSH T4,4-^D8		;POSITION 4TH BYTE
	IOR T1,T4		;INCLUDE WITH 1ST 3 BYTES
	PUSH P5,T1		;SAVE WORD FOR NSPSRV
	AOBJN P3,RCVDT3		;LOOP BACK FOR REST OF MESSAGE
	POP P,T2		;GET DATA ADR BACK
	LOAD T4,LINSR		;GET LINE SERVICE INDICATOR
	CALL @KDPQ(T4)		;GIVE MESSAGE TO SERVER(NSP/DCP)
	LOAD T1,DDRMN		;LAST MESSAGE RECEIVED OK
	AOS T1			;NEW LAST MESSAGE RECEIVED OK
	STOR T1,DDRMN		;SAVE NEW ONE
	AOS PGRMCN(P1)		;COUNT MESSAGE RECEIVED CORRECTLY
	CALL XMTACK		;TRY TO SEND AN ACK
	JRST RCVFLU		;THEN FLUSH MESSAGE

KDPSPC:	JRST NSPSPC		;NSP ASSIGN BUFFER
	JRST DCPSPC		;DCP ASSIGN BUFFER
KDPQ:	JRST NSPQ		;QUEUE MESSAGE TO NSP
	JRST DCPQ		;QUEUE MESSAGE TO DCP
	SUBTTL	DDCMP INTERFACE SERVICE ROUTINES

;THESE ROUTINES PROVIDE SERVICE FOR DIRECT USER ACCESS
;TO DDCMP LINES -- THESE ROUTINES PARELLEL ROUTINES IN NSP
;HERE TO GET A BUFFER SET UP FOR INPUT
;ACCEPTS T2/BYTE COUNT OF RECEIVED MESSAGE
;RETURNS T1/ADDR OF BUFFER

DCPSPC:	LOAD T3,DDINP		;HOW MANY ALREADY BUFFERED
	CAILE T3,MAXIN		;ARE WE FULL
	  RETBAD		;YES
	STKVAR<DCPLEN>		;GET SOME TEMP STORAGE
	MOVEM T2,DCPLEN		;REMEMBER DATA BYTE COUNT
	MOVEI T1,4*MSHDR+3(T2)	;BYTE COUNT OF BUFFER
	LSH T1,-2		;CONVERT TO WORDS
	HRLI T1,.RESP1		;PRIORITY 1
	MOVE T2,[RS%SE0+.RESNP]	;FROM NET POOL
	CALL ASGRES		;GET THE SPACE
	  RETBAD		;COULDN'T
	LOAD T3,DDINP		;GET # OF BUFFERS
	AOS T3			;COUNT NEW ONE
	STOR T3,DDINP		;SAVE IT
	LOAD T2,DDDRP		;GET SYSTEM LINE #
	HRLZM T2,INDLNK(T1)	;PUT IT IN HEADER
	MOVE T4,DCPLEN		;GET BACK BYTE COUNT
	MOVEM T4,INDCNT(T1)	;PUT IT IN HEADER
	ADDI T1,MSHDR		;POINT AT DATA
	RETSKP

;HERE TO LINK A BUFFER TO INPUT QUEUE
;T2/ ADDRESS OF BUFFER

DCPQ:	SUBI T2,MSHDR		;POINT AT MESSAGE HEADER
DCPQ1:	SKIPN T1,PGLINQ(P1)	;ANYTHING IN QUEUE
	JRST [ HRRM T2,PGLINQ(P1) ;NO, START IT
	       HRLM T2,PGLINQ(P1)
		JRST DCPQ2 ]
	HLRZS T1		;GET TAIL
	HRRM T2,INDLNK(T1)	;LINK THIS IN
	HRLM T2,PGLINQ(P1)	;MAKE IT THE TAIL
DCPQ2:	SETONE DDINT		;REQUEST INTERRUPT
	RET

;HERE TO POST TRANSMIT COMPLETE
;T1/ BUFFER ADDR

DCPPST:	HRRZI T3,DDPT		;COMPLETION POSTING
	TLO T3,400000		;SET STATUS BIT
	MOVEM T3,INDCNT(T1)	;IN MESSAGE HEADER
	LOAD T3,DDDRP		;GET DROP
	HRLZM T3,INDLNK(T1)	;PUT IN MESSAGE HEADER
	MOVE T2,T1		;BUFFER ADDR FOR DCPQ
	LOAD T3,DDINP		;GET COUNT OF BUFFERED MESSAGES
	AOS T3			;COUNT THIS ONE
	STOR T3,DDINP	
	CALL DCPQ1		;QUEUE IT AS INPUT MESSAGE
	SETONE DDINT		;CAUSE AN INTERRUPT
	RET
;HERE TO QUEUE AN INPUT MESSAGE TO POST LINE GOING UP OR DOWN
;T3/DDUP,DDOWN OR DDSF

DEDDCP:
DCPINI:	PUSH P,T3		;SAVE CONDITION INDICATOR
	SETZM T2		;ZERO MESSAGE LENGTH (HEADER ONLY)
	CALL DCPSPC		;GET A BUFFER
	JRST [	POP P,T1	;NO BUFFER AVAILABLE
		STOR T1,DCHNG	;TRY AGAIN NEXT TIME
		SETOM KDPFLG
		RET ]
	SUBI T1,MSHDR		;POINT AT HEADER
	POP P,T3		;GET BACK CONDITION
	TLO T3,400000		;SET STATUS BIT
	MOVEM T3,INDCNT(T1)	;IN MESSAGE HEADER
	MOVE T2,T1		;BUFFER ADDR FOR DCPQ
	CALL DCPQ1		;QUEUE IT
	RET
	SUBTTL	DDCMP RECEIVER -- CONTROL MESSAGE

;HERE WHEN RECEIVE A CONTROL MESSAGE

RCVCTL:	LDB T1,[POINT 6,PGRMS1-PGRBD1(P2),9] ;GET CONTROL TYPE
	CAILE T1,7		;IS TYPE LEGAL ?
	JRST RCVKRD		;BAD MESSAGE
	JRST @.+1(T1)		;DISPATCH ON MESSAGE TYPE
	JRST RCVKRD		; MSG TYPE = 0
	JRST RCVACK		; MSG TYPE = 1 = ACK
	JRST RCVNAK		; MSG TYPE = 2 = NAK
	JRST RCVREP		; MSG TYPE = 3 = REP
	JRST RCVKRD		; MSG TYPE = 4 = RESET
	JRST RCVKRD		; MSG TYPE = 5 = RESAK
	JRST RCVSTR		; MSG TYPE = 6 = START
	JRST RCVSTK		; MSG TYPE = 7 = STACK
	SUBTTL	DDCMP RECEIVER -- ACK MESSAGE

;HERE WHEN RECEIVE AN ACK MESSAGE
RCVACK:	JRST @.+1(T2)		;DISPATCH ON LINE STATE
	JRST RCVFLU		;KMC11 NOT RUNNING
	JRST RCVFLU		;MAINT MODE
	JRST RCVFLU		;SENDING STARTS
	JRST RCVAK0		;SENT STACK
	JRST RCVAK2		;RUNNING

;HERE WHEN RECEIVE AN ACK AFTER RECEIVING A START
RCVAK0:	OPSTR <SKIPE>,DCHNG	;HAS THIS HAPPENED ONCE BEFORE ?
	JRST RCVFLU		;PERHAPS IGNORE IT
	CALL XMTACK		;TRY TO SEND ANOTHER ACK
	MOVEI T1,DDUP		;REMEMBER IT CAME UP
	STOR T1,DCHNG		;TELL NSPSRV ASAP
	SETOM KDPFLG		;WANT TO RUN KDPTSK
	JRST RCVFLU		;THEN DISCARD MESSAGE

;HERE WHEN RECEIVE AN ACK WHILE RUNNING
RCVAK2:	CALL RCVAK3		;PROCESS MESSAGE NUMBER
	JRST RCVFLU
	JRST RCVFLU
;HERE TO CHECK R FIELD IN ACK OR DATA MESSAGE
; CALLED AT INTERRUPT LEVEL
RCVAK3:	LDB T3,[POINT 8,PGRMS1-PGRBD1(P2),27] ;GET R NUMBER
	LOAD T1,DDHMA		;GET HIGHEST MESSAGE ACKED BEFORE
	CAIN T1,(T3)		;IS THIS NEW INFORMATION
	jrst rcvak5		;nothing new to do
	SUB T3,T1		;FIND NUMBER OF MESSAGES THIS WILL ACK
	cail t3,0		;must be between 0 and 10
	caile t3,maxout		;to be a valid ack
	caia
	jrst rcvak6		;valid continue processing
	addi t3,400		;handle wrap case
	cail t3,0		;try again
	caile t3,maxout		;0 leq A-R leq 10
	jrst rcvak5		;not a vaild  R field..

rcvak6:	AOS T1			;PLUS ONE HIGHEST MESSAGE ACKED
	STOR T1,DDHMA		;SAVE UPDATED NUMBER
	DMOVE T1,PGRMS1-PGRBD1(P2) ;PICK UP MSG HEADER OR ACK/NAK
	DMOVEM T1,PGLACK(P1)	;SAVE FOR DEBUGING
	AOS PGXMCN(P1)		;COUNT MESSAGES TRANSMITTED OK
	MOVEI T1,TIMREP		;RESET REP TIMER CUZ ITS LOOKING GOOD
	STOR T1,DDTIM
	SETZ T1,		;CLEAR REP COUNTER
	STOR T1,DDREPC
	HLRZ T1,PGDOMQ(P4)	;GET FIRST MESSAGE IN QUEUE
	JUMPE T1,rcvak5		;IF NONE RESPONSE WAS BAD
	CAMN T1,PGDLMX(P4)	;WAS THIS LAST MESSAGE TRANSMITTED ?
	SETZM PGDLMX(P4)	;FORGET POINTER
	HLRZ T2,MBKLEN(T1)	;GET DRIVER INT LOC
	MOVE T1,MBKCOD(T1)	;GET DRIVER UNIQUE CODE
	SKIPE T2		;WAS THERE ONE ?
	CALL (T2)
	HLRZ T1,PGDOMQ(P4)	;GET ADR OF MESSAGE BLOCK ADR AGAIN
	HLRZ T2,MBKLNK(T1)	;GET ADR OF NEXT MESSAGE IN QUEUE
	HRLM T2,PGDOMQ(P4)	;NEW FIRST MESSAGE IN QUEUE
	CAIN T2,MBKFRE(T1)	;DID WE CHANGE CHUNKS ?
	JRST RCVAK4		;SAME CHUNK
	SKIPN T2		;WAS THERE A NEXT MESSAGE BLOCK ?
	SETZM PGDOMQ(P4)	;NO SO QUEUE NOW EMPTY
	HRRZ T1,MBKFRE(T1)	;GET CHUNK ADR FOR MESSAGE BLOCK
	CALL SAVBLK		;RELEASE BLOCK
RCVAK4:	JRST RCVAK3		;CHECK FOR MORE MESSAGES TO FREE

rcvak5:	SKIPE T1,PGDOMQ(P4)	;IS MESSAGE QUEUE EMPTY ?
	RETSKP			;QUEUE NOT EMPTY SO KEEP REPPING
	STOR T1,DDREPC		;CLEAR REP COUNTER
	MOVEI T1,^D30		;LONG WAIT FOR NEXT REP
	STOR T1,DDTIM
	RETSKP 


;HERE TO FREE A BLOCK OF CORE
SAVBLK:	SKIPN T2,PGFCOR(P4)	;HOLDING ANY FREE BLOCKS ?
	JRST [	HRLZM T1,PGFCOR(P4) ;SAVE THIS ONE
		RET ]
	TRNE T2,-1		;HOLDING TWO ?
	JRST RELRES		;CAN'T HOLD ANY MORE
	HRRM T1,PGFCOR(P4)	;SAVE THIS ONE ALSO
	RET
	SUBTTL	DDCMP RECEIVER -- NAK MESSAGE

;HERE WHEN RECEIVE A NAK MESSAGE
RCVNAK:	JRST @.+1(T2)		;DISPATCH ON LINE STATE
	JRST RCVFLU		;KMC11 NOT RUNNING
	JRST RCVFLU		;MAINT MODE
	JRST RCVFLU		;SENDING STARTS
	JRST RCVNK0		;SENT STACK
	JRST RCVNK3		;RUNNING

;HERE IF RECEIVE A NAK AFTER SENDING A STACK
; THIS IS PROBABLY A REP RESPONSE SO DECLARE US UP
RCVNK0:	LDB T1,[POINT 8,PGRMS1-PGRBD1(P2),27] ;GET R FIELD
	JUMPN T1,RCVKRD		;IF NONZERO IS AN ERROR
	JRST RCVAK0		;TREAT AS AN ACK

;HERE IF RECEIVE A NAK WHILE RUNNING
RCVNK3:	LDB T1,[POINT 6,PGRMS1-PGRBD1(P2),35] ;GET NAK CODE
	CAILE T1,^D17		;is nak code reasonable?
	SETZ T1,		;FIRST CELL IS MISC
	move t2,naktbl(t1)	;retrieve offset into table
	addi t2,pgnrnk(p1)	;point to nak counter
	aos (t2)		;count nak
	SETZM PGDLMX(P4)	;RETRANSMIT FIRST MESSAGE IN QUEUE
	CALL RCVAK3		;PROCESS RESPONSE
	JRST RCVFLU		;ERROR RETURN
	CALL XMTDAT		;RETRANSMIT MESSAGE (IF ANY)
	JRST RCVFLU		;DISCARD MESSAGE
	SUBTTL	DDCMP RECEIVER -- REP MESSAGE

;HERE WHEN RECEIVE A REP MESSAGE
RCVREP:	JRST @.+1(T2)		;DISPATCH ON LINE STATE
	JRST RCVFLU		;KMC11 NOT RUNNING
	JRST RCVFLU		;MAINT MODE
	JRST RCVFLU		;SENDING STARTS
	JRST RCVRP0		;SENT STACK
	JRST RCVRP0		;RUNNING

;HERE WHEN RECEIVED A REP AND NEED TO SEND AN ACK OR A NAK RESPONSE
RCVRP0:	HLRZ T1,PGRMS1+1-PGRBD1(P2) ;GET MESSAGE NUMBER
	ANDI T1,377		;STRIP EXTRA BITS
	LOAD T2,DDRMN		;GET LAST THING WE GOT
	CAME T1,T2		;EVERYTHING OK ?
	JRST RCVRP3		;TELL HIM WE DIDN'T GET IT
	CALL XMTACK		;TRY TO SEND ACK
	JRST RCVFLU
RCVRP3:	MOVEI T1,NCDREP		;REASON CODE IS REP RESPONSE
	CALL XMTNAK		;TRY TO SEND NAK
	JRST RCVFLU
	SUBTTL	DDCMP RECEIVER -- START MESSAGE

;HERE WHEN RECEIVE A START MESSAGE
RCVSTR:	JRST @.+1(T2)		;DISPATCH ON LINE STATE
	JRST RCVFLU		;KMC11 NOT RUNNING
	JRST RSTRT3		;MAINT MODE
	JRST RSTRT5		;SENDING STARTS
	JRST RSTRT3		;SENT STACK
	JRST RSTRT0		;RUNNING

;HERE IF RECEIVE A START AFTER LINE WAS RUNNING
RSTRT0:	HRRZ T1,PGKDPN(P1)	;GET LINE NUMBER
	BUG (DDCSTR,<<T1,D>>)
	MOVEI T1,STASTR		;SEND STARTS AGAIN
	CALL DEDLIN		;MOURN THE DEAD LINE

;HERE IF RECEIVE A START WHICH PUTS US INTO START MODE
RSTRT3:	MOVEI T1,STASTR		;AM NOW SENDING STARTS
	STOR T1,DDSTA		;SET NEW STATE
	MOVEI T1,2		;MINIMUM TIME
	STOR T1,DDTIM		;SO WE SEND A START SOON
	JRST RCVFLU		;DISCARD MESSAGE

;HERE IF RECEIVE A START WHILE SENDING STARTS
RSTRT5:	DMOVE T1,STCKMS		;GET PROTOTYPE STACK MESSAGE
	CALL XMTCTL		;TRY TO SEND IT
	JRST RSTRT3		;FAILED SO SEND START LATER
	MOVEI T1,STASTK		;NOW CLAIM WE RECEIVED A STACK
	STOR T1,DDSTA		;SAVE NEW STATUS
	SETONE DDXAK		;NEED TO SEND AN ACK
	JRST RCVFLU		;DISCARD MESSAGE

;HERE WHEN A LINE DIES - CLEANS UP AND LETS NSPSRV KNOW
; CALLED WITH NEW STATE IN T1
DEDLIN:	LOAD T2,DDSTA		;GET LINE STATUS
	MOVEI T3,DDOWN		;LINE IS DOWN
	CAIN T2,STARUN		;WAS LINE RUNNING ?
	STOR T3,DCHNG		;YES SO TELL NSPSRV IT DIED
	STOR T1,DDSTA		;SET NEW STATE
	STOR T1,DDTIM		;START TIMER ALSO
	SETOM KDPFLG		;SO WE CHECK FLAG
DEDLN2:	PIOFF			;STOP RACES
	HLRZ T3,PGDOMQ(P4)	;GET FIRST MESSAGE IN OUTPUT MESSAGE QUEUE
	JUMPE T3,DEDLN8		;IF NONE DONE
	PUSH P,MBKLEN(T3)	;SAVE DRIVER INT LOC
	PUSH P,MBKCOD(T3)	;SAVE DRIVER UNIQUE CODE
	HLRZ T2,MBKLNK(T3)	;GET ADR OF NEXT MESSAGE BLOCK
	HRLM T2,PGDOMQ(P4)	;FORGET MESSAGE
	HRRZ T1,MBKFRE(T3)	;GET ADR OF CHUNK
	CAIE T2,MBKFRE(T3)	;DOES THIS CHANGE CHUNKS ?
	CALL SAVBLK		;SAVE THE BLOCK FOR LATER USE
	PION			;REENABLE INTERRUPTS
	POP P,T1		;GET DRIVER UNIQUE CODE
	POP P,T2		;GET DRIVER INT LOC
	HLRZS T2		;PUT DREIVER INT LOC IN RH
	SKIPE T2		;WAS THERE ONE ?
	CALL (T2)
	JRST DEDLN2
DEDLN8:	SETZM PGDOMQ(P4)	;HAVE FLUSHED OUTPUT QUEUE
	SETZM PGDLMX(P4)	;NO LAST MESSAGE NOW
	SETZM PGDMNM(P4)	;INITIALIZE MESSAGE NUMBERS
	SETZRO DDLMX		
	PION
	RET
	SUBTTL	DDCMP RECEIVER -- STACK MESSAGE

;HERE WHEN RECEIVE A STACK MESSAGE
RCVSTK:	JRST @.+1(T2)		;DISPATCH ON LINE STATE
	JRST RCVFLU		;KMC11 NOT RUNNING
	JRST RCVFLU		;MAINT MODE
	JRST RSTCK0		;SENDING STARTS
	JRST RSTCK0		;SENT STACK
	JRST RCVFLU		;RUNNING

RSTCK0:	CALL XMTACK		;SEND AN ACK
	MOVEI T1,STASTK		;CLAIM SENT A STACK
	STOR T1,DDSTA
	JRST RCVFLU		;DISCARD MESSAGE
	SUBTTL	DDCMP RECEIVER -- JUNK MESSAGE

;HERE WHEN RECEIVE A JUNK MESSAGE
RCVKRD:	MOVEI T1,NCDHFE		;HEADER FORMAT ERROR
	CALL XMTNAK		;COMPLAIN TO OTHER END

RCVFLU:	HLRZ T3,P1		;GET ADR OF BUFFER DESCRIPTOR
	LDB P3,[POINT 8,PGRMS1-PGRBD1(T3),35] ;SAVE 3RD BYTE OF MESSAGE
	CALL RCVENB		;REENABLE RECEIVER
	SKIPN PGSTAL(P1)	;MULTI-DROP LINE?
	JRST KMVCB9		;NO, ALL DONE
	TRNE P3,SELECT		;DID STATION DESELECT
	CALL SELSTA		;YES, SELECT NEXT STATION
	JRST KMVCB9		;DISMISS INTERRUPT
	SUBTTL	DDCMP TRANSMIT DONE

;HERE FOR TRANSMIT DONE
XMTDNE:	JUMPL T2,[SOJA T2,XMTDN5] ;IF SECOND DESCRIPTOR FLUSH MESSAGE
	HLRZ T1,PGXMS1-PGXBD1(T2) ;GET FIRST CHAR IN MESSAGE
	ANDI T1,377		;STRIP EXTRA BITS
	CAIE T1,ENQ		;WAS THIS A CONTROL MESSAGE ?
	JRST KMVCB9		;WAIT FOR DATA TO GO
XMTDN5:	LDB P3,[POINT 8,PGXMS1+1-PGXBD1(T2),9] ;GET A0
	SETZM P4			;CLEAR STATION TABLE ADDR 
XMTDN6:	CALL NXTSTA		;GET NEXT STATION IN LIST
	BUG (MSGCLB)
	LOAD T3,DDDRP		;DROP OF SELECTED STATION
	CAME P3,T3		;MATCH?
	JRST XMTDN6		;LOOP TO FIND STATION
	SETZM (T2)		;THIS BUFFER DESCRIPTOR LIST NOW FREE
	LOAD T2,DDSTA		;GET STATE
	CAIN	STAMAI		;IN MAINTENANCE MODE?
	JRST	MOPDNE		;DO MOP COMPLETION STUFF
	MOVEI T1,TIMREP		;GET REP INTERVAL
	CAIN T2,STASTR		;SENDING STARTS?
	MOVEI T1,TIMSTR		;YES, USE START TIMER
	LOAD T2,DDTIM		;GET CURRENT TIMER
	SKIPN T2		;STATION IDLE?
	STOR T1,DDTIM		;YES, SET REP TIMER
	HRR P4,PGCSTA(P1)	;GET CURRENTLY SELECTED STATION
	LOAD T1,DDNCD		;GET CURRENT NAK CODE
	SKIPE T1		;DO WE NEED TO SEND A NAK ?
	CALL XMTNAK		;TRY TO SEND IT NOW
	LOAD T1,DDSEL		;IS STATION WAITING FOR SELECT
	JUMPN T1,[LOAD T1,DDSTA ;YES,GET STATE
		  CALL @SELDSP(T1) ;SEND A MESSAGE
		  JRST .+1]
	SKIPN PGOLST(P4)	;ANY OUTPUT FOR THIS STATION
	JRST [SKIPN P4,PGLOUQ(P1) ;ANY OUTPUT QUEUED?
	      HRR P4,PGCSTA(P1) ;NO, JUST CHECK FOR ACK
	      JRST .+1]
	CALL XMTDAT		;TRY TO SEND SOME DATA
	JRST KMVCB9
	SUBTTL	KMC11 CONTROL OUT INTERRUPT
;HERE FOR CONTROL OUT INTERRUPT
CNTRLO:	ANDI T3,377		;LEAVE ONLY ERROR CODE
	ROT T3,-1		;FOR DISPATCH
	JUMPL T3,CNTLO3		;IN CASE BUM DISPATCH
	CAIL T3,10/2		;IN RANGE ?
	CAILE T3,26/2		;IN RANGE
CNTLO3:	JRST [	AOS PGCOXX(P1)	;COUNT TIMES THIS HAPPENS
		JRST KMVCB9 ]	;IGNORE INTERRUPT
	MOVEI T1,PGCOCN-4(P1)	;TABLE TO INCREMENT
	ADD T1,T3		;OFFSET FOR CODE
	AOS (T1)		;COUNT TYPE OF INTERRUPT
	JRST @.+1-4(T3)		;DISPATCH ON MESSAGE TYPE
	JRST CNTL10		;10 = INVALID DDCMP HEADER
	JRST CNTL12		;12 = BAD CRC
	JRST [	MOVEI T1,NCDBTU	;14 = BUFFER NOT AVAILABLE
		STOR T1,DDNCD	;SAVE REASON FOR NAK
		JRST KMVCB9 ]	;DISMISS
	JRST CNTL16		;16 = DATASET READY TRANSITION
	JRST CNTL20		;20 = NXM
	JRST CNTL22		;22 = TRANSMIT UNDERRUN
	JRST CNTL24		;24 = RECEIVER UNDERRUN
	JRST KMVCB9		;26 = KILL COMPLETE

;HERE WHEN GET A CONTROL TYPE 10 = INVALID DDCMP HEADER
CNTL10:	CALL FLUBFR		;FLUSH BUFFER
	JRST KMVCB9

;HERE WHEN GET A CONTROL TYPE 12 = BAD CRC
CNTL12:	CALL FLUBFR		;FLUSH BUFFER
	MOVEI T1,NCDBCC		;NAK CODE FOR BUM CRC
	CALL XMTNAK		;TRY TO SEND NAK
	JRST KMVCB9		;DISMISS

;HERE WHEN WE GET A CONTROL TYPE 16 = DATASET READY TRANSITION
CNTL16:	MOVX T3,DUPDSR		;BIT FOR DATASET READY
	XORB T3,PGLSTS(P1)	;CHANGE STATE
	TXNE T3,DUPDSR		;STILL UP ?
	 JRST KMVCB9		;CAME ON - DISMISS
	LOAD T3,DDSTA		;GET CURRENT STATE
	CAIE T3,STASTK		;ARE WE SENDING STACKS ?
	CAIN T3,STARUN		;OR ARE WE RUNNING ?
	SKIPA T1,[EXP STASTR]	;SEND STARTS AGAIN
	 JRST KMVCB9		;DISMISS
	HRRZ T2,PGKDPN(P1)	;GET LINE NUMBER
	CAIN T3,STARUN		;ARE WE RUNNING ?
	 BUG (DSRLST,<<T2,D>>)
	CALL DEDLIN		;DATASET NOT READY SO DECLARE LINE DOWN
	JRST KMVCB9		;DISMISS

;HERE WHEN GET A CONTROL TYPE 20 = NXM
CNTL20:	CALL KMCHLT		;KILL THE KMC11
	BUG (KMCNXM) ;TELL OPERATOR
	JRST KMVCB9

;HERE WHEN GET A CONTROL TYPE 22 = TRANSMIT UNDERRUN
CNTL22:	CALL FLUBFR		;FLUSH BUFFER
	JRST KMVCB9

;HERE WHEN GET A CONTROL TYPE 24 = RECEIVER UNDERRUN
CNTL24:	CALL FLUBFR		;FLUSH BUFFER
	JRST KMVCB9		;DISMISS

;HERE TO FREE BUFFER REFERENCED IN CONTROL OUT MSG
FLUBFR:	HLRZ T1,PGUBAD(P1)	;GET UNIBUS ADR OF PAGE
	SUB T2,T1		;LEAVE ONLY RELATIVE ADR ON PAGE
	ROT T2,-2		;CONVERT BYTES TO WORDS
	HRRZ T3,T2		;COPY BUFFER ADR
	ADDI T3,(P1)		;POINT TO BUFFER DESCRIPTOR
	CAIE T3,PGRBD1(P1)	;WAS THAT FIRST RECEIVER BUFFER ?
	CAIN T3,PGRBD2(P1)	;OR 2ND RECEIVER BUFFER
	JRST RCVENB		;REENABLE BUFFER
	CAIE T3,PGXBD1(P1)	;WAS THAT 1ST TRANSMIT BUFFER ?
	CAIN T2,PGXBD2(P1)	;OR 2ND TRANSMIT BUFFER ?
	SETZM (T3)		;FREE BUFFER
	RET

KMVCB9:	MOVSI 17,KMCACS		;BLT POINTER TO RESTORE REGS
	BLT 17,17		;RESTORE ALL REGS
	XJEN KDPXPC+4		;DISMISS INTERRUPT
	SUBTTL	HERE FROM NSPSRV WITH OUTPUT MESSAGES

;ACCEPTS:
;	F/ DRIVER UNIQUE CODE
;	T1/ DRIVER INT LOC,,DTE NUMBER
;	T2/ BYTE POINTER TO NSP DATA (WITH OR WITHOUT HEADER)
;	T3/ RH = COUNT OF BYTES IN DATA POINTED TO BE B
;	    B0 SET IF MESSAGE ALREADY SENT
;	    B1 SET IF MESSAGE FROM DCP
;
;	RETURNS:
;	+1 IF NO PACKETS AND CALLED FROM SCHEDULER. REQUEST NOT
;	   QUEUED.
;	+2 REQUEST QUEUED
;
;MAY BE CALLED FROM PI OR NON-PI LEVEL .
	; ..

DCNMSO::SAVEP			;SAVE THE P'S
	HRRZM T1,P1		;SAVE THE LINE NUMBER
	CAML P1,KDPNLN		;IS LINE NUMBER IN RANGE ?
	RET			;NO SO LOSE RETURN
	STKVAR <DRVMSG,DRVCOD,DRVLEN,DRVFLG>
	MOVEM F,DRVCOD		;SAVE DRIVER CODE
	MOVEM T2,DRVMSG		;SAVE POINTER TO MESSAGE
	HLRZS T2		;LEAVE ONLY BYTE POINTER BITS
	CAIE T2,441000		;RIGHT BITS ?
	BUG (MSGPTR)

	HRR T1,T3		;BUILD MBKLEN
	MOVEM T1,DRVLEN		;SAVE IT
	MOVEM T3,DRVFLG		;SAVE FLAGS
	MOVE P1,KDPPAG(P1)	;GET ADR OF LINES PAGE
	TXNN T3,1B1		;DCP DATA
				;%% NOT GOOD ENOUGH
	HRR P4,PGCSTA(P1)	;GET STATION TABLE ADDRESS
	LOAD T1,DDSTA		;GET LINE STATUS
	CAIE T1,STARUN		;IS LINE RUNNING ?
	RET			;CAN'T HANDLE MESSAGE
DCNMS1:	SKIPE PGFCOR(P4)	;IS THERE A FREE CORE BLOCK ?
	JRST DCNMS2		;ENOUGH CORE
	MOVE T1,[.RESP1,,BLKSIZ] ;PRIORITY AND SIZE OF BLOCK TO GET
	MOVX T2,RS%SE0+.RESNP	;GET IT FROM THE NETWORK POOL
	CALL ASGRES		;GET THE BLOCK
	JRST [	CONSO PI,PIPIIP	;ARE WE AT INTERRUPT LEVEL ?
		SKIPE INSKED	;FROM SCHEDULER ?
		RET		;LOSE
		SKIPE NSKED	;ARE WE NOSKED ?
		RET		;LOSE - CAN'T BLOCK
		HRLI T1,P1	;COPY LINES BLOCK ADR
		HRRI T1,SPCTST	;CHECK FOR ROOM
		MDISMS		;WAIT
		JRST DCNMS1 ]	;TRY AGAIN
	PIOFF			;DISABLE INTERRUPTS
	CALL SAVBLK		;SAVE BLOCK FOR LATER USE
	PION			;REENABLE INTERRUPTS
DCNMS2:	SKIPGE DRVFLG		;ALREADY SHUFFLED ?
	JRST DCNMS4		;IN CASE ALREADY SHUFFLED DATA
	MOVE T3,DRVLEN		;GET LENGTH OF MESSAGE
	HRR T2,DRVMSG		;GET ADR OF MESSAGE
	CALL	SHFFLE
DCNMS4:	PIOFF			;DISABLE INTERRUPTS WHILE WE QUEUE IT
	HLRZ T1,PGLOUQ(P1)	;GET TAIL OF STATION OUTPUT QUEUE
	JUMPE T1,[HRRM P4,PGLOUQ(P1) ;FIRST ENTRY,SET HEAD
		  MOVE T1,P4	;GET TAIL
		  JRST .+1]
	HRR T3,PGLOUQ(P1)	;GET HEAD
	HRRM T3,PGOLST(P4)	;SET FORWARD THREAD
	HRLM T1,PGOLST(P4)	;SET BACK THREAD
	HRLM P4,PGLOUQ(P1)	;SET NEW TAIL
	SKIPE T4,PGDOMQ(P4)	;ANY OUTPUT MESSAGE QUEUE FOR THE LINE
	JRST DCNMSA		;YES
	SETZM PGDLMX(P4) ;NO PREVIOUS MSG SENT
	HRRZ T3,PGFCOR(P4) ;GET BLOCK ADR
	SKIPN T3	;IS THERE ANYTHING THERE ?
	MOVSS T3,PGFCOR(P4) ;NO SO GET OTHER HALF
	HLLZS PGFCOR(P4) ;REMOVE FROM FREE SPACE
	HRLM T3,PGDOMQ(P4) ;THIS IS FIRST MESSAGE
	HRRZ T1,T3	;COPY ADR OF CHUNK
	HRLI T1,BLKSIZ-4 ;NUMBER OF FREE WORDS LEFT
	JRST DCNMS6 
DCNMSA:	MOVEI T3,MBKFRE(T4)	;ADR OF NEXT MESSAGE BLOCK
	MOVE T1,MBKFRE(T4)	;GET FREE WORD
	SUB T1,[3,,0]		;ADJUST FOR NEW STATUS
	JUMPGE T1,DCNMS5
	HRRZ T3,PGFCOR(P4)	;GET OLD BLOCK
	SKIPN T3		;WAS THERE ONE ?
	MOVSS T3,PGFCOR(P4)	;NO SO USE ONE WE JUST GOT
	HLLZS PGFCOR(P4)	;NO LONGER FREE
	HRRZ T1,T3		;COPY ADR OF CHUNK
	HRLI T1,BLKSIZ-4	;NUMBER OF FREE WORDS LEFT
DCNMS5:	HRLM T3,MBKLNK(T4)	;SET LINK TO NEXT
DCNMS6:	MOVEM T1,MBKFRE(T3)	;SAVE FREE STUFF
	MOVE T1,DRVMSG		;GET ADR OF MESSAGE
	HRRZM T1,MBKLNK(T3)	;SAVE LINK WORD
	MOVE T1,DRVCOD		;GET DRIVER UNIQUE CODE
	MOVEM T1,MBKCOD(T3)	;SAVE IT
	MOVE T1,DRVLEN		;GET LENGTH
	MOVEM T1,MBKLEN(T3)	;SAVE IT
	HRRM T3,PGDOMQ(P4)	;THIS IS NOW LAST MESSAGE IN QUEUE
	CALL XMTDAT		;TRY TO SEND THE MESSAGE
	LOAD T1,DDTIM		;GET TIMER
	SKIPN T1		;ALREADY RUNNING ?
	MOVEI T1,TIMREP		;START IT
	STOR T1,DDTIM
	PION
	JRST RSKP		;WIN RETURN

;HERE TO SEE IF WE CAN CONTINUE JOB NEEDING CORE
SPCTST:	SKIPN PGFCOR(T1)	;DID WE GET SOME CORE YET ?
	JRST 0(4)		;NOT YET
	JRST 1(4)		;GOT SOME
	SUBTTL	HERE ONCE A SECOND TO CHECK THINGS

KDPCHK::SAVEP			;SAVE THE P'S
	MOVEI T1,^D1000		;TIME TILL WE WANT TO CHECK AGAIN
	MOVEM T1,KDPTIM
	SKIPL P1,KDPLIM		;GET NUMBER OF DUP11'S
	RET			;NONE
KMCHK0:	pioff
	HRR P1,KDPPAG(P1)	;GET PAGE ADR
	HRR P4,PGCSTA(P1)	;GET DDCMP LINE TABLE
	LOAD	T1,DDSTA
	CAIN	T1,STAMAI	;MAINTENANCE MODE?
	JRST	[CALL	MOPSEC	;YES, DO MOP STUFF
		 PION		;TURN INTERRUPTS BACK ON
		 JRST	KMCHK3]	;GO ON
	AOS PGZTIM(P1)		;TIME SINCE COUNTERS ZEROED
	LOAD T1,DDTIM		;GET TIMER FOR LINE
	JUMPE T1,KMCHK2		;IF TIMER NOT RUNNING WE'RE DONE
	SOS T1			;DECREMENT THE TIMER
	STOR T1,DDTIM		;SAVE UPDATED TIMER
	JUMPN T1,KMCHK2		;IF TIMER DIDN'T EXPIRE DONE WITH LINE
	SKIPE PGSTAL(P1)	;MULTIPOINT?
	JRST [CALL SELSTA	;YES, SELECT NEW STATION
	      JRST KMCHK2]	;CONTINUE FOR REMAINING LINES
	LOAD T1,DDSTA		;GET LINE STATE
	CALL TIMDSP(T1)		;DISPATCH ON STATE
KMCHK2:	PION			;REENABLE INTERRUPTS
	LOAD T1,DDINT		;WAS AN INTERRUPT REQUESTED
	SKIPE T1
	JRST [	SETZRO DDINT	;DID IT NOW
		HRRZ T1,PGLINT(P1)  ;GET CHANNEL
		JUMPE T1,.+1	    ;IS THERE ONE?
		SOS T1		    ;ZERO INDEX
		HLRZ T2,PGLINT(P1)  ;FORK#
		CALL PSIRQ	    ;SEND INTERRUPT
		JRST .+1 ]
KMCHK3:	HRR P1,PGKDPN(P1)	;GET LINE NUMBER
	AOBJN P1,KMCHK0		;LOOP BACK FOR REST OF LINES
	RET			;HAVE DONE ALL LINES
TIMDSP:	JRST R			;KMC NOT RUNNING
	JRST R			;MAINTENANCE MODE
	JRST XSTART		;SENDING STARTS
	JRST REPCHK		;RECEIVED STACK
	JRST REPCHK		;RUNNING
	SUBTTL	HERE TO PROCESS END OF SELECTION INTERVAL

;CALLED AT INTERRUPT LEVEL OR WITH PIOFF
SELSTA:	SETZRO DDTIM		;CLEAR REP TIMER
	CALL GTNXT		;SELECT NEXT STATION
	RET			;NO ELIGABLE STATIONS
	LOAD T1,DDHMA		;HIGHEST MESSAGE ACKED
	LOAD T2,DDLMX		;HIGHEST XMITTED
	CAMLE T2,T1		;ANY OUTSTANDING?
	JRST REPCHK		;SEND A REP
	LOAD T1,DDHXM		;HIGHEST MESSAGE XMITTED LAST INTERVAL
	CAIN T1,377		;TIME TO WRAP AROUND?
	SETZM T1		;YUP
	STOR T1,DDLMX		;REMEMBER FOR NEXT TIME
	SETONE DDXAK		;SEND AN ACK (IF NO DATA)
	LOAD T1,DDSTA		;GET STATE
	CALL @SELDSP(T1)	;DISPATCH ON STATE
	RET

SELDSP:	JRST R			;KMC NOT RUNNING
	JRST R			;MAINTENANCE
	JRST XSTART		;SENDIND STARTS
	JRST XMTDAT		;RECEIVED STACK
	JRST XMTDAT		;RUNNING
	SUBTTL	HERE TO SELECT NEXT STATION TO POLL


;  A STATION IS ELEGIBLE TO BE POLLED IF IT IS RUNNING AND ACTIVE OR IN 
;STARTUP. ACTIVE/IDLE STATE IS SET VIA THE BOOT JSYS. IF NO ELEGIBLE STATION
;IS FOUND AFTER ONE PASS THRU THE STATION TABLES A TIMER IS SET TO INITIATE
;A SCAN IN ONE SECOND AND THE ROUTINE EXITS NON SKIP.
;  IN ORDER TO REDUCE POLLING DELAYS DUE TO UNRESPONSIVE STATIONS, STATIONS
;WHICH ARE IN STARTUP ARE NOT POLLED AS FREQUENTLY AS STATIONS WHICH ARE
;RUNNING. ONLY ONE STARTUP IS ATTEMPTED EVERY N TIMES ALL RUNNING STATIONS
;ARE POLLED. THE PARAMETER N IS PGSTCC IN THE LINE TABLE AND MAY BE SET VIA
;THE BOOT JSYS.
;  ACTIVE STATIONS ARE POLLED ACCORDING TO PRIORITY VALUE BETWEEN 1 AND N
;WHERE 1 IS HIGHEST. THE RELETIVE FREQUENCY OF POLLING ANY TWO STATIONS
;WILL BE THE RATIO OF THERE PRIORITY VALUES. PRIORITY VALUES DEFAULT TO 1
;RESULTING IN ROUND ROBIN POLLING OF ACTIVE STATIONS OR CAN BE SET USING THE
;BOOT JSYS.

GTNXT:	SETZB T1,T2		;CLR ELIGABLE STATION COUNTER,LOOP COUNT
	HRRZ T3,P4		;REMEMBER CURRENT STATION
GTNXT1:	LOAD P4,DDLNK		;GET NEXT STATION
	LOAD T4,DDSTT		;GET TOP OF STATION LIST
	CAMN P4,T4		;ARE WE AT TOP?
	JRST [LOAD T2,DDSSP	;PICK UP PRIORITY COUNT
	      SKIPG PGSTCC(P1)	;IF ZERO MUST BE RESET
	      MOVEM T2,PGSTCC(P1)	;OK RESET COUNT
	      SOS PGSTCC(P1)	;DECREMENT COUNT ANYWAY
	      JRST .+1]

;DETERMINE IF THIS STATION IS ELIGABLE

	LOAD T4,DDACI		;GET POLLING STATUS
	JUMPG T4,GTNXT2		;IDLE?
	LOAD T4,DDSTA		;GET STATE
	MOVEI P2,STASTK		;ASSUME MUST BE RUNNING
	SKIPG PGSTCC(P1)	;ARE STARTS ALLOWED
	MOVEI P2,STASTR		;YES
	CAMGE T4,P2		;STATION ACTIVE?
	JRST GTNXT2		;NO
	LOAD P2,DDSPC		;GET STATION'S PRIORITY COUNTER
	SOJE P2,GTNXT3		;SELECT THIS STATION IF COUNTER ZERO
	STOR P2,DDSPC		;SAVE UPDATED COUNT
	AOS T1			;MARK AN ACTIVE STATION
GTNXT2:	CAME P4,T3		;ONCE THRU YET?
	JRST GTNXT1		;NO, KEEP TRUCKIN

;HERE WHEN THRU STATION LIST
	JUMPG T1,GTNXT1		;CONTINUE IF THERE ARE ACTIVE STATIONS
	MOVEI T1,1		;QUICK TIMER
	STOR T1,DDTIM		;FOR THIS SELECTION INTERVAL
	RET			;RETURN FAILURE

GTNXT3: LOAD T1,DDIPC		;GET INITIAL PRIORITY COUNT
	STOR T1,DDSPC		;RESET STATION COUNTER
	CAIE T4,STASTR	;IS THIS A START
	JRST GTNXT4		;NO, CONTINUE
	CALL REMSTA		;REMOVE STATION FROM STATION LIST
	CALL INSTA		;INSERT IT AT END OF LIST
	LOAD T1,DDSSP		;GET INITIAL START COUNT
	MOVEM T1,PGSTCC(P1)	;YES, RESET COUNTER
	LOAD T1,DDSFC		;GET STARTUP FAILURE COUNTER
	CAILE T1,MAXSTR		;IS IT TOO HIGH
	JRST [SETZM PGDSTS(P4)	;MARK LINE DOWN
	      MOVEI T3,DDSF	;POST A STARTUP FAILURE
	      STOR T3,DCHNG	;AT SCHEDULER LEVEL
	      SETOM KDPFLG	;REQUEST THE SERVICE
	      JRST GTNXT]	;SELECT ANOTHER STATION
	AOS T1			;COUNT THIS STARTUP
	STOR T1,DDSFC		;SAVE IT
GTNXT4:	SETONE DDSEL		;MARK STATION FOR SELECT
	MOVEM P4,PGCSTA(P1)	;SET STATION SELECTED
	RETSKP			;RETURN SUCCESS
	SUBTTL	DDCMP TRANSMITTER -- DATA MESSAGES

XSTART:	SETZRO DDXAK		;DON'T NEED AN ACK NOW
	MOVEI T1,TIMSTR		;IF THIS ONE DOESN'T GET RESULTS
	STOR T1,DDTIM		;TRY AGAIN SOON
	DMOVE T1,STRTMS		;GET PROTOTYPE START MESSAGE
	CALL XMTCTL		;SEND THE START MESSAGE
	RET			;FAILED - WE'LL TRY AGAIN LATER
	RET
	SUBTTL	DDCMP TRANSMITTER -- REP MESSAGE

;HERE TO CHECK IF WE NEED TO SEND A REP MESSAGE
REPCHK:	SETZRO DDXRP		;CLEAR INDICATOR
	LOAD T2,DDREPC		;GET REP COUNTER
	LOAD T1,DDSTA		;GET STATE FOR REPHGH
	AOS T2			;MAKE IT LARGER
	CAILE T2,REPMAX		;IS THIS STILL OK ?
	JRST REPHGH		;DROP LINE
	STOR T2,DDREPC		;SAVE UPDATED REP COUNTER
	MOVEI T1,TIMREP		;HOW LONG TO WAIT UNTIL WE SEND ANOTHER REP
	STOR T1,DDTIM		;RESET TIMER
	MOVE T1,REPMSG		;GET PROTOTYPE REP MESSAGE
	LOAD T2,DDHMA		;HIGHEST MESSAGE ACKED
	SKIPE PGDOMQ(P4)	;ANY MESSAGES IN QUEUE ?
	TLOA T2,MAXOUT(T2)	;HIGHEST ACKED PLUS MAX SENT
				; IF NUMBER WRAPS IS OK CUZ OF A0
	MOVSS T2		;HIGHEST ACKED IS HIGHEST SENT
	CALL XMTCTL		;SEND THE REP MESSAGE
	RET
	RET

;HERE IF REP TIMER GOES TOO HIGH
REPHGH:	HRRZ T2,PGKDPN(P1)	;GET DDCMP LINE NUMBER
	CAIN T1,STARUN		;WERE WE RUNNING ?
	 BUG (DDCTIM,<<T2,D>>) ;TELL OPER LINE TIMED OUT
	MOVEI T1,STASTR		;SEND STARTS AGAIN
	CALL DEDLIN		;DECLARE LINE DOWN
	RET			;DISMISS
	SUBTTL	DDCMP TRANSMITTER -- ACK MESSAGE

XMTACK:	LOAD T1,DDNCD		;GET NAK CODE PENDING
	JUMPN T1,XMTNAK		;IF THERE IS ONE SEND IT INSTEAD
	SETONE DDXAK		;WANT TO SEND AN ACK
XMTAK3:	SKIPE PGSTAL(P1)	;MULTIDROP?
	JRST XMTAK4		;YUP, TRY TO SEND THE ACK
	SKIPN PGXBD1(P1)	;IS FIRST BUFFER BUSY ?
	SKIPE PGXBD2(P1)	;OR IS THE 2ND BUFFER BUSY ?
	RET			;DON'T SEND ACK YET
XMTAK4:	OPSTR <SKIPN>,DDXAK	;DO WE WANT TO SEND AN ACK ?
	RET			;NOT NOW
	LOAD T1,DDRMN		;HIGHEST MESSAGE WE RECEIVED
	LSH T1,^D8		;POSITION FOR MESSAGE
	IOR T1,ACKMSG		;GET PROTOTYPE ACK MESSAGE
	MOVE T2,ACKMSG+1	;GET REST OF PROTOTYPE MESSAGE
	CALL XMTCTL		;SEND THE MESSAGE
	RET			;FAILED
	SETZRO DDXAK		;HAVE SENT ACK NOW
	RET
	SUBTTL	DDCMP TRANSMITTER -- NAK MESSAGE

; CALL	MOVEI T1,<NAK REASON CODE>
XMTNAK:	STOR T1,DDNCD		;SAVE NAK REASON IN CASE NEED TO SEND LATER
	LOAD T2,DDRMN		;HIGHEST MESSAGE WE RECEIVED
	LSH T2,^D8		;POSITION NUMBER
	IOR T1,T2		;PUT FOLLOWING REASON FOR NAK
	IOR T1,NAKMSG		;GET PROTOTYPE NAK MESSAGE
	MOVE T2,NAKMSG+1	;GET REST OF PROTOTYPE NAK MESSAGE
	CALL XMTCTL		;SEND THE MESSAGE
	RET			;FAILED
	LOAD T1,DDNCD		;GET NAK CODE
	move t2,naktbl(t1)	;form table offset
	addi t2,pgnxnk(p1)	;point to nak counter
	AOS (T2)		;COUNT NAKS SENT
	SETZRO DDNCD		;HAVE SENT NAK NOW
	RET
	SUBTTL	DDCMP TRANSMITTER -- CONTROL MESSAGE

XMTCTL:	MOVEI T3,PGXBD1(P1)	;ASSUME 1ST XMIT BUFFER DESCRIPTOR LIST
	SKIPE @T3		;IS IT FREE ?
	MOVEI T3,PGXBD2(P1)	;NOT FREE ... TRY 2ND
	SKIPE @T3		;IS IT FREE ?
	RET			;CAN'T DO IT NOW ... RETURN TO CALLER
	LOAD T4,DDDRP		;GET DROP#
	DPB T4,[POINT 8,T2,9]	;PUT IT IN MESSAGE
	LOAD T4,DDSEL		;GET SELECT FLAG
	JUMPN T4,[ TRO T1,SELECT!QSYNC  ;YES,PUT IT IN MESSAGE
		   SETZRO DDSEL   ;SENT IT NOW
		   JRST .+1 ]   ;CONTINUE
	DMOVEM T1,PGXMS1-PGXBD1(T3) ;PUT MESSAGE IN BUFFER

	HRLZI T1,PGXMS1-PGXBD1(T3) ;ADDRESS OF BUFFER
	TLZ T1,777000		;MAKE ADR ON PAGE
	LSH T1,2		;MAKE PDP11 ADR IN LH
	ADD T1,PGUBAD(P1)	;MAKE ABSOLUTE PDP11 ADR
	HRRI T1,^D6		;BUFFER IS 6 BYTES LONG
	MOVSI T2,BDLLDS!BDLRSY!BDLSOM!BDLEOM ;COMPLETE MESSAGE
	TLZE T1,400000		;CHECK UNIBUS ADR
	TLO T2,004000		;PUT IN STATUS REG
	TLZE T1,200000		;CHECK UNIBUS ADR
	TLO T2,002000		;PUT IN STATUS REG
	DMOVEM T1,(T3)		;SAVE BUFFER DESCRIPTOR LIST

	LSH T2,4-^D18		;POSITION MEMORY EXTENSION BITS
	ANDI T2,140000		;LEAVE ONLY MEMORY EXTENSION BITS
	TRO T2,BFRENB		;SET ENABLE
	HLL T2,T1		;COPY BUFFER ADR
	SUB T2,[4*<PGXMS1-PGXBD1>,,0]	;POINT TO DESCRIPTOR
	HRRZ T1,PGKDPN(P1)	;COPY LINE NUMBER
	LSH T1,^D8		;POSITION
	IORI T1,BFADIN		;TYPE OF COMMAND
	CALL KMCINP		;GIVE BUFFER DESCRIPTOR LIST TO KMC11
	RETSKP
	SUBTTL	DDCMP TRANSMITTER -- DATA MESSAGES

;HERE TO CHECK POSSIBILITY OF SENDING A DATA MESSAGE
; CALLED AT INTERRUPT LEVEL OR WITH PIOFF
XMTDAT:	HLRZ T1,PGDOMQ(P4)	;GET ADR OF FIRST MESSAGE IN QUEUE
	SKIPE T2,PGDLMX(P4)	;GET ADR OF LAST MESSAGE SENT
	HLRZ T1,MBKLNK(T2)	;GET ADR OF NEXT MESSAGE IN QUEUE
	JUMPE T1,XMTAK3		;IN CASE NONE TO SEND NOW
	LOAD T3,DDHMA		;GET HIGHEST MESSAGE NUMBER ACKED
	SKIPN PGDLMX(P4)	;IS THIS FIRST MSG ?
	JRST XMTDT2		;YES
	LOAD T2,DDHXM		;HIGHEST MESSAGE NUMBER SENT
	SUB T2,T3		;MAKE DIFFERENCE
	SKIPGE T2		;DID NUMBERS WRAP AROUND ?
	MOVEI T2,400(T2)	;YES SO ADJUST
	CAIL T2,MAXOUT		;DO WE HAVE ENOUGH MESSAGES IN PIPE ?
	JRST XMTAK3		;DON'T SEND TOO MANY
XMTDT2:	MOVEI T4,PGXBD1(P1)	;ASSUME 1ST XMIT BUFFER DESCRIPTOR LIST
	SKIPE @T4		;IS IT FREE ?
	MOVEI T4,PGXBD2(P1)	;TRY 2ND XMIT BUFFER DESCRIPTOR LIST
	SKIPE @T4		;IS IT FREE ?
	RET			;WILL TRY AGAIN LATER
	SETZRO DDXAK		;DON'T NEED A EXPLICIT ACK NOW
	HLRZ P2,MBKLNK(T1)	;GET LINK
	JUMPN P2,XMTDT4		;LAST MESSAGE
	HRRZ T2,PGOLST(P4)	;GET FORWARD STATION THREAD
	SKIPE T2		;IS THIS A RE-XMIT TO IDLE LINE?
	CAMN T2,P4		;IS THIS THE LAST MESSAGE FOR LINE?
	JRST [SETZM PGLOUQ(P1)	;YES,MARK QUEUE EMPTY 
	      JRST XMTDT3]
	HLRZ P3,PGOLST(P4)	;GET BACK THREAD
	HRRM P3,PGOLST(T2)	;UPDATE FORWARD STATION
	HRLM T2,PGOLST(P3)	;UPDATE BACK STATION
	HRRZ P5,PGLOUQ(P1)	;GET HEAD OF QUEUE
	CAMN P5,P4		;WAS THIS THE HEAD
	HRRM T2,PGLOUQ(P1)	;YES,UPDATE IT
	HLRZ P5,PGLOUQ(P1)	;GET THE TAIL
	CAMN P5,P4		;WAS THIS THE TAIL?
	HRLM P3,PGLOUQ(P1)	;YES,UPDATE IT
XMTDT3:	SETZM PGOLST(P4)	;CLEAR THE ENTRY
XMTDT4:	SKIPN PGDLMX(P4)	;IS THIS FIRST MESSAGE IN QUEUE ?
	STOR T3,DDHXM		;1ST MSG IN QUEUE SO RESET MSG NUMBER
	HRRZM T1,PGDLMX(P4)	;REMEMBER ADR OF LAST MESSAGE SENT
	HRRZ T3,MBKLEN(T1)	;GET LENGTH (BYTES) OF MESSAGE
	HRRZ T2,T3		;COPY COUNT
	LSH T2,-^D8		;LEAVE HIGH ORDER BITS OF COUNT
	HRLI T2,SOH		;BEGIN DATAMESSAGE HEADER
	DPB T3,[POINT 8,T2,9]	;PUT REST OF COUNT IN
	LOAD T3,DDRMN		;HIGHEST MESSAGE NUMBER RECEIVED
	LSH T3,^D8		;POSITION
	IOR T2,T3		;BYTE(18)SOH+CNT*400,CNT+R*400
	LOAD P2,DDSEL		;GET SELECT FLAG
	JUMPN P2,[ TRO T2,SELECT!QSYNC  ;YES,PUT IT IN MESSAGE
		   SETZRO DDSEL   ;SENT IT NOW
		   JRST .+1 ]   ;CONTINUE
	MOVEM T2,PGXMS1-PGXBD1(T4) ;SAVE FIRST HALF OF MSG HEADER
	LOAD T3,DDHXM		;LAST MESSAGE SENT
	AOS T3			;MAKES NEW MSG NUMBER
	STOR T3,DDHXM		;REMEMER WE SENT IT
	LOAD T2,DDDRP		;GET DROP#
	DPB T2,[POINT 8,T3,27]	;ADD IT TO MESSAGE
	HRLZM T3,PGXMS1+1-PGXBD1(T4) ;SAVE REST OF MSG HEADER
	HRRZ T1,PGDLMX(P4)	;GET ADR OF MESSAGE BLOCK AGAIN
	HRRZ T2,MBKLEN(T1)	;GET LENGTH OF MESSAGE (BYTES)
	HRLZ T1,MBKLNK(T1)	;GET ADR OF MESSAGE
	HRRI T1,PGXMS1+2-PGXBD1(T4);?}HERE WERE GOING TO PUT MESSAGE
	MOVEI T2,3(T2)		;PREPARE TO ROUND
	LSH T2,-2		;CONVERT BYTES TO WORDS
	ADDI T2,(T1)		;LAST ADR IN MESSAGE
	BLT T1,(T2)		;COPY DATA

	HRLZI T1,PGXMS1-PGXBD1(T4) ;ADR OF BUFFER
	TLZ T1,777000		;MAKE RELATIVE TO START OF PAGE
	LSH T1,2		;MAKE IT A BYTE ADR
	ADD T1,PGUBAD(P1)	;MAKE AN 11 ADR
	HRRI T1,6		;BYTE COUNTE FOR HEADER
	MOVSI T2,BDLRSY!BDLEOM!BDLSOM	;FLAGS
	TLZE T1,400000		;CHECK UNIBUS ADR BITS
	TLO T2,004000		;INCLUDE IN STATUS
	TLZE T1,200000		;CHECK UNIBUS ADR BITS
	TLO T2,002000		;INCLUDE IN STATUS
	HLR T2,T1		;COPY ADR OF HEADER
	ADDI T2,10		;MAKES ADR OF DATA
	HRR T3,PGDLMX(P4)	;GET ADR OF MESSAGE AGAIN
	HRL T3,MBKLEN(T3)	;GET DATA COUNT
	HLR T3,T2		;COPY FLAGS
	TRZ T3,BDLRSY		;DON'T RESYNC
	TRO T3,BDLLDS		;LAST SEGMENT NOW
	DMOVEM T1,(T4)		;SAVE FIRST 2 WORDS OF BUFFER DESCRIPTOR LIST
	MOVEM T3,2(T4)		;SAVE SECOND BUFFER DESCRIPTOR

	LSH T2,4-^D18		;POSITION MEMORY EXTENSION BITS
	ANDI T2,140000		;LEAVE ONLY MEMORY EXTENSION BITS
	TRO T2,BFRENB		;SET ENABLE
	HLL T2,T1		;COPY BUFFER ADR
	SUB T2,[4*<PGXMS1-PGXBD1>,,0]	;POINT TO DESCRIPTOR
	HRRZ T1,PGKDPN(P1)	;COPY LINE NUMBER
	LSH T1,^D8		;POSITION
	IORI T1,BFADIN		;TYPE OF COMMAND
	CALL KMCINP		;GIVE BUFFER DESCRIPTOR LIST TO KMC11
	RET			;DONE
	SUBTTL	HERE TO ENABLE RECEIVER

; CALL	MOVEI T3,PGRBD1(OR PGRBD2)(P1)
RCVENB:	SETOM PGRMS1-PGRBD1(T3)	;DEBUGGIN AID
	SETOM PGRMS1+1-PGRBD1(T3) ;DITTO
	HRLZI T1,PGRMS1-PGRBD1(T3) ;ADR OF BUFFER
	TLZ T1,777000		;MAKE ADR RELATIVE TO PAGE
	LSH T1,2		;CONVERT TO BYTE ADR
	ADD T1,PGUBAD(P1)	;MAKES RIGHT UNIBUS ADDR
	HRRI T1,600		;LENGTH OF BUFFER
	MOVSI T2,BDLLDS
	TLZE T1,400000		;CHECK UNIBUS ADR
	TLO T2,004000		;PUT IN STATUS REG
	TLZE T1,200000		;CHECK UNIBUS ADR
	TLO T2,002000		;PUT IN STATUS REG
	DMOVEM T1,(T3)		;SAVE BUFFER DESCRIPTOR LIST

	LSH T2,4-^D18		;COPY BUFFER ADR BITS 17 & 16
	ANDI T2,140000		;STRIP EXTRA BITS
	IORI T2,BFRENB		;ENABLE BUFFER
	HLL T2,T1		;COPY BUFFER ADR
	SUB T2,[4*<PGRMS1-PGRBD1>,,0] ;MAKE ADR OF BUFFER DESCRIPTOR LIST
	HRRZ T1,PGKDPN(P1)	;COPY LINE NUMBER
	LSH T1,^D8		;POSITION LINE NUMBER
	IORI T1,BFADIN!KMCIOT	;TYPE OF REQUEST
	CALL KMCINP		;GIVE THIS TO THE KMC11
	RET
SUBTTL	TRANSMIT MOP MESSAGE

;		T1/0,,line #
;		t2/byte pointer to buffer
;		t3/data length in bytes
;		F/0,,POST ROUTINE




XMTMOP:				;
	HRRM	F,PGMXHD+1(P1)	;FOR INTERRUPT ROUTINES
	STOR	T3,MPBLEN	;SAVE THE BUFFER LENGTH
XMTMP0:	MOVEI	T4,PGXBD1(P1)	;1ST SMIT BUFFER DESCRIPTOR LIST
	SKIPE	@T4		;IS IT FREE?
	MOVEI	T4,PGXBD2(P1)	;2ND XMIT BUFFER DESCRIPTOR LIST
	SKIPE	@T4		;IS IT FREE?
	 RET			;NO, LOSE. !!!THIS CANNOT HAPPEN FOR MOP!!!
	STOR	T2,MPBPTR	;STORE NOW THAT WE'RE REALLY GOING TO GO
	PUSH	P,T2		;SAVE T2
	HRRZ	T2,T3		;MOP MSG LENGTH IN BYTES
	LSH	T2,-^D8		;LEAVE ONLY HIGH ORDER BITS
	HRLI	T2,DLE		;PUT IN MAINTENANCE MSG ID
	DPB	T3,[POINT 8,T2,9] ;PUT IN LOWER ORDER 8 BITS OF COUNT
	TRO	T2,SELECT!QSYNC	;NECESSARY FOR MAINTENANCE MSGS.
	MOVEM	T2,PGXMS1-PGXBD1(T4) ;STORE 1ST HALF OF MSG HEADER
	SETZ	T2,		;
	LOAD	T2,DDDRP	;GET THE STATION ADDRESS
	LSH	T2,^D8		;POSITION TO RIGHT PLACE
	HRLZM	T2,PGXMS1+1-PGXBD1(T4) ;STORE REST OF HEADER IN MSG
	POP	P,T1
	HRLZS	T1		;GET ADDRESS IN LH
	HRRI	T1,PGXMS1+2-PGXBD1(T4) ;DATA PART OF MESSAGE GOES HERE
	MOVEI	T2,3(T3)	;BYTE COUNT ROUNDED UP
	LSH	T2,-2		;BYTES TO WORDS
	ADDI	T2,(T1)		;LAST ADDRESS FOR THE BLT
	BLT	T1,(T2)		;BLT THE DATA INTO MESSAGE
	HRLZI T1,PGXMS1-PGXBD1(T4) ;ADR OF BUFFER
	TLZ T1,777000		;MAKE RELATIVE TO START OF PAGE
	LSH T1,2		;MAKE IT A BYTE ADR
	ADD T1,PGUBAD(P1)	;MAKE AN 11 ADR
	HRRI T1,6		;BYTE COUNTE FOR HEADER
	MOVSI T2,BDLRSY!BDLEOM!BDLSOM	;FLAGS
	TLZE T1,400000		;CHECK UNIBUS ADR BITS
	TLO T2,004000		;INCLUDE IN STATUS
	TLZE T1,200000		;CHECK UNIBUS ADR BITS
	TLO T2,002000		;INCLUDE IN STATUS
	HLR T2,T1		;COPY ADR OF HEADER
	ADDI T2,10		;MAKES ADR OF DATA
	HRLS	T3		;GET BYTE COUNT IN LH
	HLR T3,T2		;COPY FLAGS
	TRZ T3,BDLRSY		;DON'T RESYNC
	TRO T3,BDLLDS		;LAST SEGMENT NOW
	DMOVEM T1,(T4)		;SAVE FIRST 2 WORDS OF BUFFER DESCRIPTOR LIST
	MOVEM T3,2(T4)		;SAVE SECOND BUFFER DESCRIPTOR

	LSH T2,4-^D18		;POSITION MEMORY EXTENSION BITS
	ANDI T2,140000		;LEAVE ONLY MEMORY EXTENSION BITS
	TRO T2,BFRENB		;SET ENABLE
	HLL T2,T1		;COPY BUFFER ADR
	SUB T2,[4*<PGXMS1-PGXBD1>,,0]	;POINT TO DESCRIPTOR
	HRRZ T1,PGKDPN(P1)	;COPY LINE NUMBER
	LSH T1,^D8		;POSITION
	IORI T1,BFADIN		;TYPE OF COMMAND
	CALL KMCINP		;GIVE BUFFER DESCRIPTOR LIST TO KMC11
	HRLZI	T1,MPERR	;RESET TIME-OUT ERROR FLAG
	ANDCAM	T1,PGMSTS(P1)
	MOVEI	T1,PRITMO	;SPECIAL TIMEOUT DURING PRIMARY STATE
	LOAD	T2,MOPSTS	;GET THE MOP STATUS
	CAIE	T2,MPPRI	;IF IN PRIMARY USE LONGER TIMEOUT
	MOVEI	T1,MOPTMO	;USE NORMAL TIMEOUT
	STOR	T1,MOPTMR	;START THE TIMER
	RETSKP			;DONE
subttl	RECEIVE A MOP MESSAGE


RCVMOP:
	LOAD	T1,DDSTA	;GET THE LINE STATUS
	CAIE	T1,STAMAI	;IS IT IN MAINTENANCE MODE?
	 JRST	RCVFLU		;NO, FLUSH AND IGNORE THE MESSAGE
	SKIPN	PGMXHD(P1)	;ARE WE EXPECTING THIS MESSAGE?
	 JRST	RCVFLU		;NO, IGNORE THE MESSAGE
	SKIPL	PGMSTS(P1)	;IGNORE INPUT IF ERROR ALREADY DETECTED
	SKIPE	PGMRHD(P1)	;IS THERE ALREADY A MSG BEING PROCESSED
	 JRST	RCVFLU		;YES, DON'T ACCEPT ANY MORE.
	MOVE T1,PGRMS1-PGRBD1(P2) ;GET DDCMP HEADER AGAIN
	ROT T1,^D8+2		;PUT LOW ORDER 8 BITS OF COUNT IN RH
	MOVE T2,T1		;COPY HIGH ORDER BITS
	ANDI T1,377		;LEAVE ONLY LOW ORDER BITS
	LSH T2,-2		;POSITION HIGH ORDER BITS
	ANDI T2,77*400		;STRIP EXTRA BITS
	IORB T1,T2		;LEAVES COUNT IN RH OF T1 & T2
	MOVNI P3,(T1)		;MAKE NEGATIVE COUNT AND PREPARE TO ROUND
	LSH P3,^D16		;ROUND TO NUMBER OF WORDS
	CALL MOPSPC		;GET SPACE FOR MOP MESSAGE
	 JRST RCVFLU 
	PUSH	P,T1		;SAVE ADDRESS OF BUFFER
	HRRI P3,PGRMS1+1-PGRBD1(P2) ;FINISH AOBJN POINTER TO INPUT
	HRRZI	P5,-1(T1)	;WHERE TO PUT SHUFFLED MESSAGE
RCVMP3:	HRLZ T1,(P3)		;GET NEXT 16 BITS TO COPY
	HLRZ T2,1(P3)		;GET NEXT 16 BITS TO COPY
	DMOVE T3,T1		;GET ANOTHER COPY OF EACH
	LSH T1,2+^D8		;LEAVE ONLY FIRST BYTE
	TLZ T3,600377		;STRIP BITS FROM 2ND BYTE
	LSH T3,2-^D8		;POSITION BYTE
	IOR T1,T3		;INCLUDE WITH FIRST
	ANDI T2,377		;STRIP EXTRA BITS FROM FIRST BYTE
	LSH T2,4+^D8		;POSITION
	IOR T1,T2		;INCLUDE 3RD BYTE WITH 1ST AND 2ND
	ANDI T4,377*400		;STRIP EXTRA BITS FROM 4TH BYTE
	LSH T4,4-^D8		;POSITION 4TH BYTE
	IOR T1,T4		;INCLUDE WITH 1ST 3 BYTES
	PUSH	P5,T1		;SHUFFLED WORD
	AOBJN P3,RCVMP3		;LOOP BACK FOR REST OF MESSAGE
	POP	P,P2		;GET BUFFER ADDRESS BACK
	CALL MOPPST		; POST
	JRST	RCVFLU		;THEN FLUSH THE MESSAGE
SUBTTL	MOP INTERFACE SERVICE ROUTINES

MOPSPC:	STOR	T2,MPRLEN	;STORE LENGTH OF MESSAGE
	MOVEI	T1,3(T2)	;PREPARE TO ROUND
	LSH	T1,-2
	HRLI	T1,.RESP1	;PRIORITY 1
	MOVE	T2,[RS%SE0+.RESNP] ;GET FROM NET POOL
	CALL ASGRES
	 RET			;CAN'T
	HRLI	T1,(<POINT 8,>)	;MAKE A POINTER
	STOR	T1,MPRPTR	; SAVE IN DATABASE
	RETSKP			;ADDRESS OF BUFFER IN T1

MOPQ:	HRRZM	P2,PGLINQ(P1)	;PUT INTO QUEUE
	RETSKP

MOPPST:	MOVEI	T1,0		;RESET TIMER SO THAT
	STOR	T1,MOPTMR	;TIMEOUT WILL NOT OCCUR
	CALL	RLXMOP		;RELEASE TRANSMIT BUFFER
	LOAD	T3,MPPOST		;GET POST ROUTINES ADDRESS
	SKIPN	T3		;IS THERE A SPECIAL POST ROUTINE?
	RET			;NO
	CALL	(T3)		;CALL THE POST ROUTINE
	 JRST	[HRLZI	T1,MPERR	;INDICATE TO JSYS LEVEL AN ERROR
		 IORM	T1,PGMSTS(P1)
		 JRST	.+1	]
	RET

;ROUTINE TO RELEASE A RESIDENT BUFFER FOR XMITTING OF MOP MSGS
RLXMOP:	MOVEI	T1,0
	EXCH	T1,PGMXHD(P1)	;NO LONGER EXPECTING INPUT
	JUMPE	T1,R		;RETURN IF NONE
	HRRZS	T1		;FOR RELRES
	LOAD	T2,MPFLGS	;GET FLAGS
	TRNN	T2,MPSHRT	;SHORT MESSAGE?
	CALL	RELRES		;RELEASE THE RESIDENT BUFFER
	RET
;ROUTINE TO RELEASE A RESIDENT BUFFER FOR RECV OF MOP MSGS
RELMOP:	PIOFF
	MOVEI	T1,0
	EXCH	T1,PGMRHD(P1)	;ZERO POINTER TO BUFFER
	HRRZS	T1		;FOR RELRES
	SKIPE	T1		;NOTHING TO RELEASE
	CALL RELRES		;NO, RELEASE RESIDENT BUFFER
	PION
	RET
;ONCE-A-SECOND ROUTINE FOR MOP

MOPSEC:
	LOAD	T1,MOPTMR
	JUMPE	T1,R		;TIMER NOT RUNNING; DON'T UPDATE
	SOS	T1		;COUNT DOWN MOP TIMES
	STOR	T1,MOPTMR	;PUT BACK UPDATED
	SKIPE	T1		;HAVE WE TIMED OUT?
	RET			;NO, DON'T DO ANYTHING MORE
	HRLZI	T1,MPERR	;INDICATE A TIME-OUT ERROR
	IORM	T1,PGMSTS(P1)	;IN STATUS WORD
	CALL	RLXMOP		;RELEASE BUFFER SINCE NO LONGER EXPECT INPUT
	RET

;SCHEDULER TEST TO SEE IF SOME MOP INPUT HAS COME IN

MPRTST:	SKIPE	PGMRHD(T1)
	JRST	1(4)		;THERE IS ONE
	MOVE	T1,PGMSTS(T1)	;CHECK ERROR STATUS
	TLNE	T1,MPERR	;TEST FOR TIMEOUT
	JRST	1(4)		;THERE IS AN ERROR, RE-SCHEDULE PROCESS
	JRST	0(4)		;THERE IS NEITHER INPUT NOR ERROR CONDITION
MOPDNE:
	MOVEI	T1,PRITMO	;SPECIAL TIMEOUT DURING PRIMARY STAT
	LOAD	T2,MOPSTS	;GET THE MOP STATUS
	CAIE	T2,MPPRI	;IF IN PRIMARY USE LONGER TIMEOUT
	MOVEI	T1,MOPTMO	;TIME-OUT PERIOD
	STOR	T1,MOPTMR	;START COUNT-DOWN
	JRST	KMVCB9
;ROUTINE TO SHUFFLE THE DATA FOR THE KMC

;INPUTS ARE:
;		T2/BYTE POINTER TO THE DATA
;		T3/ NUMBER OF BYTES IN THE BUFFER

SECSHF:
	PUSH	P,T3		;PRESERVE T3
	MOVNI	T4,(T3)		;NEGATE AND PREPARE FOR ROUNDING
	LSH	T4,^D16		;ROUND AND PUT IN LH OF REG
	HRR	T4,T2		;GET ADR OF MESSAGE
	PUSH	P,T2		;SAVE ADDRESS OF MESSAGE
	MOVE	P3,T2		;GET BYTE POINTER
	ROT	P3,6		;POSITION POSITION FIELD
	ANDI	P3,77		;GET POSITION OF 1ST BYTE IN WORD
	MOVNS	P3		;MAKE NEGATIVE
	
SECSH0:	MOVE	T1,(T4)		;GET NEXT WORD FROM BUFFER
	MOVE	T2,1(T4)	;AND NEXT
	LSH	T1,^D36(P3)	;POSITION
	LSH	T2,4(P3)	;POSITION
	IOR	T1,T2		;AND COMBINE
	MOVE T2,T1		;COPY BYTES
	LSH	T1,-^D20	;POSITION
	LSH	T2,-4		;POSITION
	ANDI	T1,177777
	ANDI	T2,177777
	MOVSS	T1
	IOR	T1,T2
	MOVEM T1,(T4)		;SAVE SHUFFLED WORD
	AOBJN T4,SECSH0		;LOOP BACK FOR REST OF DATA
	POP	P,T2		;RESTORE T2
	POP	P,T3
	RET
SHFFLE:
	PUSH	P,T3		;PRESERVE T3
	MOVNI	T4,(T3)		;NEGATE AND PREPARE FOR ROUNDING
	LSH	T4,^D16		;ROUND AND PUT IN LH OF REG
	HRR	T4,T2		;GET ADR OF MESSAGE
	PUSH	P,T2		;SAVE ADDRESS OF MESSAGE
SHFFL0:	MOVE T1,(T4)		;GET NEXT 4 BYTES
	MOVE T2,T1		;COPY BYTES
	MOVE T3,T1		;COPY AGAIN
	LSH T1,-2-^D8		;POSITION BYTE 1
	LSH T2,-2+^D8		;POSITION BYTE 2
	TLZ T2,600377		;STRIP EXTRA BITS
	IOR T1,T2		;INCLUDE WITH BYTE 1
	LSH T3,-4-^D8		;POSITION BYTE 3
	ANDI T3,377
	HRR T1,T3		;INCLUDE BYTE 3 WITH 1ST AND 2ND
	LSH T2,-2		;POSITION BYTE 4
	ANDI T2,377*400		;MASK OFF EXTRA BITS
	IOR T1,T2		;INCLUDE WITH FIRST 3 BYTES
	MOVEM T1,(T4)		;SAVE SHUFFLED WORD
	AOBJN T4,SHFFL0		;LOOP BACK FOR REST OF DATA
	POP	P,T2
	POP	P,T3
	RET

	TNXEND
	END