Google
 

Trailing-Edge - PDP-10 Archives - tops10_704_monitoranf_bb-x140c-sb - 10,7/anf10/dncomm.p11
There are 3 other files named dncomm.p11 in the archive. Click here to see a list.
.SBTTL	DNCOMM - MAIN LOOP AND CLOCK ROUTINES   23-OCT-87

;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
; 1976,1979,1980,1981,1984,1987,1988.
;ALL RIGHTS RESERVED.
;
;
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
;ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH LICENSE AND WITH THE
;INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR ANY  OTHER
;COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
;OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF THE  SOFTWARE  IS  HEREBY
;TRANSFERRED.
;
;THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT  NOTICE
;AND  SHOULD  NOT  BE  CONSTRUED  AS A COMMITMENT BY DIGITAL EQUIPMENT
;CORPORATION.
;
;DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY  OF  ITS
;SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.

VRCOMM=066			;FILE EDIT NUMBER

.SBTTL	PARITY INTERRUPT, EMT, TRAP, ETC.

.IF GE <PDP11-34>
;HERE ON A PARITY CONTROL INTERRUPT

MP.INT:	MOV	MP.REG,#0	;SAVE FOR INTERESTED PARTIES
.IF NE FT.HLP
	RESET
	SAVE	<R0,R1>
	JSR	R0,CKTCRL
	.ASCIZ	\MEMORY PARITY ERROR	MP.REG=\
	.EVEN
	MOV	MP.INT+4,R0
	JSR	PC,CKTOCT
	JSR	PC,CM.INT
.ENDC;.IF NE FT.HLP
	STOPCD	MEM
.ENDC;.IF GE <PDP11-34>



;HERE ON A BUS TIMEOUT

NXMINT:	TST	TRPPC		;SOMEBODY REQUESTING TRAP INTERCEPT?
	BEQ	100$		;NO, GO DIE IN PEACE
	MOV	(P)+,TRPDPC	;YES, REMEMBER TRAP PC AND
	MOV	(P)+,TRPDPS	; PS WORDS IN CASE ANYONE CARES
	MOV	TRPSP,P		;RESET THE STACK TO KNOWN STATE
	MOV	4(P),6(P)	;CONCOCT AN RTI BLOCK
	MOV	TRPPC,4(P)	; TO RESTORE PI ET AL ON INTERCEPT
	MOV	(P)+,TRPSP	;POP A LEVEL OF NXM INTERCEPTING
	MOV	(P)+,TRPPC	; . . .
	RTI			;INTERCEPT TRAP, RESETTING PI LEVELS ETC.

100$:
.IF NE FT.HLP
	SAVE	<R0,R1>
	JSR	R0,CKTCRL
	.ASCIZ	\BUS TRAP\
	.EVEN
	JSR	PC,CM.INT
.ENDC;.IF NE FT.HLP
	STOPCD	NXM			;DIE IN USUAL WAY
;HERE ON A ILLEGAL INSTRUCTION
ILSINT:
.IF NE FT.HLP
	SAVE	<R0,R1>
	JSR	R0,CKTCRL
	.ASCIZ	\ILL\
	.EVEN
	BR	ILSCOM
.ENDC;.IF NE FT.HLP
 

;HERE ON A BPT
BPTINT:					;DIE IN USUAL WAY
.IF NE FT.HLP
	SAVE	<R0,R1>
	JSR	R0,CKTCRL
	.ASCIZ	\BREAK POINT\
	.EVEN
	BR	ILSCOM
.ENDC;.IF NE FT.HLP


.IF EQ FT.TSK
;HERE ON A IOT INSTRUCTION
IOTINT:					;DIE IN USUAL WAY
.IF NE FT.HLP
	SAVE	<R0,R1>
	JSR	R0,CKTCRL
	.ASCIZ	/IOT/
	.EVEN
	BR	ILSCOM
.ENDC;.IF NE FT.HLP
.ENDC;.IF EQ FT.TSK
;HERE ON A EMT INSTRUCTION
EMTINT:					;DIE IN USUAL WAY
.IF NE FT.HLP
	SAVE	<R0,R1>
	JSR	R0,CKTCRL
	.ASCIZ	/EMT/
	.EVEN
	BR	ILSCOM
.ENDC;.IF NE FT.HLP

;HERE ON RANDOM INTERRUPT
ERRINT:					;DIE IN USUAL WAY
.IF NE FT.HLP
	SAVE	<R0,R1>
	JSR	R0,CKTCRL
	.ASCIZ	/FATAL ERROR/
	.EVEN
	BR	ILSCM0
ILSCOM:	JSR	R0,CKTSTR
	.ASCIZ	\ INSTRUCTION\
	.EVEN
ILSCM0:	JSR	PC,CM.INT
.ENDC;.IF NE FT.HLP

	STOPCD	ILS


.IF NE FT.HLP
CM.INT:	MOV	6(P),R0
	JSR	PC,CKTYPC	;TYPE " @PC=<VALUE><CR><LF>"
	RESTORE	<R0,R1>
	RTS	R0
.ENDC ;.IF NE FT.HLP
.IF NE FT.HLP
CKTYPC:				;TYPE " @PC=<VALUE><CR><LF>
	JSR	R0,CKTSTR
	.ASCIZ	\ @PC=\
	.EVEN
	JSR	PC,CKTOCT
	JSR	PC,CKCRLF
	RTS	PC
.ENDC
;HERE ON A TRAP INSTRUCTION
Q=0	;OFFSET FOR PC ON STACK
TRPINT:	SUB	#2,(P)			;BACKUP TO TRAP INSTRUCTION

.IIF NE FTDL10,	MOV	@DL10AD,#0	;SAVE DL10 STATUS HERE
;	TWIDDLE	SW			;PUT SWICHES HERE
	MOV	%5,-(P)			;SAVE REGISTERS
	MOV	%4,-(P)
	MOV	%3,-(P)
	MOV	%2,-(P)
	MOV	%1,-(P)
	MOV	%0,-(P)
CRSPDL:	MOV	P,#0			;FOR THOSE WHO READ DUMPS
	Q=14			;OFFSET FOR PC HAS CHANGED
.IF NE DEBUG
.IF EQ FT.SLB
.IF NE NLINES
	MOV	#FRSTLB,J		;GET LINE BLOCK ADR FOR FIRST LINE
	BR	21$
20$:	MOV	LB.SLA(J),DQ		;GET SYNCHRONOUS LINE HDW ADR
	MOV	DQ,R0			;COPY ADDRESS OF DEVICE
	MOV	J,R1			;COPY LINE BLOCK ADDRESS
	ADD	#LB.CRS,R1		;POINT TO SAVE AREA
	MOV	(R0)+,(R1)+		;SAVE SYNCHRONOUS LINE HDW STATE
	MOV	(R0)+,(R1)+		;SAVE TRANSMITTER STATUS
	MOV	(R0)+,(R1)+
	MOV	(R0)+,(R1)+
.IF NE FTDQ11
	DQREGS	PRA
	MOV	6(DQ),(R1)+
	DQREGS	SRA
	MOV	6(DQ),(R1)+
	DQREGS	PTA
	MOV	6(DQ),(R1)+
	DQREGS	STA
	MOV	6(DQ),(R1)+
.ENDC;.IF NE FTDQ11
21$:	MOV	LB.LNK(J),J		;GET ADR OF NEXT LINE BLOCK
	BNE	20$
.ENDC;.IF NE NLINES
.ENDC;.IF EQ FT.SLB
.ENDC;.IF NE DEBUG

	CLR	R0		;HESITATE
27$:	SOB	R0,27$
	RESET

.IF NE FT.HLP
	JSR	R0,CKTCRL
	.ASCIZ	\TRAP\
	.EVEN
	MOVB	@Q(P),R0		;GET CODE IF ANY
	BEQ	30$
	JSR	PC,CKTBOC		;TYPE CODE AND BLANK
30$:
	MOV	Q(P),R0
	JSR	PC,CKTYPC	;TYPE " @PC=<VALUE><CR><LF>
