Google
 

Trailing-Edge - PDP-10 Archives - tops10_703_distr_bb-x140b-sb - 10,7/703anf/dntsk.p11
There are 3 other files named dntsk.p11 in the archive. Click here to see a list.
.SBTTL	DNTSK - TASK ROUTINES  28 MAR 79

;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,1984 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.

VRTSK=013			;FILE EDIT NUMBER

.SBTTL		TASK BLOCK DEFINITIONS

.IF NE FT.TSK
	BLOCK	TK	;DEFINE X & XX MACROS

X	STS,1	;STATUS WORD
	TK.RUN=100000	;TASK IS RUNNABLE
	TK.LGI=040000	;JOB IS LOGGED IN - I.E. HASN'T EXITED YET
	TK.TRG=020000	;TASK HAS BEEN TRIGERRED BY ANOTHER TASK
	TK.WAK=010000	;SOMETHING HAS OCCURED TO WAKE TASK
	TK.NOP=004000	;DEVICE ON THIS CALL WAS NOT OPENED
	TK.SLP=002000	;SLEEP BIT WILL NOT WAKE UNTIL SPECIFIED NO OF 
			;COUNTS (IN JIFFIES) HAS OCCURRED OR HOST DIES
X	LNK,1	;LINK TO NEXT TASK BLOCK
X	RQL,1	;RUN QUEUE LINK
X	PRI,1	;POINT TO PRIORITY QUEUE
X	JSA,1	;ADDRESS TO CONTINUE TASK
X	RSA,1	;ADDRESS TO USE ON A RESTART
X	PDL,2	;1ST WORD IS ADR OF PDL, 2ND WORD IS CURRENT PDL POINTER
X	ZER,0	;START CLEARING HERE ON A RESTART
X	TIM,1	;SECOND TIMER
XX	QTM,1	;QUANTUM TIME - COUNTS TICKS WITHOUT INTERRUPTION
X	TPC,1	;ROUTINE TO GO TO WHEN CLOCK GOES OFF
X	DTK,1	;DB.TSK FOR CURRENT SVC
X	SPT,1	;SEND QUEUE PUTTER
X	STK,1	;SEND TAKER
X	SQU,TKSQSZ	;SEND QUEUE
X	ARG,1	;SAVE VALUE TO RETURN TO CALLER
X	SIZ,0	;SIZE OF TASK BLOCK
;MACRO TO DEFINE TASKS FOR THE SYSTEM
;	1ST ARGUMENT IS 3 CHAR TASK NAME
;	2ND ARGUMENT IS TASK STARTING ADDRESS
;	3RD ARGUMENT IS THE RESTART ADDRESS
;	4TH ARGUMENT IS THE TASK PRIORITY
;	5TH ARGUMENT IS THE STACK SPACE THE TASK WILL USE
.MACRO	TSKGEN	JOBNAM,JBSA,JBRSA,PRIOR,PDLSIZ
	TSKNUM=TSKNUM+1
	.EVEN
FIRTSK=.
JOBNAM'TKB:
	.WORD	0	;TK.STS
	.WORD	TSKLNK	;TK.LNK
	TSKLNK=FIRTSK
	.WORD	0	;TK.RQL
	Z=RUNQUE+<2*PRIOR>-TK.RQL
	.WORD	Z	;TK.PRI
	.WORD	JBSA	;TK.JSA
	.WORD	JBRSA	;TK.RSA
	.WORD	.-TK.PDL+TK.SIZ+<2*PDLSIZ>+60	;INITIAL PDL POINTER
	.BLKW	1	;TK.PDL+2(CURRENT PDL POINTER)
	.BLKB	TK.SIZ-TK.ZER
	.BLKW	PDLSIZ+30
.ENDM	TSKGEN
	TSKNUM=0
	TSKLNK=0
;MACRO TO GET A CHUNK OF FREE CORE
.MACRO	CNKGET	DATA
.NTYPE	Z,DATA
;.IF EQ <R0-Z>
;	JSR	PC,GETCNK	;JUST GET A CHUNK
;.IFF
	CLR	-(P)		;WE WILL PUT CHUNK ADR HERE LATER
	MOV	R0,-(P)		;SAVE REGISTER
	CLR	R0		;ASSUME NO CHUNKS
	CMP	#ERSCNT*2,FRECNT	;WANT TASK TO FAIL BEFORE SYSTEM
	BGE	.+6		;OK TO CONTINUE
	JSR	PC,GETCNK	;TRY TO GET SOME FREE CORE
	MOV	R0,2(P)		;SAVE ADR OF CHUNK
	MOV	(P)+,R0		;GET ADR OF CHUNK BACK
	MOV	(P)+,DATA	;GIVE USER ADR OF CHUNK
;.ENDC;.IF EQ <R0-Z>
.ENDM	CNKGET

;MACRO TO RETURN A CHUNK OF FREE CORE
.MACRO	CNKFRE	DATA
	MOV	R0,-(P)		;SAVE REGISTER
	MOV	DATA,R0		;GET ADDRESS OF CHUNK
	JSR	PC,FRECNK	;RELEASE CHUNK
	MOV	(P)+,R0		;RESTORE REGISTER
.ENDM	CNKFRE

;MACRO TO GET 32 BIT UPTIME
.MACRO	TIMER	DATA
	MOV	LOWUP,DATA	;GET UPTIME
.NTYPE	Z,DATA
.IF EQ <Z&70>
	MOV	HIGHUP,DATA+1	;PUT HIGH BITS IN NEXT REG
.IFF
	MOV	HIGHUP,DATA+2	;GET HIGH ORDER BITS
.ENDC;.IF EQ <Z&70>
.ENDM	TIMER
;MACROS WHICH GENERATE SUPERVISOR CALLS
; FORMAT OF CALL IS:
;	IOT
;	.BYTE	CODE,FLAGS
;	TTY # (-1 = CTY) OR TSK BLOCK ADR
;	ARG1 (OR 0)
;	ARG2 (OR 0)
; FLAGS ARE:
	IO.NBK=001	;CALL DOESN'T WANT TO BLOCK
	IO.KYB=002	;CALL IS FOR KEYBOARD
	IO.PUT=004	;CALL IS FOR PUTS
	IO.IDX=006	;IO INDEX IS OR OF IO.KYB & IO.PUT
	IO.ARG=010	;ARGUMENT IS REG
	IO.AR2=020	;ARG2 IS IN A REG
	IO.AR1=040	;ARG1 IS IN A REG
; CODES WHICH HAVE BEEN ASSIGNED ARE:
;	0	;OPEN
;	2	;GET
;	4	;PUT
;	6	;RELEASE
;	10	;IMGPUT (ONLY FOR DH11 OUTPUT)
;	12	;GET BIT
;	14	;SET BIT
;	16	;CLEAR BITS
;	20	;DIAL
;	200	;WAKE
;	202	;TRIGGER
;	204	;SEND
;	206	;RECEIVE
;	210	;HIBER
;	212	;EXIT
;	214	;SLEEP
;MACRO TO PUT CALLS INTO RIGHT FORMAT
.MACRO	UUOARG	ARG
.IF NB <ARG>
    FOOEY=FOOEY&077777
	.IF IDN <ARG><PUT>
		Z=Z!IO.PUT
		FOOEY=FOOEY!100001	;HAVE SET PUT/GET
	.ENDC;.IF IDN <ARG><PUT>
	.IF IDN <ARG><GET>
		FOOEY=FOOEY!100002	;HAVE SET PUT/GET
	.ENDC;.IF IDN <ARG><GET>
	.IF IDN <ARG><NONBLOCKING>
		Z=Z!IO.NBK
		FOOEY=FOOEY!100004	;HAVE SET BLOCKING/NONBLOCKING
	.ENDC;.IF IDN <ARG><NONBLOCKING>
	.IF IDN <ARG><BLOCKING>
		FOOEY=FOOEY!100010	;HAVE SET BLOCKING/NONBLOCKING
	.ENDC;.IF IDN <ARG><BLOCKING>
	.IF IDN <ARG><KEYBOARD>
		Z=Z!IO.KYB
		FOOEY=FOOEY!100020	;HAVE SET PRINTER/KEYBOARD
	.ENDC;.IF IDN <ARG><KEYBOARD>
	.IF IDN <ARG><PRINTER>
		FOOEY=FOOEY!100040	;HAVE SET PRINTER/KEYBOARD
	.ENDC;.IF IDN <ARG><PRINTER>
    .IF EQ <FOOEY&100000>
	.ERROR	ARG	;CAN'T RECOGNIZE MACRO ARGUMENT
    .ENDC;.IF EQ <FOOEY&100000>.ENDC;.IF NB <ARG>
.ENDC;.IF NB <ARG>
.ENDM	UUOARG
.MACRO	UUO	CODE,RDWRT,IO,MODE,DEV,ARG1,ARG2
	FOOEY=0	;COLLECT INFORMATION ABOUT ARGUMENTS HERE
	IOT		;THIS IS SUPERVISOR CALL INSTRUCTION
Z=0
	UUOARG	RDWRT
	UUOARG	IO
	UUOARG	MODE
.IF NB <DEV>
	.NTYPE ZZ,DEV
	.IIF EQ <ZZ&70>,Z=Z!IO.ARG
.ENDC;.IF NB <DEV>
.IF NB <ARG1>
	.NTYPE ZZ,ARG1
	.IIF EQ <ZZ&70>,Z=Z!IO.AR1	;ARG1 IN A REGISTER ?
.ENDC;.IF NB <ARG1>
.IF NB <ARG2>
	.NTYPE ZZ,ARG2
	.IIF EQ <ZZ&70>,Z=Z!IO.AR2	;ARG2 IN A REGISTER ?
.ENDC;.IF NB <ARG2>
	.BYTE	CODE,Z
	.WORD	DEV	;TSK BLOCK ADR OR TTY #
.IF NB ARG1
	.WORD	ARG1	;ARG1
.IFF
	.WORD	ZERO	;DEFAULT ZERO
.ENDC;.IF NB ARG1
.IF NB ARG2
	.WORD	ARG2	;ARG2
.IFF
	.WORD	ZERO	;DEFAULT IS ZERO
.ENDC;.IF NB ARG2
.ENDM	UUO

;MACRO FOR A TASK TO KILL ITSELF
.MACRO	EXIT
	UUO	212,,,,0,0,0
.ENDM	EXIT

;MACRO TO PAUSE IN EXECUTION
.MACRO	HIBER	ARG1
	UUO	210,,,,0,ARG1,0
.ENDM	HIBER

;MACRO TO WAKE ANOTHER TASK
.MACRO	WAKE	JOBNAM
	UUO	200,,,,JOBNAM'TKB,0,0
.ENDM	WAKE

;MACRO TO BEGIN ANOTHER TASK
.MACRO	TRIGER	JOBNAM
	UUO	202,,,,JOBNAM'TKB,0,0
.ENDM	TRIGER

;MACRO TO SEND A MESSAGE TO A TASK
.MACRO	SEND	JOBNAM,ARG1,MODE
	UUO	204,,,MODE,JOBNAM'TKB,ARG1,0
.ENDM	SEND

;MACRO TO PICK UP ENTRIES FROM SEND QUEUE
.MACRO	RECEIVE	ARG1,MODE
	UUO	206,,,MODE,0,ARG1,0
.ENDM	RECEIVE
;IO MACROS

;MACRO TO REQUEST EXCLUSIVE USE OF A TTY
.MACRO	OPEN	DEV,IO,RDWRT
	UUO	0,RDWRT,IO,,DEV,0,0
.ENDM	OPEN

;MACRO TO GET INPUT FROM A TTY
.MACRO	GET	DEV,IO,MODE,ARG1
	UUO	2,GET,IO,MODE,DEV,ARG1,0
.ENDM	GET

;MACRO TO WRITE ON A TTY
.MACRO	PUT	DEV,IO,MODE,ARG1
	UUO	4,PUT,IO,MODE,DEV,ARG1,0
.ENDM	PUT

;MACRO TO FREE UP A TTY
.MACRO	RELEASE	DEV,IO,RDWRT
	UUO	6,RDWRT,IO,,DEV,0,0
.ENDM	RELEASE

;MACRO TO TRANSMIT A STRING ON DH11 LINE(NO FILLERS ETC.)
;	ARG1 IS LENGTH
;	ARG2 IS ADR OF STRING
.MACRO	IMGPUT	DEV,IO,MODE,ARG1,ARG2
	UUO	10,PUT,IO,MODE,DEV,ARG1,ARG2
.ENDM	IMGPUT
;MACRO TO PUT TASK TO SLEEP
.MACRO	SLEEP	ARG1
	UUO	214,,,,0,ARG1,0