.ENDC
.IIF NE FT.DTE,	JSR	PC,DTERLD	;ASK -10 TO RELOAD US
;THE PROGRAM ENTRY INTO THE M9301 ROM TAKES IN R0 THE ADDRESS
;    OF A FOUR WORD ARGUMENT BLOCK.  THE ARGUMENTS IN THIS BLOCK ARE
;    AS FOLLOWS.
;	1)  THIS IS THE SERIAL NUMBER OF THIS 11 (DEFAULT'S TO OUR
;	    NODE NUMBER FOR CONVENIENCE)
;	2)  THIS IS THE NODE NUMBER OF THE TEN THAT WE WANT TO BOOT
;	    US.  (ZERO MEANS ANY TEN)
;	3)  THIS IS THE NUMBER OF THE DQ-11 TO USE WHEN BOOTING
;	4)  THIS IS THE ADDRESS OF AN ASCIZ STRING TO PASS AS A
;	    COMMAND STRING TO NETLDR.  ZERO IMPLIES NO COMMAND STRING


;THE FOLLOWING MACRO BUILDS THE PARAMETER BLOCK FOR THE ROM.

.MACRO NETLDR S,N,L,TEXT
	.WORD	S
	.WORD	N
	.WORD	L
.IF NB <TEXT>
	.WORD	.+2
	.ASCIZ \TEXT\
	.EVEN
.IFF
	.WORD	0
.ENDC
.ENDM ;NETLDR

.IF NE FT.ROM
GO.ROM:	JSR	R0,ROMADR		;GO BOOT FROM THE PROM

    .IF NE FTNTLD			;IF THE USER SPECIFIED THE PARMS,
	LDCNFG				;THEN USE HIS CONFIG.
    .IFF				;OTHERWISE USE THE DEFAULT
	NETLDR	OURNNM,0,0		;SERIAL=OURNNM,NODE=0,DQ=0,NO TEXT.
    .ENDC
.ENDC; FT.ROM

.IIF NE FT.MOP,JMP	MOPDMP		;IF A DN22, GO USE MOP HACK

.IF EQ FT.MOP!FT.ROM			;IF NEITHER ROM OR MOP
	MOVB	@Q(P),R0		;GET STOPCD(IF ANY)
	BEQ	97$
.IF NE FTDL10
	BIT	#DL.PEN,@DL10AD		;IS PORT ENABLED ?
	BEQ	95$
	MOV	DL10AD,R1		;POINT INTO WINDOW
	MOV	R0,DL.STP(R1)		;SAVE STOP CODE FOR LOSER
.ENDC;.IF NE FTDL10
95$:	HALT
97$:	MOV	Q(P),R0			;GET TRAP ADR
	HALT
	JMP	BEGIN			;RESTART
.ENDC; FT.ROM!FT.MOP
;JMP HERE ON SOME IMPOSSIBLE ERRORS

SYSERR:	TRAP


.CKTTS
.SBTTL	TRAP INTERCEPT SET/CLEAR