.ENDM	SLEEP
;MACRO TO GET STATUS BITS FROM RDA OR TTY DEVICE BLOCK
.MACRO	GETBIT	DEV,ARG1
	UUO	12,,,,DEV,ARG1,0
.ENDM	GETBIT
;MACRO TO SET STATUS BITS IN RDA OR TTY DEVICE BLOCK
.MACRO	SETBIT	DEV,ARG2,ARG1
	UUO	14,,,,DEV,ARG1,ARG2
.ENDM	SETBIT
;MACRO TO CLEAR STATUS BITS IN RDA OR TTY DDB
.MACRO	CLRBIT	DEV,ARG2,ARG1
	UUO	16,,,,DEV,ARG1,ARG2
.ENDM	CLRBIT
;MACRO TO ALLOW TASK TO DIAL OUT
;INITIATE A STATUS REQUEST OR TERMINATE A CALL
;
;
;	THE FORMAT OF THE CALL:
;	DIAL	LINE#,BLOCKING,TYPE,ADR
;	TYPE IS ONE OF THE FOLLOWING
;	0 - TERMINATE PREVIOUS CALL
;	1 - SEND DIAL STATUS TO WORD POINTED TO BY ADR
;	2 - INITIATE A DIAL REQUEST.  THE NUMBER TO DIAL
;		IS POINTED TO BY ADR
;
;	AUTO DIAL STATUS
	DNRREQ=000200	;AUTO DIAL REQ OUTSTANDING SET BY MACRO CLEARED IN RDXSER
	DNRERR=100000	;ERROR ON PREVIOUS CALL
	DNREAD=000010	;AUTO DIAL FAILURE
	DNRANS=000020	;CALL ANSWERED
	DNRENC=000040	;NO CARRIER SET FOR NO ANSWER, BUSY, OR DROPPED CARRIER IN MIDDLE OF CALL
	DNREBY=000100	;ALREADY DIALING NUMBER
;
;
.MACRO	DIAL	DEV,MODE,ARG1,ARG2
	UUO	20,,,MODE,DEV,ARG1,ARG2
.ENDM	DIAL

.ENDC;.IF NE FT.TSK
.SBTTL		SCHEDULE BACKGROUND TASKS

;HERE TO SCHEDULE A TASK TO EXECUTE
;CALL (FROM LOOP)
;	JSR PC,LOOPTK

.IF NE FT.TSK
LOOPTK:	MOV	#RUNQUE,R0		;LOCATE THE RUN QUEUES
10$:	MOV	(R0)+,J			;GET THE TASK ON THIS QUEUE
	BNE	60$			;IF THERE IS ONE RUN IT
	CMP	R0,#RUNQUE+<TKPMAX*2>	;IF THERE IS ANOTHER QUEUE,
					;BETTER TRY THAT ONE
	BLO	10$
	RTS	PC			;EXIT
60$:
;CHECK THINGS ARE STILL OK
	.IF	NE	FT.CHK
	BIT	#TK.SLP,@J		;TASK SLEEPING
	CHK	EQ			;TROUBLE IF IT IS!
	.ENDC ;END IF NE FT.CHK
	MOV	SP,LPTKSP		;SAVE SYSTEM PDL
	MOV	J,TASK			;REMEMBER WHO WAS RUNNING
	MOV	TK.PDL+2(J),P		;GET NEW STACK POINTER
	RESTORE	<R5,R4,R3,R2,R1,R0>
	RTS	PC			;DISPATCH TO TASK
;HERE WHEN TASK DONE EXECUTING
LOPTK7:	SAVE	<R0,R1,R2,R3,R4,R5>	;SAVE REGISTERS FOR TASK
	MOV	TASK,J			;GET POINTER TO TASK BLOCK
	MOV	P,TK.PDL+2(J)		;SAVE STACK POINTER
	MOV	(PC)+,SP		;RESTORE SYSTEM PDL
LPTKSP:	0				;SP AT ENTRY TO LOOPTK
	CLR	TASK			;FLAG NOT RUNNING USER
	RTS	PC			;EXIT

.ENDC;.IF NE FT.TSK
.SBTTL		TASK HANDLING
.IF NE FT.TSK
IOTINT:	BIC	#17,2(P)		;CLEAR BITS IN USERS PS
	MOV	2(P),PS			;SET PROCESSOR LEVEL
	SAVE	<R5,R4,R3,R2,R1,R0>	;SAVE ALL REG'S ON STACK
	MOV	14(P),R3		;GET CALLING PC
	MOV	(R3)+,R0		;GET DISPATCH AND FLAGS
	MOV	R0,R1			;COPY FLAGS
	SWAB	R1
	MOVB	R1,@TASK		;SAVE FLAGS
	MOV	(R3)+,J			;GET DEVICE NUMBER
	MOV	(R3)+,R2		;GET DATA ADR
	MOV	(R3)+,R1		;GET ARG2
	BIT	#IO.AR1*400,R0		;IS ARG1 IN A REG ?
	BEQ	12$
	ASL	R2			;CONVERT TO WORD OFFSET
	ADD	P,R2			;POINT TO PLACE ON STACK
12$:
	BIT	#IO.AR2*400,R0		;IS ARG2 IN A REG?
	BEQ	11$			;NO
	ASL	R1			;POINT TO REG ON STACK
	ADD	P,R1
11$:
	SAVE	<J>
	MOV	TASK,J
	TSTB	TK.QTM(J)		;CHECK QUANTUM TIME
	BNE	17$			;SKIP IF TIME STILL LEFT
	PIOFF
	BIS	#TK.SLP,@J		;PUT TASK TO SLEEP
	MOV	#4*TKQTIM,TK.TIM(J)	;FOR 4 QUANTUM TIMES
	JSR	PC,STPTSK
	PION
	JSR	PC,LOPTK7		;GO TO MAIN SCHEDULAR
17$:
	MOV	R2,TK.ARG(J)		;SAVE VALUE TO RETURN TO CALLER
	RESTORE	<J>
	MOV	R3,14(P)		;SO WE RETURN TO RIGHT PLACE
	MOV	R0,R3			;COPY FLAGS AND DISPATCH
	BIC	#^C77,R0		;STRIP FLAG BITS
	TSTB	R3			;IS THIS AN IO CALL ?
	BMI	20$
	BIT	#IO.ARG*400,R3		;WAS ARGUMENT IN A REG ?
	BEQ	14$
	ASL	J			;CONVERT REG ADR TO WORD
	ADD	P,J			;POINT TO RIGHT POINT ON STACK
14$:	MOV	@J,J			;GET ARGUMENT
.IIF NE FT.CTY,	CMP	J,#-1		;CHECK FOR CTY OR GREATER
	BMI	IOTBUM			;IF TOO SMALL REJECT
	CMP	J,#TTYN+RDAN			;RANGE CHECK
	BPL	IOTBUM			;AND FLUSH LOSING CALLS
	ASL	J			;SO WE CAN INDEX INTO TABLE
	MOV	TTYTAB(J),J		;CONVERT TO DEVICE BLOCK ADDRESS
	JMP	@IOTDSP(R0)		;DISPATCH ON TYPE
20$:	JMP	@SVCDSP(R0)		;DISPATCH ON TYPE
IOTBUM:	BIS	#10,16(P)		;SET N BIT FOR LOSER
	BR	IOTFIN
;HERE TO RETURN DATA TO USER, DATA IN R0
IOTRET:
	MOV	TASK,J
	MOV	R0,@TK.ARG(J)		;RETURN RESULT TO USER
	CLR	ZERO

IOTFIN:	MOV	TASK,J			;POINT TO CURRENT TASK BLOCK
	BIT	#TK.NOP,@J		;WAS DEVICE OPENED OR NOT USED ?
	BEQ	10$			;CAUZ THAT'S SIMPLE
	CLR	@TK.DTK(J)		;FORGET WHO USED DEVICE LAST
	BIC	#TK.NOP,@J		;ASSUME NEXT DEVICE IS OPENED
10$:	RESTORE	<R0,R1,R2,R3,R4,R5>	;RESTORE ALL REG'S
.IF NE NLINES
	CMP	QI.PTR,QI.TKR		;DDCMP WAITING ?
	BNE	80$
.ENDC;.IF NE NLINES
	TSTB	JIFFLG			;SHOULD WE PAUSE ?
	BEQ	90$
80$:	JSR	PC,LOPTK7		;YES
90$:	RTI

SVCDSP:	WAKTSK			;CODE (200) WAKE TASK
	TRGTSK			;CODE (202) TRIGER TASK
	SNDTSK			;CODE (204) SEND TO TASK
	RCVTSK			;CODE (206) RECEIVE FROM TASK
	HIBER.			;CODE (210) HIBER
	TSKEND			;CODE (212) EXIT
	SLEEP.			;CODE (214) SLEEP

IOTDSP:	IOTOPN			;CODE (0) OPEN
	IOTGET			;CODE (2) GET
	IOTPUT			;CODE (4) PUT
	IOTREL			;CODE (6) RELEASE
	IOTIMP			;CODE (10) IMGPUT
	IOTGTB			;CODE (12) GET BIT
	IOTSET			;CODE (14) SET BIT
	IOTCLR			;CODE (16) CLEAR BITS
	IOTDNL			;CODE (20) DIAL
;HERE FOR AN OPEN MACRO
IOTOPN:	JSR	PC,IOCOWN		;SEE IF HE CAN HAVE IT
	BIC	#TK.NOP,@TASK		;DEVICE WAS OPENED
	BR	IOTFIN			;RETURN
;HERE FOR A GET MACRO
IOTGET:	JSR	PC,IOCOWN		;CHECK USER OWNS DEVICE
	BEQ	50$			;BRANCH IF GETTING PRINTER

;HERE IF GETTING A CHAR FROM KEYBOARD
10$:	MOV	DB.KTK(J),R1		;GET KEYBOARD TAKER
	CMP	R1,DB.KPT(J)		;IS THE KEYBOARD DATA IN QUEUE ?
	BNE	20$			;IF SO GET IT
	JSR	PC,IOTIOW		;WAIT A WHILE
	BR	10$			;AND CHECK AGAIN
20$:	ADD	J,R1			;RELOCATE ADDRESS
	MOV	(R1)+,R0		;GET DATA
	SUB	J,R1			;MAKE ADDRESS RELATIVE AGAIN
	CMP	R1,#DB.KQU+TQS+TQS	;IS THAT END OF QUEUE ?
	BNE	24$
	MOV	#DB.KQU,R1		;YES SO RESET POINTER
24$:	MOV	R1,DB.KTK(J)		;SAVE POINTER
	BR	IOTRET			;RETURN DATA TO USER

;HERE IF GETTING CHAR FROM PRINTER (=NCL)
50$:	TST	DB.TOC(J)		;ANY CHARS IN QUEUE ?
	BNE	52$			;IF SO HE WINS ONE
	JSR	PC,IOTIOW		;WAIT FOR ONE
	BR	50$
52$:	MOV	DB.TOB(J),R0		;GET PRINTER TAKER
	MOVB	(R0)+,R1		;GET NEXT CHARACTER
	ADVCNK	R0 FREE
54$:	MOV	R0,DB.TOB(J)		;SAVE TAKER
	DEC	DB.TOC(J)		;COUNT CHAR OUT
	BNE	60$
	TST	R0
	BEQ	55$
	BIC	#CNKSIZ-1,R0		;POINT TO ADR OF CHUNK
	JSR	PC,FRECNK		;RELEASE CHUNK
55$:	CLR	DB.TOB+2(J)		;NO MORE PUTTER
	CLR	DB.TOB(J)		;AND NO MORE TAKER
60$:	MOV	R1,R0			;PUT DATA IN RIGHT REG FOR RETURN
	MOV	R1,#0
66$:	JMP	IOTRET			;RETURN DATA TO USER
;HERE FOR A PUT MACRO
IOTPUT:	JSR	PC,IOCOWN		;CHECK USER OWNS DEVICE
	BNE	20$			;IN CASE PUTTING TO KEYBOARD=NCL

;HERE FOR A PUT TO PRINTER
10$:	CMP	#ERSCNT,FRECNT		;ANY ROOM LEFT ?
	BMI	14$			;IF SO PROCEDE
	BIT	#DS.ACT,@J		;IS PRINTER RUNNING ?
	BEQ	14$			;IF NOT LET HER RIP
	JSR	PC,IOTIOW		;WAIT FOR CORE TO BE AVAILABLE
	BR	10$
14$:	PIOFF
	MOV	DB.PPT(J),R0		;GET PRINTER PUTTER
	BNE	16$
	JSR	PC,ERSGET		;GET A CHUNK FOR CHAR
	TST	(R0)+			;SKIP LINK WORD
	MOV	R0,DB.PTK(J)		;INITIALIZE THE TAKER