;TRPST  --  SET UP FOR INTERCEPTION OF NXM ERRORS (ANYTHING THROUGH TRAP 4)
;CALL IS:
;
;	JSR	R0,TRPST
;		.WORD	ADR
;
;WHERE ADR IS THE INTERCEPT TRAP ADDRESS WHICH SHOULD GAIN CONTROL SHOULD
;A TRAP THROUGH 4 OCCUR.
;
;THE CALLER MUST NOT HAVE ANY DATA PUSHED ONTO THE STACK (HE MUST BE
;READY TO "RTS PC" TO HIS CALLER!!!
;
;YOU MAY NEST AS MANY CALLS TO TRPST AS THERE IS STACK SPACE (I.E., YOU
;DON'T HAVE TO WORRY ABOUT THE "TRAP" RESOURCE, IT IS RECURSIVE).
;
;THE TRAP INTERCEPT WILL BE AUTOMATICALLY CLEARED WHEN THE CALLER EXECUTES
;HIS "RTS PC".
;
;ON A TRAP, THE TRAP SERVICE ROUTINE IS ENTERED WITH THE STACK AND PI AT
;THE SAME LEVEL AS AT THE CALL TO TRPST (E.G., YOU MAY POINT THE TRAP
;ADDRESS AT THE ROUTINE'S "RTS PC", SEE DTEINI FOR AN EXAMPLE).
;
;THE CARRY BIT IS PRESERVED, ALL OTHER CONDITION CODE BITS ARE LOST.

TRPST:	MOV	@#PS,-(P)	;SAVE THE CURRENT PI/PROCESSOR STATUS
	MOV	TRPSP,-(P)	;SAVE THE OLD (CURRENT) STACK
	MOV	TRPPC,-(P)	; AND PC WORDS
	MOV	P,TRPSP		;SET THE NEW TRAP STACK
	MOV	(R0)+,TRPPC	; AND PC WORDS.
	MOV	R0,-(P)		;ADDRESS OF CALLER TO BE CALLED
	MOV	10(P),R0	;RESTORE R0 FOR CALLER
	JSR	PC,@(P)+	;AND CALL OUR CALLER

;HERE WHEN OUR CALLER HAS FINISHED AND "RTS PC"'ED BACK TO US TO CLEAR
;THE TRAP INTERCEPT

	MOV	(P)+,TRPPC	;RESTORE PREVIOUS LEVEL'S PC
	MOV	(P)+,TRPSP	; AND STACK WORDS
	BIT	(P)+,(P)+	;POP OFF TWO MORE JUNK WORDS
	RTS	PC		;RETURN TO CALLER'S CALLER
;TRPCL  --  UNDO A CALL TO TRPST
;CALL IS:
;
;	JSR	PC,TRPCL
;
;MUST BE CALLED AT SAME STACK LEVEL AS TRPST CALL.

TRPCL:	MOV	(P)+,10(P)	;FINAL RETURN ADDRESS
	BIT	(P)+,P		;POP OFF JUNK (TRPST JSR) WORD
	MOV	(P)+,TRPPC	;RESTORE PREVIOUS LEVEL'S PC
	MOV	(P)+,TRPSP	; AND STACK WORDS.
	BIT	(P)+,P		;POP OFF ANOTHER JUNK WORD
	RTS	PC		;AND RETURN
.SBTTL	POWER FAIL INTERRUPT

PWFINT:	TWIDDLE				;COUNT POWER FAIL TRAPS
	MOV	#PWFINU,PWFVEC		;ON POWER RESTART, RESTART US
	CLR	R0			;INITIALIZE SOB
	SOB	R0,.			;WAIT FOR POWER RESTART

;IF THE SOB FALLS THROUGH TO HERE (SEVERAL CLOCK TICKS LATER) THEN WE
;HAVE A SPURIOUS POWER FAIL CONDITION.

	TWIDDLE				;AN INTERESTING EVENT IN ITSELF
;	BR	PWFINU			;ASSUME POWER FAIL RESTART
.SBTTL	NORMAL STARTUP AND POWER FAIL RESTART

;HERE ON EITHER POWER FAIL RESTART, OR SUPRIOUS POWER FAIL INTERRUPT

PWFINU:	TWIDDLE				;COUNT POWER FAIL RESTARTS
	CLR	R0			;INIT FOR SOB LOOP
	SOB	R0,.			;WAIT FOR THINGS TO SETTLE DOWN

;NORMAL NODE STARTUP

BEGIN:	RESET				;CLEAR THE WORLD
	MOV	#PDL,P			;GET A GOOD STACK
	CLR	TRPPC			;NO TRAP INTERCEPT IN EFFECT
	MOV	#PWFINT,PWFVEC		;RESET POWER FAIL IN CASE POWER RESTART

.IF NE FT.87S+FT.D20
;THE FIRST TIME THROUGH HERE THE ROM HAS LEFT R1 POINTING TO THE
;STATUS REGISTER FOR THE DTE THAT LOADED US. SAVE THAT INFO FOR USE
;LATER ON. ON A POWER-FAIL RESTART, R1 WILL BE JUNK SO WE ASSUME
;THAT .PRDTE WILL STILL BE THE CORRECT DTE. IF NOT, THEN TENSEC (OR
;SOMEONE) WILL NOTICE AND CLEAR IT, FORCING TENSEC TO START SCANNING
;FOR AN EXTANT DTE. SIMILARLY, IF BOOTED VIA A SYNC LINE TENSEC WILL
;EVENTUALLY FIND A WORKING DTE (IF ANY EXIST). THE ONLY REAL REASON
;THIS CODE EXISTS IS TO FORCE THE -11 TO USE THE DTE FROM WHICH IT
;WAS LOADED ON THE OFF CHANCE THE -11 HAS MORE THAN ONE DTE.

	BIC	#TE.BNX-1,R1		;ADJUST TO START OF REGISTERS
	CMP	R1,#TE.BAS		;IS R1 POINTING TO A DTE?
	BLO	5$			;BELOW FIRST DTE, FORGET IT
	CMP	R1,#TE.BAS+<TE.NNN*TE.BNX>  ;IS R1 POINTING TO A DTE?
	BHIS	5$			;ABOVE LAST DTE, FORGET IT
	MOV	R1,.PRDTE		;VALID DTE, SAVE OUR LOADING DTE
	ADD	#TE.STW,R1		;OFFSET TO DTE STATUS REGISTER
	MOV	R1,.PRSTA		;SAVE DTE STATUS REG ADR ALSO
5$:
.ENDC;.IF NE FT.87S+FT.D20

	JSR	PC,CHK.11		;BE SURE HDW ALL HERE
	.WORD	MYNAME
RCOUNT:	TWIDDLE				;COUNT RESTARTS
	MOV	#NXMINT,NXMVEC		;SET BUS TRAP LOCATION
.SBTTL	INITIALIZATION CODE

;ENABLE THE MEMORY PARITY OPTION
.IF GE <PDP11-34>
MP.ARM:	MOV	#MP.ENB,MP.REG		;ARM PARITY OPTION
.ENDC;.IF GE <PDP11-34>

.IF NE FTDL10
09$:	BIT	#DL.PEN,@DL10AD		;IS DL10 PORT ENABLED ?
	BNE	09$			;IF SO WAIT FOR 10
.ENDC
	Z=ROMLOW&160000
.IF NE Z-160000	;IF ROM PROG IN READ/WRITE MEMORY - BETTER BE CAREFUL
	MOV	#ROMLOW,PHYLIM
.ENDC
;THE FOLLOWING ZEROES HIGH CORE FOR DUMPS
.IF NE FTCLEAR
	MOV	PRGEND,R0		;FIRST LOCATION TO ZERO
10$:	CLR	(R0)+			;CLEAR HIGH CORE
	CMP	R0,PHYLIM
	BNE	10$
.ENDC;.IF NE FTCLEAR
;INITIALIZE CHUNKS
	CLR	FRECNT			;NO CHUNKS YET
	CLR	LSTFRE			;NO CHUNKS YET
	MOV	PRGEND,R2		;ADR OF CHUNK
15$:	MOV	R2,R0			;COPY ADR OF CHUNK
	ADD	#CNKSIZ,R2		;MAKE ADR OF NEXT CHUNK
	CMP	R2,PHYLIM
	BHI	20$			;EXIT IF WE'RE AT THE END OF MEMORY
	JSR	PC,FRECNK		;FREE CHUNK
	BR	15$
20$:
	MOV	FRECNT,FREMAX

;INITIALIZE THE QUEUES
.MACRO	X	Q
	MOV	#Q'.QUE,Q'.PTR
	MOV	#Q'.QUE,Q'.TKR
.ENDM	X
	X	QI
	X	QO
	X	NC
.IIF NE,FT.DCP,	X	NS		;NSP QUEUE
.IIF NE DEVN,	X	DV
.IIF NE FTDL10,	CLR	T10QUE		;CLEAR TO-10 QUEUE POINTER
.IIF NE FT.DTE,	JSR	PC,DTEINI	;INIT DTE DATA BASE IF WE HAVE ONE
.IIF NE DMCN,	JSR	PC,DMCONC	;SET UP THE DMC-11 MESSAGE BUFFER POOL
;HERE TO INITIALIZE THE DDCMP LINES
INI.10:
.IF NE NTLINE
	.IF NE,FT.DCP
		.IIF NE FTDCP3!FTDCP4,	JSR PC,NSPINI	; CLEAR DCP DATABASE
	.ENDC
	MOV	#FRSTLB,J		;ADR OF FIRST BLOCK
	BR	13$
10$:	MOV	#<LB.SIZ-LB.ZER>/2,R0	;ESTABLISH COUNTER
	MOV	J,R1			;MAKE ADDR OF WORD TO ZERO
	ADD	#LB.ZER,R1
12$:	CLR	(R1)+
	SOB	R0,12$
	BIC	#^C<LS.MPT>,(J)		;VIRGIN LINE STATUS
	JSR	PC,DDCINI		;DO DDCMP INITIALIZATION
13$:	MOV	LB.LNK(J),J		;GET ADR OF NEXT BLOCK
	BNE	10$
.ENDC;.IF NE NTLINE

;INITIALIZE THE STATION CONTROL BLOCKS
	MOV	#<SEQLIM*2>,R0
20$:	CLRB	SQNTAB-1(R0)
	SOB	R0,20$
	MOV	#OURSCB,SB		;GET STATION BLOCK
30$:	JSR	PC,CLRSCB		;CLEAR REST OF BLOCK
	SB.ADV	30$			;CLEAR NEXT BLOCK ALSO
.IF NE FTDL10!FT.DTE
	CLR	TENSCB			;NO PATH TO THE TEN
.ENDC ;END .IF NE FTDL10!FT.DTE
	MOV	#OURSCB,SB		;OUR SCB ADR AGAIN
	BIS	#SBF.SQ!SBF.IC!SBF.IU!SF.HID,@SB	;FLAG BLOCK IN USE
	MOV	SB,SQNTAB		;1ST NONSEQUENTIAL NODE IS US
;INITIALIZE THE DEVICES
.IF NE DEVN
DDBINI:	MOV	FIRDDB,J		;GET FIRST DEVICE BLOCK
10$:	BIC	#DS.QUE!DS.ACT,@J	;CLRDDB WON'T HIT THESE BITS
.IF NE FT.TSK
	MOV	J,R0
	ADD	#DB.TSK,R0
	CLR	(R0)+			;AND WON'T GET THESE
	CLR	(R0)+
	CLR	(R0)+
	CLR	(R0)
.ENDC;.IF NE FT.TSK

	JSR	PC,CLRDDB		;CLEAN OUT DEVICE BLOCK

.IF NE FT.CTY!TTYN!RDAN
	BIT	#DS.TTY,@J		;WAS THIS A TTY ?
.IF NE FT.RDA
	BNE	14$			; YES
	BIT	#RDEASC,DB.RDT(J)	;ASCII RDX ?
.ENDC
	BEQ	90$			; NO

;INITIALIZE ASCII TTY AND RDA DEVICES

14$:	MOV	J,R0			;POINT TO BYTES TO CLEAR
	ADD	#DB.TZR,R0
	MOV	#DB.TSZ-DB.TZR,R1	;AND GET THERE NUMBER
11$:	CLRB	(R0)+			;AND CLEAR THEM
	SOB	R1,11$
	CLR	DB.TOB(J)		;NO TTY OUTPUT YET
	CLR	DB.TOB+2(J)
.IF NE FT.TSK
	MOV	#DB.KQU,DB.KPT(J)	;INITIALIZE KEYBOARD PUTER
	MOV	#DB.KQU,DB.KTK(J)	;INITIALIZE KEYBOARD TAKER
.ENDC;.IF NE FT.TSK
.IF NE FT.RDA
	BIT	#RDEASC,DB.RDT(J)	;ASCII RDX ?
	BNE	15$			; YES, DONT DO IT
.ENDC
	MOV	#RSTMSG,DB.STR(J)	;START UP MESSAGE
15$:
.IF NE FT.CTY
	CMP	J,#CTYDDB		;IS THIS CTY ?
	BEQ	44$			;IF SO DON'T INITIALIZE DL11
.ENDC;.IF NE FT.CTY
	MOV	DB.DHB(J),R3		;GET ADR OF DH/DZ11 BLOCK FOR LINE
	MOV	DB..LN(J),R2		;SET UP LINE # FOR DH/DZ.INI
.IF NE FT.RDA
	BIT	#DS.TTY,@J		;IS IT TTY?
	BEQ	67$			; NO
.ENDC

;ASCII TTY ONLY

.IF NE TTYN
	JINDEX	JMP,DB.TYP(J),R0,29$
29$:		.WORD	30$		; DH-11
		.WORD	31$		; DZ-11

30$:
.IF EQ TTYDHN
	TRAP				; NO DH TTYS!
.IFF
	SAVE	<#TTDHOU,#TTDHIN,DB.LCB(J)>
	JSR	PC,DH.INI		; INITIALIZE THE DH11 AND LCB
	BR	40$			; CONTINUE
.ENDC ;.IF EQ TTYDHN

31$:
.IF EQ TTYDZN
	TRAP				; DO DZ TTYS!
.IFF
	SAVE	<#TTDZOU,#TTDZIN,DB.LCB(J)>
	JSR	PC,DZ.INI
.ENDC ;.IF EQ TTYDZN
.ENDC ; TTYN

40$:	ADD	#6,P			; POP THE ARGS TO DH/DZ.INI

.IF NE FTDN11
	BITB	#40,DB.DVT(J)		;IS IT AUTO-DIAL LINE?
	BEQ	44$			;NO, CONTINUE
	BIC	#^CDNDISP,DB.DNS(J)	;CLEAR DIAL BIT & TIMER
	JSR	PC,DNADDR		;R1=DNTAB,R2=HDW
	BIC	#7,R2			;INITIALIZE
	MOV	#DN..ME,(R2)+		;SET MASTER ENABLE IN FIRST UNIT
	CLR	(R2)+			;CLR 2ND UNIT
	CLR	(R2)+			;CLR 3RD UNIT
	CLR	(R2)+			;CLR 4TH UNIT
	MOV	J,2(R1)			;PUT DDB ADDRESS INTO DNBLK
.ENDC;.IF NE FTDN11

44$:	JSR	PC,BEGXMT		;START LINE TYPING
	BR	90$			;THE TTY LINE IS INITIALIZED
.ENDC;.IF NE FT.CTY!TTYN!RDAN

;ASCII RDA

.IF NE FT.RDA
67$:	JINDEX	JMP,DB.TYP(J),R0,69$
69$:		.WORD	70$		; DH-11 RDA
		.WORD	71$		; DZ-11 RDA

70$:
.IF EQ RDADHN
	TRAP				; NO DH-11 RDAS!
.IFF
	SAVE	<#RDDHOU,#RDDHIN,DB.LCB(J)>
	JSR	PC,DH.INI		; SET UP DH AND LINE BLOCK
	BR	40$
.ENDC ;.IF EQ RDADHN

71$:
.IF EQ RDADZN
	TRAP				; NO DZ-11 RDAS!
.IFF
	SAVE	<#RDDZOU,#RDDZIN,DB.LCB(J)>
	JSR	PC,DZ.INI
	BR	40$
.ENDC ;.IF EQ RDADZN
.ENDC ;.IF NE FT.RDA

;STEP TO NEXT DDB

90$:	MOV	DB.LNK(J),J		;GET NEXT DEVICE BLOCK
	BEQ	99$
	JMP	10$			;CLEAR IT OUT
99$:
.ENDC;.IF NE DEVN
;INITIALIZE THE TTY'S
.IF NE <FT.CTY+TTYN+RDAN>
	MOV	#TI.QUE,TI.PTR		;POINTER TO TTY INPUT SILO
	MOV	#TI.QUE,TI.TKR
.IIF NE FT.CTY,	BIS	#100,CTISTS	;ENABLE CTY KEYBOARD
.ENDC;.IF NE <FT.CTY+TTYN+RDAN>

.IF NE FT.TSK
TSKINI:	MOV	#RUNQUE,R0		;POINT TO 1ST RUN QUEUE
	MOV	#TKPMAX,R1		;GET THE NUMBER OF QUEUES
12$:	CLR	(R0)+			;AND CLEAR THEM
	SOB	R1,12$
	CLR	TASK			;FLAG NO CURRENT JOB
	CLR	L.TASK
	MOV	#FIRTSK,J		;GET FIRST TASK BLOCK ADR
20$:	BEQ	30$
	MOV	TK.JSA(J),R0		; START ADDR
	CMP	#1,RCOUNT+2		; RESTARTING ?
	BEQ	25$			; YES, WE ARE
	MOV	TK.RSA(J),R0		; NO, USE RESTART ADDR
25$:	JSR	PC,TSKBEG		; START TASK
	MOV	TK.LNK(J),J		; NEXT TASK, PLEASE
	BR	20$
30$:
.ENDC;.IF NE FT.TSK
	CLR	PS			;ENABLE INTERRUPTS

.IIF NE FT.87S+FT.D20,JSR PC,RINIDB	;RING THE -10'S CHIMES (KEEP DTELDR HAPPY)

;START THE CLOCK
	MOV	#CLKENB,CLKWRD
.SBTTL	MAIN PROGRAM LOOP

LOOP:
					;COMMON BUG IS TO CLEAR THIS
	ASSERT	0 EQ #ERRINT
	ASSERT	#NXMINT EQ NXMVEC	;AND CHECK BUS TRAP LOCATION ALSO
	ASSERT	#7*40 CLEAR IN PS	;CHECK TO SEE PION
	ASSERT	#PDL EQ P		;DID SOMEONE GARBAGE STACK ?
	MOV	#2$,NXMVEC		;RESET BUS TRAP VECTOR
	MOV	@SW,SW			;DISPLAY IN THE LIGHTS
2$:	MOV	#NXMINT,NXMVEC		;RESET BUS TRAP VECTOR
	MOV	#PDL,P			;IN CASE WE TRAPPED
	SPL	0			;REENABLE INTERRUPTS
	TST	JIFFLG			;HAS CLOCK TICKED ?
	BEQ	4$
	JSR	PC,JIFSCN		;YES SO DO ONCE PER TICK CODE
	CLR	JIFFLG			;RESET FLAG FOR NEXT TIME
4$:

.IF NE <FT.CTY+TTYN+RDAN>
	QUEGET	TI,5$		;GET NEXT ENTRY ON TTY INPUT QUEUE
	JSR	PC,RECINT		;GO HANDLE INPUT
	BR	4$			;NOW GO BACK FOR MORE
5$:
.ENDC;.IF NE <FT.CTY+TTYN+RDAN>
;HERE TO CHECK DDCMP

.IF NE NTLINE
	QUEGET	QI,20$			;GET ENTRY FROM QUEUE
	JMP	DDCINP			;CHECK DDCMP INPUT

20$:					;CHECK OUTPUT QUEUE
	QUEGET	QO,30$			;GET ENTRY FROM QUEUE
;	ASSERT	J  BETWEEN #LBLK0 #<LBLK0+<NTLINE*LB.SIZ>>
	TRACE	DD
	JMP	DDCXMT			;TRY TO SEND SOMETHING

.ENDC;.IF NE NTLINE
30$:					;CHECK NCL QUEUE
.IF NE,FT.DCP
	JSR	PC,NSPCHK		;CHECK TO SEE WHAT IS TO BE DONE
.ENDC; NE,FT.DCP
	QUEGET	NC,40$			;GET STATION WHICH WANTS ATTENTION
	BIT	#SBF.IU,@SB		;IS BLOCK STILL IN USE ?
	BEQ	30$			;WHERE TO GO WHEN NONE
	TRACE	NC
.IIF NE FT.SNK,	CLR	J
	JSR	PC,NCLCHK		;GO CHECK STATION
40$:

.IF NE DEVN
	QUEGET	DV,50$			;GET ENTRY FROM QUEUE
	TRACE	DV			;KEEP TRACKS
	JSR	PC,@DB.OPC(J)		;DISPATCH TO ROUTINE
50$:
.ENDC;.IF NE DEVN
.IIF NE FTDL10,	JSR	PC,LOOPDL	;CHECK ON 10'S ACTIVITIES
.IIF NE FT.DTE,	JSR	PC,LOOPDT	;DITTO
.IIF NE FT.TSK,	JSR	PC,LOOPTK	;SEE WHAT CAN BE DONE FOR TASKS
	JMP	LOOP			;NOW REPEAT ALL THIS UNTILL
					;YOU GET IT WRONG
.SBTTL	QUEUE PUT,GET ROUTINES
;
;HERE TO QUEUE INPUT AND OUTPUT (DDCMP)
;
.IF NE NTLINE
	QUEPUT	QO CODE		;PROCEDURE FOR INSERTING IN THE QO QUEUE
	QUEPUT	QI CODE		;PROCEDURE FOR INSERTING IN THE QI QUEUE
.ENDC ; .IF NE NTLINE
;
.SBTTL	CHUNK HANDLING ROUTINES

;CHUNK CONVENTIONS
; CHUNK SIZE IS A POWER OF TWO
; ADR OF CHUNK IS A MULTIPLE OF CHUNK SIZE
; FIRST WORD OF CHUNK IS A LINK TO THE NEXT CHUNK ADR OR 0
; 2ND WORD OF CHUNK IS A POINTER TO NEXT BYTE IN CHUNK TO FILL
;CABLTB  --  "BLT" A BYTE STREAM, ALLOCATING NEW CHUNK (ERSGET)
;CGBLTB  --  "BLT" A BYTE STREAM, ALLOCATING NEW CHUNK (GETCNK)
;CALL:	MOV	<SRC>,R1
;	MOV	<CNT>,R2
;	JSR	PC,CABLTB
;	RETURN
;
;WHERE <SRC> IS SOURCE BYTE ADDRESS, AND <CNT> IS THE COUNT OF BYTES TO BE
;COPIED.
;
;CABLTB AND CGBLTB WILL MAKE A COPY OF THE BYTE STREAM POINTED TO BY R1/R2,
;STARTING WITH A NEW FRESH CHUNK. FOR CGBLTB, IF A NEW STREAM COULDN'T BE
;STARTED, RETURN IS "BEQ".
;
;ON RETURN, R0 POINTS TO FIRST CHUNK IN RESULTANT COPY, R1/R2 UPDATED.

CABLTB:	JSR	PC,ERSGET	;GET A CHUNK OR ELSE
	BNE	CMBLTB		;WE GOT IT
	TRAP			;"OR ELSE" GOT US INSTEAD

CGBLTB:	JSR	PC,GETCNK	;GET A CHUNK IF CONVENIENT
	BNE	CMBLTB		;WE GOT IT
	RTS	PC		;WE DIDN'T GET IT, SO IT GOES

CMBLTB:	MOV	R2,CN.LEN(R0)	;PRESET FINAL COPYED LENGTH
	MOV	R0,-(P)		;SAVE START OF COPYED BYTE STREAM
	ADD	#CN.NCT,R0	;FIRST DATA BYTE WITHIN NEW BYTE STREAM
	JSR	PC,CNBLTB	;COPY THE DATA, ALLOCATING AS NEEDED
	MOV	(P)+,R0		;RESTORE ORIGINAL NEW COPY ADDRESS
	RTS	PC		;RETURN WITH COPYED BYTE STREAM
;CNBLTB  --  "BLT" A BYTE STREAM, ALLOCATING NEW CHUNKS AS NEEDED
;CALL:	MOV	<DST>,R0
;	MOV	<SRC>,R1
;	MOV	<CNT>,R2
;	JSR	PC,CNBLTB
;	RETURN
;
;WHERE <DST> IS THE DESTINATION BYTE ADDRESS TO START STORING THE COPIED BYTE
;STREAM; <SRC> IS THE SOURCE BYTE ADDRESS TO COPY FROM; AND <CNT> IS THE NUMBER
;OF BYTES TO BE COPIED.
;
;ON RETURN, R0/R1/R2 UPDATED.

.REPT	0
CNBLTB:	MOVB	(R1)+,(R0)+	;COPY ANOTHER BYTE
	ADVCNK	R0 EXTEND	;ALLOCATE NEW CHUNK IF NEEDED
	ADVCNK	R1 FREE		;FREE UP STALE CHUNK IF FINISHED
	SOB	R2,CNBLTB	;LOOP FOR ENTIRE BYTE STREAM
	RTS	PC		;RETURN WITH COPYED BYTES
.ENDR ;.REPT 0

CNBLTB:	MOV	R3,-(P)		;SAVE A REGISTER
1$:	MOV	#CNKSIZ-1,R3	;PROTOTYPE CHUNK BOUNDRY TESTER

;LOOP COPYING BYTES

10$:	MOVB	(R1)+,(R0)+	;COPY ANOTHER BYTE
	BIT	R3,R0		;ADVCNK R0 EXTEND
	BNE	14$		;CONTINUE
	JSR	PC,GTCKR0	; EXTEND
14$:	BIT	R3,R1		;ADVCNK R1 FREE
	BNE	16$		;CONTINUE
	JSR	PC,FRCKR1	; FREE
16$:	SOB	R2,10$		;LOOP FOR ENTIRE BYTE STREAM
17$:	MOV	(P)+,R3		;RESTORE SCRATCH REGISTER
	RTS	PC		;RETURN WITH COPYED BYTES
;AVCKRN  --  ADVANCE TO NEXT CHUNK IN CHAIN, NEITHER FREEING NOR ALLOCATING

;ACVKR0 - R0 CHUNK ADDRESS

AVCKR0:	BIT	#CNKSIZ-1,R0	;IF NOT AT A CHUNK BOUNDARY
	BNE	10$		;EXIT ITS OK
	MOV	-CNKSIZ(R0),R0	;ELSE ADVANCE TO THE NEXT CHUNK
	BEQ	10$		;AND EXIT IF NONE
	ADD	#2,R0		;ELSE SKIP THE LINK WORD
10$:	RTS	PC


;AVCKR3 - R3 CHUNK ADDRESS

AVCKR3:	BIT	#CNKSIZ-1,R3	;IF NOT AT A CHUNK BOUNDARY
	BNE	10$		;EXIT ITS OK
	MOV	-CNKSIZ(R3),R3	;ELSE ADVANCE TO THE NEXT CHUNK
	BEQ	10$		;AND EXIT IF NONE
	ADD	#2,R3		;ELSE SKIP THE LINK WORD
10$:	RTS	PC
;GTCKRN  --  ADVANCE TO NEXT CHUNK IN CHAIN, ALLOCATING NEW CHUNK IF REQUIRED

;GTCKR0 - R0 CHUNK ADDRESS

GTCKR0:	BIT	#CNKSIZ-1,R0	;IF NOT END OF CHUNK, EXIT
	BNE	10$
	SAVE	<R2>
	MOV	R0,R2
	MOV	-CNKSIZ(R0),R0	;IS THERE A NEXT CHUNK ALREADY?
	BNE	5$		;YES, DON'T HAVE TO ALLOCATE A NEW ONE
	JSR	PC,ERSGET	;ALLOCATE A NEW CHUNK
	MOV	R0,-CNKSIZ(R2)	;AND LINK IT IN
5$:	RESTORE	<R2>
	TST	(R0)+		;AND BE SURE TO POINT TO THE DATA
10$:	RTS	PC


;GTCKR1 - R1 CHUNK ADDRESS

GTCKR1:	BIT	#CNKSIZ-1,R1	;IF NOT AT END OF CHUNK,EXIT
	BNE	10$
	SAVE	<R0>
	MOV	-CNKSIZ(R1),R0	;IS THERE A NEXT CHUNK ALREADY?
	BNE	5$		;YES, USE IT
	JSR	PC,ERSGET	;GET NEXT CHUNK
	MOV	R0,-CNKSIZ(R1)	;LINK NEW CHUNK TO PREVIOUS
5$:	MOV	R0,R1		;COPY CHUNK ADR
	TST	(R1)+		;SKIP LINK SLOT
	RESTORE	<R0>
10$:	RTS	PC


;GTCKR2 - R2 CHUNK ADDRESS

GTCKR2:	BIT	#CNKSIZ-1,R2	;IF NOT AT END OF CHUNK,EXIT
	BNE	10$
	SAVE	<R0>
	MOV	-CNKSIZ(R2),R0	;IS THERE A NEXT CHUNK ALREADY?
	BNE	5$		;YES, USE IT
	JSR	PC,ERSGET	;GET NEXT CHUNK
	MOV	R0,-CNKSIZ(R2)	;LINK NEW CHUNK TO PREVIOUS
5$:	MOV	R0,R2		;COPY CHUNK ADR
	TST	(R2)+		;SKIP LINK SLOT
	RESTORE	<R0>
10$:	RTS	PC
;GTCKR3 - R3 CHUNK ADDRESS

GTCKR3:	BIT	#CNKSIZ-1,R3	;IF NOT AT END OF CHUNK,EXIT
	BNE	10$
	SAVE	<R0>
	MOV	-CNKSIZ(R3),R0	;IS THERE A NEXT CHUNK ALREADY?
	BNE	5$		;YES, USE IT
	JSR	PC,ERSGET	;GET NEXT CHUNK
	MOV	R0,-CNKSIZ(R3)	;LINK NEW CHUNK TO PREVIOUS
5$:	MOV	R0,R3		;COPY CHUNK ADR
	TST	(R3)+		;SKIP LINK SLOT
	RESTORE	<R0>
10$:	RTS	PC


;GTCKR4 - R4 CHUNK ADDRESS

GTCKR4:	BIT	#CNKSIZ-1,R4	;IF NOT AT END OF CHUNK,EXIT
	BNE	10$
	SAVE	<R0>
	MOV	-CNKSIZ(R4),R0	;IS THERE A NEXT CHUNK ALREADY?
	BNE	5$		;YES, USE IT
	JSR	PC,ERSGET	;GET NEXT CHUNK
	MOV	R0,-CNKSIZ(R4)	;LINK NEW CHUNK TO PREVIOUS
5$:	MOV	R0,R4		;COPY CHUNK ADR
	TST	(R4)+		;SKIP LINK SLOT
	RESTORE	<R0>
10$:	RTS	PC
;FRCKRN  --  ADVANCE TO NEXT CHUNK, FREEING OLD STALE CHUNK

;FRCKR0 - R0 CHUNK ADDRESS

FRCKR0:	BIT	#CNKSIZ-1,R0	;WAS THAT LAST CHAR IN CHUNK ?
	BNE	10$
	SUB	#CNKSIZ,R0	;MAKE ADR OF CHUNK
	MOV	(R0),-(P)	;SAVE ADR OF NEXT CHUNK
	JSR	PC,FRECNK	;RELEASE DEAD CHUNK
	MOV	(P)+,R0		;GET ADR OF NEXT CHUNK
	BEQ	10$
	TST	(R0)+		;SKIP LINK WORD
10$:	RTS	PC


;FRCKR1 - R1 CHUNK ADDRESS

FRCKR1:	BIT	#CNKSIZ-1,R1	;WAS THAT LAST CHAR IN CHUNK ?
	BNE	10$
	SAVE	<R0>
	MOV	R1,R0
	SUB	#CNKSIZ,R0	;MAKE ADR OF CHUNK
	MOV	(R0),R1		;SAVE ADR OF NEXT CHUNK
	BEQ	.+4
	TST	(R1)+		;SKIP LINK WORD
	JSR	PC,FRECNK	;RELEASE DEAD CHUNK
	RESTORE	<R0>
10$:	RTS	PC
;GETCNK  --  GET A FREE CHUNK IF LOTS AVAILABLE
;ERSGET  --  GET A FREE CHUNK IF ANY AVAILABLE
; CALL	JSR	PC,GETCNK
;	RETURN WITH CHUNK ADR IN R0
;
;ON RETURN, "BEQ" IS ERROR, "BNE" IS SUCCESS

GETCNK:	CMP	#ERSCNT,FRECNT	;DO WE HAVE ENOUGH ?
	BMI	ERSGET		;IF WE DO GIVE HIM ONE
	TWIDDLE			;MORE CORE MIGHT HELP
NOCNKS:	CLR	R0		;CAN'T AFFORD TO GIVE HIM ONE
	RTS	PC

ERSGET:	PIOFF			;SET LEVEL 7
	DEC	FRECNT		;COUNT CHUNK OUT OF LIST
.IF EQ DGUTS
	ASSERT PL		;BE SURE SOME STILL LEFT
.IFF
	BPL	ERSGT0
	CTYMSG	LSW		;REPORT FAILURE, AND RETURN VALUE =0
	INC	FRECNT
	PION
	BR	NOCNKS
ERSGT0:
.ENDC ; .IF EQ DGUTS
	MOV	FIRFRE,R0	;GET ADR OF FIRST FREE CHUNK
	ASSERT	NE		;HOPE WE GOT ONE
	ASSERT CHUNK R0		;IS CHUNK ADDRESS REASONABLE
	TST	@R0
	ASSERT	NE
	ASSERT CHUNK @R0	;CHECK ALSO ON HIS FRIEND
	MOV	@R0,FIRFRE	;RESET ADR OF FIRST FREE CHUNK
	PION			;RESTORE PROCESSOR LEVEL
	CLRCNK	R0		;ZERO THE WHOLE THING, OR JUST THE LINKAGES
	TRACE	CN
	CLZ			;SET PS SO CALLER KNOWS HE WON A CHUNK
	RTS	PC		;DISMISS CALL
;FRECNL  --  FREE UP A CHAIN OF LINKED CHUNKS
;CALL:	MOV	<ADR>,R0
;	JSR	PC,FRECNL
;	RETURN

FRECNL:	MOV	CN.MLK(R0),-(P)	;SAVE NEXT LINKED LIST OF CHUNKS
	JSR	PC,FRECKS	;FREE UP THIS LINKED LIST OF CHUNKS
	MOV	(P)+,R0		;RESTORE ADDRESS OF NEXT LINKED LIST
	BNE	FRECNL		;AND FREE IT UP TOO
	RTS	PC		;ALL DONE



;FRECKS  --  FREE UP LINKED LIST OF CHUNKS
; CALL:	MOV	R0,<ADR OF 1ST CHUNK>
;	JSR	PC,FRECKS

FRECKS:	TST	R0
10$:	BEQ	FCNK99		;IF NO CHUNKS LEFT DISMISS
	TRACE	CN
	MOV	@R0,-(P)	;SAVE ADR OF NEXT CHUNK
	JSR	PC,FRECNK	;FREE FIRST CHUNK
	MOV	(P)+,R0		;GET ADR OF NEXT CHUNK
	BR	10$



;FRECNK  --  FREE UP (DEALLOCATE) USED CHUNK
; CALL:	MOV	R0,<ADR OF CHUNK>
;	JSR	PC,FRECNK
;	RETURN

FRECNK:
	SET.CD	CNK
	ASSERT	FRECNT LO FREMAX;HAVE WE FREED ONE TOO MANY CHUNKS ?
	ASSERT CHUNK R0		;CHECK ADDRESS IS REASONABLE
	ASSERT NE R0
	BIC	#CNKSIZ-1,R0	;BE SURE IT POINTS TO START OF CHUNK
	CMP	R0,PRGEND
	BLO	FCNK99
	CMP	R0,PHYLIM
	BHIS	FCNK99
	PIOFF			;SET LEVEL 7
	CLR	@R0		;CLEAR LINK WORD IN NEW FREE CHUNK
	TST	LSTFRE		;IS THERE ALREADY AN OLDEST CHUNK ?
	BNE	5$
	MOV	R0,FIRFRE	;NEW FIRST CHUNK
	BR	7$
5$:	MOV	R0,@LSTFRE	;SET LINK WORD IN PREVIOUS OLDEST CHUNK
7$:	MOV	R0,LSTFRE	;SAVE ADDRESS OF OLDEST CHUNK
	PION			;RESTORE PROCESSOR LEVEL
	INC	FRECNT
FCNK99:	RTS	PC
.SBTTL	CLOCK (KW11) ROUTINES

;HERE BECAUSE CLOCK INTERRUPTED
CLKINT:	ASSERT	#<15.*60.> GE JIFFLG	;MAKE SURE LOW LEVEL IS RUNNING
	INC	JIFFLG			;ONE MORE JIFFY
	ADD	#1,LOWUP		; UP TIME OF NODE GOES UP
	ADC	HIGHUP
	DEC	SECTIC			;COUNT DOWN TO THE NEXT SECOND
	BNE	10$			;SKIP IF NOT AN EVEN SECOND
	INC	SECFLG			;INDICATE A SECOND HAS PASSED
	MOV	#JIFSEC,SECTIC		;RESTART SECOND TIMER
10$:	;
	PROFILE				;JUST INCASE SOMEONE IS INTERESTED
	RTI				;AND THAT'S ALL
;HERE AT LOW LEVEL WHEN CLOCK HAS GONE OFF

JIFSCN:

;THIS CODE ENABLES ONE TO CHANGE THE SPEED OF A DH LINE ON THE FLY
;WITH DDT11

.IF DF DIDLLS
	MOV	#0,J
DHHLC=.-2
	BEQ	$10$
	PIOFF
	CLR	DHHLC
	BIC	#17,(J)
	BIS	#0,(J)
DHHLN=.-2
	MOV	#0,4(J)
DHHLO=.-4
	PION
$10$:
.ENDC	; .IF DF DIDLLS


;HERE TO CHECK ALL DDB'S ONCE EACH TICK
.IF NE DEVN
	MOV	FIRDDB,J		;GET FIRST DEVICE BLOCK
10$:	SPL	7			;INHIBIT INTERRUPTS
	TSTB	DB.TIM(J)		;IS TIMER RUNNING FOR DEVICE ?
	BLE	20$
	DECB	DB.TIM(J)
	BNE	20$
	MOVB	DB.TIM+1(J),R0		;GET TIMER TYPE CODE
	CLR	DB.TIM(J)
	SPL	0			;ENABLE INTERRUPTS
	JSR	PC,@DB.TPC(J)		;DISPATCH TO DEVICE DEPENDENT ROUTINE
20$:	SPL	0			;ENABLE INTERRUPTS
	MOV	DB.LNK(J),J		;GET NEXT DEVICE BLOCK ADR
	BNE	10$
.ENDC;.IF NE DEVN
;HERE TO CHECK TASKS ONCE EACH TICK
.IF NE FT.TSK
	MOV	#FIRTSK,J		;GET ADR OF FIRST TASK BLOCK
30$:	TST	TK.TIM(J)		;ARE WE TIMING ?
	BEQ	36$			;IF NOT DONE
	DEC	TK.TIM(J)		;COUNT TIMER
	BNE	36$
	BIC	#TK.SLP,@J		;CLEAR SLEEP BIT
	JSR	PC,TSKWAK		;WAKE THE TASK
36$:	MOV	TK.LNK(J),J		;GET NEXT TASK BLOCK
	BNE	30$
.ENDC;.IF NE FT.TSK

;HERE TO CHECK DM11-BB'S EVERY 167 MS (EVERY 10 TICKS)
.IF NE FTDM11!NDZ11
	SUB	JIFFLG,DSCLCK		;COUNT DOWN THE DATA-SET TIMER
	BGT	40$			;DON'T CHECK MODEMS TILL NEGATIVE
.IIF NE FTDM11,JSR	PC,DMSCN		;CALL DM11 CLOCK ROUTINE IN DNDM11
.IIF NE NDZ11,JSR	PC,DZSCN
	MOV	#DSCSPD,DSCLCK		;RESET TIMER FOR NEXT TIME
40$:
.ENDC

;HERE TO CALL NCL SO IT CAN RE-ROUTE ANY MESSAGES IT MAY NEED TO
	JSR	PC,NCLJIF		;DO NCL JIFFY PROCESSING

;HERE TO SEE IF IT'S TIME TO DO DDCMP REP CHECKING.  THIS IS DONE
;EVERY "REPSPD" TICKS
.IF NE NTLINE
	SUB	JIFFLG,RPCLCK		;COUNT OFF THE JIFFYS
	BGT	50$			;IF STILL POS THEN DON'T CHECK YET
	JSR	PC,REPCHK		;CHECK FOR DDCMP TIMEOUTS
	MOV	#REPSPD,RPCLCK		;RESET TIMER FOR NEXT CHECK
50$:
.ENDC ;.IF NE NTLINE


;HERE TO SEE IF A SECOND HAS PASSED, AND IF SO CALL THE ROUTINE
;THAT PROCESSES ONCE / SECOND STUFF
	TST	SECFLG			;HAS A SECOND PASSED ?
	BEQ	90$			;IF NOT, DON'T CALL SECOND SCAN
	JSR	PC,SECSCN		;A SECOND HAS PASSED, CALL SECSCN
	CLR	SECFLG			;RESET IT FOR NEXT TIME
90$:	RTS	PC			;RETURN BACK TO THE MAIN LOOP
;HERE ONCE PER SECOND
SECSCN:
.IF NE FTDL10!FT.DTE
	JSR	PC,TENSEC		;DO DL10/DTE SECOND SCAN
.ENDC

;HERE ONCE A SECOND TO CHECK EACH LINE
SEC.10:
.IF NE NTLINE
	MOV	#FRSTLB,J		;SCAN LINE BLOCK STARTING WITH FIRST
	BR	90$
05$:
;	JSR	PC,SL.SEC		;DRIVER ONCE PER SEC CHECK
.IF NE FT.MPT
	BIT	#LS.MPT,(J)		;IF MULTIPOINT
	BEQ	10$
	BITB	#MP.SEL,LB.MPS(J)	;AND IF SELECTED
	BEQ	90$
	TSTB	LB.MPT(J) 		;AND IF SELECTION  TIMER RUNNING
	BEQ	10$
	DECB	LB.MPT(J)		; DECREMENT TIME LEFT
					;IF TIME RAN OUT
	BNE	10$
	JSR	PC,SELNXT		;MUST FORCE SELECT TO BE SENT
.IF NE FTTRIB
	TST	LB.MPL(J)		;IF YOU'RE A TRIBUTARY
	BNE	9$
	BISB	#MP.SNM,LB.MPS(J)	;YOU MUST SEND A SELECT
	CLRB	LB.MPT(J)		;AND STOP THE TIMER
	BR	10$
9$:
.ENDC
	BITB	#MP.SFF,LB.MPS(J)	;IF COUNTER RAN OUT
	BNE	07$
.IF NE FT.RDM!FT.RDP
	JSR	R0,RDESST		;IF A RDE DEV, REPORT THE STATE
	.BYTE	0,240
.ENDC
	JSR	PC,L.DOWN		;PUT THE STATION OFFLINE
	BR	90$
07$:	DECB	LB.MPS(J)		;DECREMENT THE FAILURE COUNTER
.ENDC
10$:
40$:	TSTB	LB.BNN+1(J)		;IF BOOT MODE, ITS TIMER IS RUNNING
	BEQ	90$			;IF NOT WE ARE DONE
	INCB	LB.BNN+1(J)
	BNE	90$
	CLR	LB.BNN(J)		;REVOKE EXCLUSIVE LICENSE

90$:	MOV	LB.LNK(J),J		;NOW TRY THE NEXT LINE BLOCK
	BNE	05$			;IF THERE IS ONE
.ENDC;.IF NE NTLINE
.IF NE FTDCP3!FTDCP4			;NSP CODE HAS CLOCK STUFF TOO
	JSR	PC,NSPSEC		;CALL IT
.ENDC
;HERE ONCE A SECOND TO CHECK EACH SCB
SECNCL:	MOV	#OURSCB,SB		;GET 1ST STATION BLOCK
	BR	82$
10$:	BIT	#SBF.IU,@SB		;IS BLOCK IN USE ?
	BEQ	82$			;IF NOT DON'T CHECK IT
	MOV	SB,DNA			;SAVE DESTINATION ADR
	JSR	PC,NCLQRQ
	MOV	#SQNTAB,SQNODE
20$:	MOV	@SQNODE,SNA		;IS THERE A SOURCE FOR THIS SLOT ?
	BEQ	80$			;BRANCH IF DONE WITH SEQUENTIAL NODES
	MOV	SB,R0			;COPY SCB POINTER
	ADD	#SB.IMQ-CN.MLK,R0	;POINT TO INPUT MSG QUEUE
	JSR	PC,TIMQUE		;CHECK FOR ANTIQUE ENTRIES
	.WORD	FRECKS
	TSTB	SB.TIM(SB)		;ARE WE TIMING ?
	BEQ	50$
	DECB	SB.TIM(SB)		;DECREMENT TIMER
	BNE	50$			;BRANCH IF TIMER HASN'T GONE OFF
	JSR	PC,NCLSEC		;GO DO ONCE A SECOND NCL STUFF
50$:	ADD	#2,SQNODE		;ADVANCE TO NEXT SEQUENTIAL NODE
	ADD	#SQNSIZ,SB		;ADVANCE TO NEXT SNA
	BR	20$
80$:	MOV	DNA,SB			;GET SCB ADR AGAIN
82$:	SB.ADV	10$			;GET NEXT STATION BLOCK
;HERE ONCE A SECOND TO CHECK DEVICES
.IF NE DEVN
SECDEV:	MOV	FIRDDB,J		;GET FIRST DEVICE BLOCK
	Z=DS.COR
	.IIF NE FT.TSK,Z=Z!DS.PAU
10$:	BIT	#Z,@J			;DOES DEVICE WANT TO RUN AGAIN ?
	BEQ	20$
	TWIDDLE				;COUNT TIMES THIS HAPPENS
	BIC	#Z,@J			;CLEAR REQUEST
	JSR	PC,QUEDEV		;REQUEST EXECUTION
20$:	SPL	7			;INHIBIT INTERRUPTS
	TSTB	DB.TIM(J)		;IS SECONDS TIMER RUNNING
	BPL	22$
	INCB	DB.TIM(J)		;IF SO INCREMENT IT
	BNE	22$
	MOVB	DB.TIM+1(J),R0		;IF TIMER RAN OUT, GET FUNCTION CODE
	CLR	DB.TIM(J)
	SPL	0			; ENABLE INTERRUPTS
	JSR	PC,@DB.TPC(J)		;AND SERVICE THE TIMER
22$:	SPL	0			;ENABLE INTERRUPTS
.IF NE FTDN11
.IF NE FT.RDA
	BIT	#RDEASC,DB.RDT(J)
	BNE	23$
.ENDC
	BIT	#DS.TTY,@J		;IS THIS A TTY ?
	BEQ	30$
.IF NE FT.CTY
	CMP	J,#CTYDDB
	BEQ	30$
.ENDC;.IF NE FT.CTY
23$:	BITB	#DNTIME,DB.DNT(J)	;DN11 TIMER GOING?
	BEQ	30$			;NO, CHECK DATASET STATUS
.IF NE FT.CHK
	BITB	#40,DB.DVT(J)		;AUTO DIAL LINE?
	ASSERT	NE			;IT HAD BETTER BE!
	BITB	#DNDIAL,DB.DNS(J)	;UNDER CONTROL OF DN11/801?
	ASSERT	NE			;IT HAD BETTER BE!
.ENDC;.IF NE FT.CHK
	DECB	DB.DNT(J)		;DECREMENT TIMER
	MOVB	DB.DNT(J),R0		;AND GET NEW VALUE
	BITB	#DNTIME,R0		;TIMER EXPIRED?
	BNE	30$			;NO, DONE
	BIC	#177477,R0		;CLEAR UNWANTED BITS
	ASL	R0			;PUT CODE
	ASL	R0			;INTO RIGHT
	ASL	R0			;PLACE
	SWAB	R0
	JSR	PC,@DNTDSP(R0)		;EXECUTE TIMER ROUTINE
	BR	30$			;DO NEXT DDB
.ENDC;.IF NE FTDN11
30$:	MOV	DB.LNK(J),J		;GET NEXT DEVICE BLOCK
	BNE	10$
.ENDC;.IF NE DEVN

;HERE IS THE ONCE / SECOND STUFF FOR TASKS.
.IF NE FT.TSK
	MOV	TASK,J			;GET ADDR OF RUNNING TASK
	BEQ	40$			;SKIP IF NONE
	SUB	SECFLG,TK.QTM(J)	;COUNT DOWN HIS QUANTUM
40$:
.ENDC


;HERE IS SOME CODE THAT SUPPORTS THE SINK MACRO
	ND	LPTSNK,0		;USE THE LPT FOR SINK ONLY IF REQUESTED
.IF NE LPTSNK
	SINK	LP0DDB
.IFF
	SINK	CTYDDB
.ENDC	;.IF NE LPTSNK

	CTYMSG				;CTY LOGGING
;
;******** here is a convenient place for source macro calls ******
;


;HERE TO CHECK IF A MINUTE HAS PASSED, AND IF SO CALL ONCE/MINUTE CODE
	SUB	SECFLG,MINTIC		;COUNT DOWN TO NEXT MINUTE
	BGT	90$			;BRANCH IF HASN'T PASSES
	JSR	PC,MINSCN		;BRANCH TO ONCE/MINUTE ROUTINE
	MOV	#60.,MINTIC		;RESET MINUTE TICKER
90$:	RTS	PC			;POP BACK TO MAIN LOOP

;HERE IS THE ONCE / MINUTE CODE (A GOOD PLACE FOR DEBUGING CHECKS)
MINSCN:
	RTS	PC			;POP BACK TO MAIN LOOP
;HERE TO CHECK FOR DDCMP REP TIMEOUTS
.IF NE NTLINE
REPCHK:	MOV	#FRSTLB,J	;SCAN LINE BLOCKS STARTING WITH THE FIRST
	BR	10$
15$:
.IIF NE FTDUP11,JSR PC,DUPJIF	;KISS THE DUP'S A ONCE IN A WHILE
.IF NE FT.MPT
	BIT	#LS.MPT,(J)	;IF NOT MULTIPOINT, GO AHEAD AND CHECK IT
	BEQ	12$
	BITB	#MP.SEL,LB.MPS(J) ;ELSE IF NOT SELECTED,SKIP THE LINE
	BEQ	10$
	.ENDC
12$:	DEC	LB.REP(J)	;POKE THE TIMER
	BGT	10$
	JSR	PC,DDCSEC	;IF TIMER RAN OUT, DO SOMETHING
10$:	MOV	LB.LNK(J),J	;STEP TO NEXT BLOCK, AND LOOP
	BNE	15$
	RTS	PC		;EXIT IF NO BLOCK
.ENDC ;.IF NE NTLINE
;HERE TO TIME ENTRIES IN A QUEUE
; CALL	MOV	#FOO,R0		;POINTER TO FIRST ENTRY IN QUEUE
;	JSR	TIMQUE
;	.WORD	WHERE		;TO GO WHEN ENTRY HAS EXPIRED
;	RETURN
TIMQUE:	BR	20$
10$:	MOV	R1,R0
20$:	MOV	CN.MLK(R0),R1		;GET POINTER TO NEXT MSG
	BEQ	90$			;IF NO MORE WE ARE DONE
	DEC	CN.TIM(R1)		;DECREMENT TIMER
	BNE	10$
	TWIDDLE				;COUNT DEAD MSGS
	MOV	CN.MLK(R1),CN.MLK(R0)	;DELINK OBSOLETE MSG
	MOV	R0,-(P)			;SAVE GOOD POINTER
	MOV	R1,R0			;POINT TO DEAD MSG
	MOV	@2(P),R1		;GET ADR OF WHERE TO GO
	JSR	PC,@R1			;DISPOSE OF MESSAGE
	MOV	(P)+,R0			;GET GOOD POINTER BACK
	BR	20$
90$:	ADD	#2,@P
	RTS	PC