16$:	ADVCNK	R0 EXTEND
18$:	MOVB	@R2,(R0)+		;PUT CHAR INTO QUEUE
	MOV	R0,DB.PPT(J)		;SAVE UPDATED PUTTER
	INC	DB.PCN(J)		;COUNT CHAR
	PION
	JSR	PC,BEGXMT		;BEGIN TYPING
	JMP	IOTFIN

;HERE FOR A PUT TO KEYBOARD (=NCL)
20$:
	BIT	#DS.DIE!DS.DSC,@J	;IS HOST DOWN
	BNE	30$
	BIT	#DS.CON,@J		;ARE WE STILL CONNECTED
	BEQ	30$
	CMPB	#TTYMIC,DB.ICC(J)	;IS MSG ALREADY FULL ?
	BPL	26$
23$:	JSR	PC,IOTIOW		;WAIT OR GIVE ERROR RETURN
	BR	20$
26$:	MOVB	@R2,R0			;GET DATA
	BIC	#^C377,R0		;MASK OUT GARBAGE
	BIS	#DS.PAU,@J		;SET PAUSE FOR LINE EFFICIENCY
	JSR	PC,RECINT		;GO HANDLE INPUT CHARACTER
	BIS	#DS.Q10,@J		;FLAG WE SENT KYBD DATA
	JMP	IOTFIN
30$:	JMP	IOTBUM		;ERROR RETURN
;HERE FOR AN IMGPUT MACRO
IOTIMP:	JSR	PC,IOCOWN		;SEE IF WE CAN HAVE DEVICE
	BEQ	10$			;BRANCH IF PUTTING TO PRINTER
7$:	JMP	IOTBUM			;ONLY DO THIS FOR PRINTER
10$:
.IF NE FT.CTY
	CMP	J,#CTYDDB
	BEQ	7$
.ENDC;.IF NE FT.CTY
11$:	PIOFF
	BIT	#DS.ACT,@J		;IS PRINTER ACTIVE ?
	BEQ	12$
	PION
	JSR	PC,IOTIOW		;WAIT FOR PRINTER TO STOP
	BR	11$
12$:	BIS	#DS.ACT,@J		;FLAG IS ACTIVE NOW
	;MOV	R1,R1			;PUT ADR OF STRING IN RIGHT REG
	MOV	@R2,R0			;PUT COUNT IN RIGHT REG
	BMI	14$			;CHECK COUNT IS NEGATIVE
	NEG	R0			;MAKE IT NEGATIVE
14$:	JSR	PC,DHIMTY		;TYPE STRING
	PION
80$:	BIT	#DS.ACT,(J)		; ACTIVE (I.E. TYPING)
	BEQ	90$
	JSR	PC,IOTIOW			; IO WAIT
	BR	80$			; TILL DONE
90$:	JMP	IOTFIN
;HERE FOR A RELEASE MACRO
IOTREL:	JSR	PC,IOCOWN		;CHECK USER OWNS DEVICE
	CLR	@R0			;CLEAR OUT DB.TSK
	JMP	IOTFIN

;HERE TO CHECK IF TASK OWNS (OR CAN HAVE) A DEVICE
; CALL:	JSR	PC,IOCOWN
;	  IF CAN'T HAVE WILL GO TO IOTBUM
;	RETURNS WITH Z BIT SET IF PRINTER REQ; ELSE Z BIT CLEAR
;	 AND R0 POINTS TO RIGHT DB.TSK SLOT
IOCOWN:	MOV	R3,R0			;GET FLAGS
	SWAB	R0			;PUT FLAGS IN RH
	BIC	#^CIO.IDX,R0		;LEAVE ONLY IO INDEX
	ADD	J,R0			;WE WANT IO.IDX+J+DB.TSK
	ADD	#DB.TSK,R0		; SO FINISH DOUBLE INDEX
	TST	@R0			;ANYONE ALREADY USING FACILITY ?
	BEQ	20$			;CAUZ IF FREE U WIN
	CMP	TASK,@R0		;OR MAYBE WE ALREADY OWN IT ?
	BEQ	22$			;CAUZ THAT COOL ALSO
	TST	(P)+			;CLEAN OFF STACK
	JMP	IOTBUM			;AND EXIT SVC
20$:	BIS	#TK.NOP,@TASK		;DEVICE HAS NOT BEEN OPENED
22$:	MOV	TASK,-(P)		;SAVE TASK BLOCK ADR ON STACK
	MOV	@P,@R0			;STUFF TASK BLOCK ADR IN DDB
	ADD	#TK.DTK,@P		;POINT TO DEVICE SLOT
	MOV	R0,@(P)+		;SAVE <DEVICE BLOCK ADR>+DB.TSK+IO.IDX
	BIT	#IO.KYB*400,R3		;SET/CLEAR Z BI
	RTS	PC

IOTIOW:	BIT	#IO.NBK,@TASK		;IS THIS A NONBLOCKING REQUEST ?
	BEQ	10$
	TST	(P)+			;POP RETURN OFF STACK
	JMP	IOTBUM			;GIVE ERROR RETURN
10$:	MOV	J,-(P)			;SAVE DDB POINTER
	MOV	TASK,J			;POINT TO RIGHT TASK
	JSR	PC,STPTSK		;STOP TASK
	MOV	(P)+,J			;RESTORE DDB POINTER
	JSR	PC,LOPTK7		;WAIT FOR A WHILE
	RTS	PC			;AND BACK TO CALLER

;HERE TO REMOVE A TASK FROM A RUN QUEUE
STPTSK:	MOV	R0,-(P)			;SAVE REG
	PIOFF				;DISABLE INTERRUPTS
	MOV	TK.PRI(J),R0		;POINT TO RUN QUEUE
	CMP	TK.RQL(R0),J		;DID WE FIND OURSELVES YET ?
	BEQ	20$
	TRAP
20$:	MOV	TK.RQL(J),TK.RQL(R0)	;DELINK US
	BIC	#TK.RUN,@J		;CLEAR RUNNING FLAG
	BIT	#TK.WAK,(J)		;WAKE TASK ?
	BEQ	90$
	JSR	PC,TSKWAK		; WAKE HIM UP
90$:	PION
	MOV	(P)+,R0			;RESTORE REGISTER
	RTS	PC
.IF NE FTDM11
;
;MACROS TO GET SET AND CLEAR BITS
;	BIT0	IF ONE SET IS A DATASET LINE (READ ONLY)
;	BIT1	DATA TERMINAL READY (READ ONLY)
;	BIT2	REQUEST TO SEND
;	BIT3	SECONDARY TRANSMIT
;	BIT4	SECONDARY RECEIVE
;	BIT5	CLEAR TO SEND
;	BIT6	CARRIER
;	BIT7	RING
;	BIT8	=0 IF LINE CONNECTED
;	BIT9	=0 IF HOST IS THERE
;	BIT15	=1 IF EITHER BIT8 OR BIT9 SET
;
;CODE (12) GETBIT
IOTGTB:	JSR	PC,DMSETU		;POINT DM11BB TO LINE
	BEQ	IOTGTX			;IN CASE OF ERROR
	BIC	#^C376,R0		;CLEAR GARBAGE
	BIT	#LCB.DS,R2		;IS THIS A DATA SET LINE
	BEQ	05$			;SKIP IF NOT
	INC	R0			;SET DSL BIT
05$:	BIT	#DS.CON,@J		;IS DEVICE CONNECTED?
	BNE	10$			;SKIP IF OK
	BIS	#B8+B15,R0		;SET ERROR STATUS
10$:	BIT	#DS.DIE!DS.DSC,@J	;IS HOST THERE
	BEQ	20$			;SKIP IF OK
	BIS	#B9+B15,R0		;SET ERROR STATUS
20$:	JMP	IOTRET			;RETURN BITS

;CODE (14) SET BITS
IOTSET:	MOV	@R1,R4			;PICK UP MASK
	BIC	#177761,R4		;STRIP EXTRANEOUS BITS
	JSR	PC,DMSETU		;POINT TO DM11BB LINE
	BEQ	IOTGTX			;IN CASE OF ERROR
	BIS	R4,@R1			;SET BITS
	BR	IOTGTB			;GET NEW BITS AND RETURN

;CODE (16) CLEAR BITS
;
IOTCLR:	MOV	@R1,R4			;GET MASK
	BIC	#177761,R4		;STRIP EXTRANEOUS BITS
	JSR	PC,DMSETU		;POINT DM11BB TO LINE
	BEQ	IOTGTX			;IN CASE OF ERROR
	BIC	R4,@R1			;CLEAR BITS
	BR	IOTGTB			;GET NEW BITS AND RETURN

IOTGTX:	JMP	IOTBUM			;ERROR RETURN TO USER
;HERE TO POINT DM11BB TO A PARTICULAR LINE
;
;CALL	JSR	PC,DMSETU	;J POINT TO DDB
;	Z BIT SET IF FAIL
;	Z BIT CLEARED IF OK
;	CONTENTS OF DB.LCB IN R2
;	AND CONTENTS OF DM11BB REG ON R0
DMSETU:
	MOV	@DB.LCB(J),R2
	BIT	#LCB.DS,R2		;IS LINE A DATA SET?
	BEQ	90$			;NO SO RET WITH ERROR
	MOV	DB.HDW(J),R3		;POINTER TO DH11 BLOCK
	MOV	DHB.DM(R3),R3		;DM11BB HARDWARE ADDRESS
	BEQ	90$			;DONE
	MOV	#140,R0			;COUNTER TO BE SURE DM11BB WORKS
	MOV	#DM.SCN,@R3		;CLEAR SCANNER
20$:	MOV	R3,R1			;COPY ADDRESS OF DM11BB
	BIT	#DM.BSY,(R1)+		;TEST FOR STILL BUSY
	BEQ	21$
	SOB	R0,20$
	TWIDDLE	R3			;COUNT BUSTED DM11BB'S
	SEZ				;FLAG WE LOST
	BR	90$
21$:	MOVB	DB..LN(J),R0		;GET LINE NO
	MOV	R0,@R3			;POINT TO LINE
	BIS	#1,@R1			;WANT TO LOOK AT LINE
.IF NE FT.CHK
	MOV	@R3,R0			;GET DM11BB REGISTER
	BIC	#^C17,R0		;STRIP ALL BUT LINE SELECT
	CMPB	DB..LN(J),R0		;IS THIS LINE DESIRED
	CHK	EQ
.ENDC ;IF NE FT.CHK
	MOV	@R1,R0			;GET STATUS FOR LINE
	CLZ				;CLEAR Z BIT
90$:	RTS	PC
.IFF
IOTGBT:
IOTSET:
IOTCLR:
	CLR	R0
	JMP	IOTRET
.ENDC ;.IF NE FTDM11
.IF NE DN11N
;
;CODE (20)	DIAL MACRO 
;
;SUBROUTINE TO START AN AUTO DIAL SEQUENCE
;CALLED BY TTYSER FOR AN RDX DEVICE
;ROUTINE DESTROYS REGS 0,1,2
;
;
DNSTTJ:
	BIT	#DNRREQ,DB.DNR(J)	;NEED TO DIAL
	BEQ	20$			;NO
	BIC	#DNRREQ,DB.DNR(J)	;CLEAR REQUEST
	BIC	#TS.DTR+TS.RNG,DB.DCS(J)	;IN CASE LOSE
	JSR	PC,DNADDR		;R1=DNTAB,R2=HDW
	BIT	#DN.PWI+DN.ACR,@R2	;POWER ON AND HEALTHY?
	BNE	40$			;NO
	MOV	DB.LCB(J),R0		;SET STATE TO DIAL
	MOVB	#LCS.DL,LC.STA(R0)	;GET DTR UP
	BISB	#DNDIAL,DB.DNS(J)	;FLAG WE ARE DIALING
	BIT	#DN..CR+DN.DLO,@R2	;CALL REQUEST UP?
	BNE	10$
	JMP	DNBEGN
10$:	BIC	#^CDN..ME,@R2	;CLEAR CALL
	MOVB	#<100*TMDLO+DN.TDL>,DB.DNT(J)	;SET TIMER
20$:	RTS	PC
40$:	BIS	#DNRERR+DNREAD,DB.DNR(J)	;AUTO DIALER FAILER
;	JSR	PC,WAKEPP	;WAKE PRINTER TASK
;	RTS	PC
;
WAKEPP:
	SAVE	<J>
	MOV	DB.TSK+4(J),J
	BEQ	50$		;NO TASK ATTACHED
	JSR	PC,TSKWAK	;WAKE THE TASK
50$:	RESTORE	<J>
	RTS	PC
;
IOTDNL:	JSR	PC,IOCOWN		;ERROR RETURN IF SOMEONE ELSE OWNS TTY
	BIT	#40,DB.DVT(J)		;IS THIS AN AUTODIAL LINE?
	BEQ	12$			;NO, TAKE ERROR RETURN
	TSTB	(R2)			;TERMINATE REQUEST?
	BEQ	70$			;YES
	CMPB	#1,(R2)			;STATUS REQUEST?
	BEQ	50$			;YES
					;NO, MUST BE A DIAL REQUEST
	BITB	#DNDIAL,DB.DNS(J)	;ARE WE ALREADY DIALING
	BEQ	20$			;NO
10$:	BIS	#DNREBY+DNRERR,DB.DNR(J) ;SET ERROR CONDITIONS
12$:	JMP	IOTBUM			;FAILURE RETURN
20$:
	BIT	#TS.DTR,DB.DCS(J)	;CALL UP ON LINE?
	BNE	10$			;YES, ERROR RETURN
	BIC	#DNRERR+DNREAD+DNRANS+DNRENC+DNREBY,DB.DNR(J) ;CLEAR FLAGS
	BITB	#IO.AR2,@TASK		;CHECK IF IN A REG
	BEQ	25$			;SKIP IF NO
	MOV	@R1,R1			;GET ADR OFF STACK
25$:	MOV	R1,R3			;MOVE ADDRESS OF CHARACTERS
	JSR	PC,DNADDR		;GET DNTAB ADDRESS IN R1
					;DN STATUS REG IN R2. R0 DESTROYED
	MOV	#6,R4			;DISPLACEMENT INTO DNTAB
	ADD	R1,R4			;OF FIRST DIGIT
	MOV	R4,4(R1)		;INITIALIZE POINTER
	CLRB	(R4)+			;FIRST BYTE IS 0
	MOV	#16.,R2			;MAXIMUM # OF CHARACTERS
30$:	MOVB	(R3)+,R0		;GET NEXT CHARACTERS
	BIC	#177600,R0		;KEEP 7 BITS
	CMP	#60,R0			;IS IT LESS THAN 0?
	BGT	35$			;YES, INSERT A 17
	CMP	#71,R0			;IS IT GREATER THAN 9?
	BLT	35$			;YES, INSERT A 17
	BIC	#177760,R0		;STRIP EXTRA BITS
	MOVB	R0,(R4)+		;INSERT IT
	DEC	R2			;ALL DONE?
	BNE	30$			;NO
35$:	MOVB	#17,(R4)		;YES INSERT TERMINATOR
40$:	BIS	#DNRREQ,DB.DNR(J)	;DIAL REQUEST
	JSR	PC,QUEDEV		;WAKE SERVICE ROUTINE
45$:	JSR	PC,IOTIOW		;WAIT UNTIL ALL DONE
	BIT	#DNRERR,DB.DNR(J)	;ERROR?
	BNE	12$			;YES, TAKE ERROR RETURN
	BIT	#DNRANS,DB.DNR(J)	;CALL ANSWERED?
	BEQ	45$			;NO, WAIT
	JMP	IOTFIN			;ALL DONE
50$:	MOV	DB.DNR(J),(R1)		;RETURN STATUS
	JMP	IOTFIN			;ALL DONE
70$:	JSR	PC,DNADDR		;DIALER SHOULD DISCONNECT
	JSR	PC,DNCLR

.IFF
IOTDNL:
.ENDC ;IF NE DN11N
	JMP	IOTFIN
;CODE (200) WAKE TASK
WAKTSK:	JSR	PC,TSKWAK
	JMP	IOTFIN

;CODE (202) TRIGGER TASK
TRGTSK:	BIS	#TK.TRG,@J		;RESTART WHEN REASONABLE
	BIT	#TK.LGI,@J		;HAS TASK BEEN EXITED ?
	BNE	90$			;IF NOT WE ARE DONE
	MOV	TK.JSA(J),R0		;GET STARTING ADDRESS
	JSR	PC,TSKBEG		;SETUP TO RUN
90$:	JMP	IOTFIN

;HERE TO LOG A TASK IN, I.E. EITHER START OR RESTART IT
; CALL	MOV	#<TSK BLK ADR>,J
;	MOV	#<STARTING ADR>,R0
;	JSR	PC,TSKBEG
TSKBEG:	MOV	J,R1			;COPY BLOCK ADR
	ADD	#TK.ZER,R1		;MAKE ADR OF 1ST LOCATION TO CLEAR
	MOV	#<TK.SIZ-TK.ZER>/2,R2
22$:	CLR	(R1)+			;CLEAR NEXT LOCATION IN BLOCK
	SOB	R2,22$
	MOV	TK.PDL(J),R1		;GET STACK POINTER
	MOV	R0,-(R1)		;SAVE STARTING ADR
	SUB	#14,R1			;SKIP REGS
	MOV	R1,TK.PDL+2(J)		;SAVE CURRENT PDL POINTER
	PIOFF
	MOV	#TK.LGI,@J		;INITIALIZE THE STATUS WORD
	JSR	PC,TSKRUN		;SET TASK RUNNABLE
	PION
	RTS	PC

;CODE (204) SEND TO TASK
SNDTSK:	MOV	TK.SPT(J),R0		;GET QUEUE PUTTER
	TST	(R0)+			;ADVANCE PUTTER
	CMP	#TKSQSZ*2,R0		;HIT END OF QUEUE ?
	BNE	10$
	CLR	R0			;RESET TO BEGINING OF QUEUE
10$:	CMP	R0,TK.STK(J)		;WOULD THAT HIT TAKER ?
	BEQ	SNDT69			;IF SO REJECT REQUEST
	ADD	J,R0			;MAKE ABSOLUTE
	MOV	@R2,TK.SQU(R0)		;PUT DATA INTO QUEUE
	SUB	J,R0
	MOV	R0,TK.SPT(J)		;SAVE UPDATE PUTTER
	BR	WAKTSK			;NOW WAKE RECEIVING TASK

SNDT69:	JMP	IOTBUM

;CODE (206) RECEIVE FROM TASK
RCVTSK:	MOV	TASK,J			;GET OUR TASK BLOCK
	MOV	TK.STK(J),R0		;GET QUEUE TAKER
	CMP	R0,TK.SPT(J)		;IS IT SAME AS PUTTER ?
	BNE	20$
	JSR	PC,IOTIOW		;WAIT
	BR	RCVTSK			;THEN TRY SAME SILLY TEST
20$:	TST	(R0)+			;ADVANCE TAKER
	CMP	#TKSQSZ*2,R0		;TIME TO WRAP ?
	BNE	24$
	CLR	R0
24$:	MOV	R0,TK.STK(J)		;SAVE TAKER
	ADD	J,R0			;MAKE ABSOLUTE
	MOV	TK.SQU(R0),R0		;GET NEXT ENTRY FROM QUEUE
	JMP	IOTRET			;RETURN DATA


;CODE (210) HIBER
HIBER.:	MOV	TASK,J			;GET OUR TASK BLOCK
	PIOFF
HIBSLP:	MOV	@R2,TK.TIM(J)		;SET TIMER
	JSR	PC,STPTSK		;STOP THE TASK
;	BIT	#TK.WAK,@J		;HAS A WAKE HAPPENED ?
;	BEQ	20$			;IF NOT JUST CALL SCHEDULER
;	JSR	PC,TSKRUN		;SET TASK RUNNABLE AGAIN
20$:	PION				;REENABLE INTERRUPTS
	JSR	PC,LOPTK7		;BACK TO SCHEDULER
	JMP	IOTFIN			;THEN EXIT UUO

;CODE (214) SLEEP
SLEEP.:	MOV	TASK,J		;GET TASK BLOCK
	TST	@R2		;CHECK SLEEP TIME
	BEQ	20$		;FINISHED IF ZERO
	PIOFF
	BIS	#TK.SLP,@J	;SET SLEEP BIT
	BR	HIBSLP		;PUT TO SLEEP
20$:	JMP	IOTFIN		;DONE
;CODE (212) EXIT
TSKEND:	MOV	TASK,J			;POINT TO OUR TASK BLOCK
	MOV	FIRDDB,R0		;POINT TO FIRST DEVICE BLOCK
	BR	28$			;IN CASE NONE
20$:
.IF NE FT.RDA
	TST	DB.RDT(R0)		;RDA?
	BNE	23$			;YES, SKIP IT
.ENDC;IF NE FT.RDA
	BIT	#DS.TTY,@R0		;IS IT A TTY ?
	BEQ	26$
23$:	MOV	R0,R1			;COPY DDB ADR
	ADD	#DB.TSK,R1		;POINT TO TASK WORDS
	MOV	#4,R2			;COUNTER
22$:	CMP	J,@R1			;IS THIS ONE US ?
	BNE	24$
	CLR	@R1			;THIS NO LONGER TRUE
24$:	TST	(R1)+			;ADVANCE TO NEXT SLOT
	SOB	R2,22$
26$:	MOV	DB.LNK(R0),R0		;GET NEXT DEVICE BLOCK
28$:	BNE	20$
	CLR	TK.TIM(J)		;STOP TIMER
	PIOFF				;WHILE WE STOP THE TASK
	BIC	#Tk.WAK,(J)		;KILL IT IN ALL CASES
	JSR	PC,STPTSK		;STOP THE TASK
	BIC	#TK.LGI,@J		;KILL TASK
	PION
	BIT	#TK.TRG,@J		;WAS TASK TRIGERED ?
	BEQ	90$
	MOV	TK.JSA(J),R0		;GET STARTING ADDRESS
	JSR	PC,TSKBEG
90$:	JSR	PC,LOPTK7		;AND OUT

;HERE TO SET A TASK RUNNABLE
; CALL	MOV	#<TSK BLOCK ADR>,J
;	JSR	PC,TSKRUN
TSKRUN:	SAVE	<R0,R1>
	MOV	TK.PRI(J),R1		;POINT TO RUN QUEUE HEADER
32$:	MOV	R1,R0
	MOV	TK.RQL(R0),R1		;GET ADR OF NEXT TASK
	BNE	32$
	CLR	TK.RQL(J)		;CLEAR OUR RUN-QUEUE LINK
	MOV	J,TK.RQL(R0)		;PUT NEW TASK AT END OF QUEUE
	BIS	#TK.RUN,@J
	BIC	#TK.WAK,@J
	MOVB	#TKQTIM,TK.QTM(J)	;RESET QUANTUM RUN TIME
	RESTORE	<R1,R0>
	RTS	PC

;HERE TO WAKE A TASK
; CALL	MOV	#<TSK BLK ADR>,J
;	JSR	PC,TSKWAK
TSKWAK:	PIOFF				;DISABLE INTERRUPTS FOR A WHILE
	BIT	#TK.LGI,@J		;DID TASK EXIT ?
	BEQ	90$			;IF SO WE ARE DONE
	BIT	#TK.SLP,@J		;IS TASK SLEEPING
	BNE	90$			;DONT WAKE IF IT IS
	BIS	#TK.WAK,@J		;SET WAKEUP FLAG
	BIT	#TK.RUN,@J		;TASK ALREADY RUNNING ?
	BNE	90$			;IF SO WE ARE DONE
	JSR	PC,TSKRUN		;SET TASK RUNNABLE
90$:	PION
	RTS	PC

;HERE TO WAKE A TASK ASSOCIATED WITH 'PRINTER GETS'
; CALL	MOV	<DDB ADR>,J
;	JSR	PC,TK0WAK
;	  RETURN WITH Z BIT SET IF NO TASK
;	  ELSE Z BIT CLEARED
TK0WAK:	TST	DB.TSK(J)		;IS THERE A TASK
	BEQ	90$			;IF NOT JUST RETURN
	MOV	J,-(P)			;SAVE DDB ADR
	MOV	DB.TSK(J),J		;POINT TO TASK BLOCK
	JSR	PC,TSKWAK		;GO WAKE THE TASK
	MOV	(P)+,J			;RESTORE DDB POINTER & CLR Z BIT
90$:	RTS	PC
;HERE TO WAKE A TASK ASSOCIATED WITH 'CONNECTION BROKEN"
;CALL	MOV	<DDB ADR>,J
;	JSR	PC,HSTWAK
;	RETURN WITH Z BIT SET IF NO TASK
;	ELSE Z BIT CLEARED
HSTWAK:	MOV	J,-(P)	;SAVE DDB ADR
	MOV	DB.TSK(J),J	;POINT TO TASK BLOCK
	BEQ	90$		;EXIT IF NO TASK
	BIC	#TK.SLP,@J	;CLEAR SLEEP BIT
	CLR	TK.TIM(J)	;AND SLEEPING TASKS
	JSR	PC,TSKWAK	;WAKE TASK
90$:	MOV	(P)+,J		;RESTORE DDB POINTER AND CLEAR Z BIT
	RTS	PC
.ENDC;.IF NE FT.TSK