Google
 

Trailing-Edge - PDP-10 Archives - BB-PBDED-BB_1990 - 10,7/unsmon/xtcser.mac
There are 9 other files named xtcser.mac in the archive. Click here to see a list.
TITLE	XTCSER - DA28 SERVICE ROUTINE AND XTTSK. UUO PROCESSOR - V163
SUBTTL	DONALD LEWINE/DAL/RCR/TAH/KR/RDH/KR   17-APR-90

	SEARCH F,S
	$RELOC			;RELOCATE

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
;  OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
; 1974,1975,1976,1977,1978,1979,1980,1984,1986,1988,1990.
;ALL RIGHTS RESERVED.

.CPYRT<1974,1990>


XP	VXTCSR,163		;PUT VERSION NUMBER IN STORAGE MAP AND GLOB

XTCSER::ENTRY	XTCSER		;LOAD XTCSER IF NEEDED FROM LIBRARY

SUBTTL	REVISION HISTORY
COMMENT \		;;; REVISION HISTORY

V064	FIX INPUT BUFFER SIZE CHECK & ADD NEW EP MODES

V065	ADD FTFRC CONDITIONAL, FIX HUNG DEVICE RECOVERY (RDYCHK)

V066	ADD HISTORY TABLE TO TRACE DA28C TRANSACTIONS

V067	ADD ADDITION ERROR RECOVERY & FIX TTY RESET ON GET

V070	CORRECT OUTPUT OF WFO ETC. AND ADD MESSAGE ACK
	ADD XTGRB AND XTRET SUB-FUNCTIONS TO XTTSK. UUO

V071	FIRST ROUND MODS FOR 5.07/6.01

V072	FIX BUFFER LOOK AHEAD CODE IN INPUT/OUTPUT

V073	VARIOUS FIXES + RE-WRITE OF UNIT INTERLOCK LOGIC

V074	USE WORD COUNT SUPPLIED BY USER AND NOT THE BUFFER SIZE
	ON OUTPUT UUO'S. MOREOVER IGNORE EMPTY BUFFERS

V075	REMOVE A RACE CONDITION BETWEEN RECCLS CODE AND RFI OUTPUT

V076	USE DEVIOS INSTEAD OF S AT UUO LEVEL

V077	LAST BUFFER WAS LOST DUE TO WRONG END OF FILE LOGIC

V100	THE USE OF S CAUSES THE GLOBAL PIOMOD TO RETURN THE WRONG
	IOMODE. USE A GLOBAL PIOMOD INSTEAD

V101	THE XTGRB FUNCTION SHOULD REMOVE A DEVICE FROM THE CONSO
	SKIP CHAIN AS ELSEWHISE REAL TIME USE OF THE DA28 WILL
	CAUSE PROBLEMS WHENEVER A DEVICE ON THE SAME PI CHANNEL
	IS BEING USED

V102	ANY XTGRB CONDITION SHOULD FAIL AS LONG AS THE CONTROLLER
	HAS NOT BEEN RETURNED

V103	XTCOUT USED THE WRONG LOGIC FOR EMPTY BUFFERS

V104	TTY I/O NO LONGER ALLOWED A USER TO LOG IN ON A DA28 TERMINAL
	AS UNNECESSARY WAKES WERE BEING DONE

V105	CLEAR XMIT STATUS BITS ON AN INIT SO A DDB CAN BE REUSED WITHOUT
	DELETING IT
V106	IF AN EP WANTS TO KNOW WHETHER A PROCESS ON THE DECSYSTEM-10
	IS SLOW OR THAT THE DECSYSTEM-10 HAS BEEN RELOADED IT HAS NO
	TOOL. MOREOVER IT CANNOT COMMUNICATE ITS OPINION ON THE STATE OF
	AFFAIRS. THEREFORE INTRODUCE A RESTART STATUS (SF=7), WHICH
	IS SENT BY THE EP TO THE DECSYSTEM-10 AND STATES THE EP'S OPINION
	0 IS DOWN;-1 IS UP. THIS INFO IS IN THE LAST 16 BITS OF A CTL WORD
	THE -10 WILL RESPOND BY SENDING ITS STATUS. THIS WILL ABORT -10 JOBS
	IF THE EP HAS PROBLEMS

V107	A RECEIVED REJECT SHOULD CLEAR IOACT IN DEVIOS TO PREVENT HUNG DEVICES

V110	STOP USING BITS IN RIGHT HALF OF DEVIOS AND REPLACE THIS BY LOGIC
	TO RETURN AN OLD FASHIONED S

V111	DUMP MODE AND BUFFERED MODE NEED A DIFFERENT IO(D)END BIT

V112	STOP USING DEVIOS FOR ALL PROTOCOL STATUS BITS AND USE
	A PROTOCOL STATUS WORD

V113	STOP CLOBBERING S IN XOSYNC AND XISYNC ROUTINE

V114	REDO ALL THE GETCTL AND XMT PROTOCOL LOGIC IN SUCH A WAY
	THAT STOPCODE KNF SHOULD BE IMPOSSIBLE

V115	UNDO EDIT 105 AND USE THE RELEASE UUO TO RESET THE PROTOCOL STATUS
	MOREOVER SEND A RESTART TASK MESSAGE

V116	ONLY DO A WAKE OF A .C0JOB IF XTCSER HAS DONE A HIBER FOR IT

V117	SEVERAL RETURNS WERE MADE BY XTCSER FOR XTTSK UUO'S
	WHICH SHOULD HAVE BEEN JRSTS TO AN ERROR CODE GENERATOR

V120	NEEDLESS RESCHEDULING WAS DONE OF UUO CODE USE A COROUTINE ME-
	CHANISM	TO RUN UUO CODE ONLY WHEN AN EVENT NEEDED TO EXIT TO THE
	UUO CODE OCCURRED

V121	IN LOGICAL MODE 11 THE BUFFER SIZE WAS LIMITED TO THE SIZE OF THE
	MONITOR	BUFFER. THIS RESTRICTION SEEMS UNNECESSARY

V122	BUFFERED AND DUMP MODE I/O USE DIFFERENT CODE FOR MANY PURPOSES
	REDO I/O SO BUFFERED MODE IS A SPECIAL CASE OF DUMP MODE I/O

V123	MAKE DEVICES  ALWAYS IO ACTIVE EVEN IN THE RFI RFO STATUS, THIS
	WILL CAUSE FAST RESPONSES TO BENEFIT

V124	DO NOT FORCE UNITS OFFLINE AT IOGO TIME AS REMOTES CAN USE THE RESTART
	STATUS TO DETECT PROBLEMS
V125	ADD MORE DATA TO GET CHARACTERISTICS FUNCTION OF XTTSK UUO

V126	HUNG LOGIC IS WRONG YOU ONLY SHOULD CLEAR THE DA28C WHEN
	THE DDB USING THE DA28C IS THE HANGING ONE

V127	A WAKE UUO WAKING A .C0JOB DOING I/O TO OR FROM A TASK DDB
	CAN RESULT IN I/O ERRORS

V130	USERS RELIED FORMERLY ON WAKES DONE BY XTCSER TO HIBER UNTIL
	AN EVENT HAPPENED.

V132	INCLUDES UNDOCUMENTED BUG FIXES

V7132	IS 132 MODIFIED TO RUN ON KL-10 FOR 6.02

V135	INCLUDES UPDATE TO DDB STRUCTURE FOR 6.03

V7135	INCLUDES FIXES TO RUN ON KL-10 FOR 6.03, ALSO ADDS
	NEW DEBUGGING FEATURE (EXECUTION TRACE)

V141	CONVERT TO SMP (7.01), REMOVE FTKA10 ETC.

V142	PICK UP FIXES FROM KR'S CODE, ETC. RESTORE POPJ IN
	OUT UUO CODE SO OUTPUT WORKS. SEND A RESTART-10 TO ALL SMALL
	COMPUTERS AT SYSINI TIME (SO FIRST PROGGIE THAT TRIES TO
	TALK TO SMALL COMPUTER DOESN'T GET "OPR ACTION REQUESTED).
	DON'T FLUSH CACHE ON CONTROL-WORD I/O FOR KL-10 (USE NIFTY
	OUCHE ROUTINE INSTEAD) - SEEMS TO PROVIDE 10% BETTER THROUGH-
	PUT AND 10% LESS KL LOAD AT THE SAME TIME.
V7136	Includes bug fix in SYNC$, HIBER call change for 6.03A, startup patch
	and addition of documentation (6.03A only)
V143	Makes 7136 changes to 7.01 version (142)

V155	Move code from LINKDB to a new routine called XTCLNK.
\
SUBTTL	TABLE OF CONTENTS
;               TABLE OF CONTENTS FOR XTCSER
;
;
;                        SECTION                                   PAGE
;    1. REVISION HISTORY..........................................   1
;    2. TABLE OF CONTENTS.........................................   5
;    3. DEFINITIONS
;         3.1   PARAMETERS AND FEATURE TESTS......................   9
;         3.2   BIT DEFINITIONS...................................  11
;         3.3   MACRO DEFINITIONS.................................  12
;         3.4   CONTROL WORD FUNCTION CODES.......................  13
;         3.5   I/O STATUS BITS...................................  14
;         3.6   KDB LAYOUT........................................  15
;         3.7   UDB LAYOUT........................................  16
;         3.8   DDB LAYOUT........................................  17
;    4. CONSTANTS
;         4.1   BYTE POINTERS.....................................  19
;         4.2   I/O DISPATCH TABLE................................  20
;    5. TIMER ROUTINES............................................  21
;    6. XTTSK. UUO
;         6.1   SUB-FUNCTION DISPATCH TABLE.......................  22
;         6.2   UUO ENTRY.........................................  23
;         6.3   XT.RDR, XT.RDS, XT.SCH, XT.DEL....................  24
;         6.4   XT.IDN............................................  25
;         6.5   XT.MMD............................................  26
;         6.6   XTWAKF............................................  26
;         6.7   XT.GCH, XTSTAT....................................  27
;         6.8   XT.ATB............................................  28
;         6.9   SEND CLOSE INFO...................................  29
;         6.10  SPECIAL UNIT FUNCTIONS XTFRCL, XTLDXL, XTDSTL.....  30
;         6.11  XTGRB, XTRET MAINTENANCE FUNCTIONS................  31
;    7. XTTSK. SUBROUTINES
;         7.1   DELETE AN XTC DDB.................................  32
;         7.2   XTCDEV, XTCIOS....................................  33
;         7.3   FNDxxx SEARCH ROUTINES............................  34
;    8. INITIALIZATION AT SYSINI TIME.............................  35
;    9. INPUT UUO
;         9.1   DUMP MODE.........................................  37
;         9.2   BUFFERED MODE.....................................  38
;   10. OUTPUT UUO
;        10.1   DUMP MODE.........................................  39
;        10.2   BUFFERED MODE.....................................  40
;   11. I/O UUO SUBROUTINES
;        11.1   INSET, OUTSET, PSACT, MAKACT......................  42
;        11.2   IFDMP, XTCBTL, ZAPACT, XTCIPM, XFRRST, SETIPM.....  42
;        11.3   DMPSET, SETIOW, NXTIOW............................  43
;        11.4   SBINIO............................................  44
;        11.5   MPIOWD............................................  45
;        11.6   RDYCHK............................................  46
;   12. CLOSE AND RELEAS UUOS.....................................  47
;   13. INTERRUPT SERVICE
;        13.1   XTCINT, CLRERR, SETSCN............................  48
;        13.2   REMINT, DOINP.....................................  48
;        13.3   UNIINT............................................  49
;        13.4   RECUCW............................................  49
;        13.5   CHKPRC, CHKWAK....................................  50
;        13.6   DDBINT, IOREDY, BUFDON, DDBRST....................  51
;        13.7   FINDDB, FINUNI....................................  52
;   14. ERROR ROUTINES
;        14.1   UNIERR, DWNUNI....................................  53
;        14.2   CHKCER, DDBERR, NXTERR............................  54
;   15. DEBUGGING CODE
;        15.1   CONSOLE CONTROL WORD TRACE........................  55
;        15.2   EXECUTION TRACE...................................  56
;   16. RECEIVE CONTROL WORDS
;        16.1   ATTRIBUTE BYTE....................................  57
;        16.2   CLOSE.............................................  58
;        16.3   REJECT............................................  59
;        16.4   READY FOR INPUT...................................  60
;        16.5   WAITING FOR INPUT.................................  61
;        16.6   WAITING FOR OUTPUT................................  62
;        16.7   RESTART...........................................  63
;        16.8   DEAD-START........................................  64
;        16.9   TTY FUNCTION......................................  65
;        16.10  TTY SUBROUTINES...................................  66
;        16.11  DA28 SCHEDULING SUBROUTINES.......................  67
;   17. TTY FUNCTION SCNSER INTERFACE.............................  68
;   18. TRANSMITTERS OF CONTROL WORDS.............................  69
;   19. MAKE CONTROL WORDS
;        19.1   MAKxxx............................................  70
;        19.2   FINISH UP COMMON CODE.............................  71
;        19.3   SUBROUTINES ADDSIZ, GETMOD, CHKMOD................  72
;        19.4   SETACS............................................  73
;        19.5   RING BUFFER CONTROL WORD TRACE....................  74
;        19.6   SENDW.............................................  75
;        19.7   WAIT ROUTINES.....................................  76
;        19.8   ROUTINES TO GET ACCESS TO DA28 HARDWARE...........  77
;   20. DATA TRANSFER BEGIN
;        20.1   STOUTP, STINPT....................................  78
;        20.2   D28XCW TO START CONTROL WORD......................  79
;        20.3   SETUP SUBROUTINES SETKON, D28CLR, FRCOFL..........  80
;   21. COROUTINE SUPPORT ROUTINES $COROUT, SYNC$, CPOPJx.........  81
;   22. SLEEP AND WAKE ROUTINES...................................  82
;   23. EVENT COUNTERS............................................  83
; DEFINE the documentation macros

; The documentation of XTCSER's internals is normally extracted with
;RUNOFF; if the user sets the symbol LSTPLM to any value he will
;also see the RUNOFF input in the assembly listing.

DEFINE PLM <IFNDEF LSTPLM,<XLIST>>
DEFINE MLP <IFNDEF LSTPLM,<LIST>>

PLM
;+
;.autoparagraph.flag index.flag capital.lower case
;.page size 60,70
;.title ^^XCTSER\\ ^Program ^Logic ^Manual
;^^
;####
;.br;###
;.skip 5
;.center
;Program Logic Manual
;.skip 2
;.center
;XTCSER
;.skip 2
;.center
;6.03A Version 7136
;.center
;7.01 Version 143
;.skip 2
;.center
;Kalman Reti
;.skip 19
;Copyright (C) 1979 by Digital Equipment Corporation, Maynard, Massachusetts
;.skip
;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.
;.skip;The information in this software is subject to change without notice
;and should not be construed as a commitment by Digital Equipment
;Corporation.
;.skip;Digital assumes no responsibility for the use or reliability of its
;software on equipment which is not supplied by Digital.
;.page;.subtitle Table of Contents
;.nofill.nojustify;^^
;1 Introduction
;##1.1 Scope of this Document.....................................1-1
;##1.2 Purpose and Major Functions of XTCSER......................1-1
;##1.3 XTCSER Protocol............................................1-2
;##1.3.1 Data Transfer Protocol...................................1-3
;##1.3.2 Protocol not associated with data transfer...............1-4
;##1.3.2.1 TTY function control words.............................1-4
;##1.3.2.2 Reject control words...................................1-5
;##1.3.2.3 Ack control word.......................................1-5
;##1.3.2.4 Close control word.....................................1-6
;##1.3.2.5 Attribute byte control words...........................1-6
;##1.3.2.6 Restart control words..................................1-6
;##1.3.2.7 Dead start protocol word...............................1-8
;2 Data Structures
;##2.1 Feature Test Switches and Parameters.......................2-1
;##2.2 Data Blocks................................................2-3
;##2.2.1 Controller Data Block....................................2-3
;##2.2.1.1 Detailed Description...................................2-4
;##2.2.1.2 KDB Layout.............................................2-6
;##2.2.2 Unit Data Block..........................................2-8
;##2.2.2.1 Detailed Description...................................2-8
;##2.2.2.2 UDB Layout.............................................2-10
;##2.2.3 Device Data Block........................................2-10
;##2.2.3.1 Detailed Description...................................2-11
;##2.2.3.2 DDB Layout.............................................2-14
;##2.3 Other Data Structures......................................2-16
;3 Code Description
;##3.1 Periodic Routines..........................................3-2
;##3.1.1 XTCHNG...................................................3-2
;##3.1.2 XTCSEC...................................................3-2
;##3.2 XTTSK. UUO Processing......................................3-3
;##3.2.1 Functions................................................3-4
;##3.3 Initialization code........................................3-7
;##3.4 Input/Output Routines......................................3-7
;##3.4.1 Co-routine Mechanism.....................................3-8
;##3.4.2 Input UUO................................................3-10
;##3.4.2.1 Detailed Logic.........................................3-11
;##3.4.3 Output UUO Processing....................................3-13
;##3.5 Interrupt Service..........................................3-15
;##3.5.1 XTCINT...................................................3-15
;##3.5.2 DDBIO....................................................3-16
;##3.5.3 RECUCW...................................................3-17
;##3.6 Send Control Words.........................................3-19
;4 Debugging Aids
;##4.1 XTDUMP.....................................................4-1
;##4.2 Console and Execution Trace................................4-2
;##4.2.1 Console Trace of protocol words..........................4-2
;##4.2.2 Execution Trace..........................................4-3
;.fill.justify;\\
;.page;.chapter Introduction
;^^
;.hl 1 Scope of this Document
;^^
; This document is intended to give the background information
;necessary for the reader to be able to follow and/or modify
;the XTCSER software.  It assumes a knowledge of the TOPS-10
;monitor and also of the DA28 hardware.  
;.hl 1 Purpose and Major Functions of XTCSER
;^^
; The DA28 hardware provides an high-speed half-duplex data path
;between a DECsystem-10 and up to 16 "small computers" (PDP-8s,
;PDP-11s or PDP-15s).  The XTCSER software supports this hardware
;in such a way as to provide:
;.list;.le;the most comprehensive functionality for the user,
;namely any number of bi-directional data links to any number of small
;computers
;.le;an interface that is compatible with other I/O devices and hence
;usable from high-level languages such as FORTRAN
;.end list
;It accomplishes these goals by giving the user the ability to create
;a "device" which is in reality merely a representation for a single
;"conversation" between a program in the DECsystem-10 and a
;program in the small computer.  Once the user has created this "device"
;he may use only the standard I/O calls to read and write data from/to the
;small computer.  If he wishes a greater degree of control or flexiblity, he
;also has some extra monitor calls available to perform operations which
;are not analogous to those for any other I/O device.
;Therefore the main functions of XTCSER are:
;.list;.le;to implement a new CALLI (XTTSK.) to perform the control and
;extra I/O functions necessary to communicate with the small computers
;.le;to implement the normal I/O UUO's (IN, OUT, CLOSE, RELEAS) for
;the XTCSER "devices"
;.le;to handle the interrupts from the DA28 hardware in such a
;way as to allow multiple I/O operations on a single
;small computer, as well as multiple operations to several
;small computers, simultaneously.
;.end list
;These functions correspond to the three major divisions of the
;code, as well as the three major parts of this manual.
;.HL 1 XTCSER Protocol
;^^
; To implement the above-mentioned goals requires that the DECsystem-10
;and the small computer with which it is communicating exchange some control
;information about what type of data transfer is to take place; at the
;very minimum this information includes:
;.list
;.le;the desired direction of the data transfer (from -10 to small computer or vice versa)
;.le;the intended receiver process (because more than one set of pairs of tasks
;may be communicating at the same time)
;.le;the number of words to be transferred
;.le;the DA28 hardware mode of the forthcoming transfer
;.end list
;Only after both processors agree on all this information can they
;correctly set up the DA28 hardware to actually perform the transfer.
; Additional information is also necessary to ensure orderly
;termination of data communication between two processes:
;.list
;.le;notification that one process no longer intends to transmit
;data (end-of-file)
;.le;notification if a task aborts or is terminated (so that the other
;side doesn't try to communicate with a non-existent or unintended program)
;.le;notification that the operating system of the other
;computer has been restarted
;.end list
;Even more data exchange is useful to inform the other computer
;if it sends incorrect or conflicting information and
;to make certain functions more efficient.
; XTCSER conveys this information to the small computer through a
;protocol of 1-word data transfers called control words.
;There are four control words for data transfer information and
;synchronization (RFI, RFO, WFI and WFO) and six other control
;word types (some with various sub-functions) to transfer the
;rest of the control information.
;The small computer wishing to talk to XTCSER
;must adhere to the rules of this protocol (although it may not necessarily
;have to implement all the functions -- some apply only to features
;which are optional).
;.hl 2 Data Transfer Protocol
;^^
; The data transfer protocol consists of the four control words
;RFI (ready for input), RFO (ready for output), WFO (waiting for
;output) and WFI (waiting for input).  In the normal case each
;processor transmits either RFI or RFO as soon as the user task
;issues an input or output request (respectively). Either
;one may come first, depending upon which process is ready to do
;I/O first.  If the two processes both send RFI or both send RFO,
;both get an appropriate error return to their I/O requests.
; Once the two processors have agreed to the direction of transfer
;via the exchange of RFI/RFO, then the sending processor must get
;ready to actually transfer the data (e.g. perhaps swap in the job,
;map the user's buffer, do any conversion necessary, etc.).
;Then the sending processor sends a WFO control word, which
;means it is all set to transfer data.  This control word contains
;the mode and length of the transfer.  The receiving processor
;checks the mode and length; if they are unacceptable it may respond
;with either a "reject blocksize" or a "reject data mode" control
;word.  If they are both acceptable, it responds with a WFI to indicate
;that it expects a data block of the size and mode specified in the
;WFO as the next transfer.  The sending computer must then immediately
;transfer the data.
; This protocol exchange may be depicted as below:
;.nofill;.nojustify;.skip
;030550/  400001,,000220  637570,,200020        _<-- A0  RFI (1)
;030552/  000001,,000220  677573,,600020        --_> A0  RFO (1)
;030554/  000001,,000221  777573,,600020        --_> A0  WFO (1)
;030556/  400001,,000221  737570,,200020        _<-- A0  WFI (1)
;030560/  200001,,000221  777777,,000000  _>  D
;.fill;.justify;.skip
;(The above is an excerpt from the output of XTDUMP which
;displays the contents of a large circular buffer in XTCSER
;used to record protocol word transfers. For a detailed explanation
;of what all the fields mean, see Chapter 4.)
; The small computer interface may shorten this protocol when it
;is receiving input from the DECsystem-10 by sending WFO instead of
;RFO.  XTCSER assumes that the stronger protocol word (WFO) implies
;the weaker (RFO). Such a data transfer might look like this:
;.nofill;.nojustify;.skip
;031270/  400001,,000002  777764,,200020        _<-- A0  WFO (1)
;031272/  000001,,000201  737767,,600020        --_> A0  WFI (1)
;031274/  600001,,000201  777777,,000000  _<  D
;.fill;.justify;.skip
;The LIP11M driver for the DA28 under RSX11M uses this shortened
;form of the protocol when transferring data to the DECsystem-10.
; It is absolutely essential for proper operation of the protocol
;that nothing but the data to be transferred appear on the DA28
;after a WFI has been transmitted; data messages are wholly transparent,
;can contain whatever they want (even something that looks like
;a protocol word) and are therefore only identified by their
;association with the RFI, RFO, WFO and WFI control words which
;precede them.
;.hl 2 Protocol not associated with data transfer
;^^
; The other defined control words deal either with exceptional
;situations or permit a more efficient transfer of small amounts of
;specialized data.  Some of the protocol described below
;is no longer used, and exists merely to remain compatible with
;older implementations. We shall describe all the other control
;words briefly -- for more detail see the descriptions of the
;routines which actually use them.
;.hl 3 TTY function control words
;^^
;There are five TTY control words which allow a data path through
;the DA28 which behaves like a terminal line.  These functions were used on
;the RSX11-D implementation of LIPS to provide a controlling terminal
;line to the DECsystem-10 via the MCR terminal and could only be used
;by a privileged task named CONTAS.  They are not implemented at all
;on the RSX11M version of the LIPS driver.
; The five protocol words are:
;.list
;.le;"TTY get" which the small computer sends to request a line
;from the DA28 pool (receiving either a "TTY ack" or a "TTY nak"
;depending upon whether a line was available or not)
;.le;"TTY char" control word which contains a character
;which the destination processor should consider as input on the
;"terminal" line.
;(This will receive a "TTY nak" control word if the line number
;specified in the task ID field is not an XTCSER line.)
;.le;"TTY ack" (also called "TTY more") used by the -10 to acknowledge a successful "TTY get"
;request and by the small computer to acknowledge receipt of a "TTY char"
;message from the -10. (Note that only the small computer uses this
;message to answer a "TTY char"; when the DECsystem-10 receives
;a "TTY char" it doesn't send anything in response.)
;.le;"TTY nak" (also called "TTY reject") used to inform the destination processor that
;the source processor detected some illegality or that the "TTY get"
;request could not be satisfied.
;.le;"TTY delete" which the small computer sends to the -10 to
;relinquish the use of the specified DA28 "terminal" line.
;.end list
;.hl 3 Reject control words
;^^
;There are eight control words which signal errors of some kind. They are:
;.list
;.le;"reject no task" -- sent in response to any control word
;whose task identification does not match that of a currently active
;task.
;.le;"reject hung" (historical) -- used in previous implementations
;if the task in the small computer was present but couldn't be
;started. Never sent by LIP11M.
;.le;"reject function" -- sent whenever a control word with
;an illegal function or sub-function code is received.
;.le;"reject improper mode" (historical) -- sets the IOIMPM error bit
;if received by the -10. Never sent by LIP11M.
;.le;"reject improper data mode" -- sent instead of WFI if the intended data
;recipient doesn't like the data mode specified in WFO (this
;means that the two programs are not agreeing on data mode).
;The only data mode supported in LIP11M is "binary", i.e. 16-bit
;words packed as 16-bit bytes on the -10.
;.le;"reject blocksize" -- sent instead of WFI if the intended data
;recipient doesn't specify the same or greater blocksize as the sender.
;Sets IOBKTL (block too large) error on the -10 side.
;.le;"reject data error" (historical) -- sets IODTER (data error) on -10
;side; never sent by LIP11M.
;.le;"reject operation error" -- sent only by the -10 when
;it detects that the protocol has been violated (such as
;both sides trying to output to the same task).
;.end list
;.hl 3 Ack control word
;^^
;This is an historical control word, never sent by LIP11M.
;If the -10 should receive this, it would set the status
;bit IO.ACK in DEVIOS.
;.hl 3 Close control word
;^^
;This control word has a single valid sub-function which makes the
;"close EOF" control word.  This signals normal shutdown of
;communications between two processes.
;.hl 3 Attribute byte control words
;^^
;These four control words are also historical.  They were used by
;the RSX11-D implementation of LIPS, and are not sent by LIP11M. Their
;purpose was to provide a single 8-bit packet of information
;that was maintained in the -10 but could be interrogated and/or
;modified by either the -10 program or the small computer program.
;The same effect could be obtained by tranferring data messages
;according to some higher-level protocol known to the two tasks; however,
;this would require more overhead to transfer the data.
; The attribute byte control words are:
;.list
;.le;"query attribute byte" -- sent from the small computer to the -10
;to request the latter to send the attribute byte via a "transmit
;attribute byte" control word.
;.le;"transmit attribute byte" -- sent either as response to "query attribute
;byte" control word, or if user on -10 issues XTTSK. function to
;manipulate attribute bytes with the sub-function "send attribute
;byte".  Includes the attribute byte in the supplementary information field
;of the control word.
;.le;"OR attribute byte" (also called "set attribute byte" ) -- 
;this control word allows the small computer
;to turn on bits in the attribute byte individually.  The contents of
;the supplementary information field are ORed into the attribute stored in the
;DDB.
;.le;"AND attribute byte" (also called "clear attribute byte") -- 
;this control word allows the small computer to
;selectively turn off bits in the attribute byte.  The bit mask given
;in the supplementary information field of the control word is
;complemented and ANDed with the attribute byte stored in
;the DDB.
;.end list
;.hl 3 Restart control words
;^^
;The restart control words inform the destination processor
;that something in the source processor has restarted, either
;a single user task or the whole operating system (i.e. all user
;tasks that were there before have gone away). The functions are:
;.list
;.le;"restart 16-bit small computer" (also known as "restart -11") --
;sent from an -11 to the -10 to indicate that its entire operating
;system has restarted.  This will give errors to any -10 jobs currently
;doing I/O over the DA28.  This is also a pre-requisite for considering the
;small computer ready if the -10 has been restarted or after the
;unit has been forced off-line.
;.le;"restart 18-bit small computer" (also known as "restart -15") --
;same as previous except from a PDP-15.
;.le;"restart 12-bit small computer" (also known as "restart -8") --
;same as previous except from a PDP-8.
;.le;"restart remote processor" -- (historical and never sent by
;LIP11M) sent to restart all "units" within a "REP".  The task ID
;field was originally made up of two parts, a REP and a unit; this was to allow
;a single program to multiplex functions by using the high order
;part (the REP) to route data to the program, and the lower order part
;(the unit) to let the program know which sub-stream the
;data was for.  This protocol word restarts all tasks on the -10 whose
;REP field matches that passed in the control word.
;This is not useful now since LIP11M uses the concatenation
;of the REP and unit fields as a single, unique task ID.
;.le;"restart release" (also known as "restart -10") -- this
;control word is sent from the -10 to the small computer either
;at SYSINI time or whenever it does the first I/O request after
;the small computer has been off-line.  The small computer should
;respond with a "restart -11, -15 or -8" (whichever is appropriate)
;which will inform XTCSER that the small computer is alive. This
;message is illegal from the small computer, and results in a
;"reject operation error" control word response.
;.le;"restart task" -- this control word is the most common restart
;control word, and informs the destination processor that the
;task whose task-ID is given in the control word is no longer the
;same as before (it has been either halted, run anew, etc.).
;.le;"restart status" -- (historical, never sent by LIP11M) this 
;control word is sent only from the small computer to the -10
;and contains a 0 or 1 in the supplementary information
;field to indicate that the small computer has restarted
;all the tasks communicating over the DA28 or that the
;small computer wants information only, respectively.  The -10
;will respond with a "restart status" containing its opinion of the
;state of the small computer (0=down, -1=up) and also,
;if the small computer had sent a 0, perform the same functions as
;if it had received a "restart -11, -15 or -8".
;.end list
;.hl 3 Dead start protocol word
;^^
;This is an historical control word, used (I believe) in conjunction
;with the JAM XTTSK. function to bootstrap a small computer.  LIP11M
;never sends it.  Upon its receipt, XTCSER copies the entire
;control word into the cell XUBDST in the unit
;control block and wakes the associated job.
;.page.chapter Data Structures
;^^
; By data structures this document refers not only to the collection of
;data on which XTCSER operates and by which it controls its execution
;(for the most part contained in the various data blocks) but also to
;the symbols and parameters which control its assembly.  Their 
;descriptions will follow the order in which they are defined in
;XTCSER, which is not always the same as one would
;choose were one trying to organize the information logically.
;.hl 1 Feature Test Switches and Parameters
;^^
; XTCSER has several feature test switches which govern the code
;being generated.  Most are for compatibility with old versions of
;XTCSER.  It also has some parameters which govern its execution.
;Both type of symbol definition are briefly summarized below:
;.list
;.le;FTCMPx -- compatibility switches. There are four of these; all
;use the value of 0 to indicate that the "new" feature is enabled and
;the value of non-zero to indicate that the "new" feature is disabled
;(i.e. that we are trying to be compatible with older versions of XTCSER).
;They are:
;.list
;.le;FTCMP0 -- 0 means add word count to RFI/RFO/WFI; formerly it was
;only included in WFO
;.le;FTCMP1 -- 0 means to generate a "restart task"
;control word on a RELEAS UUO.
;.le;FTCMP2 -- 0 means to set IOBKTL error bit in dump mode I/O when
;a data transfer from the small computer is too short.
;.le;FTCMP3 -- 0 means do no extraneous wakes.  The previous versions of
;XTCSER would wake the job whenever an interrupt occurred, and user
;applications had come to depend upon this behavior.
;.end list
;.le;DA28Y -- this feature test assembles code for the long-line driver
;option available on the DA28.  However, I do not think
;that this will work correctly.
;.le;MX11BF -- this parameter defines the size of the monitor buffer used
;to copy data when the transfer is in "image binary" mode, i.e. 16-bit words
;right justified in each halfword.  This mode is not used
;by LIP11M, so the setting of this parameter is not usually
;necessary.  If it is changed, it must also be changed in
;COMDEV (the symbols are globals so that LINK will detect mismatched
;values).
;.le;_.DBLEN -- this is the length of the in-core circular buffer used
;to trace protocol words.  It is this buffer that XTDUMP reads; it
;is recommended that this feature remain on at all times, as the extra
;overhead is minimal and the benefits in tracking down what has
;gone wrong are enormous.  To completely disable the control
;word tracing feature one must set this symbol equal to zero.
;.le;LIVE -- this is a feature test for generating debugging code; if
;LIVE is non-zero, then we are running a "live" i.e. non-debugging
;XTCSER.  If LIVE=0, then two debugging features are
;enabled:
;.list;.le;a trace of protocol words on the CTY
;.le;another circular buffer trace, but this time of routines executed
;within XTCSER (called the "execution trace").
;.end list
;.le;FTETR -- this feature controls assembly of the execution
;trace code. If it is non-zero, each NULL macro in the source
;becomes a two-word skippable call to the execution tracer
;routine ETRACE.
;ETRACE will only trace the execution PC if the high order bit
;of the ETRFLG word is on; if the next lower order bit is on, it will
;inhibit wraparound.  Any call to ETRACE can be patched to
;be a call to ETRCON or ETRCOF instead, with the effect of setting
;or clearing the high order bit in ETRFLG (thus enabling or disabling tracing).
;The default value for FTETR is -1 if LIVE=0.
;.le;FTFRC -- if non-zero the SYSINI time initialization code
;will force all units off-line. An XTTSK. function will have to be
;executed by some program to put them on-line again. This is an old
;feature for which I can think of no use.
;.le;_.IOLEN -- the value of this parameter defines the number
;IOWD slots reserved in the DDB.  XTCSER will copy I/O words from the
;user's list (in dump mode only) into the DDB until the DDB is full, then
;execute them.  At the end of the data transfer, if there are more
;it will repeat the process.  This may cause more interrupts on the
;DA28 if the next IOWD was a continuation of the previous one.
;.le;ACCTIM -- this parameter is the number of seconds a job is "pseudo"
;active, which means that it is active but not for immediate
;data transfer.
;Once this time has expired without completion of the transfer, the
;job is made inactive (more precisely, IOACT is cleared) so
;that it may be swapped. When the final protocol steps preceding
;the data transfer have finally completed it is made active again.
;.le;QLPCNT -- this parameter is the number of times UUO level should
;loop waiting for interrupt level to complete its tasks before HIBERing.
;The normal setting is 0; the advantage of a non-zero setting is that
;if the small computer is very fast, at the expense of some small
;amount of looping in the monitor we can save the overhead associated
;with a HIBER and a subsequent WAKE.
;.end list
;In addition to these there are the normal TOPS-10 monitor feature
;test switches (such as FTKL, etc.).
;-
MLP
	COMMENT	&

THIS VERSION IS INCOMPATIBLE WITH PREVIOUS VERSIONS OF XTCSER UNLESS
SOME SPECIAL COMPATIBILITY FEATURE SWITCHES ARE TURNED ON. ALL
KNOWN INCOMPATIBILITIES ARE LISTED BELOW:

1 RFI, RFO AND WFI PROTOCOL WORDS CONTAIN THE NEGATIVE WORD COUNT OF THE
  I/O DATA TRANSFER WHEN THEY ARE SENT ON ISSUING A IN OR OUT UUO.
  PREVIOUSLY THE WORD COUNT FIELD WAS ZERO.
	COMPATIBLITY SWITCH: FTCMP0=1 GENERATE A ZERO COUNT FIELD

2 WHEN A RELEASE UUO IS EXECUTED A RESTART TASK PROTOCOL WORD IS TRANS-
  MITTED TO THE EP. THIS ENABLES A TASK ON AN EP TO DETERMINE WHETHER IT
  CAN COMMUNICATE WITH THE 10 WITHOUT WAITING (THIS IS EQUIVALENT TO A 
  DISCONNECT VALID UNTIL THE FIRST RFI OR RFO).
	COMPATIBILITY SWITCH: FTCMP1=1 DO NOT GENERATE A RESTART TASK WORD

3 IF THE TRANSFER TO OR FROM AN EP IS ENDED PREMATURELY AND DUMP MODE
  I/O IS USED THEN THE IOBKTL ERROR BIT WILL BE SET. FORMERLY THIS
  CONDITION WAS IGNORED AND THE I/O WAS TREATED AS COMPLETED.
	COMPATIBLITY SWITCH: FTCMP2=1 SET NO ERROR FLAG

4 THE DA28C IS ASSUMED TO BE AT ECO LEVEL 3. IF THE ECO LEVEL
  IS LOWER THEN RESTART THE DA28C SCANNER AT THE NEXT UNIT AT LABEL
  CLRERR.
	COMPATIBILITY SWITCH: NONE

5 PREVIOUSLY MANY UNNECESSARY WAKES WERE DONE BY XTCSER SOME USERS
  HAVE USED THIS FACT AS AN IMPLICIT WAKE FOR XTCSER ACTIVITY.
  ANY .C0JOB RELYING ON THIS FACT WILL WITHOUT REDEFINITION OF FTCMP3
  GO INTO AN INFINITE HIBER. A BETTER SOLUTION SEEMS TO BE THE USE
  OF THE XT.WAK XTTSK SUBFUNCTION, WHICH ALLOWS THE SPECIFICATION OF
  A ONE TIME EVENT FLAG FOR WHICH A WAKE WILL BE DONE. THIS FUNCTION
  IS CONTROLLED BY FTCMP3 = 0
	COMPATIBILITY SWITCH FTCMP3=1 ;DO EXTRANEOUS WAKES

6 IF THE DA28-C IS BEFORE ECO LEVEL 7 (REV D) THEN THE SWITCH ECO7 SHOULD
  BE SET 0 SO THAT THE SETKON ROUTINE WILL NOT RE-SELECT THE SMALL
  COMPUTER UNLESS THE UNIT IS CHANGING.
AS HIBERNATES ARE DONE BY XTCSER WHEN SYNCHRONIZATION WITH
AN EP HAS TO BE OBTAINED, IT SEEMS LIKELY THAT A REDUCTION IN THE
NUMBER OF HIBER CALLS MIGHT REDUCE THE OVERHEAD.
FOR THAT PURPOSE THE PARAMETER QLPCNT HAS BEEN DEFINED.
BELOW THE RESULTS FOR A LIPS IMPLEMENTATION UNDER RSX11D ARE GIVEN,
IT SHOULD BE NOTED THAT FOR CERTAIN SYSTEMS A ZERO VALUE MIGHT BE THE
BEST CHOICE.

PERFORMANCE MEASUREMENT WITH A LIPS SYSTEM RUNNING 4 TASKS
COMMUNICATING WITH 4 PDP10 JOBS SHOWED THAT:
1 IF THE LIPS DRIVER DOES NOT TRACE THEN
    PER 14 I/O UUO'S 4 HIBERS ARE DONE WITH QLPCNT=40
    PER 14 I/O UUO'S 7 HIBERS ARE DONE WITHOUT ANY DELAY IN SYNC$
  SO AT THE EXPENSE OF 14*(32+3)=490 INSTRUCTIONS
  3 CALLS TO HIBERS AND ASSOCIATED WAKJOB CALLS ARE SAVED,APPR.
  165 INSTRUCTIONS (LESS THAN 500 MUSEC)
  ANY CHOICE OF QLPCNT LOWER THAN 40 IS A LOSS IN CPU TIME.
  THE DELAY COUNT IN WTQEMP IS ALSO MAXIMAL AT A VALUE OF 40.
  VALUES LESS MAKE NO SENSE AND HIGHER VALUES DO NOT IMPROVE.

2 IF THE LIPS DRIVER TRACES THEN QLPCNT SHOULD BE AT LEAST 100
  ALL THIS APPLIES TO A SYSTEM LOADED WITH 5 JOBS OF WHICH 3 ARE 
  SWAPPING.

  NOTE THAT HIBERS DO NOT NEED TO RESULT IN A SCHEDULER CALL.
  THE LOAD MAY SIGNIFICANTLY INFLUENCE THE DA28C THRUPUT.
  VARYING PARAMETERS WITH FILDDT AND MEASURING OF THRUPUT
  WILL BE REQUIRED.
&
SUBTTL	DEFINITIONS -- PARAMETERS AND FEATURE TESTS
;ASSEMBLY PARAMETERS

;COMPATIBILITY SWITCHES:

NDL	FTCMP0,0		;ADD - COUNT TO RFI/RFO/WFI WORDS
				;FOR INPUT AND OUTPUT UUO'S

NDL	FTCMP1,0		;GENERATE A RESTART TASK WORD
				;ON A RELEASE UUO

NDL	FTCMP2,0		;SET IOBKTL ERROR BIT FOR DUMP MODE
				;I/O WHEN A TRANSFER IS TOO SHORT

NDL	FTCMP3,0		;DO NO EXTRANEOUS WAKES

NDL	DA28Y,0			;LONG LINE DRIVER

NDL	ECO7,0			;DA28-C IS PRE-ECO 7 (REV D) LEVEL

;THE PARAMETER MX11BF DEFINES THE MAXIUM NUMBER
; OF PDP-10 WORDS WHICH CAN BE TRANSFERED TO A PDP-11 IN THE
; "PDP-11 BINARY" (REALLY "IMAGE-BINARY") MODE.
XP	MX11BF,^D129		;MAXIMUM -11 BUFFER SIZE IN IMAGE-BINARY
NDL	MAXBSZ,<MX11BF/3>*2	;SIZE OF MONITOR BUFFER

ND	.DBLEN,400		;DEFINE TO BE .NE. 0 FOR RING BUFFER FEATURE
NDL LIVE,-1			;MAKE ZERO FOR DEBUG TRACING
				;SW LH 40 disables Receive CW trace
				;SW LH 10 disables Xmit XW trace
				;.TRCF RH 1 disables receive CW trace
				;.TRCF RH 4 disables Xmit CW trace
XP	FTFRC,0			;0 TO NOR FORCE UNITS OFF-LINE IN ONCE
NDL	.IOLEN,4		;FOR EFFICIENT DUMP MODE I/O
NDL	ACTTIM,2		;PSEUDO ACTIVE TIME
NDL	QLPCNT,0		;NUMBER OF TRIES BEFORE SLEEPING

IFE LIVE <
NDL FTETR,-1			;default is execution trace enabled
NDL ENMENT,4000			;default number of entries in ex. trace table
>;end IFE LIVE

;Define dummy trace macros
	DEFINE	NULL <>		;default is to do nothing
	DEFINE	TRCON <>	;"
	DEFINE	TRCOF <>	;"

IFE LIVE <
IFN FTETR <			;if execution trace enabled
	DEFINE NULL (arg) <
IFB <arg> <
	PUSHJ	P,ETRACE	;trace execution
	SKIPA			;to handle skips before instruction
>;end IFB <arg>
>;end DEFINE NULL

	DEFINE TRCON <		;turns on software trace enable bit
	PUSHJ	P,ETRCON	;turn on
	SKIPA			;handle prior skips
>;end DEFINE TRCON

	DEFINE TRCOF <
	PUSHJ	P,ETRCOF
	SKIPA
>;end DEFINE TRCOF

>;end IFN FTETR
>;end IFE LIVE
; SYMBOL CONVENTIONS:

;	SYMBOLS BEGINNING XKB ARE WORDS IN CONTROLLER DATA BLOCK
;	SYMBOLS BEGINNING XK. ARE BITS IN CONTROLLER DATA BLOCK
;	SYMBOLS BEGINNING XUB ARE WORDS IN UNIT DATA BLOCK
;	SYMBOLS BEGINNING XU. ARE BITS IN UNIT DATA BLOCK
;	SYMBOLS BEGINNING DVX ARE DDB LOCATIONS UNIQUE TO XTCSER
;	SYMBOLS BEGINNING XT. ARE BITS IN DDB
;	SYMBOLS BEGINNING XS. ARE DA28C STATUS REGISTER BITS
;	SYMBOLS BEGINNING XC. ARE DA28C COMMAND REGISTER BITS
;	SYMBOLS BEGINNING DVY ARE BYTE POINTERS INTO THE DDB
;	SYMBOLS BEGINNING CTY ARE BYTE POINTERS TO CONROL WORD IN P1
;	SYMBOLS BEGINNING XUY ARE BYTE POINTERS INTO UDB

;AC USAGE:

;S)	DEVIOS WORD FROM DDB

;P)	PUSH DOWN POINTER

;J)	USER JOB NUMBER

;R)	LOW SEGMENT RELOCATION

;F)	POINTER TO THE DDB

;U)	POINTER TO THE UNIT DATA BLOCK

;T1 TO T4) TEMPS

;M)	USER ARG LIST POINTER

;W)	CONTROLLER DATA BLOCK ADDRESS

;P1 TO P4 PRESERVED
SUBTTL	DEFINITIONS -- BIT DEFINITIONS

;BITS IN CONI/CONO DAS WORD

XS.UNI==17B21	;UNIT NUMBER
XS.ETM==1B22	;ENABLE TEST MODE
XS.EVP==1B23	;EVEN PARITY
XS.FRC==1B24	;FORCE
XS.ENL==1B24	;ENABLE LEFT
XS.ENR==1B25	;ENABLE RIGHT
XS.CLR==1B25	;CLEAR DAC
XS.NRD==1B26	;*NOT READY
XS.ETI==1B27	;ENABLE TIMER INTERRUPT
XS.TER==1B28	;*TIMER ERROR
XS.REM==1B29	;*REMOTE ERROR
XS.PAR==1B30	;*PARITY ERROR
XS.CON==1B31	;*CONNECT ERROR
XS.NXM==1B32	;*NXM ERROR
XS.PIA==7B35	;PRIORITY INTERRUPT ASSIGNMENT

;BITS IN CONI/CONO DAC WORD

XC.DRD==000040	;LEFT HAND BIT UNIT IS NOT READY


XC.ERR==1B18	;*ERROR
XC.SCN==1B19	;SCAN
XC.TST==1B20	;TEST
XC.FST==1B21	;FAST TRANSFER
XC.MOD==3B23	;MODE
XC.MEM==1B24	;MEMORY (OPPOSED TO IO BUS)
XC.CON==1B25	;CONNECT
XC.OUT==1B26	;DIRECTION (XC.OUT=1 FOR OUTPUT)
XC.SRQ==1B27	;*SELECT REQUEST
XC.ERI==1B28	;ENABLE REMOTE INTERRUPT
XC.RMI==1B29	;*REMOTE INTERRUPT
XC.EOT==1B30	;*EOT
XC.BSY==1B31	;BUSY
XC.DUN==1B32	;*DONE
XC.FT==1B33	;READ FEATURES
XC.JAM==1B34	;JAM
;MAGIC SHIFTS

UNILSH==^D36-^L<XS.UNI>-4	;AMOUNT TO SHIFT UNIT FOR CONO DAS
MODLSH==^D36-^L<XC.MOD>-2	;AMOUNT TO SHIFT XC.MOD FOR CONO
CNTLSH==^D22			;SHIFT TO POSITION WORD COUNT

;DATA PACKING MODES
DM.IMI==0B23	;IMAGE MODE
DM.ASC==1B23	;ASCII
DM.PKI==2B23	;PACKED IMAGE
DM.BIN==3B23	;BINARY

;HARDWARE MODES
MD.IMI==0	;IMAGE MODE
MD.ASC==1	;ASCII MODE
MD.PKI==2	;PACKED IMAGE
MD.BIN==3	;BINARY MODE

;MACRO TO GENERATE THE WORD COUNT
DEFINE WC(X),<-<<X>_4>>


;DEFINE FUNCTION WORD FIELDS

PR.UIS==4			;UNIT ID SIZE
PR.TIS==^D8			;TASK ID FIELD SIZE
PR.TIM==1_PR.TIS-1		;TASK ID MASK
PR.UIM==<1_PR.UIS-1>_PR.TIS	;UNIT ID MASK
SUBTTL	DEFINITIONS -- MACRO DEFINITIONS
;MACRO DEFINITIONS

;MACRO COROUT STARTS A COROUTINE SHARED BETWEEN UUO AND
;INTERRUPT LEVEL. THIS MACRO IS VALID ON BOTH LEVELS AS IT
;IS A NOOP ON INTERRUPT LEVEL.
;NOTE THAT IN ORDER TO PREVENT THE USE OF STACKS IN THE DDB
;ALL INVOCATIONS HAVE TO EXIT AT THE LEVEL OF THE COROUT
;APPEARANCE

	DEFINE	COROUT(MASK)
<	MOVE	T1,[ MASK ]	;;GET EVENT FLAGS
	PUSHJ	P,$COROUT
>

;MACROS TO RETURN FROM AN UNKNOWN LEVEL TO THE JOB UUO LEVEL
;RETURNS ARE TO THE CALLER OF THE SHARED CODE

	DEFINE	$CPOPJ		;NORMAL RETURN
<	PJRST	CPOPJ$
>

	DEFINE	$POPJ1		;SKIP RETURN
<	PJRST	CPOJ1$
>

	DEFINE	$POPJ2		;DOUBLE SKIP RETURN
<	PJRST	CPOJ2$
>

;MACRO TO SYNC ON ANY LEVEL WITH INTERRUPT EVENTS
;AND TO WAIT FOR MASK BITS IN DEVIOS
;NOTE THAT THERE IS NO RACE CONDITION!!

	DEFINE	$SYNC(MASK)
<	MOVE	T1,[ MASK ]
	PUSHJ	P,SYNC$		;RETURN HERE
>

;SEND VALUE GO TO XMT ' VALUE AND SEND OUT RESULT
;SEND RESULT AND WAIT IF W  EQUALS WAIT 

	DEFINE	SEND(V)
<	PUSHJ	P,MAK'V		;GET CONTROL WORD IN P1
	PUSHJ	P,SENDW		;THEN WAIT
>	;END O F SEND

;DELAYY IS A MACRO TO DELAY FOR DA28YS IT USES ACC TO COUNT DOWN A WAIT COUNT
	DEFINE	DELAYY(ACC)
<	IFN	DA28Y,<
	MOVSI	ACC,-20		;;DELAY COUNT
	AOBJN	ACC,.		;;WAIT HERE
> >	;END OF DELAYY
SUBTTL	DEFINITIONS -- CONTROL WORD FUNCTION CODES
;FUNCTION CODE DEFINITIONS

FN.TTY==01		;TTY CONTROL
	SF.TTC==01	;TTY CHAR IN SFI
	SF.TTM==02	;MORE
	SF.TTG==03	;GET A TTY
	SF.TTN==04	;NO TTY AVAIL
	SF.TTR==05	;RETURN A TTY LINE

FN.REJ==02		;REJECT
	SF.NOT==01	;EXTERNAL TASK DOES NOT EXIST
	SF.HNG==02	;EXTERNAL TASK IS HUNG
	SF.FNE==03	;FUNCTION ERROR
	SF.IMP==04	;IMPROPER MODE
	SF.IDM==05	;IMPROPER DATA MODE
	SF.BTL==06	;BLOCK TOO LARGE
	SF.DTE==07	;DATA ERROR
	SF.OPE==10	;OPERATION ERROR

FN.ACK==03		;ACKNOWLEDGE MSG RECEIPT
	SF.ACK==00	;UNUSED

FN.CLS==04		;CLOSE
	SF.EOF==1	;END OF FILE


FN.ATB==05		;MANIPULATE ATTRIBUTE BYTE
	SF.QAB==01	;QUERY ATTRIBUTE BYTE
	SF.XAB==02	;XMT ATTRIBUTE BYTE
	SF.OAB==03	;"OR" ATTRIBUTE BYTE
	SF.AAB==04	;"AND" ATTRIBUTE BYTE

FN.RST==06		;RESTART
	SF.6BP==01	;16 BIT PROCESSOR (PDP-11)
	SF.8BP==02	;18 BIT PROCESSOR (PDP-15)
	SF.2BP==03	;12 BIT PROCESSOR (PDP-8, PDP-12)
	SF.RRP==04	;RESTART REMOTE PROCESSOR
	SF.REL==05	;RELEASE
	SF.RTK==06	;RESTART TASK
	SF.RST==07	;RESTART STATUS

FN.DST==07		;DEAD-START

FN.RFI==14		;READY FOR INPUT
	SF.RFI==00	;UNUSED

FN.RFO==15		;READY FOR OUTPUT
	SF.RFO==00	;UNUSED

FN.WFI==16		;WAITING FOR INPUT
	SF.WFI==00	;UNUSED

FN.WFO==17		;WAITING FOR OUTPUT
	SF.WFO==0	;WFO NO SUBCODE
SUBTTL	DEFINITIONS -- I/O STATUS BITS
;IO STATUS BITS IN LH(DVXPST)

IOXXCW=(1B0)		;A CONTROL WORD IS IN THE SEND PIPE LINE
IOXRFI==(1B1)		;READY FOR INPUT HAS BEEN SENT
IOXRFO==(1B2)		;READY FOR OUTPUT HAS BEEN SENT
IOXWFI==(1B3)		;WAITING FOR INPUT HAS BEEN SENT
IOXWFO==(1B4)		;WAITING FOR OUTPUT HAS BEEN SENT
IORRFI==(1B5)		;THE EXTERNAL TASK IS READY FOR INPUT
IORRFO==(1B6)		;THE EXTERNAL TASK IS READY FOR OUTPUT
IORWFI==(1B7)		;THE EXTERNAL TASK IS WAITING FOR INPUT
IORWFO==(1B8)		;THE EXTERNAL TASK IS WAITING FOR OUTPUT

;BITS USED IN LEFT HALF OF S
;THERE IS IMPORTANT DIFFERENCE BETWEEN BITS HIBTSK
;AND WAKTSK.  HIBTSK IS USED ALWAYS WHEN A DDB PROCESS HIBERS
;WHEN USED ALONE IT MEANS THAT IT WAITS FOR AN EVENT. WAKTSK
;IS SET TO ENABLE A PROCESS TO WAIT FOR THE EMPTYING OF ALL
;OUTPUT REQUESTS.


WAKTSK==(1B8)		;JOB WAITS FOR AN EMPTY SEND Q
HIBTSK==(1B9)		;SITS IN LEFT HALF!!
FRSTIN==(1B10)		;INPUTS SET THIS WHEN STARTED
			;JOB WAITS FOR A WAKE

;BITS TURNED ON FOR USER PROGRAMS IN S
;ON A STATZ STATO OR GETSTS UUO
;NEVER USE THEM IN DEVIOS(F)!!
IO.RFI==1B24		;EXTERNAL TASK SENT AN RFI
IO.RFO==1B25		;EXTERNAL TASK SENT AN RFO
IO.WFI==1B26		;EXTERNAL TASK IS IN INPUT WAIT
IO.WFO==1B27		;EXTERNAL TASK IS IN OUTPUT WAIT
IO.BYP==1B28		;PROTOCOL BYPASS
IO.ACK==1B29		;MSG ACK (UGH)

;BITS USED TO CLEAR TRANSFER INFO

ANYACT==IOXWFI!IOXWFO!IORWFI
LHCLR==IOXRFI!IOXRFO!IOXWFI!IOXWFO!IORRFI!IORRFO!IORWFO!IORWFI!HIBTSK!FRSTIN

;BITS USED TO DO TEST ON STATUS

RHERR==IOBKTL!IODTER!IODERR!IOIMPM	;ERROR BITS
RHSTOP==RHERR!IODEND			;END OF FILE
PLM
;+
;.lm 0
;.hl 1 Data Blocks
;^^
; XTCSER has three main data blocks -- the controller data
;block (KDB) which gives information specific to a DA28C as a whole,
;the unit data block (UBD) which gives information specific to a
;single small processor on a DA28C and the DDB which contains all
;the standard DDB fields plus the DA28 information about the
;state of a single conversation through the DA28 unit.  These blocks
;are all chained together, and are hierarchical:
;.lm+10
;.nofill.nojustify
;.skip 2
;##################KDB
;####UDB-----------! !-------------UDB
;DDB-! !--DDB#################DDB--! !--DDB
;.skip
;.fill.justify
;.lm-10
;(The fact that the blocks in the above illustration have only
;two lower level blocks connected is an artifact of the primitive
;graphics scheme and does not represent any XTCSER restriction.)
;The following sections will describe each block in greater
;detail.
;-
MLP
SUBTTL	DEFINITIONS -- KDB LAYOUT
COMMENT	&

  The following code is copied from COMDEV where the interrupt
start and KDB are actually defined.  This is for information only;
to see what is actually generated one must check in COMDEV.

XP	MX11BF,^D129	;MAXIMUM PDP-11 IMAGE BINARY BUFFER SIZE
DEFINE	XTCDEF	(X),<
	IFNDEF	XT'X'S,<XT'X'S==420+X*10>
	IFNDEF	XT'X'C,<XT'X'C==424+X*10>
XP	XKBSKP,400450

XT'X'INT:: CONSO	XT'X'C,XKBSKP	;EXTERNAL PROCESSOR INTERRUPT?
	JRST	.-1		;NO, GO DOWN THE SKIP CHAIN
	JSR	XT'X'SAV##	;SAVE ALL THE AC'S
	PUSHJ	P,SAVE4##	; ..
	JSP	W,XTCINT##	;CALL XTCSER

XP	XTCCHN,XT'X'CHN##

DEFINE	XTLNK	(A) <
	IFN	A-XTCN,<
XKBKDB::!EXP	XKB'A'		;LINK TO NEXT KDB
>
	IFE	A-XTCN,<
XKBKDB::!EXP	0		;NO MORE KDB'S
>
>
XP	XKBINT,<XT'X'INT-.>

Z=X+1
XKB'X::	PHASE	0		;BEGIN CONTROLLER DATA BLOCK
XKBNAM::!XWD	'EPA'+X,0	;EP NAME
	XTLNK	\Z		;LINK TO NEXT KDB
XKBUDB::!BLOCK	21		;SPACE FOR LINKS TO UDBS
XTSCNO::!CONO	XT'X'S,(T1)
XTCCNO::!CONO	XT'X'C,(T1)
XTSCNI::!CONI	XT'X'S,T1
XTCCNI::!CONI	XT'X'C,T1
XTSDTI::!DATAI	XT'X'S,T1
XTCDTI::!DATAI	XT'X'C,T1
XTCDTO::!DATAO	XT'X'C,T1
XTSDTO::!DATAO	XT'X'S,T2
XTCBSY::!CONSZ	XT'X'C,20
XKBLOK::!EXP	-1		;INTERLOCK
XKBDDB::!BLOCK	1		;POINTER TO DDB WAITING FOR INTRPT
XKBIUN::!BLOCK	1		;POINTER TO UDB WAITING FOR INTERRUPT
XKBDAC::!BLOCK	1		;INFO FROM LAST CONI DAC
XKBDAS::!BLOCK	1		;INFO FROM LAST CONI DAS
XKBTIM::!BLOCK	1		;COUNTER FOR TIMEOUT
XKBIOW::!BLOCK	1		;IOWD FOR DAC OR PNTR TO IOLIST
XKBCUR::!BLOCK	1		;CUR PNTR TO IOLIST (KI10 ONLY)
XKBGRB::!Z			;0 IF FREE 1 IF GRABBING
				;CONTROL -1 IF GRABBED
XKBPAC::!BLOCK	1		;# OF PSEUDO ACTIVE DDB'S ON THIS
				; CONTROLLER
XKBREQ::!BLOCK	1		;OLDEST JOB # REQUESTING USE OF UDB
XKBMBF::!BLOCK	<MX11BF*3>/2	;MONITOR BUFFER
	DEPHASE

>
&;end of excerpt from COMDEV
PLM
;+
;.lm 0
;.hl 2 Controller Data Block
;^^
;.subtitle Controller Data Block
; This block contains data specific to a single DA28C; normally
;XTCSER addresses it via register W.
;Foremost among its contents are the CONO/CONI/DATAO/DATAI words, which contain
;the appropriate forms of those instructions for each DA28C.
;This enables the code to merely XCT the instruction at a specific
;offset into the KDB.
; Also in the KDB are pointers to each of the unit data blocks (UDBs),
;one for each small computer (with a spare 0 word at then end to terminate
;the list); the monitor buffer used for reading and writing data if
;information has to be reformatted in the user buffer; the words
;controlling access to the DA28C hardware either for total use (e.g.#by
;diagnostics) or in normal data transfer (for example between
;segments of a data transfer) and a few words to keep track of the
;current unit using the DA28C, where to continue processing on an
;interrupt, etc.
; The controller data block is defined and built in COMDEV; a copy of
;the code is included in XTCSER as a comment. There is a small
;amount of code generated as a prefix to each controller data
;block; this code includes the actual skip chain
;tests.  If the test succeeds (i.e. this controller is wanting to
;interrupt) it saves the registers and does a JSR W,XTCINT to
;go to XTCSER's common interrupt handling code.  Since this instruction
;immediately precedes the controller data block, this has the effect
;of loading W (the register used in XTCSER to hold the KDB address)
;correctly.
;.hl 3 Detailed Description
;^^
;The following lists all the fields of the KDB and explains
;(briefly) their uses.
;.list
;.le;XKBNAM -- this cell contains the name of the controller in
;SIXBIT.  These names are EPA for the first DA28C, EPB for
;the second, etc.  This naming convention is analogous to the naming
;of disk controllers (DPA, DPB ...) and lets the unit number refer to
;the small computer on the DA28C (EPA0 is the first computer, EPA1 the
;next, and so forth).
;.le;XKBUDB -- this is the start of a 17(8) word block; each cell
;contains the address of the corresponding UDB (i.e. XKBUDB+0 has the
;UDB address for small computer 0, XKBUDB+1 has the UDB address for
;small computer 1, etc.).  The UDB's are built at system startup time;
;their number depends upon the scan limit setting in the DA28C (a
;strap option).  This allows one to add more small computers (or
;delete them) without having to rebuild the monitor.
;A final 0 word ensures that even if there are all 16 small computers on a
;DA28C our scan for units will still terminate.
;.le;XTdCNo --these are several words which contain the
;appropriate CONI/CONI words for the DA28C.  Each DA28C responds
;to two device codes, called DAS (for DA status) and DAC (for DA
;control). For the first DA28C these correspond to codes
;420 and 424 respectively.  Each subsequent DA28C will have different
;I/O codes assigned (they are again a strap option of the hardware).
;XTdCNo (where "d" is S for DAS and C for DAC and "o" is I for
;CONI and O for CONO) words in the KDB contain the appropriate
;I/O instruction to set or read the bits using T1. This allows XTCSER
;(who always points to the KDB with register W) to do an
;.indent 20;.sk;XCT XTCCNO_#_#(W) (for example)
;.sk;to set the bits in the control register for whichever DA28C
;it is working with.
;.le;XTdDTo -- four words similar to the above but containing DATAI/DATAO DAC/DAS instructions.
;All use T1, except the DATAO DAS (XTSDTO) which uses T2 (because
;a single subroutine wants arguments for both a DATAO DAS and a CONO DAC).
;.le;XTCBSY -- contains a CONSZ DAC,20 (which tests the busy
;bit).
;.le;XKBLOK -- this is the controller interlock word.  This is -1
;if anything can be started on the controller, and 0 if "locked".  This
;happens, for example, between the time XTCSER receives a remote interrupt
;(a small computer wants to send something) and therefore starts a
;read from the small computer and the time that the done interrupt
;occurs signalling the completion of that read.  The routine D28GET sets
;this word to 0 when it gives a success return to the caller.
;This word is necessary because once we have set up a DMA read or
;write on the DA28C hardware we do not want to start up another (say
;a write of a control word for some other process) until we have
;received the done interrupt for the current one.
;.le;XKBDDB -- this word contains 0 or the address of the DDB doing
;data I/O.  XTCINT checks this word and if non-zero goes to tag
;DDBINT instead of to UNIINT.  The routine DDBIO stores F
;(the register which holds the DDB address) in this cell every time it starts
;a new IOWD.  The routine IOREDY clears this when all IOWDs have been
;processed.
;.le;XKBIUN -- this word has the address of the UCB for which the next
;done interrupt is intended in the RH, and if the transfer is associated
;with a DDB, the DDB address in the LH.  The only interrupt for
;which neither XKBDDB nor XKBIUN has a value is a select request (REMINT).
;All done interrupts require that either XKBDDB or XKBIUN (but not both)
;record who set up the transfer that is currently finishing.
;.le;XKBDAC -- on every interrupt, the result of the CONI DAC is stored here.
;.le;XKBDAS -- on every interrupt the result of the CONI DAS is
;stored here.
;.le;XKBTIM, XKBIOW, XKBCUR -- no longer used.
;.le;XKBGRB -- a flag word for the XTTSK. grab function.  Diagnostics
;"grab" the controller (as may user programs that want to do direct
;I/O [perhaps a bootstrap loader]) which means that the DA28C is
;removed from the skip chain and therefore from XTCSER's ken.
;This word is 0 if the controller is not grabbed, 1 when we are in the
;process of grabbing the controller, and -1 if the controller is grabbed.
;.le;XKBPAC -- this is a count of all the pseudo-active DDB's on this
;controller. It is there primarily to catch errors involving mismatched
;calls to make a job pseudo active and to make it no longer
;pseudo active.
;.le;XKBREQ -- this contains 0 or the job number of the first
;job requesting to grab the controller.  If the controller is busy
;at the instant that a program wishes to grab it, the XTTSK. grab
;subfunction checks this cell. If there is already a request here
;it merely goes to sleep and tries again later.  If there is no
;request here, it stores the job number of the requestor in this cell.
;When the next interrupt routine exits via SCNQUE, the fact
;that this cell is non-zero will force the DA28C to be cleared and
;the job to be awakened.
;.le;XKBMBF -- this is the monitor buffer for reading and writing to
;the DA28 if we have to transform the data for the user. This only
;occurs with "image-binary" mode, which is not supported with LIP11M.
;The length of this section depends on the parameter MX11BF
;(see above).
;.end list!KDB
;.hl 3 KDB Layout
;^^
;A pictorial representation of the controller data block would be:
;.test page 56
;.nofill.nojustify.skip 2
;          +-------------------------------------------------------+
;  XKBNAM  !         controller name in SIXBIT (e.g. EPA)          !
;          !-------------------------------------------------------!
;  XKBUDB  !         address of first UDB (PDP-11 #0) or 0         !
;          !        address of second UDB (PDP-11 #1) or 0         !
;          _\                          ...                          _\
;          !         address of last UDB (PDP-11 #17) or 0         !
;          !                 0 (to terminate list)                 !
;          !-------------------------------------------------------!
;  XTSCNO  !                    CONO DAS,0(T1)                     !
;          !-------------------------------------------------------!
;  XTCCNO  !                    CONO DAC,0(T1)                     !
;          !-------------------------------------------------------!
;  XTSCNI  !                      CONI DAS,T1                      !
;          !-------------------------------------------------------!
;  XTCCNI  !                      CONI DAC,T1                      !
;          !-------------------------------------------------------!
;  XTSDTI  !                     DATAI DAS,T1                      !
;          !-------------------------------------------------------!
;  XTCDTI  !                     DATAI DAC,T1                      !
;          !-------------------------------------------------------!
;  XTCDTO  !                     DATAO DAC,T1                      !
;          !-------------------------------------------------------!
;  XTSDTO  !                     DATAO DAS,T2                      !
;          !-------------------------------------------------------!
;  XTCBSY  !                CONSZ DAC,20 (busy bit)                !
;          !-------------------------------------------------------!
;  XKBLOK  !          controller lock (0=in use, -1 free)          !
;          !-------------------------------------------------------!
;  XKBDDB  !          DDB waiting for I/O interrupt or 0           !
;          !-------------------------------------------------------!
;  XKBIUN  !       DDB addr or 0       !   UDB waiting for done    !
;          !-------------------------------------------------------!
;  XKBDAC  !                data from last CONI DAC                !
;          !-------------------------------------------------------!
;  XKBDAS  !                data from last CONI DAS                !
;          !-------------------------------------------------------!
;  XKBTIM  !            counter for timeout (obsolete)             !
;          !-------------------------------------------------------!
;  XKBIOW  !         IOWD or pointer to IOLIST (obsolete)          !
;          !-------------------------------------------------------!
;  XKBCUR  !          pointer to current IOWD (obsolete)           !
;          !-------------------------------------------------------!
;  XKBGRB  !         0=not grabbed, 1=grabbing, -1=grabbed         !
;          !-------------------------------------------------------!
;  XKBPAC  !        no. of pseudo active DDBs on controller        !
;          !-------------------------------------------------------!
;  XKBREQ  !   0 or job number of first job grabbing controller    !
;          !-------------------------------------------------------!
;  XKBMBF  !                    monitor buffer                     !
;          _\                          ...                          _\
;          !                _<MX11BF*3_>/2 words long                !
;          +-------------------------------------------------------+
;.fill.justify.skip
;-
MLP
SUBTTL	DEFINITIONS -- UDB LAYOUT

XTCUDB::PHASE	0		;PROTOTYPE UDB
XUBNAM::!SIXBIT	/EP/		;UNIT NAME
XUBKDB::!
XUBDDB::!XWD	0,0		;DDB LIST,,KDB
XUBUNO::!BLOCK	1		;UNIT NUMBER
XUBUNI::!XWD	0,0		;RESERVED,,NEXT UDB
XUBRCW::!BLOCK	1		;RECEIVED CONTROL WORD
XUBXCW::!BLOCK	1		;CONROL WORD TO SEND
XUBQUE::!BLOCK	1		;START OF A WORK Q OF 4 WORD BLOCKS
XUBIPC::!BLOCK	1		;INTERRUPT EVENT PC
XUBLOK::!BLOCK	1		;INTERLOCK FOR UNIT (CONTAINS DDB ADDRS)
XUBRDY::!BLOCK	1		;=0 IF WE ARE WAITING FOR A RESTART
				;=-1 IF WE GOT A RESTART
XUBDST::!BLOCK	1		;DEAD-START INFO
XUBEND::!BLOCK	1		;END OF WORK LIST
XUBPAC:!BLOCK	1		;NUMBER OF PSEUDO ACTIVE TASKS FOR UNIT
XUBSIZ==:.
	DEPHASE
	RELOC	XTCUDB		;DO NOT NEED PROTOTYPE
PLM
;+
;.lm 0
;.hl 2 Unit Data Block
;^^
;.subtitle Unit Data Block
; The unit data block (UDB, addressed via register U) contains the information
;which pertains to a particular small computer interface on the
;DA28C.  This includes the unit name, the last protocol words sent
;and received, the PC with which to continue when we receive a done interrupt
;for a unit, information about whether the small computer is alive or not
;and a queue of control words to send for this unit that are
;not associated with a DDB.  Normal control word traffic is handled in
;the DDB, but there are control words (rejects, TTY functions, etc.)
;which must be sent to the small computer even if no normal data
;traffic is present.
;.hl 3 Detailed Description
;^^
;The following is a list of all the UDB fields:
;.list
;.le;XUBNAM -- this contains the unit name in SIXBIT.
;For example, the first unit on the first DA28C would be EPA0,
;the next EPA1, etc.
;.le;XUBKDB, XUBDDB -- both symbols refer to the same word.
;The LH contains the address of the first DDB on this
;unit.  The right half contains the address of the KDB for this DA28C.
;.le;XUBUNO -- this word contains the unit number in binary form.
;It is useful for shifting into the CODE position of the DA28C
;status register.
;.le;XUBUNI -- the LH is reserved, the RH contains the
;address of the next UDB on this KDB.
;.le;XUBRCW -- this is the cell into which we read control words
;from the small computer.  The DMA transfer set up at REMINT after
;we find out the small computer wishes to send us something does
;a one-word transfer into this location.
;.le;XUBXCW -- this is were we put the control word which we
;wish to send to the small computer; the DMA transfer
;to write the control word does a one-word transfer from here.
;.le;XUBQUE -- this contains either 0 or the address of the first in
;a queue of work requests for the unit.  These work requests are
;gotten from free core (in routine D28WNF) and are 4 words long.
;The contents of an entry is:
;.skip
;.lm+20;0##control word to send
;.br;1##job number
;.br;2##unused
;.br;3##address of next work request or 0.
;.lm-20
;.sk
;When SCNQUE gets control after an interrupt has
;occurred it checks this queue.  If it finds an entry, it goes to
;PHS2N0 which sets up XUBIPC to be XDNXU0 and then sends the control
;word. The done interrupt gets us to XDNXU0 which wakes the
;job, frees the work request block and starts another queued request
;(if there is one).
;.le;XUBIPC -- this word contains the routine which is to process
;the done interrupt for a unit (i.e. a control word was sent or
;received). The routine UNIINT dispatches to the address
;contained in this cell.  The possible place to dispatch
;are:
;.list;.le;RECUCW -- here after we have set up to read a control
;word at REMINT.
;.le;XDNDDB -- here if we have sent a control word for a DDB.
;.le;XDNXUB -- here if we have sent a control word not for a DDB and
;the controller was not busy. In this case we did not have to
;queue anything.
;.le;XDNXU0 -- here if we sent a control word from the XUBQUE queue.
;We have to have a different routine because it must wake the job and
;throw away the queue entry 4-word block.
;.end list
;.le;XUBLOK -- this cell contains the address of the DDB for which
;we are "locking" the unit.  This has to take place between the sending
;of WFI and doing input -- even if we have control words queued to go
;to this unit (either for other DDB's or in the unit queue) we had
;better not start anything between these points.
;This cell is set to the contents of F at XDNDDB.  When
;the small computer decides to respond, we get a select request
;interrupt and go to REMINT; this routine checks XUBLOK and if
;it is non-zero goes to DOINP to start up the data transfer.
;.le;XUBRDY -- this cell contains XTCSER's opinion of the state of
;the small computer.  If it is 0 we have not yet seen a "restart -8, -11 or -15"
;control word since 1) TOPS-10 came up or 2) the unit had been set offline
;for some reason.  In this case we believe it is down; RDYCHK will attempt
;to send it a "restart -10" control word, but in any case wait until
;the receipt of a "restart -8, -11 or -15" has set this
;to -1.
;.le;XUBDST -- if the small computer sends a dead start control word
;to XTCSER it is copied here.  The program can use an XTTSK. function
;to retrieve the information.
;.le;XUBEND -- this cell contains the address of the last 4-word
;block in the XUBQUE queue.  This is so that we may easily append a
;new entry to the queue.
;.le;XUBPAC -- this cell contains a count of the number of DDB's on this
;unit that are pseudo active.  Its usage is similar to that of XKBPAC,
;namely to catch any unmatched "make pseudo active" and "unmake pseudo active" calls.
;.end list!UDB
;.hl 3 UDB Layout
;^^
;The following is a pictorial representation of the UDB:
;.test page 30
;.nofill.nojustify.skip
;          +-------------------------------------------------------+
;  XUBNAM  !              unit name in SIXBIT (EPA0)               !
;          !-------------------------------------------------------!
;  XUBKDB  !                           !                           !
;  XUBDDB  !  addr of 1st DDB on unit  !        addr of KDB        !
;          !-------------------------------------------------------!
;  XUBUNO  !                      unit number                      !
;          !-------------------------------------------------------!
;  XUBUNI  !         reserved          !  addr of next UDB on KDB  !
;          !-------------------------------------------------------!
;  XUBRCW  !                 received control word                 !
;          !-------------------------------------------------------!
;  XUBXCW  !                 control word to send                  !
;          !-------------------------------------------------------!
;  XUBQUE  !              addr of start of work queue              !
;          !-------------------------------------------------------!
;  XUBIPC  !       PC to continue with after done interrupt        !
;          !-------------------------------------------------------!
;  XUBLOK  !           0 or addr of DDB using this unit            !
;          !-------------------------------------------------------!
;  XUBRDY  !       0=waiting restart, -1=have gotten restart       !
;          !-------------------------------------------------------!
;  XUBDST  !                dead start control word                !
;          !-------------------------------------------------------!
;  XUBEND  !              addr of end of XUBQUE list               !
;          !-------------------------------------------------------!
;  XUBPAC  !          no. of pseudo active DDB's on unit           !
;          +-------------------------------------------------------+
;.fill.justify.skip
;-
MLP
SUBTTL	DEFINITIONS -- DDB LAYOUT
XT1DDB==:0			;DUMMY OUT UNWANTED DDB'S
XT2DDB==:0
XT3DDB==:0

	$LOW

XT0DDB::
XTCDDB:	PHASE	0
	SIXBIT	//		;(0) DEVNAM
	XWD	6*HUNGST,41	;(1) DEVCHR
	0			;(2) DEVIOS
	XWD	0,XTCDSP	;(3) DEVSER
	XWD	1003,115403	;(4) DEVMOD
	0			;(5) DEVLOG
	0			;(6) DEVBUF
	0			;(7) DEVIAD
	0			;(10) DEVOAD
	0			;(11) DEVSTS
	XWD	<.TYXTC*.TYEST>!DEPLEN,DEPEVM	;(12) DEVSTA
	0			;(13) DEVXTR
	0			;(14) DEVEVM
	0			;(15) DEVPSI
	0			;(16) DEVESE
	0			;(17) DEVHCW
	0			;(20) DEVCPU
	0			;(21) DEVISN
	0			;(22) DEVDRV
	0			;(23) DEVJOB
;END OF STANDARD DDB DEFINITIONS, NEXT ARE THE XTCSER-SPECIFIC WORDS
;IN THE DDB.

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

DVXUDB:!0			;XWD DDB LIST,UDB
DVXDSC:!0			;DVXDSC
				;FORMAT OF DVXDSC:
	XT.PRM==400000		;DDB DOES NOT DISSAPPEAR AT LOGOUT
				;BITS 16-23 ARE ATTRIBUTES BYTE
				;BITS 24-35 ARE TASK ID
DVXMOD:!BYTE	(4)0,0,0,0,0,0,0,0,10 ;MODE CORRESPONDENCE
	BYTE	(4)11,0,13,14,0,0,17
DVXFZR:!			;FIRST LOCATION ZEROED
DVXCTL:!0			;LAST CONTROL WORD RECEIVED FROM TASK
DVXXCW:!BLOCK	1		;LAST CONTROL WORD SENT, OR
				; SEND THIS CONTROL WORD
DVXST4:!BLOCK	1		;SAVE PROTOCOL WORD HERE DURING XIOWAT CALL
DVXQUE:!BLOCK	1		;FUNCTION TO PERFORM WHEN
				; CONTROLLER IS IDLE
DVXIPC:!BLOCK	1		;WHERE TO GO WHEN AN 
				; INTERRUPT HAPPENS
DVXPRC:!BLOCK	1		;RETURN ADDRESS OF COROUTINE
DVXCOR:!BLOCK	1		;ADDRESS OF INTERRUPT COROUTINE
DVXMSK:!BLOCK	1		;EVENT FLAGS FOR INTERRUPT CODE
DVXRFI:!BLOCK	1		;WORD COUNT SENT BY REMOTE IN RFI
DVXWFO:!XWD	0,0		;LH - DATA MODE REC FROM TASK
				; RH - WORD COUNT REC FROM TASK
				; ALWAYS STORED POSITIVE.
DVXBSZ:!BLOCK	1		;SIZE OF INPUT AREA OR OF OUTPUT AREA
DVXIWA:!BLOCK	1		;ADDRESS OF NEXT DUMP MODE IOWD
DVXLLM:!BLOCK	1		;FIRST OF TWO TEMPS FOR DUMP MODE
DVXULM:!BLOCK	1		;SECOND OF TWO TEMPS FOR DUMP MODE
DVXCUR:!BLOCK	1		;ADDRESS IN DVXIWD LIST
DVXIWD:!BLOCK	.IOLEN-1	;IOWD FOR DUMP MODE IO
DVXILS:!BLOCK	1		;LAST WORD OF IOWD LIST
DVXPAC:!BLOCK	1		;PSEUDO ACTIVE LOCATION
DVXPST:!BLOCK	1		;PROTOCOL STATUS
DVXWAK:!BLOCK	1		;SET OF WAKE EVENTS
DVXLZR:!			;LAST LOCATION ZEROED
	DEPHASE
XTCDDW==.-XTCDDB
	$HIGH			;BACK TO HIGH SEGMENT
PLM
;+
;.lm 0
;.hl 2 Device Data Block
;^^
;.subtitle Device Data Block
; The device data block (DDB, addressed via register F) is the central collection of information
;for all I/O devices in TOPS-10.  It includes information that all
;devices have in common; this part is called the "standard" DDB, and
;the symbolic names for the offsets have the form "DEVxxx".  XTCSER
;needs additional information to correctly handle each conversation over
;the DA28 between a program on the DECsystem-10 and a process in the
;small computer; rather than invent a new data structure it simply added
;an extension to the DDB (which is not unique -- other devices
;in the monitor have done the same).
; The types of data in this DDB extension include: information
;about the state of the protocol between the -10 and the small computer,
;the IOWDs used to transfer data between the user buffer and the
;small computer, the last control word read or written on behalf
;of this DDB and the size and mode information
;from previously received control words.
;The DDB's point to the UDB of the unit that they are on, and all
;DDB's on a particular unit are also chained together.  Also,
;DDB's waiting to transfer protocol words may be chained together in
;a queue waiting for the DA28 hardware to become free.
;.hl 3 Detailed Description
;^^
;The following is a field-by-field description of the DDB extension:
;.list
;.le;DVXUDB -- the LH contains the address of the next DDB on this
;unit, the RH contains the address of this unit's UDB.  These fields
;are initialized when the DDB is built by the XT.IDN sub-function
;of the XTTSK. UUO.
;The DDB chain is used in FNDTSK, FNDDDB and FINUNI to
;look at only the DDB's on a specific unit. I/O UUO's in which only
;the DDB is known (such as CLOSE) use the RH to get the pointer to
;the UDB.
;.le;DVXDSC -- this word contains three distinct fields.  The sign bit is the
;bit that flags a DDB as permanent (XT.PRM). Bits 16-23 are the
;attribute byte and bits 24-35 are the task ID.  The latter is
;conveyed in the protocol words and serves to link a task on the
;small computer with a DDB on the DECsystem-10.
;.le;DVXMOD -- this word and the following represent the mapping
;between the software modes that the user specifies when opening
;I/O devices (e.g. 17 = dump mode, 0 = ASCII mode) and the
;hardware mode that the DA28 will use in transferring data for that
;device.  These two words consist of 16(10) 4 bit bytes, the first
;corresponding to mode 0, the next to 1 and so on.  The actual
;hardware mode values may be changed by an XTTSK. UUO sub-function.
;.le;DVXCTL, DVXXCW -- both symbols refer to the same word. The
;symbol DVXCTL is used to refer to the last control word received
;from the small computer.  The routine RECUCW copies the
;control word from the KDB into this word if the task ID is found to match
;that of a DDB. The word is also used to store the control word we
;have built to send to the small computer (DVXXCW);
;PHS2F in the SENDW routine stores the control word in this cell. 
;.le;DVXST4 -- this word is used to save the protocol word (built
;in T4, hence the name) in the DDB over the call to D28WTF (which
;puts its caller's PC in DVXQUE and returns).
;.le;DVXQUE -- this cell contains the PC at which to continue after
;a control word queued in the DDB is ready to be sent.
;If the SENDW code decides that it has no other protocol words to
;send for this DDB but that the DA28 is busy for some other process,
;it calls D28WTF, which POPs the caller's PC into DVXQUE, then returns
;to previous caller.  At some subsequent done interrupt, SCNQUE notices
;that DVXQUE for the DDB is non-zero, and jumps to the address
;contained in DVXQUE to continue processing.
;.le;DVXIPC -- no longer used by XTCSER; presumably fulfilled the
;function of XUBIPC in a previous version.
;.le;DVXPRC -- this word contains the PC of the co-routine caller.
;The eventual exit (via $CPOPJ or $CPOPJ1) of the co-routine
;will be to this address or this address plus 1.  The only co-routine
;callers are INPCOM and OUTCOM, the common parts of the IN(PUT) UUO
;and OUT(PUT) UUO processing routines.  The $COROUT routine (invoked at the
;beginning of both co-routines, XISYNC and XOSYNC) merely
;takes this PC from the stack and stores it in DVXPRC.
;.le;DVXCOR -- this is the other word used in the co-routine mechanism.
;The SYNC$ routine stores its caller PC in DVXCOR if it doesn't have
;a match of bits on DVXMSK.  Then whenever there is an interrupt, the
;routine CHKPRC will notice that DVXCOR is non-zero (i.e. a co-routine
;is running) and dispatch to it at interrupt level to accomplish the
;next piece of the synchronization process.  In this case, SYNC$ was
;called the first time at UUO level and is therefore HIBERing. When
;interrupt level executes the $CPOPJ or $CPOPJ1 code this latter will
;clear DVXCOR (to indicate that the co-routine is no longer running), increment DVXPRC (if $CPOPJ1) and then call WAKJOB to cause the HIBER
;to finish.  The rest of the SYNC$ UUO level call will notice that
;DVXCOR is zero, and then return to the PC in DVXPRC.
;.le;DVXMSK -- these are the DEVIOS bits upon which to continue processing the
;co-routine. They are set by the SYNC$ code and tested by
;CHKPRC.
;.le;DVXRFI -- the RH of this word contains the positive word
;count extracted from the last RFI received.
;.le;DVXWFO -- the LF of this word contains the mode and the RH contains the word count, both extracted from
;the last WFO received.
;.le;DVXBSZ -- this word contains the user buffer size (or the
;size of the dump-mode transfer if in dump mode) in the RH. It is
;compared with the size in DVXWFO to decide whether or not
;to set IOBKTL or shorten the "user" requested length.
;.le;DVXIWA -- in dump mode, this has the address of the next user
;IOWD to process (by calling NXCMR).  The routine DMPSET fills
;up the IOWD space in the DDB by calling COMCHK the first time and
;then NXCMR for subsequent I/O words. These words return the IOWD as well
;as (in M) the address of the next user IOWD to process (or 0).
;This M is stored here.  If we have transferred all the IOWDs
;in the DDB and DVXIWA is still non-zero, interrupt level calls DMPSET again
;to fill more IOWDs into the DDB so it can continue the transfer.
;.le;DVXLLM -- this is the user virtual address lower limit (as
;returned by COMCHK).
;.le;DVXULM -- this is the user virtual address upper limit (as
;returned by COMCHK).
;.le;DVXCUR -- this is the address within the DDB IOWD area of the
;next IOWD to transfer over the DA28.  Initially set to DVXIWD.
;.le;DVXIWD -- this is the start of the IOWD space in the
;DDB. There are .IOLEN-1 words set aside here in which to put user
;virtual address IOWDs so the MPIOWD can convert them to
;hardware IOWDs.  This space is used so the dump mode and buffered
;mode can have common I/O handling code -- buffered mode and
;dump mode simply fill in the IOWDs here, and the rest of the code
;has only one source for them.
;.le;DVXILS -- this is the cell for the last IOWD. It has a tag
;merely to make it easier to check when we have filled up the
;DDB IOWD space.
;.le;DVXPAC -- this is a count of the number of seconds remaining for
;the DDB to be "pseudo-active". Normally a DDB is made I/O active (by
;setting IOACT in DEVIOS) only when a transfer to or from the
;user address space is in process. This is because being I/O active
;prevents a job from being moved in memory or swapped out. For
;high performance XTCSER makes a job I/O active at the beginning
;of I/O processing in anticipation that the small computer will
;respond quickly to the control words and transfer data. This may
;not be the case, however, and so this state is called a "pseudo-active"
;state because we are active only on the hope of imminent transfer,
;not on the actuality.  XTCSEC once a second code decrements
;DVXPAC for all DDB's; if the value reaches 0 (i.e. the pseudo active
;time has expired) IOACT is cleared and the job can now be swapped.
;Just before data transfer really takes place the job is made active
;again.
;This cell is initialized in PSACT to the value of the parameter
;ACTTIM (currently 2).
;.le;DVXPST -- this cell contains the current protocol status bits.
;There are bits for the receipt and transmission of all the data-oriented
;protocol words.  Most of the RECxxx routines merely set the
;IORxxx bit in this word, and the done interrupt on sending a control
;word for data transfer sets the IOXxxx bit.
;.le;DVXWAK -- these are the user-requested wake bits.  There is a 
;sub-function of the XTTSK. UUO which allows the user to test the
;current DEVIOS bits for the DDB against a mask.  If none of the
;bits are on, this mask is copied into DVXWAK.  Whenever one of these
;bits is subsequently set, a WAKJOB call
;will be done for the user job, so the combination XTTSK, HIBER UUOs
;can have the same effect as if one had new hiber-condition bits for
;XTCSER.
;.end list!DVX
;.hl 3 DDB Layout
;^^
;The following is a pictorial representation of the XTCSER
;extensions to the DDB:
;.test page 52
;.nofill.nojustify.skip
;          +-------------------------------------------------------+
;  DVXUDB  !  link to next DDB on UDB  !        addr of UDB        !
;          !-------------------------------------------------------!
;  DVXDSC  !prm!     reserved      ! attr byte  !     task ID      !
;          !-------------------------------------------------------!
;  DVXMOD  !        first word of mode correspondence bits         !
;          !-------------------------------------------------------!
;          !        second word of mode correspondence bits        !
;          !-------------------------------------------------------!
;  DVXCTL  !        last control word received for this DDB        !
;  DVXXCW  !       or next control word to send for this DDB       !
;          !-------------------------------------------------------!
;  DVXST4  !   saved control word if we have to wait for old one   !
;          !-------------------------------------------------------!
;  DVXQUE  !   PC to continue with if DDB had to be queued or 0    !
;          !-------------------------------------------------------!
;  DVXIPC  !      PC to continue on done interrupt (obsolete)      !
;          !-------------------------------------------------------!
;  DVXPRC  !                 co-routine caller PC                  !
;          !-------------------------------------------------------!
;  DVXCOR  !            0 or PC to continue co-routine             !
;          !-------------------------------------------------------!
;  DVXMSK  !            mask bits to wake up co-routine            !
;          !-------------------------------------------------------!
;  DVXRFI  !         positive count from last RFI received         !
;          !-------------------------------------------------------!
;  DVXWFO  !    data mode from WFO     !    word count from WFO    !
;          !-------------------------------------------------------!
;  DVXBSZ  !         reserved          !        buffer size        !
;          !-------------------------------------------------------!
;  DVXIWA  !   address of next user IOWD to process in dump mode   !
;          !-------------------------------------------------------!
;  DVXLLM  !          user dump mode lower limit (COMCHK)          !
;          !-------------------------------------------------------!
;  DVXULM  !          user dump mode upper limit (COMCHK)          !
;          !-------------------------------------------------------!
;  DVXCUR  !        address of next IOWD for DA28 transfer         !
;          !-------------------------------------------------------!
;  DVXIWD  !             first IOWD for DA28 transfer              !
;          _\                          ...                          _\
;          !          next to last IOWD for DA28 transfer          !
;          !-------------------------------------------------------!
;  DVXILS  !              last IOWD for DA28 transfer              !
;          !-------------------------------------------------------!
;  DVXPAC  !     timer for how long DDB has been pseudo active     !
;          !-------------------------------------------------------!
;  DVXPST  !                 protocol status bits                  !
;          !-------------------------------------------------------!
;  DVXWAK  !               user-requested wake bits                !
;          +-------------------------------------------------------+
;.fill.justify.skip
;-
MLP
SUBTTL	CONSTANTS -- BYTE POINTERS

DVYTAT:	POINT	8,DVXDSC(F),23		;ATTRIBUTE BYTE
DVYTID:	POINT	12,DVXDSC(F),35		;TASK ID
DVYMFC:	POINT	4,DVXCTL(F),3		;RECEIVED MAJOR FUNCTION CODE
DVYXMF:	POINT	4,DVXXCW(F),3		;XMITTED MAJOR FUNCTION CODE
DVYFSC:	POINT	4,DVXCTL(F),7		;FUNCTION SUB CODE
DVYSFI:	POINT	8,DVXCTL(F),15		;SUPP. FUNCTION INFORMATION
DVYMOD:	POINT	4,DVXCTL(F),19		;DATA PACKING MODE
DVYUNI:	POINT	PR.UIS,DVXCTL(F),23	;UNIT
DVYTIF:	POINT	12,DVXCTL(F),31		;TASK ID FIELD(COMBINED UNIT AND TASK ID)
DVYWDC:	POINT	12,DVXCTL(F),15		;WORD COUNT IN WFO
DVYIOM:	POINT	4,DVXBSZ(F),3		;I/O MODE
DVYHWM:	POINT	4,DVXBSZ(F),7		;HARDWARE MODE
CTYMFC:	POINT	4,T4,3			;MAJOR FUNCTION CODE
CTYFSC:	POINT	4,T4,7			;FUNCTION SUB CODE
CTYSFI:	POINT	8,T4,15			;SUPP. FUNCTION INFORMATION
CTYMOD:	POINT	4,T4,19			;DATA PACKING MODE
CTYUNI:	POINT	PR.UIS,T4,23		;UNIT
CTYTIF:	POINT	12,T4,31		;TASK ID FIELD(COMBINED UNIT AND TASK ID)
XUYMFC:	POINT	4,XUBRCW(U),3		;MAJOR FUNCTION CODE
XUYFSC:	POINT	4,XUBRCW(U),7		;FUNCTION SUB CODE
XUYSFI:	POINT	8,XUBRCW(U),15		;SUPP. FUNCTION INFORMATION
XUYMOD:	POINT	4,XUBRCW(U),19		;DATA PACKING MODE
XUYUNI:	POINT	PR.UIS,XUBRCW(U),23	;UNIT
XUYTIF:	POINT	12,XUBRCW(U),31		;TASK ID FIELD(COMBINED UNIT AND TASK ID)
PIOMOD:	POINT	4,DEVIOS(F),35		;I/O STATUS
PLM
;+
;.lm 0
;.hl 1 Other Data Structures
;^^
; There are a few other pieces of the "data structures" which
;I will not describe in detail but wish to mention.
;.list
;.le;There are a group of cells whose names look like DVYxxx, CTYxxx,
;or XUYxxx which are byte pointers for subfields (mostly within
;control words) of cells in the data structures described above.
;There is no need to enumerate them here as their function is
;obvious from the listing.
;.le;There is a dispatch table with the tag XTCDSP.  This is
;the I/O dispatch table used by UUOCON to call a device service
;routine to perform specific functions. Each XTCSER DDB has the address
;of this dispatch table in it (in the RH of the DEVSER word).
;It is via this mechanism that the code to support I/O functions is
;executed.  Note that there are separate entries in the dispatch
;table for dump mode and normal buffered mode I/O.
;Also note that there are negative displacements off the
;dispatch table address.
; There are two other entries into the XTCSER code: the CALLI dispatch
;table has an external symbol (XTUUO) as the service routine for
;the XTTSK. UUO and CLOCK1 has a call to XTCSEC for once a second processing.
;(If there are no XTCSER devices, XTCSEC is equated to
;CPOPJ in COMDEV.)
;.end list
;-
MLP
SUBTTL	CONSTANTS -- I/O DISPATCH TABLE

	POPJ	P,		;*-5 DEVICE OFFLINE?
	POPJ	P,		;*-4 EXTENDED SOFTWARE ERROR STATUS
	JRST	REGSIZ##	;*-3 RETURN BUFFER SIZE
	JRST	XTCINI		;*-2 INITIALIZATION
	JRST	XTCHNG		;*-1 HUNG DEVICE
XTCDSP::JRST	XTCREL		;(00) RELEASE THE TASK IS RESTART
	JRST	XTCLSO		;(01) CLOSE OUTPUT
	JRST	XTCOUT		;(02) BUFFERED OUTPUT
	JRST	XTCIN		;(03) BUFFERED INPUT
;END OF SHORT DISPATCH TABLE
	JRST	CPOPJ1##	;(04) ENTER
	JRST	CPOPJ1##	;(05) LOOKUP
	JRST	XTCDOU		;(06) DUMP MODE OUTPUT
	JRST	XTCDIN		;(07) DUMP MODE INPUT
	POPJ	P,		;(10) SETO
	POPJ	P,		;(11) SETI
	POPJ	P,		;(12) GETF
	JRST	CPOPJ1##	;(13) RENAME
	JRST	XTCLSI		;(14) CLOSE INPUT
	POPJ	P,		;(15) UTPCLR
	POPJ	P,		;(16) MTAPE

SUBTTL	TIMER ROUTINES
XTCHNG:	NULL
	PUSHJ	P,SETACS	;SET UP THE ACCS
	PUSHJ	P,ZAPACT		;CLEAN UP PSEUDO ACTIVE ACCOUNTING
	SETZM	DVXQUE(F)	;NO MORE REQUESTS
	CONO	PI,PI.OFF	;NO INTERRUPTS
	SKIPN	T1,XKBDDB##(W)	;IS THERE ANY ONE USING IT
	HLRZ	T1,XKBIUN##(U)	;DDB ADDRESS IF THERE IS ONE
	JUMPE	T1,NODHNG	;DA28C IS NOT BUSY
	CAME	T1,F		;ARE WE STUCK?
	JRST	NODHNG		;(NO) ANOTHER ONE MAYBE
	MOVEI	T1,XS.CLR	;CLEAR THE
	XCT	XTSCNO##(W)	;COMMAND REGISTER
	SETZ	T1,		;READY TO DISCONNECT
	XCT	XTCCNO##(W)	;DO IT
	SETZM	XKBDDB##(W)	;YES: ZAP EVERYTHING AND FREE CTL
	SETZM	XKBIUN##(W)
	CONO	PI,PI.ON	;WE CAN HEAR AGAIN
	PJRST	SCNQUE		;AND FIND WORK
NODHNG:	NULL
	CAMN	F,XUBLOK(U)	;ARE WE LOCKING IT
	SETZM	XUBLOK(U)	;NO LONGER
	PJRST	ONPOPJ##

;XTCSEC CHECK IF PSEUDOACTIVE TASKS HAVE RUN OUT OF TIME
;CALLED ONCE A SECOND

XTCSEC::NULL
	PUSHJ	P,SAVE1##		;SAVE P1 RETURN RESTORES IT
	PUSH	P,W		;SAVE ACCS
	PUSH	P,U		;USED
	PUSH	P,F		;IN THIS CODE
	MOVEI	W,XKB0##	;CONTROL BLOCK NUMBER 1
LPKDB:	SKIPN	XKBPAC##(W)	;ANY PSEUDO ACTIVE UNITS?
	JRST	NXTKDB		;GET THE NEXT KDB
	MOVEI	P1,XKBUDB##(W)	;ADDRESS OF FIRST UDB
LPUDB:	MOVE	U,(P1)		;GET NEXT KDB
	JUMPE	U,NXTKDB	;NEXT CONTROL
	SKIPN	XUBPAC(U)	;ANY ACTIVITY?
	JRST	NXTUDB		;NOPE GET THE NEXT ONE
	HLRZ	F,XUBDDB(U)	;ADDRESS OF FIRST DDB
LPDDB:	JUMPE	F,NXTUDB	;FORGET IT
	HRRZ	T1,DVXPAC(F)	;GET THE PSEUDO TIME
	JUMPE	T1,NXTDDB	;UNINTERESTING
	SOJG	T1,NXTDD0	;STILL TIME ON THE ACCOUNT
	AOS	PSZERO		;ACCOUNT THE LOSS
	PUSHJ	P,ZAPACT		;DO ALL THE ACCOUNTING
	JRST	NXTDDB		;GET THE NEXT DDB
NXTDD0:	NULL
	HRRM	T1,DVXPAC(F)	;UPDATE THE ACCOUNT
NXTDDB:	HLRZ	F,DVXUDB(F)	;GET THE NEXT DDB
	JRST	LPDDB		;AND LOOP TILL DONE
NXTUDB:	AOJA	P1,LPUDB	;GET NEXT UDB
NXTKDB:	HRRZ	W,XKBKDB##(W)	;GET THE NEXT CONTROL ADDRESS
	JUMPN	W,LPKDB		;AND LOOP AGAIN
	POP	P,F		;GET REGISTERS BACK
	POP	P,U
	POP	P,W
	POPJ	P,
PLM
;+
;.chapter Code Description
;^^
;.subtitle Introduction
; This chapter will describe most of the routines in XTCSER briefly.
;No attempt is made to be exhaustive and therefore it is recommended
;that this section be read with a listing available.
; The routines in XTCSER fall into three large groups, with a
;few little ones left over.  The groups are 1) routines to process
;the XTTSK. UUO (which has numerous sub-functions), 2) routines to
;process the I/O UUOs (IN, OUT, CLOSE, RELEAS) and 3) routines to
;handle the DA28 interrupts and to continue the process of completing
;the I/O operations started by the second group.  Naturally this
;document will also have such major divisions.
; The code in XTCSER follows this outline to a large extent, but there
;are several routines that are out of place.  Because this manual
;is imbedded in the code, the descriptions of these routines will
;similarly seem to defy logic.
; All of the code in XTCSER uses the following register convention:
;.list
;.le;S -- DEVIOS word from DDB
;.le;P -- stack pointer
;.le;J -- user job number
;.le;R -- low segment relocation (JBTADR value)
;.le;F -- address of DDB
;.le;U -- address of UDB
;.le;W -- address of KDB
;.end list
;.hl 1 Periodic Routines
;^^
;.subtitle Periodic Routines
; XTCSER has only two periodic routines -- XTCHNG and XTCSEC.  The
;former is called by UUOCON if it detects that a device has been
;I/O active for more than its hung time (6 seconds in the case of
;the XTCSER DDB).  The latter is called from CLOCK1 once a second
;to allow XTCSER to time the pseudo active state of a DDB.
;.hl 2 XTCHNG
;^^
;.subtitle XTCHNG
; When a device is hung, the monitor gives a message to the
;timesharing user; however, it calls the device service
;routine to clear out the device.  Therefore XTCHNG's responsibilities are:
;.list
;.le;to take the device out of I/O active state so that it can be swapped
;.le;to clean up any information it was keeping about the device
;.le;to free any resources that the device was using (i.e. the
;DA28.
;.end list
;So the XTCHNG logic is:
;.list
;.le;set up all the ACs (U, W, S, J and R) based on F
;.le;zero DVXQUE so that interrupt level call of SCNQUE doesn't try to
;continue processing for the DDB
;.le;turn off PI's and check if this unit and this DDB were waiting for
;a done interrupt ([LH XKBIUN=F and RH=U] or XKBDDB=F) and if so,
;clear out the DA28 hardware, clear out the controller flags (XKBDDB, XKBIUN),
;allow interrupts again and exit via SCNQUE to do work on DA28 for
;some other DDB or unit.
;.le;or, if we had been waiting for an I/O transfer for this DDB (XUBLOK=F), clear lock and exit allowing interrupts.
;.end list
;.hl 2 XTCSEC
;^^
;.subtitle XTCSEC
; This routine makes all DDB's that have been pseudo-active
;for more than ACTTIM seconds no longer so. Its logic is:
;.list
;.le;save some registers and point W to first KDB
;.le;LPKDB -- if this KDB has 0 pseudo-active DDB's, go to NXTKDB; else point U to its first UDB
;.le;LPUDB -- if no more UDB's (U=0) go to NXTKDB; else if no pseudo-active
;DDB's on this UDB go to NXTUDB; else point to first DDB on unit
;.le;LPDDB -- if no more DDB's (F=0) go to NXTUDB
;.le;if DVXPAC is zero, go to NXTDDB; else decrement
;DVXPAC. If that goes to zero call ZAPACT to clear I/O active
;state and increment counter of times we've done this (PSZERO).
;.le;NXTDDB -- point to next DDB and go to LPDDB
;.le;NXTUDB -- point to next UDB slot and go to LPUDB
;.le;NXTKDB -- get pointer to next KDB and if non-zero go to LPKDB; else
;restore registers and exit.
;.end list
;Note that the logic of this routine goes to the next KDB as
;soon as it finds a 0 UDB slot in the current KDB; this means
;that if there exist small computers, say, on units 0 and 3 only
;the UDB's for units 1 and 2 must be built (they are marked offline).
;-
MLP
SUBTTL	XTTSK. UUO -- SUB-FUNCTION DISPATCH TABLE

	SALL
XT.DDB==400000		;A DDB IS REQUIRED (SIGN BIT)
XT.PRV==200000		;JOB HAS TO BE PRIVILIGED
XT.NUM==200		;FACTOR TO MOVE ARG NUMBER IN PROPER PLACE

DEFINE X(A,B),<XX A,B,0> 		;NO DDB NO PRIV
DEFINE XF(A,B),<XX A,B,XT.DDB> 		;A DDB IS NEEDED
DEFINE XPR(A,B),<XX A,B,XT.PRV> 	;PRIVILIGE NEEDE
DEFINE XFP(A,B),<XX A,B,<XT.DDB+XT.PRV>> ;PRIV & DDB
DEFINE XX(A,B,C),<C+<A*XT.NUM>,,B>
CUSDEF==.-FUNTAB
	X	0,CPOPJ##	;PLACE FOR USER TO PATCH A FUNCTION
FUNTAB:	X	0,CPOPJ##	;INVALID FUNCTION
	XF	2,XTRDR		;(01) SEND READY TO RECEIVE
	XF	2,XTRDS		;(02) SEND READY TO SEND
	X	4,XTIDN		;(03) IDENTIFY A TASK
	XF	2,XTMMD		;(04) MODE MODIFICATION
	XF	3,XTGCH		;(05) GET CHARACTERISTICS
	X	2,CPOPJ##	;(06) SET CHARACTERISTICS
	XF	3,XTATB		;(07) ATTRIBUTE BYTE DIDDLE
	XF	2,XTDEL		;(10) DELETE A TASK
	XPR	2,XTLDX		;(11) LOAD EXTERNAL PROCESSOR (JAM)
	XF	3,XTCLS		;(12) SEND CLOSE
	XPR	2,XTFRC		;(13) FORCE UNIT OFF-LINE
	XPR	2,XTDST		;(14) GET DEAD-START INFO
	XPR	2,XTGRB		;(15) GRAB CONTROLLER & RETURN TO USER (SCANNER OFF)
	XPR	2,XTRET		;(16) RESTART SCANNER & UNLOCK CTL
	X	2,XTSTAT	;(17) GETSTATISTICS 
IFE	FTCMP3,<
	XF	3,XTWAKF	;(20) WAKE ON EVENTS
>	;END OF FTCMP3=0
IFN	FTCMP3,<
	X	0,CPOPJ##	;(20) ILLEGAL
>	;END OF FTCMP3 .NEQ. 0
DECDEF==.-FUNTAB-1
PLM
;+
;.lm 0
;.hl 1 XTTSK. UUO Processing
;^^
;.subtitle XTTSK. UUO
; Roughly a quarter of the code in XTCSER is to process
;XTTSK. UUO functions.
;There are 16 XTTSK.#sub-functions; UUOCON enters the code at the
;tag XTUUO: which then uses the dispatch table FUNTAB
;to validate some of the arguments and find the address of
;the subroutine to actually perform the requested function.
;The register in an XTTSK. call contains "length of block,,addr of block".
;The first word of the argument block contains the function code; the
;next generally contains either a DDB name or channel number (if the function
;requires a DDB) or the SIXBIT controller or unit name (if the
;function pertains only to a controller or unit).
; All the routines use the standard GETWDU and PUTWDU to retrieve argument
;block words and to store results into the argument block. They also
;use the standard ECODx routines to return an error code in the
;user-register and cause an unsuccessful return (non-skip).
; A number of the XTTSK.#UUO functions can have an arbitrarily
;long list of arguments, that is they loop getting new arguments
;to operate on until there are no more.  For example, XTWAKF allows
;a list of:
;.sk;#########function
;.br;#########DDB name
;.br;#########bits
;.br;#########DDB name 2
;.br;#########bits 2
;.br;############.
;.br;############.
;.br;############.
;.skip;for as many DDB/bits pairs as you want.  The current
;status will be returned in each of the "bits" words.
;.hl 2 Functions
;^^
;.subtitle XTTSK. Functions
; The legal functions of the XTTSK. UUO are given
;in the FUNTAB table.  This table consists of words with the LH
;containing requirements for the sub-function and the RH containing the address of the
;routine to perform the function.
;The requirements halfword consists of two bits XT.PRV (needs privileges) and XT.DDB (needs
;a DDB) along with minimum number of arguments that this function takes.
;Negative displacements off FUNTAB are for customer defined XTTSK.
;functions and positive offsets are for DEC-defined
;functions.
;  XTCSER defines four macros to
;make setting of all the combinations of privilege bits easier --
;1) X (no DDB, no PRV); 2) XF (DDB, no PRV); 3) XPR (no DDB, PRV) and 4) XFP (DDB, PRV).
; FUNTAB has the following entries:
;.list
;.le;displacement -1 -- a spare for the purpose of allowing a 
;customer to patch in his own XTTSK. function. Currently has
;no requirement bits, 0 arguments and executes CPOPJ.
;.le;0 -- illegal, goes to CPOPJ.
;.le;1 (XTRDR, needs F, 2 arguments) -- send an RFI to the
;small computer to signal readiness to do input.
;.le;2 (XTRDS, needs F, 2 arguments) -- send an RFO to the
;small computer to signal readiness to do output.
;.le;3 (XTIDN, 4 arguments) -- create a DDB (mnemonic refers to "identify a task").
;This function dynamically builds an XTCSER DDB. It can have any
;name (as long as it is unique within the system) and can be
;thought of as a link between the program doing I/O to it on the
;DECsystem-10 and a particular task on the small computer (as
;identified by the Task ID parameter that the creator of the
;DDB must supply).  If the creator is privileged, he may mark
;the DDB as permanent (i.e.#must be explicitly deleted by another
;XTTSK.#UUO function).  Many installations therefore use
;a privileged program running under the startup command file (OPR.ATO) to create DDB's named mnemonically by their
;purpose which will remain there as long as the system is up.
;.le;4 (XTMMD, needs F, 2 arguments) -- the "modify mode" subfunction
;allows the caller to change the mapping between software modes (the
;low order four bits of DEVIOS) and DA28 hardware modes (by
;changing the contents of the two DVXMOD words in the DDB).
;Thus the user may run existing programs in conjunction with the
;DA28 devices and ensure that they will work correctly no matter
;what data mode they were designed to use.
;.le;5 (XTGCH, needs F, min 3 arguments) -- the sub-function "get characteristics" various pieces of information about the 
;XTCSER DDB to the user. It requires a minimum of three arguments, but
;up to 8 words of data (starting with the 3rd word of the argument list)
;if the list is long enough.  The words are:
;.list
;.le;DVXCTL(F)
;.le;DEVSTS(F)
;.le;DEVIOS(F) plus the special XTCSER protocol bits
;.le;DVXDSC(F)
;.le;DEVMOD(F)
;.le;DEVCHR(F)
;.le;DVXPST(F) (where the special XTCSER protocol bits actually come from)
;.le;DVXXCW (which is now the same as DVXCTL)
;.end list
;.le;6 (not implemented, goes to CPOPJ) -- "set characteristics" was planned but never implemented.
;.le;7 (XTATB, needs F, 2 arguments) -- the sub-function "manipulate attribute byte" allows the user to:
;.list
;.le;set a new attribute byte
;.le;read the current attribute byte stored in the DDB
;.le;ANDCAM (i.e. clear) bits in the attribute byte
;.le;AND bits in the attribute bytes
;.le;OR bits into the attribute byte
;.le;send the current attribute byte to the small computer.
;.end list
;See the description of the protocol above for the functions the
;small computer can perform on the attribute byte.
;These functions are not usable with LIP11M.
;.le;10 (XTDEL, needs F, 2 arguments) -- the "delete DDB"
;function destroys an XTCSER DDB (even if the permanent bit is
;set). Normal (i.e. single user) DDB's need not be deleted in this manner because they are destroyed
;when they are deassigned (logout does this as well).
;.le;11 (XTLDX, needs privileges, 2 arguments) -- this function allows
;the privileged user to "jam" the small computer to a specific
;starting address (usually switch or strap selectable in the
;small computer DA28 interface).  Another function (performed if
;the argument word has a right half of -1) is to force all
;the units on a specific controller on-line.
;.le;12 (XTCLS, needs F, 3 arguments) -- the function "send close eof"
;sends the "close eof" protocol word
;to the specified task on the small computer.
;This is equivalent to doing a CLOSE UUO if one has output some data,
;but is necessary if one wants to merely send an EOF (and
;nothing else) to the small processor because UUOCON never calls
;the device service routine (in this case XTCSER) if
;the user issues an OPEN immediately followed by a CLOSE.
;.le;13 (XTFRC, needs privileges) -- the function "force a unit off-line"
;causes the DA28C to force the unit offline. This might be useful
;if the small computer is misbehaving.  To talk to the small computer
;again one must set the unit on-line with another XTTSK. function.
;When forcing the unit off-line XTCSER also zeroes the
;XUBRDY word of the UDB, so that the small computer must send a 
;restart before XTCSER believes it is alive once more.
;.le;14 (XTDST, needs privileges, min 2 arguments) -- "get dead-start info" retrieves
;the dead-start protocol word for each unit in the argument list.
;This dead-start word was previously used when bootstrapping a 
;small computer. LIP11M never sends it at all
;.le;17 (XTSTAT, min 2 arguments) -- this call provides overall
;statistics about XTCSER.  The size of the argument
;block determines how many arguments are returned from the
;following list:
;.list
;.le;DBGPAR (contains address and length of XTDUMP trace buffer)
;.le;CNTINP (number of input UUOs)
;.le;CNTOUT (number of output UUOs)
;.le;CNTHIB (number of HIBERs, i.e. calls to DOZE routines)
;.le;CNTWAK (number of WAKEs, i.e. calls to XTWAK routines)
;.le;CNTQWT (number of calls to WTQEMP)
;.le;CNTWTQ (number of times HIBERing to wait for the queue to empty in WQEMP)
;.le;PSZERO (number of times we cleared pseudo-active state of a DDB in
;XTCSEC)
;.le;PSMAKE (number of times we made a DDB pseudo active)
;.le;XTCPAR (the parameters, ACTTIM in LH, and -QLPCNT in RH)
;.end list
;.le;20 (XTWAKF, needs F, min 3 arguments) -- this is the WAKE on specific events XTTSK. function.
;If FTCMP3 is on (i.e. non-zero) this function is illegal and goes to
;CPOPJ. (This is because the job is always being WAKEd with this
;feature test on.) If FTCMP3 is 0 (the default) the user may issue
;this UUO to inquire about the state of DEVIOS bits for one or
;more DDB's.  The current values of the status bits are returned
;in place of the mask bits the user supplied in the argument
;block.  If none of the masked bits were on, then if the user
;later issues a HIBER and one of the events corresponding to the
;bits occurs, the job will be awakened.  If any of the bits specified
;in the mask are set at the time the XTTSK.#UUO is issued, the wake will NOT
;be done; it is the user's responsibility to check the current
;status returned, and not do the HIBER if a bit he is interested
;in is on.
;.end list
;-
MLP
SUBTTL	XTTSK. UUO -- UUO ENTRY
;CALLING SEQUENCE:
;	MOVE	AS,[LENGTH,,ADDRESS OF ARGUMENT LIST]
;	XTTSK.	AC,
;	ERROR RETURN		;AC = ERROR CODE
;	SUCCESS RETURN
;	. . .
;	ADDR:	FUNCTION
;	ARGUMENTS
;
;ON ENTRY:
;  (T1) = LENGTH,,ADDRESS
;
XTUUO::	NULL
	PUSHJ	P,SAVE3##	;SAVE PRESERVED AC'S
	HRR	M,T1		;M GETS ARGUMENT LIST ADDRESS
	HLRE	P3,T1		;P3 GETS LIST LENGTH
	JUMPLE	P3,ECOD1##	;LENGTH MUST BE POSITIVE
	PUSHJ	P,GETWDU##	;GET FUNCTION INTO T1
	CAML	T1,[CUSDEF]	;FUNCTION MUST BE WITHIN CUSTOMER DEFINED CODES
	CAILE	T1,DECDEF	;  AND DEC DEFINED CODES
	POPJ	P,		;  ERROR IF NOT
	LDB	T2,[POINT 9,FUNTAB(T1),10] ;GET MINIMUM ARG LIST LENGTH
	CAMGE	P3,T2		;IS LIST LONG ENOUGH?
	JRST	ECOD1##		;  NO, ERROR
	MOVE	P2,T1		;SAVE  FUNCTION
	PUSHJ	P,GETWD1##	;GET TASK ID
	SUBI	P3,2		;UPDATE ARG COUNT
	SKIPL	P1,FUNTAB(P2)	;IS A DDB REQUIRED?
	JRST	XTUUO0		;(NO) CHECK FOR PRIVILIGES
	PUSHJ	P,FNDDDB		;(YES) SEE IF DDB OKAY
	PJRST	ECOD2##		;SHOULD BE THERE
	MOVE	P1,FUNTAB(P2)	;GET TABLE ENTRY
XTUUO0:	NULL
IFN FTMP,<
	PUSH	P,T1		;PRESERVE TASK ID
	MOVEI	T1,0		;GET A ZERO
	PUSHJ	P,ONCPUN##	;  AND GET TO THE DA28'S CPU
	POP	P,T1		;RESTORE TASK ID
>
	TLZN	P1,XT.PRV	;ANY PRILIGES REQUIRED
	JRST	@FUNTAB(P2)	;(NO) GO TO TASK PROCESSING
	PUSHJ	P,PRVJ##		;(YES) CHECK THEM
	JRST	@FUNTAB(P2)	;OKAY YOU MAY DO IT
	PJRST	ECOD0##		;NO PRIVILEGES
SUBTTL	XTTSK. UUO -- XT.RDR, XT.RDS, XT.SCH, XT.DEL

;SEND READY TO RECEIVE
;ARGUMENT LIST:
;	SIXBIT	/DEVICE/ OR CHANNEL NUMBER


;SEND READY TO SEND
;ARGUMENT LIST:
;	SIXBIT	/DEVICE/ OR CHANNEL NUMBER

XTRDR:	NULL
	PUSHJ	P,MAKRFI		;MAKE THE RFI CODE
	SKIPA			;AND FALL IN COMMON CODE

XTRDS:	NULL
	PUSHJ	P,MAKRFO		;MAKE RFO CODE
;START OF CODE SHARED BY SEND RFO OR RFI
	PUSHJ	P,SENDW		;SEND CODE AND WAIT TILL DONE
	PUSHJ	P,XIOWAT		;WAIT FOR COMPLETION
	MOVE	S,DEVIOS(F)	;GET A FRESH COPY
	TDNE	S,[ IOEND,,RHSTOP ]	;ALL ARE WRONG
	PJRST	ECOD3##		;I/O ERROR
	JRST	CPOPJ1##	;SUCESS RETURN


;SET DEVICE CHARACTERISTICS
;NOT YET DEFINED

XTSCH:	POPJ	P,0		;UNDEFINED FUNCTION


;DELETE A TASK
;ARGUMENT LIST:
;	SIXBIT	/DEVICE/ OR CHANNEL NUMBER

XTDEL:	NULL
	MOVSI	T1,XT.PRM	;DELETE EVEN PERMANENT DDBS
	ANDCAM	T1,DVXDSC(F)	;
	MOVEI	T1,ASSCON	;IF ASSIGNED BY CONSOLE,
	TDNN	T1,DEVMOD(F)	;  DEASG WILL GIVE SKIP RETURN
	AOS	(P)		;GIVE SUCCESS RETURN
	PJRST	DEASG1##	;DEASSIGN & RELEASE
SUBTTL	XTTSK. UUO -- XT.IDN

;BUILD AN EXTERNAL TASK  (MAKE A DDB)
;PARAMETER LIST FORMAT:
;	SIXBIT	/DEVICE NAME/
;	SIXBIT	/EP NAME/
;	XWD	TASK UNIT ID, TASK ID
;	XWD	PERMANENT FLAG, BUFFER SIZE
;	EXP	DEVMOD BITS
;	XWD	FLAGS,ATTRIBUTE BYTE

XTIDN:	NULL
	MOVSI	P1,PHONLY	;SEARCH ONLY PHYSICAL NAMES
	PUSHJ	P,DEVSRC##	;LOOK FOR A DDB WITH THIS NAME
	SKIPA			;NOT FOUND IS GOOD
	  JRST	ECOD2##		;  FOUND IS ERROR
	MOVE	P2,T1		;SAVE NAME FOR LATER
	PUSHJ	P,GETWD1##	;GET NAME OF EXTERNAL PROCESSOR
	PUSHJ	P,FNDEXP	;FIND EXTERNAL PROCESSOR UDB
	  JRST	ECOD3##		;  ERROR IF NOT FOUND
	PUSHJ	P,GETWD1##	;GET TASKID
	HLRZ	P1,T1		;SEPARATE TASK UNIT ID
	HRRZ	T1,T1		;  AND TASK ID
	CAIG	T1,PR.TIM	;LARGE
	CAILE P1,PR.UIM_-PR.TIS	; ID'S
	JRST	ECOD4##		;  NOT ALLOWED
	LSH	P1,PR.TIS	;MOVE TASK UNIT OVER
	IORB	P1,T1		;  AND COMBINE WITH TASK ID
	JUMPE	P1,ECOD4##	;ZERO ID NOT ALLOWED
	PUSHJ	P,FNDTSK	;ANOTHER DDB WITH THIS ID NOT ALLOWED
	  SKIPA
	PJRST	ECOD4##		;ERROR
	MOVEI	T2,XTCDDW	;LOAD DDB SIZE
	PUSHJ	P,GETWDS##	;GET CORE FOR NEW DDB
	  JRST	ECOD5##		;  NO ROOM, TELL USER
	HRRZ	F,T1		;THIS IS THE DDB
	HRLI	T1,XTCDDB	;BUILD BLT WORD
	BLT	T1,XTCDDW-1(F)	;COPY PROTOTYPE TO NEW DDB
	HRLM	F,XTCDDB+DEVSER	;LINK NEW DDB INTO CHAIN
	MOVEM	U,DVXUDB(F)	;LINK DDB TO UDB
	HLR	T1,XUBDDB(U)	;PICK UP START OF UDB DDB LIST
	HRLM	T1,DVXUDB(F)	;LINK DDB TO REST OF DDB'S
	HRLM	F,XUBDDB(U)	;LINK UDB TO DDB
	MOVEM	P2,DEVNAM(F)	;SET DEVICE NAME
	MOVEM	P1,DVXDSC(F)	;SET TASK ID INTO DDB
	SUBI	P3,2		;PROCESSED TWO MORE WORDS
	JUMPLE	P3,XTIDN1	;IF NO MORE ARGS, THEN SET DEFAULTS
	PUSHJ	P,GETWD1##	;GET NEXT ARG
	TRNE	T1,7777		;NEW DEFAULT BUFFER SIZE?
	DPB	T1,PBUFSZ##	;YES, SET IT
	HLRZ	T2,T1		;GET FLAG
	CAIE	T2,-1		;WANT PERMANENT DDB?
	JRST	XTIDN1		;  NO
	PUSHJ	P,PRVJ##	;YES, PRIVILEGED TO MAKE ONE?
	JRST	XTIDN2		;YES
XTIDN1:	DPB	J,PJOBN##	;NO, SET OWNER'S JOB NUMBER
	MOVEI	T1,ASSCON	;SET
	IORM	T1,DEVMOD(F)	;  ASSIGNED BIT
	JRST	XTIDN3		;GO CHECK FOR MORE PARMS
XTIDN2:	MOVSI	T1,XT.PRM	;THIS DDB WILL STAY
	IORM	T1,DVXDSC(F)	;
XTIDN3:	SOJLE	P3,CPOPJ1##	;IF NO MORE PARMS, EXIT
	PUSHJ	P,GETWD1##	;GET DEVMOD BITS
	TRO	T1,ASSCON	;SAVE ASSCON BIT
	ANDM	T1,DEVMOD(F)	;TURN OFF UNWANTED BITS
	SOJLE	P3,CPOPJ1##	;EXIT IF DONE
	PUSHJ	P,GETWD1##	;GET NEXT ARG
	DPB	T1,DVYTAT	;SET ATTRIBUTES BYTE
	AND	T1,DSCBTS	;MASK OUT UNWANTED BITS
	IORM	T1,DVXDSC(F)	;SET FLAGS
	JRST	CPOPJ1##	;EXIT


	$LOW

DSCBTS:	XWD	0,0		;FLAGS MASK
	$HIGH
SUBTTL	XTTSK. UUO -- XT.MMD
;SPECIFY CORRESPONDENCE BETWEEN HARDWARE AND INIT MODE
;ARGUMENT LIST:
;	SIXBIT	/NAME/ OR EXP CHANNEL
;	XWD	INIT MODE, HARDWARE MODE
;	XWD	. . .
;	. . .

XTMMD:	NULL
	SOJL	P3,CPOPJ1##	;IF NO ARGS LEFT, EXIT
	PUSHJ	P,GETWD1##	;GET NEXT ARG
	HLRZ	T2,T1		;SEPARATE OUT INIT MODE
	HRRZS	T1		;  AND HARDWARE MODE
	CAIG	T1,20		;HARDWARE MODE .GE. 20?
	CAILE	T2,17		;  AND INIT MODE .GE. 17?
	  JRST	ECOD3##		;YES, ERROR
	MOVEI	T3,1		;POSITION ACCESS BIT
	LSH	T3,(T2)		;  . . .
	IORM	T3,DEVMOD(F)	;THIS MODE ALLOWED NOW
	CAIN	T1,20		;DID HE REALLY WANT TO DISALLOW IT?
	ANDCAM	T3,DEVMOD(F)	;YES, TURN IT OFF
	IDIVI	T2,^D9		;DIVIDE BY MODES/WORD
	MOVNS	T3		;CALCULATE
	ADDI	T3,10		;  BIT POSITION (SCALED BY 4)
	ROT	T3,-4		;SET BIT POSITION WITHIN WORD
	TLO	T3,(POINT 4,0(F),35) ;BUILD BYTE POINTER
	HRRI	T3,DVXMOD(T2)	;SET ADDRESS INTO POINTER
	DPB	T1,T3		;PUT MODE INTO CORE
	JRST	XTMMD		;LOOP FOR NEXT ARG
IFE FTCMP3,<

SUBTTL	XTTSK. UUO -- XTWAKF

;ONLY THERE FOR SYSTEMS WITH NO EXTRANEOUS WAKES
;XTWAKF SET A WAKE EVENT FLAG IN A DDB WORD (DVXWAK)
;RETURN TO THE JOB THE SET OF ALL FLAGS SET FOR THE DDB
;IF NO FLAGS WERE SET AND EVENTS WERE SPECIFIED THEN A WAKE
;WILL BE DONE IF A FLAG IS RAISED LATER ON.
;ARGUMENTS:
;	FUNCTION
;	LIST OF ONE OR MORE PAIRS OF WORDS
;THE FORMAT OF AN ARGUMENT PAIR IS:
;	DDB OR CHANNEL NUMBER
;	EVENT MASK
;THE EVENT MASK WILL BE UPDATED TO THE SET DEFINED
;FOR THE DDB

XTWAKF:	NULL
	SOJL	P3,CPOPJ1##	;ALL ARGUMENTS PROCESSED
	PUSHJ	P,GETWD1##	;GET NEXT ARGUMENT
	MOVEM	T1,DVXWAK(F)	;AND UPDATE THE FLAG
	PUSHJ	P,IFEBTS	;SEE IF ANY BITS ARE SET
	SETZM	DVXWAK(F)	;IN THAT CASE DISABLE THE WAKE
	MOVE	T1,T2		;GET CURRENT MASK
	PUSHJ	P,PUTWDU##	;AND STORE IT
	SOJL	P3,CPOPJ1##	;MORE ARGUMENTS?
	PUSHJ	P,GETWD1##	;GET DDB NAME OR CHANNEL
	PUSHJ	P,FNDDDB	;FIND THE DDB
	PJRST	ECOD2##		;WRONG IT IS BNOT KNOWN
	JRST	XTWAKF		;NEXT ROUND
>;END OF FTCMP3=0
SUBTTL	XTTSK. UUO -- XT.GCH, XTSTAT
;RETURN DEVICE CHARACTERISTICS TO USER
;ARGUMENT LIST:
;	SIXBIT	/DEVICE NAME/ OR CHANNEL NUMBER
;	SPACE FOR RETURNED VALUES

XTGCH:	NULL
	CAILE	P3,CHLEN	;DON'T RETURN MORE INFORMATION
	MOVEI	P3,CHLEN	;  THAN I KNOW ABOUT
	MOVEI	P1,CHLST	;GET ADDR OF LIST
	JRST	XTGCHL		;SHARE XTSTAT LOGIC

;XTSTAT  ALLOWS A USER TO OBTAIN DA28 CONFIGURATION DATA

XTSTAT:	NULL
	ADDI	P3,1		;GET RID OF GETWD1 CALL 
	SUBI	M,1		;IN XTUUO CODE
	CAILE	P3,CHLENS	;MORE THAN THE MAXIMUM
	MOVEI	P3,CHLENS	;THEN LIMIT HIM
	MOVEI	P1,STLIST	;GET THE LIST AND

;SHARE LOGIC WITH XTGCH

XTGCHL:	NULL
	MOVE	T1,@0(P1)	;GET FIRST PARM
	CAIE	P1,IOSPOS	;GETTING DEVIOS
	JRST	XTGCH0		;NO
	PUSHJ	P,XTCIOS	;YES DIFFERENT LOGIC
	MOVE	T1,S		;COPY
XTGCH0:	PUSHJ	P,PUTWD1##	;MOVE WORD TO USER AREA
	AOS	P1		;INCREMENT LIST POINTER
	SOJG	P3,XTGCHL	;LOOP IF HE WANTS MORE
	JRST	CPOPJ1##	;SUCCESS RETURN

CHLST:	DVXCTL(F)
	DEVSTS(F)
IOSPOS:	DEVIOS(F)
	DVXDSC(F)
	DEVMOD(F)
	DEVCHR(F)
	DVXPST(F)	;PROTOCOL STATUS
	DVXXCW(F)	;LAST CONTROL WORD TRANSMITTED
CHLEN==.-CHLST		;GCH LIMIT

STLIST:	DBGPAR		;DEBUG PARAMETERS
	CNTINP		;NUMBER OF INPUT UUO'S
	CNTOUT		;NUMBER OF OUTPUT UUO'S
	CNTHIB		;NUMBER OF HIBERS IN WAIT FOR AN EVENT
	CNTWAK		;NUMBER OF EVENT WAKES
	CNTQWT		;COUNT OF ENTERING WTQEMP
	CNTWTQ		;NUMBER OF TIMES HIBERRING TO TO Q WAIT
	PSZERO		;NUMBER OF TIMES PSEUDO ACTIVE LOST
	PSMAKE		;NUMBER OF TIMES PSEUDO ACTIVE INVOKED
	XTCPAR
CHLENS==.-STLIST
SUBTTL	XTTSK. UUO -- XT.ATB
;DIDDLE ATTRIBUTES BYTE
;ARGUMENT LIST:
;	SIXBIT	/DEVICE NAME/ OR CHANNEL NUMBER
;	FUNCTION,,BITS
;	. . .

XTATB:	NULL
	LDB	P1,DVYTAT	;GET CURRENT ATTRIBUTES
XTATBL:	SOJL	P3,XTATBE	;EXIT IF NO MORE ARGS
	PUSHJ	P,GETWD1##	;GET NEXT ARG
	HLRZ	T2,T1		;SEPARATE OUT FUNCTION CODE
	JUMPE	T2,ECOD3##	;CODE .GT. 0
	CAILE	T2,XTATBN	;  AND .LT. MAX?
	  JRST	ECOD3##		;  NO, ERROR
	XCT	XTATBF-1(T2)	;DO FUNCTION
	JRST	XTATBL		;LOOP FOR MORE

XTATBE:	DPB	P1,DVYTAT	;STORE NEW ATTRIBUTES
	JRST	CPOPJ1##	;SUCCESS RETURN

XTATBF:				;table of instructions of XCT for sub-function [7136]
	MOVEM	T1,P1		;(1) SET NEW BYTE
	PUSHJ	P,XTATBR	;(2) RETURN BYTE
	ANDCAM	T1,P1		;(3) ANDCAM BITS
	ANDM	T1,P1		;(4) AND BITS
	IORM	T1,P1		;(5) OR BITS
	PUSHJ	P,ATSEND	;(6) SEND BYTE TO TASK
XTATBN==.-XTATBF

XTATBR:	NULL
	MOVE	T1,P1		;MOVE BYTE
	ANDI	T1,377		;GET RID OF EXTRA BITS
	HRL	T1,T2		;RESTORE FUNCTION
	PUSHJ	P,PUTWDU##	;PUT INTO ARG LIST
	POPJ	P,		;RETURN

ATSEND:	NULL
	MOVE	T3,P1		;COPY ATTRIBUTE BYTE TO SFI
	SEND	XAB		;DO NOT WAIT
	POPJ	P,
SUBTTL	XTTSK. UUO -- SEND CLOSE INFO

;ARGUMENT LIST:
;	SIXBIT /DEVICE-NAME/ OR CHANNEL NUMBER
;	CLOSE CODE (0-3)

XTCLS:	NULL
	PUSHJ	P,GETWD1##	;FETCH ARG
	CAIGE	T1,3		;CHECK RANGE
	SKIPN	T1		;AND VALIDITY
	MOVEI	T1,3		;SUPPLY DEFAULT
	XCT	XTCLTB-1(T1)	;PERFORM FUNCTION
	PUSHJ	P,XIOWAT		;WAIT TILL DONE
	MOVE	S,DEVIOS(F)	;GET A FRESH COPY
	TRNE	S,RHSTOP	;CHECK FOR ERRORS
	PJRST	ECOD3##
	JRST	CPOPJ1##

XTCLTB:	POPJ	P,		;(1)CLOSE INPUT
	PUSHJ	P,XMTEOF	;(2)SEND EOF
	PUSHJ	P,XMTEOF	;(3)SEND EOF
SUBTTL	XTTSK. UUO -- SPECIAL UNIT FUNCTIONS XTFRCL, XTLDXL, XTDSTL

;ROUTINE TO FORCE A UNIT OFF-LINE
;ARGUMENT LIST:
;	SIXBIT /EP NAME/
;	......

XTFRCL:	NULL
	SOJL	P3,CPOPJ1##	;RETURN IF NO MORE ARGS
	PUSHJ	P,GETWD1##	;GET ARG
XTFRC:	NULL
	PUSHJ	P,FNDEXP	;FIND UNIT #
	  PJRST	ECOD4##		;NO SUCH UNIT
	PUSHJ	P,FRCOFL		;FORCE UNIT OFFLINE
	PJRST	ECOD3##		;YOU LOOSE
	JRST	XTFRCL	;AND YOU WIN
;ROUTINE TO SET JAM BIT IN CTL (FORCE LOAD)
;ARGUMENT LIST:
;	SIXBIT /EP NAME/ OR EPX,,-1 FOR ALL UNITS
;	......

XTLDXL:	NULL
	SOJL	P3,CPOPJ1##	;RETURN IF NO MORE ARGS
	PUSHJ	P,GETWD1##	;GET ARG
XTLDX::	NULL
	HRRZ	T2,T1		;CHECK SPECIAL
	CAIN	T2,-1		;...
	JRST	XTLDXA		;FORCE UNITS ON-LINE

	PUSHJ	P,FNDEXP	;FIND UNIT #
	  PJRST	ECOD4##		;LOSE
	PUSHJ	P,GRBCTL	;GET CTL
	MOVE	T1,XUBUNO(U)	;UNIT #
	LSH	T1,UNILSH
	XCT	XTSCNO##(W)	;SET CODE
	MOVEI	T1,XC.CON!XC.JAM
	XCT	XTCCNO##(W)	;POW
	PUSHJ	P,GIVCTL	;RETURN CTL
	JRST	XTLDXL		;HANDLE MORE

XTLDXA:	NULL
	PUSHJ	P,FNDKON	;FIND KDB
	  JRST	ECOD4##
	MOVE	W,U		;KDB ADDR TO CORRECT PLACE
	PUSHJ	P,GRBCTL	;GO GET CTL
	PUSHJ	P,XTRETX		;GIVE CONTROL BACK
	JRST	XTLDXL		;CONTINUE
;ROUTINE TO RETURN DEAD-START INFO FROM UDB
;ARGUMENT LIST:
;	SIXBIT /EP NAME/
;	......
;RETURNS D-S INFO  OVER EP-NAME

XTDSTL:	NULL
	SOJL	P3,CPOPJ1##	;RETURN IF NO MORE ARGS
	PUSHJ	P,GETWD1##	;GET NEXT ARG
XTDST:	NULL
	PUSHJ	P,FNDEXP	;LOCATE UDB
	  PJRST	ECOD4##		;LOSAGE
	MOVEI	T1,0		;CLR INFO
	EXCH	T1,XUBDST(U)	;FETCH DEAD-START WORD
	PUSHJ	P,PUTWDU##	;GIVE TO CALLER
	JRST	XTDSTL		;TRY NEXT
SUBTTL XTTSK. UUO -- XTGRB, XTRET MAINTENANCE FUNCTIONS

;ROUTINE TO GRAB A CONTROLLER WHOSE NAME APPEARS IN T1
;ARGUMENT LIST:
;	SIXBIT /CONTROLLER NAME/

XTGRB:	NULL
	TRNN	T1,-1		;GRNTEE ZERO IN RH
	PUSHJ	P,FNDKON	;LOOK FOR CONTROLLER
	  JRST	ECOD4##		;LOSE
	MOVE	W,U		;KDB ADDRESS TO W
	PUSHJ	P,GRBCTL	;GO GET IT
	MOVEI	T2,XKBUDB##(W)	;GET START OF UDB LIST
XTGRB1:	HRRZ	U,0(T2)		;LOCATE A UDB
	JUMPE	U,CPOPJ1##	;RETURN WHEN END FOUND
	SETZM	XUBRDY(U)	;MARK UNIT NOT READY
	AOJA	T2,XTGRB1	;GO DO NEXT

;ROUTINE TO RETURN CONTROLLER TO SYSTEM USE AND RESTART SCANNER
;ARGUMENT LIST:
;	SIXBIT /CONTROLLER NAME/

XTRET:	NULL
	TRNN	T1,-1		;GUARANTEE ZERO IN RH
	PUSHJ	P,FNDKON	;FIND KDB
	  JRST	ECOD4##		;NO SUCH KDB
	MOVE	W,U		;ADDRESS TO W
	SKIPN	XKBGRB##(W)	;IS IT REALLY GRABBED?
	JRST	CPOPJ1##	;THE COMPETITION DID IT
	AOS	(P)		;SET FOR SKIP RETURN
XTRETX:	MOVEI	T1,XC.JAM	;FORCE EM ON-LINE
	XCT	XTCCNO##(W)
	PJRST	GIVCTL		;GIVE CONTROLLER BACK

SUBTTL	XTTSK. SUBROUTINES -- DELETE AN XTC DDB
;ROUTINE TO DELETE A DDB
;CALL:
;	MOVEI	F,DDB
;	PUSHJ	P,XTKLDB
;	POPJ	P,

XTKLDB::NULL			;SUBROUTINE TO DELETE A DDB  (ALSO
				;CALLED FROM DEASSIGN CODE)
	PUSHJ	P,XTCDEV	;SEE IF IT IS A TASK DDB
	PJRST	CPOPJ##		;NO
	MOVSI	T1,XT.PRM	;PERMANENT FLAG VALUE
	TDNE	T1,DVXDSC(F)	;IS IT ON?
	POPJ	P,		;THEN DO NOT DELETE IT
	HRRZ	T1,DVXUDB(F)	;LOCATE ITS UDB
	HLRZ	T2,XUBDDB(T1)	;START DOWN UDB'S DDB LIST
	CAIE	T2,0(F)		;FOUND THE DDB YET?
	JRST	KDBUL		;NO, FOLLOW LIST
	HLRZ	T3,DVXUDB(F)	;YES, LOCATE NEXT DDB
	HRLM	T3,XUBDDB(T1)	;TAKE DDB OUT OF LIST
	JRST	KDBD		;GO TAKE DDB OUT OF SYSTEM LIST
KDBUL:	MOVE	T1,T2		;FOLLOW DDB LIST
	HLRZ	T2,DVXUDB(T1)	;
	CAIE	T2,0(F)		;FOUND DDB YET?
	JRST	KDBUL		;NO, LOOP
	HLRZ	T3,DVXUDB(F)	;YES, LOCATE NEXT DDB
	HRLM	T3,DVXUDB(T1)	;TAKE THIS ONE OUT OF LIST
KDBD:	MOVEI	T2,XTCDDB	;LOCATE FIRST POSSIBLE DDB
KDBDL:	MOVE	T1,T2		;FOLLOW DDB LIST
	HLRZ	T2,DEVSER(T1)	;
	CAIE	T2,0(F)		;FOUND MINE YET?
	JRST	KDBDL		;NO, LOOP
	HLRZ	T3,DEVSER(T2)	;YES, FOLLOW ONE MORE
	HRLM	T3,DEVSER(T1)	;TAKE MINE OUT OF LIST
	MOVEI	T1,XTCDDW	;GET DDB SIZE
	PJRST	GIVWDS##	;FREE THE CORE
SUBTTL	XTTSK. SUBROUTINES -- XTCDEV, XTCIOS
;XTCDEV CALLED TO FIND WHETHER A DDB IS A TASK DDB AND
;TO RETURN S IN THAT CASE WITH THE IO.XXX BITS BIT
;NORMAL RETURN	NO TASK DDB
;SKIP RETURN	A TASK DDB, S REPLACED
;NO ACCUS (EXCEPT S ON A SKIP RETURN) ARE CHANGED

XTCDEV:	NULL
	PUSH	P,T1		;SAVE ACCU
	MOVE	S,DEVIOS(F)	;GET STANDARD S
	LDB	T1,DEYTYP##	;GET DEVICE TYPE
	ANDI	T1,77		;MASK UNNEEDED BITS
	CAIE	T1,.TYXTC	 ;IS IT A TASK DDB?
	PJRST	TPOPJ##		;(NO) FALSE RETURN
	LDB	T1,[POINT 4,DVXPST(F),8]  ;GET PTOTOCOL STATUS
	DPB	T1,[POINT 4,S,27]  ;AND COPY TO MAKE IT VISIBLE
	PJRST	TPOPJ1##		;TRUE EXIT

XTCIOS::NULL			;CALLED FROM REST OF MONITOR TO GET DEVIOS
	PUSHJ	P,XTCDEV	;GET S
	POPJ	P,		; IGNORE FALSE RETURN.
	POPJ	P,
SUBTTL	XTTSK. SUBROUTINES -- FNDxxx SEARCH ROUTINES
;ROUTINE TO LOCATE KDB WHOSE NAME IS IN T1
;RETURNS KDB ADDRESS IN U

FNDKON:	MOVEI	U,XKB0##	;BASE ADDRESS
	HLLZ	T2,T1		;CONTROLLER NAME IN T2
FNDKN1:	CAMN	T2,XKBNAM##(U)	;THIS ONE?
	JRST	CPOPJ1##	;YES - GIVE GOOD RETURN
	HRRZ	U,XKBKDB##(U)	;LINK TO NEXT
	JUMPN	U,FNDKN1
	POPJ	P,		;ERROR RETURN

;SUBROUTINE TO FIND DDB WITH GIVEN TASK ID ON THIS EP
;CALL:
;	MOVEI	T1,TASKID	;12 BITS
;	PUSHJ	P,FNDTSK
;	ERROR RETURN
;	SUCCESS RETURN		;WITH (F)=ADDRESS OF DDB

FNDTSK:	NULL
	HLRZ	F,XUBDDB(U)	;LOCATE FIRST DDB
FNTSK1:	JUMPE	F,CPOPJ##	;WE HAVE FAILED IF OUT OF DDBS
	LDB	T2,DVYTID	;GET TASK ID
	HRRZ	U,DVXUDB(F)	;SET UP U 
	HRRZ	W,XUBKDB(U)	; AND W
	CAMN	T1,T2		;THIS IT?
	JRST	CPOPJ1##	;  YES
	HLRZ	F,DVXUDB(F)	;NO, LOCATE NEXT DDB
	JRST	FNTSK1		;LOOP

;SUBROUTINE TO FIND DDB WITH GIVEN NAME
;  AND PERFORM ACCESS CHECKING
;CALL:
;	MOVE	T1,[SIXBIT /DDB NAME/] OR MOVEI T1,CHANNEL
;	PUSHJ	P,FNDDDB
;	FAILURE RETURN
;	SUCCESS RETURN		;WITH (F) = ADDRESS OF DDB

FNDDDB:	NULL
	PUSHJ	P,DVCNSG##	;LOCATE DDB
	  JRST	ECOD2##		;  ERROR IF NONE
	LDB	T2,DEYTYP##	;GET DEVICE TYPE CODE
	ANDI	T2,77		;MASK DOWN TO TYPE BITS
	CAIE	T2,.TYXTC	;IS IT AN EXTERNAL TASK?
	  JRST	ECOD2##		;  NO, ERROR
	HRRZ	U,DVXUDB(F)	;SET UP U
	HRRZ	W,XUBKDB(U)	; AND W
	LDB	T2,PJOBN##	;GET CONTROLLING JOB NUMBER
	CAME	T2,.CPJOB##	;THIS JOB OWN IT?
	PUSHJ	P,PRVJ##	;  OR OPR JOB?
	JRST	CPOPJ1##	;YES, SUCCESS RETURN
	  JRST	ECOD2##		;  NO, ERROR
;FIND UDB WITH GIVEN NAME
;CALL:
;	MOVE	T1,[SIXBIT /EP NAME/]
;	PUSHJ	P,FNDEXP
;	ERROR RETURN
;	NORMAL RETURN		;WITH (U) = ADDRESS OF UDB

FNDEXP:	NULL
	PUSHJ	P,FNDKON	;LOCATE KDB FOR THIS ONE
	  POPJ	P,		;ERROR
	MOVEI	T2,XKBUDB##(U)	;GET START OF UDB LIST
FNDXP1:	HRRZ	U,0(T2)		;LOCATE A UDB
	JUMPE	U,CPOPJ##	;ERROR IF NONE
	CAME	T1,XUBNAM(U)	;THIS THE UDB?
	AOJA	T2,FNDXP1	;NO, TRY ANOTHER
	HRRZ	W,XUBKDB(U)	;SET UP CONTROLLER ADDRESS
	JRST	CPOPJ1##	;YES, SUCCESS RETURN

;FIND SPECIFIED UNIT
;CALL:
;	MOVE	T2,<DESIRED UNIT>
;	MOVE	T3,<DESIRED XKB>
;	PUSHJ	P,FNDUNI
;	ERROR RETURN
;	NORMAL RETURN - U SETUP

FNDUNI:	NULL
	HRRZ	U,XKBUDB##(T3)	;LOOK AT FIRST UNIT
FNDUN0:	CAMN	T2,XUBUNO(U)	;THIS DA ONE?
	JRST	CPOPJ1##	;YES - GIVE GOOD RETURN
	HRRZ	U,XKBUDB##(T3)	;NO - GET NEXT UDB
	JUMPE	U,CPOPJ##	;DONE IF ZERO
	AOJA	T3,FNDUN0	;TRY NEXT
SUBTTL	INITIALIZATION AT SYSINI TIME

;SUBROUTINE TO INIT THE DA28-C CALLED AT ONCE TIME
;
XTCINI:	NULL
	PUSHJ	P,SAVE1##	;NEED A P AC
	SETZM	DEVNAM+XT0DDB	;CLEAR OUT DEVICE NAME
	MOVEI	W,XKB0##	;START WITH FIRST XKB
XTINL1:	SETZM	XKBIUN##(W)	;CLEAR INTERRUPT
	SETZM	XKBDDB##(W)	; FLAGS
	SETZM	XKBGRB##(W)	;FLAG NOT YET GRABBED
	SETOM	XKBLOK##(W)	;GIVE UP THE CONTROL
	MOVEI	P1,XKBUDB##(W)	;ADDRESS OF FIRST UDB ADDRESS
XTINL2:	SKIPN	U,(P1)		;ADDRESS OF NEXT UDB
	JRST	XTINL7		;JUMP IF DONE
	SETZM	XUBRDY(U)	;NEED A NEW RESTART
	SETZM	XUBQUE(U)	;TAKE OFF ANY QUEUES
	SETZM	XUBLOK(U)	;NO I/O GOING ON
IFN	FTFRC,<CALL FRCOFL>	;FORCE UNIT OFFLINE
IFE	FTFRC,<
	SETZ	F,		;NO DDB!
	MOVE	T1,XUBUNO(U)	;GET UNIT NUMBER
	LSH	T1,UNILSH	;SHIFT TO HARDWARE POSITION
	IORI	T1,XS.CLR!XS.ETI;DA28 BITS TO SELECT UNIT,
	XCT	XTSCNO##(W)	;CLEAR DA28, AND ENABLE TIMING ERRORS
	MOVEI	T1,XC.ERR!XC.CON;CONNECT TO SPECIFIC UNIT
	XCT	XTCCNO##(W)	;AND CLEAR ERRORS
	XCT	XTSCNI##(W)	;READ DA28 STATUS
	TRNE	T1,XS.NRD	;UNIT READY?
	AOJA	P1,XTINL2	;NO, STEP TO NEXT UNIT

;UNIT IS THERE, SEND A RESTART -10

	PUSHJ	P,MAKREL	;GET A RESTART -10 COMMAND
	MOVE	T2,T4		;AND PUT IT IN T2 FOR XTSDTO
	MOVEI	T1,XC.ERR!XC.FST!XC.CON!XC.OUT!XC.BSY!DM.BIN
	XCT	XTCCNO##(W)	;PREPARE DA28 TO SEND COMMAND WORD
	XCT	XTSDTO##(W)	;TELL SMALL COMPUTER TO RESTART
	MOVEI	T3,XC.ERR!XC.DUN;ERROR AND DONE BIT MASK
	MOVEI	T2,^D16000	;A SMALL NUMBER OF CLOCK TICKS
	XCT	XTCCNI##(W)	;READ DA28 [COMMAND] STATUS
	TDNN	T1,T3		;IF ERROR OR DONE THEN FINISHED
	SOJG	T2,.-2		;ELSE LOOP A [SHORT] WHILE
	TRNE	T1,XC.ERR	;TERMINATE DUE TO ERROR?
	JRST	XTINL4		;YES, ABORT THIS UNIT

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;READ SMALL COMPUTER RESPONSE IF HE'S QUICK ENOUGH

	MOVEI	T1,XC.ERR	;TURN OFF CONNECT BIT
	XCT	XTCCNO##(W)	;SO SMALL COMPUTER GETS EOT
	MOVN	T3,XUBUNO(U)	;GET UNIT NUMBER
	HRLI	T3,(1B0)	;UNIT SELECT BIT
	LSH	T3,(T3)		;POSITION FOR THIS UNIT
	ANDCMI	T3,-1		;CLEAR EXTRANEOUS JUNK
	MOVEI	T2,^D16000	;A SMALL NUMBER OF CLOCK TICKS
	XCT	XTSCNI##(W)	;READ DA28 STATUS
	TDNN	T1,T3		;OUR UNIT RESPONDED?
	SOJG	T2,.-2		;NOT YET
	JUMPLE	T2,XTINL4	;NO, HE'LL JUST HAVE TO WAIT A WHILE
	MOVEI	T1,XC.FST!XC.CON!XC.BSY!DM.BIN
	XCT	XTCCNO##(W)	;PREPARE TO READ RESPONSE
	XCT	XTSDTI##(W)	;READ SMALL COMPUTER RESPONSE
	MOVEM	T1,XUBRCW(U)	;SAVE IT
	XCT	XTCCNI##(W)	;READ DA28 [COMMAND] STATUS
	TRNN	T1,XC.ERR	;IF ERROR THEN ABORT
	TRNN	T1,XC.EOT	;IF NOT EOT THEN ABORT
	JRST	XTINL4		;ERROR OR NOT-EOT (I.E., DATA)
	LDB	T1,XUYMFC	;GET MAJOR FUNCTION RECEIVED
	CAIE	T1,FN.RST	;A RESTART?
	JRST	XTINL4		;NO, ABORT
	LDB	T1,XUYFSC	;GET SUB-FUNCTION
	CAIL	T1,SF.6BP	;IN RANGE OF
	CAILE	T1,SF.2BP	;SMALL-COMPUTER RESTART?
	JRST	XTINL4		;NO, TOSS OUT COMMAND
	SETOM	XUBRDY(U)	;YES, FLAG UNIT READY TO GO
XTINL4:	MOVEI	T1,XS.CLR	;CLEAR ALL BIT
	XCT	XTSCNO##(W)	;RELEASE DA28 AND REMOTE SMALL COMPUTER
> ;END IFE FTFRC

	AOJA	P1,XTINL2	;POINT TO NEXT UDB

;ALL UNITS INITIALIZED AS APPROPRIATE, PUT DA28 CONTROLLER ONLINE

XTINL7:	PUSHJ	P,CLRERR	;START WORLD
	HRRZ	W,XKBKDB##(W)	;GO TO NEXT KDB
	JUMPN	W,XTINL1	;LOOP BACK UNLESS DONE
	POPJ	P,0		;RETURN
	$INIT

;ROUTINE TO CREATE ALL UDBS (CALLED BY LINKDB)
XTCLNK::PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	MOVEI	W,XKB0##	;GET LOC OF FIRST KDB

XTCLN1:	MOVEI	T1,1B33		;WANT TO READ
	XCT	XTCCNO##(W)	;  DA28 FEATURE REG
	XCT	XTSDTI##(W)	;READ FEATURES
	JUMPE	T1,XTCLN4	;NOT THERE
	ANDI	T1,17		;WANT ONLY NUMBER OF UNITS
	MOVE	P1,T1		;SAVE UNITS
	MOVEI	P2,XKBUDB##(W)	;GET ADDRESS OF UDB TABLE

XTCLN2:	MOVEI	T1,XUBSIZ	;SIZE OF UDB
	PUSHJ	P,INICOR##	;ALLOCATE CORE
	MOVEM	T2,0(P2)	;SAVE UDB ADDRESS
	MOVEM	W,XUBKDB(T2)	;LINK UDB TO KDB
	MOVE	T3,P2		;GET UDB STORAGE POINTER
	SUBI	T3,XKBUDB(W)	;CALCULATE UNIT NUMBER
	MOVEM	T3,XUBUNO(T2)	;STORE IN XUB
	ADDI	T3,2120		;CONVERT TO SIXBIT
	TRZN	T3,10
	LSH	T3,6
	LSH	T3,6		;POSITION IN WORD
	MOVEM	T3,XUBNAM(T2)	;MOVE INTO UNIT NAME
	MOVE	T3,XKBNAM(W)	;PICK UP KNOTROLLER NAME
	HLLM	T3,XUBNAM(T2)	;FILL IN REST OF UNIT NAME

XTCLN3:	AOS	P2		;BUMP UDB TABLE POINTER
	SOJGE	P1,XTCLN2	;LOOP IF MORE UNITS

XTCLN4:	HRRZ	W,XKBKDB##(W)	;NO, GET ADDR OF NEXT KDB
	JUMPN	W,XTCLN1	;LOOP IF IT IS THERE
	POPJ	P,		;RETURN

	$HIGH

PLM
;+
;.lm 0
;.hl 1 Initialization code
;^^
; There are two pieces of initialization code for the DA28 software: XTCINI
;and XTCLNK, both in XTCSER.
;The routine LINKSR in ONCE calls LINKDB in COMMON to build the
;DDBs XTCLNK is called by LINKDB to loop through all the KDBs and building
;UDBs for all the units (taken from section zero free core) that could
;conceivably exist (as determined by the scan limit setting on the DA28C).
; XTCINI is called later during SYSINI via the initialization dispatch entry
;to clean up the XTCSER data base for a given controller and also to attempt
;to send a "restart -10" control word to all small
;computer interfaces.  If a small computer is up and answers quickly, XTCINI
;sets XUBRDY to -1 so that the first I/O attempt does not have to wait for the
;restart.
;-
MLP
SUBTTL	INPUT UUO -- DUMP MODE

;HERE FROM UUOCON WITH ALL THE AC'S SET UP .

XTCDIN:	NULL
	PUSHJ	P,INSET		;SETUP
	  POPJ	P,		;ERROR - IMPROPER MODE
	PUSHJ	P,DMPSET		;GET DUMP MODE DATA
	PJRST	ADRERR##	;OOPS SOMETHING IS WRONG
	PJRST	INPCOM		;EXECUTE COMMON CODE
SUBTTL	INPUT UUO -- BUFFERED MODE

;HERE FROM UUOCON WHEN THE USER DOES AN INPUT UUO
;ACS CONTAIN:
;	S - DEVICE STATUS
;	P - PUSH DOWN POINTER TO JOB DATA AREA
;	J - JOB NUMBER
;	R - ADDRESS OF JOBDAT
;	F - XTC DDB
;	P1 - CHANNEL NUMBER
;	P4 - ADDRESS OF CPU DATA BLOCK

XTCIN:	NULL
	PUSHJ	P,INSET		;SET UP ALL GOOD THINGS
	  POPJ	P,		;ERROR - IMPROPER MODE
	HRRZ	T1,DEVIAD(F)	;GET INPUT BUFFER ADDRESS
	PUSHJ	P,BUFCLR##	;GO CLEAR IT
	  PJRST	ADRERR##	;ADDRESS CHECK
	MOVE	T2,DEVIAD(F)	;POINT TO BUFFER HEADER
	EXCTUX <LDB T3,[POINT 17,0(T2),17]> ;GET THE BUFFER SIZE
	SUBI	T3,1		;SUBTRACT OVERHEAD
	HRRM	T3,DVXBSZ(F)	;REMEMBER THE SIZE
;****FALL INTO COMMON INPUT CODE

;CODE SHARED BY DUMP AND BUFFERED MODES

INPCOM:	NULL
	AOS	CNTINP		;COUNT THE INPUTS
	TRNE	S,IO.BYP	;CHECK BYPASSING
	JRST	[HRRZM T3,DVXWFO(F) ;SAVE W.C.
		    JRST XTCIN1]
	PUSHJ	P,XISYNC	;GET IN SYNC
	  PJRST	XFRRST		;ERROR
	HRRZ	T3,DVXWFO(F)	;GET HIS BUFFER SIZE
	CAILE	T3,@DVXBSZ(F)	;COMPARE AGAINST OURS
	PJRST	XTCBTL		;BLOCK IS TOO LARGE
	HRRM	T3,DVXBSZ(F)	;REMEMBER FOR WFI
XTCIN0:	PUSHJ	P,CHKMOD	;CHECK DATA MODE
	  PJRST	XTCIPM		;IMPROPER MODE
XTCIN1:	NULL
	PUSHJ	P,IFDMP		;SEE IF DUMP MODE
	SKIPA	T1,DEVIAD(F)	;BUFFERED MODE
	PJRST	XMTWFI		;THEN ALL SET

	HRRZ	T2,DVXWFO(F)	;PICK UP WORD COUNT
	EXCTXU	<MOVEM T2,1(T1)> ; STORE IN BUFFER
	PUSHJ	P,SETIOW		;SET UP IOWD LOGIC
XMTWFI:	NULL
	POP	P,T1		;REMOVE RETURN TO ZAPACT CODE
	PUSHJ	P,MAKACT		;ACTIVATE DEVICE
	PUSHJ	P,MAKWFI		;MAKE WFI WORD
IFE	FTCMP0,<
	PUSHJ	P,ADDSIZ		;ADD SIZE TO IT
>		;IFE FTCMP0
	PJRST	SENDW		;SEND AND DO NOT WAIT
				;AND RETURN VIA ZAPACT
;SUBROUTINE TO ESTABLISH INPUT SYNC WITH THE EXTERNAL TASK
;CALL WITH:
;	PUSHJ	P,XISYNC
;	  RETURN HERE IF I/O ERROR
;	RETURN HERE IF OK TO SEND WFI
;THIS ROUTINE STARTS AT UUO LEVEL AND IS SHARED WITH
;INTERRUPT LEVEL
;
XISYNC:	COROUT	<IOEND!IORWFI!IORWFO,,RHSTOP>	;START OF COROUTINE
XISYN0:	NULL
	MOVE	S,DEVIOS(F)	;GET DEVICE STATUS
	TDNE	S,[IOEND,,RHSTOP]	;GET EXIT CONDITIONS
	$CPOPJ			;EXIT TO CALLER AT UUO LEVEL
	MOVE	T1,DVXPST(F)	;GET THE PROTOCOL STATUS
	TLNE	T1,IORWFO	;IS SMALL COMPUTER
	$POPJ1			;DO THE RIGHT THING!
	TLNE	T1,IOXRFI	;DID WE SEND AN RFI?
	JRST	XISYN1		;YES--DO NOT SEND ANOTHER
	PUSHJ	P,MAKRFI		;MAKE RFI WORD
IFE	FTCMP0,<	;ADDING THE COUNT
	PUSHJ	P,ADDSIZ		;ADD SIZE TO WORD
>				;IF ZERO
	PUSHJ	P,SENDW		;SEND (OR TRY) AND DO NOT WAIT
XISYN1:	NULL
	MOVE	S,DEVIOS(F)	;IT MAY HAVE CHANGED
	TDNE	S,[IOEND,,RHSTOP]	;AT THE END
	$CPOPJ			;EXIT TO CALLER AT UUO LEVEL
	MOVE	T1,DVXPST(F)	;GET STATUS AGAIN
	TLNE	T1,IORWFI	;IS SMALL COMPUTER WAITING FOR
	JRST	[MOVEI S,IOIMPM	;YES--LIGHT IO.IMP
		 IORB  S,DEVIOS(F)
		 SEND OPE
		 $CPOPJ]	;AND GO BACK
;CATCH UP WITH THE LATEST EVENTS OR SYNCHRONIZE
	$SYNC	<IOEND!IORWFI!IORWFO,,RHSTOP>	;GET IN SYNC WITH REMOTE
	JRST	XISYN0		;SEE IF IT CAME
PLM
;+
;.lm 0
;.hl 1 Input/Output Routines
;^^
;.subtitle Input and Output Routines
; The main use of XTCSER is to transfer data between processes in two computers using the normal
;IN(PUT) and OUT(PUT) monitor calls.  This section of the code contains
;support for dump and buffered mode input, dump and buffered mode output, CLOSE and RELEAS UUO's.
;Because of the basic similarities both between dump and buffered
;mode I/O and between input and output, a good deal of code is common
;to all the variations of I/O calls.
; The basic flow of both IN and OUT UUO processing is as follows:
;.list
;.le;Set up for the proper type of I/O (dump or buffered) and go
;to a common routine to actually do it.
;.le;xxxCOM -- if IO.BYP set to bypass protocol exchange (for example
;in a bootstrap program) skip over the next step.
;.le;call a subroutine XdSYNC (where "d" is I for input and O for output) to get in synchronization with the
;small computer.  This routine uses the co-routine mechanism (described below)
;to start the protocol word exchange at UUO level, continue it (if
;necessary) at interrupt level and finally return to UUO level (giving
;a success or failure indication) when finished. If the attempt failed,
;simply give error return to UUOCON on IN or OUT call.
;.le;Once we are in sync with the small computer (i.e. we both
;agree on the direction of data transfer) start the data transfer.
;This is slightly different depending upon whether we are doing input
;or output.  For input, the synchronization phase ends when we have
;received a WFO, and therefore this step sends the WFI and
;sets things up so that the next remote interrupt (REMINT) starts the incoming data transfer.
;For output, the synchronization phase ends when we have received an
;RFI and therefore this step sends the WFO.  When we receive the WFI
;we will start the outgoing data transfer.
;.end list
;.lm 0
;.hl 2 Co-routine Mechanism
;^^
; The so-called co-routine mechanism allows the UUO to begin at
;UUO level, to wait there for the occurrence of various events,
;to continue processing at interrupt level after these
;events and, when all has been completed, to return to UUO level.
;It does this by starting the "co-routine" code with a call to
;$COROU which removes the return PC of the caller of the co-routine
;from the stack and stores it in the DVXPRC word of the
;DDB. To wait for some particular events to occur the XISYNC or
;XOSYNC routine issues a $SYNC macro, which calls the SYNC$ routine with
;a mask of bits to be wakened on.  If any of the
;bits are on, the SYNC$ routine merely returns (so that the XISYNC or
;XOSYNC routine can continue either by sending more protocol words or
;by exiting).  If no bits are on, if it is called at UUO level
;it POPs the return address into DVXCOR (which both flags that a co-routine is running and remembers where to continue the
;co-routine) and calls DOZE0 to HIBER; if it is called
;at interrupt level it merely POPs the return PC (of the SYNC$ call) into
;DVXCOR and returns (to the return PC of the call to CHKPRC).
; To exit,  the co-routine executes one of two macros, $CPOPJ and $POPJ1 (which call CPOPJ$ and CPOPJ1$
;respectively). These adjust the return PC in DVXPRC as required (either
;by doing nothing or incrementing it by one, respectively) and then test if
;they are at interrupt or UUO level.  If at UUO level, they simply
;jump to the address contained in DVXPRC to return to the
;co-routine caller.  If at interrupt level, they merely do a wakejob
;call, which will wake UUO level (which is in the HIBER resulting from
;the first $SYNC done at UUO level).
; An example will make this clearer; both co-routines have the format:
;.list;.le;XdSYNC: -- call $COROUT to store the XdSYNC caller's return PC in DVXPRC
;.le;various tests for completion. The error completions use $CPOPJ
;and the successful completions use $POPJ1 to exit the co-routine.
;.le;$SYNC with mask bits for events of interest (i.e. error bits and
;bits corresponding to the arrival of control words we are waiting for).
;.le;A jump back to step 2.
;.end list
;In the case of the input sync routine (XISYNC) the
;tests are:
;.list
;.le;If there are any error or EOF bits exit via $CPOPJ.
;.le;If we have received a WFO exit via $POPJ1.
;.le;If we have not sent an RFI, call MAKRFI to make it and SENDW to start sending it.
;.le;If we have received WFI  (i.e. we are both trying to input) set
;IOIMPM error bit and exit via $CPOPJ.
;.end list
; We are now ready to describe a possible sequence of events during
;an input UUO.
;.list
;.le;The IN UUO processing starts at UUO level and does a PUSHJ#P,XISYNC
;at INPCOM+n.
;.le;XISYNC routine calls $COROU, which stores the XISYNC caller's
;return PC (namely INPCOM+n+1) in DVXPRC and then returns to XISYNC.
;.le;XISYNC performs its tests, finds no errors and decides it
;needs to send an RFI.  The call to MAKRFI builds the
;control word, and the call to SENDW either starts it out if the DA28C
;was idle, or queues it to be started (whenever the DA28C completes
;whatever it is doing) if the DA28C was not free.
;.le;XISYNC does a $SYNC which puts the bits upon which the co-routine
;should awaken into DVXMSK.  Since this call is at UUO level and none of the
;desired bits are on, SYNC$ will call DOZE0 which will HIBER the job.
;It will also POP the return address (i.e. that of the instruction
;after the $SYNC macro in XISYNC) into DVXCOR.
;.le;At some later time a done interrupt comes in which signals the
;end of transmission of the RFI.  This sets the bit IOXRFI. The
;interrupt routine then calls CHKPRC which notices that DVXCOR is
;non-zero (i.e.#a co-routine is running) and sees if any bits in
;the co-routine mask (DVXMSK) are on. None are, because IOXRFI is
;not among the bits tested.
;.le;Even later the remote processor wants to do output. This
;causes first a remote interrupt at the 10, which merely sets up
;to read the control word, and then later a done interrupt when
;the read of the control word is finished. It is a WFO, and sets IORWFO.
;This time the CHKPRC call finds that a bit included in DVXMSK is set and therefore
;jumps to the address in DVXCOR, i.e. to right after the $SYNC
;macro. This is a jump back to try the synchronization tests over again.
;.le;We now execute the co-routine test loop again, but this time at
;interrupt level.  Because IORWFO is set and there are no
;error bits, we do a $POPJ1 which increments DVXPRC by one, clears DVXCOR
;to indicate that the co-routine has exited, sees that we are at
;interrupt level and therefore calls XTWAKE and returns (to the caller
;of CHKPRC) to dismiss the interrupt.
;.le;When the scheduler gets around to scheduling our job again, we find
;ourselves after the HIBER call in SYNC$. The code here notices
;that DVXCOR is zero (i.e. the co-routine is finished) and
;so jumps to the address in DVXPRC (now INPCOM+n+2) which continues
;the input UUO by beginning the sending of the WFI and then returning
;to UUOCON.
;(It can do this because we have started the input.  UUOCON will
;put the job in I/O wait if necessary.)
;.end list
;Note that if the WFO control word had been received from
;the small computer before the -10 issued the IN UUO, the entire
;XISYNC routine would have only been executed once and only at
;UUO level.
;.hl 2 Input UUO
;^^
;.subtitle Input UUO
; The code to service IN or INPUT UUO's has two entries:
;XTCDIN for dump mode and XTCIN for buffered mode. They
;merely set up some things a little bit differently, then merge at INPCOM (common input code).
;The reason for this is that XTCSER builds its own IOWD list for data
;transfers in the DDB; dump mode simply copies the user IOWD's
;into the DDB and buffered mode simply constructs an IOWD to describe
;the buffer.  After that, all other operations that XTCSER
;needs to perform are identical.
; The major requirement for input is that the proper protocol words
;be exchanged with the small computer.  INPCOM calls XISYNC to ensure
;this.  XISYNC is one of two examples (the other is XOSYNC) of the
;co-routine mechanism described above.  XISYNC will return to the
;success return (skip) if a WFO has been seen and no conflicts exist.
;It will give the error word if it receives a WFI (indicating that
;both sides are trying to do input) or if any error or EOF bits are
;set in DEVIOS (for example by reject or restart or EOF control words).
;.hl 3 Detailed Logic
;^^
;The following is the detailed logic of the input code:
;.list
;.le;XTCDIN: -- call INSET to do input setup. This routine:
;.list;.le;sets the IO bit in DEVIOS to 0 to indicate input
;.le;sets FRSTIN bit in DEVIOS (used as a flag if we
;have to copy data in image-binary mode)
;.le;then skips into the common part of OUTSET.
;.end list
;The routine OUTSET:
;.list
;.le;set the IO bit to one for output (this is skipped when
;INSET skips into this routine)
;.le;sets up F, U, W, S, J and R by calling SETACS
;.le;calls GETMOD to get (from DVXMOD) the hardware mode that
;corresponds to the software mode in DEVIOS and to store it
;in DVXBSZ.
;.le;checks if user has privileges if IO.BYP was set and
;if not, goes to SETIPM to give IOIMPM error.
;.le;if not bypassing, calls RDYCHK to wait until we know that
;the small computer is up (by the fact that it sent
;a restart).
;.le;PSACT: -- falls into the code that makes
;the job I/O active but not really for data transfer (yet).
;It stores ACTTIM in DVXPAC so that we can time out this
;"pseudo-active" state.  If the transfer doesn't happen soon, we
;are taken out of IOACT state; just before the transfer takes
;place we are made active again.
;This routine also places a call to ZAPACT (which
;clears I/O active and all protocol status) on the stack
;so that in error cases this will do the clean up for us. When
;we get ready to do the real data transfer this is cleaned up.
;.end list
;.le;XTDIN then calls DMPSET which copies the user IOWDs into
;the .IOLEN words starting at DVXIWD in the DDB.  If there are
;more IOWDs than will fit, DVXIWA will have a non-zero value and
;DVXLLM and DVXULM will have values so we can call COMCHK and NXTCMR
;at interrupt level when we have finished as much as we have got.
;DMPSET also calculates the transfer size and stores it in DVXBSZ.
;XTCDIN then branches to INPCOM.
;.le;XTCIN: -- this is the buffered mode entry. It also calls INSET
;(see above) to set things up for input, then gets the address of the
;buffer from DEVIAD and calls BUFCLR (in UUOCON) to clear it.
;From the buffer header in the user address space it extracts the
;size in words, and stores it in DVXBSZ. Then it falls into INPCOM.
;.le;INPCOM: -- common input code. This increments the number
;of inputs done (CNTINP) and if not bypassing the protocol calls
;the input co-routine XISYNC to get in synchronization with the small computer (see below).
;If the result is an error, it jumps to XFRRST which clears the protocol
;status and returns (using the ZAPACT call on the stack to clear
;everything out).
;INPCOM then compares the size the small computer wants to send with
;the size of the buffer we have, and if the former is too large gives
;a "block to large" (IOBKTL) error.
;It then calls CKHMOD to compare the mode requested and desired, and gives
;the improper mode error (IOIMPM) if they do not match.
;If it is dump mode, it goes to XMTWFI; else it gets the word count
;the small computer will send, stores that in the user's
;buffer header, then calls SETIOW to generate the IOWD cells in the
;DDB to describe the buffer and falls into XMTWFI.
;.le;XMTWFI: -- the first thing this routine does is pop the ZAPACT call off the stack. Then it calls MAKACT to ensure that the job is really
;I/O active now, calls MAKWFI to build the WFI control word, calls
;SENDW to start it out (or queue it) and returns to UUOCON, the input started.
;.end list
; The only remaining piece of code to decribe for the INPUT UUO is
;XISYNC:
;.list
;.le;XISYNC: -- call $COROUT to put co-routine return in DVXPRC and
;event bits into DVXMSK.
;Then fall into the checking loop, XISYN0.
;.le;XISYN0: -- this routine consists of a series of tests.
;They are:
;.list;.le;test for EOF or error bits in DEVIOS and if
;any are present, exit co-routine via call to $CPOPJ.
;.le;Test DVXPST for bit saying we have received a WFO (IORWFO) and if
;it is set, take success exit from co-routine via $POPJ1.
;.le;Test if we have sent RFI yet (IOXRFI) and if not, call MAKRFI
;to make it, ADDSIZ to add the data transfer size to it and SENDW
;to send it.
;.le;XISYN1: -- test again for error or EOF bits in DEVIOS and
;exit co-routine $CPOPJ if any are on.
;.le;test if we have received a WFI control word and if so, send
;a "reject operation" control word back to the small computer and
;exit co-routine $CPOPJ after setting IOIMPM to give an error to the user.
;.end list
;.le;XISYNC then calls $SYNC to wait for some significant event (errors, EOF, receipt of WFO or WFI). This will 
;cause UUO level to go to sleep until the co-routine eventually exits.
;Whenever one of the specified events occurs, interrupt level
;will execute the co-routine code beginning immediately after the $SYNC
;call.
;.le;after the $SYNC call, the co-routine merely jumps back to XISYN0 to try
;all the tests again.
;.end list
;-
MLP
SUBTTL	OUTPUT UUO -- DUMP MODE

XTCDOU:	NULL
	PUSHJ	P,OUTSET	;SETUP OUTPUT
	  POPJ	P,		;ERROR - IMPROPER MODE
	PUSHJ	P,DMPSET		;GET DUMP MODE DATA
	PJRST	ADRERR##	;ADDRESS ERROR
	PJRST	OUTCOM		;GO TO COMMON OUT CODE
SUBTTL	OUTPUT UUO -- BUFFERED MODE

XTCOUT:	NULL
	PUSHJ	P,OUTSET	;SET UP GOOD STUFF
	  POPJ	P,		;ERROR - IMPROPER MODE
XTCOUA:	NULL
	MOVE	T1,DEVOAD(F)	;POINT TO BUFFER
	EXCTUX	<HRRZ	T1,1(T1)>		;PICK UP WORD COUNT
	HRRM	T1,DVXBSZ(F)	;STORE NUMBER OF WORDS
	JUMPN	T1,OUTCO0	;GO TO COMMN CODE
	PUSHJ	P,ADVBFE##	;SEE IF THERE ARE OTHER ONES?
	POPJ	P,		;NONE
	PJRST	XTCOUA		;TRY IT AGAIN

OUTCO0:	NULL
	PUSHJ	P,SETIOW		;SET UP THE BUFFER LOGIC

	;*****FALL INTO OUTCOM CODE


;START OF COMMON OUTPUT CODE

OUTCOM:	NULL
	AOS	CNTOUT		;COUNT THE OUTPUTS
	HRRZ	T1,DVXBSZ(F)	;GET THE WC
	CAILE	T1,7777		;FIELD LIMITATION
	PJRST	XBTLRG		;BLOCK IS TOO BIG
	TRNE	S,IO.BYP	;BYPASS?
	JRST	XTCOU1		;YES -- SKIP OVER SYNC
	PUSHJ	P,XOSYNC	;GET IN SYNC
	  PJRST	XFRRST		;ERROR
XTCOU0:	NULL
	MOVE	T1,DVXPST(F)	;CURRENT STATUS
	TLNN	T1,IORRFI	;SEEN A RFI
	JRST	XTCOU1		;APPARENTLY NO NEED FOR IT
	HRRZ	T1,DVXRFI(F)	;GET THE COUNT
	CAIGE	T1,@DVXBSZ(F)	;IF WE DO NOT AGREE THEN
	PJRST	XTCBTL		;SEN A BLOK TO LARGE MESSAGE 
XTCOU1:	NULL
	POP	P,T1		;GET RID OF ZAPACT RETURN
	PUSHJ	P,MAKACT		;YOU BETTER GET ACTIVE
	TRNN	S,IO.BYP	;BYPASSING ALL?
	JRST	XTCOU2		;NO USE A WFO
	PUSHJ	P,D28GET		;GET THE DA28 CONTROL
	PUSHJ	P,D28WTF		;WAIT FOR A DDB PROCES
	JRST	DDBIO0		;ADDRESSABLE AND S OKAY
XTCOU2:	NULL
	PUSHJ	P,MAKWFO		;MAKE A WFO
	PUSHJ	P,ADDSIZ		;ADD THE SIZE TO IT
	PJRST	SENDW		;AND THROW IT OUT
				;AND RETURN VIA ZAPACT
;SUBROUTINE TO GET INTO OUTPUT SYNC
;CALL WITH:
;	PUSHJ	P,XOSYNC
;	  RETURN HERE IF IO ERROR
;	RETURN HERE IF OK TO START OUTPUT
;
XOSYNC:	NULL
	COROUT	<IORWFI!IORWFO!IORRFI!IOXWFO,,RHERR>	;EVENTS 
	MOVE	T1,DVXPST(F)	;GET THE PROTOCOL STATUS
	TLNE	T1,IORWFI	;IS HE WAITING FOR US?
	$POPJ1			;(YES) SEND THE DATA
	TLNE	T1,IOXRFO	;DID WE SEND AN RFO
	JRST	XOSYN1		;(YES) ONCE IS ENOUGH
	PUSHJ	P,MAKRFO		;MAKE THE RFO
IFE	FTCMP0,<	;ADD THE NEGATIVE COUNT
	PUSHJ	P,ADDSIZ		;ADD THE SIZE TO IT
>				;IF ZERO
	PUSHJ	P,SENDW		;AND OUT YOU GO
XOSYN1:	NULL
	MOVE	T1,DVXPST(F)	;IT CAN HAVE CHANGED
	TLNE	T1,IORWFO	;DID WE GET A WFO
	JRST	[MOVEI S,IOIMPM	;YES--FATAL ERROR
		 IORB  S,DEVIOS(F)
		 SEND	OPE	;INFORM EP
		 $CPOPJ	]
	TLNE	T1,IORWFI!IORRFI	;DID HE START TO WAIT
	$POPJ1			;YES SEND WFO IF POSSIBLE
	$SYNC	<IORWFI!IORWFO!IORRFI,,RHERR>	;SEE YOU LATER
	MOVE	S,DEVIOS(F)	;GET S
	TRNN	S,RHERR		;ANY ERRORS?
	JRST	XOSYN1		;NO--KEEP WAITING
	$CPOPJ			;ERROR RETURN
PLM
;+
;.lm 0
;.hl 2 Output UUO Processing
;^^
;.subtitle Output UUO
; The output UUO code is very similar to the input UUO code. The
;following is a detailed description:
;.list
;.le;XTCDOU: -- dump mode entry, calls OUTSET (see above) to
;set up everything and then DMPSET to copy the user IOWD's
;to the DDB and save the transfer size in DVXBSZ. Then jumps to OUTCOM.
;.le;XTCOUT: -- buffered mode entry calls OUTSET as well.
;.le;XTCOUA: -- then it gets the address of the user buffer from DEVOAD
;followed by the size of the data transfer, which it stores in
;DVXBSZ. If the size is zero, it calls ADVBFE in
;UUOCON to let the latter know this buffer is finished and if UUOCON
;indicates (by the skip return) that there is another, goes back to
;XTCOUA to examine that one. If the ADVBFE call produces no
;more buffers, it just ends the OUTPUT by returning to UUOCON.
;If the buffer did have data, it falls into XTCOU0.
;.le;XTCOU0: -- calls SETIOW to set up the IOWD parts
;of the DDB to describe the buffer then falls into OUTCOM.
;.le;OUTCOM: -- start of code common to dump and buffered mode.
;Increments the number of OUTPUTs we have done (CNTOUT), gets the data
;transfer size and compares it to 7777(8).  If it is greater, jumps
;to XBTLRG to set block too large error bit in DEVIOS (IOBKTL) and to
;call SETIOD to let UUOCON know we are finished.
;If the size of the transfer is within range, OUTCOM tests if IO.BYP
;is set; if not, it calls XOSYNC to synchronize protocol word exchange
;with the small computer (see below).
;If this co-routine returns an error (non-skip) OUTCOM transfers control
;to XFRRST which clears protocol status and returns via ZAPACT to
;finish the UUO.
;.le;XTCOU0: -- tests if we have seen an RFI control word and
;if not goes to XTCOU1.  Otherwise, compares the size in the RFI to the
;user's size, and set IOBKTL and calls SETIOD if our output won't fit.
;.le;XTCOU1: -- this first gets rid of the ZAPACT call on the top
;of the stack, then calls MAKACT to ensure that the job is I/O active, then test IO.BYP. If it is not set, jumps to XTCOU2 to
;send a WFO. Otherwise it calls D28GET to see if DA28 is free.
;If so (skip return) it goes directly to DDBIO to start
;data transfer, otherwise it calls D28WTF to wait
;till hardware is finished and then go to DDBIO at interrupt level.
;.le;XTCOU2: -- here to do normal output I/O. The code calls
;MAKWFO to build the WFO control word, ADDSIZ to put the transfer
;size into it, and SENDW to send it or queue it, and then returns
;to UUOCON with the OUTPUT completed.
;.end list
; The co-routine for
;output is again very similar to that for input. Here it is:
;.list
;.le;XOSYNC: -- call $COROUT to set up coroutine stuff.
;Then test if we have already received WFI; if so exit coroutine with success return.
;.le;Test if we have sent RFO, and if not call
;MAKRFO, ADDSIZ and SENDW to do so.
;.le;XOSYN1: -- testing loop for output co-routine. This is the
;part of the coroutine that can be executed either at UUO level (the
;first time) or at interrupt level.
;Performs these tests:
;.list
;.le;If we have received a WFO (i.e. both are trying to output)
;set IOIMPM, send a "reject operation" control word to the small
;computer and exit co-routine with error ($CPOPJ).
;.le;If we have received either WFI or RFI, exit co-routine with
;success return ($POPJ1).
;.end list
;XOSYNC then calls $SYNC to wait for any of 1) receipt of WFI,
;2) receipt of RFI, 3) receipt of WFO or any error bits.
;When $SYNC returns it tests if the
;wake-up reason was an error bit and if so exits the co-routine
;$CPOPJ.  Otherwise it goes back to XOSYN1 to repeat its
;tests.
;.end list
;-
MLP
SUBTTL	I/O UUO SUBROUTINES -- INSET, OUTSET, PSACT, MAKACT
;ROUTINES TO SETUP FOR INPUT/OUTPUT AND TO
;WAIT FOR DA28 TO BE FREE

INSET:	NULL
	MOVSI	S,IO		;SET FOR INPUT
	ANDCAB	S,DEVIOS(F)	;...
	MOVSI	S,FRSTIN	;USED BY BINARY I/O
	SKIPA			;GO AND SET BIT

OUTSET:	NULL
	MOVSI	S,IO		;SET FOR OUTPUT
	IORB	S,DEVIOS(F)	;...
	PUSHJ	P,SETACS		;SET UP THE ACCS
	TDNE	S,[ IOEND,,RHSTOP] ;ERROR FLAGS
	POPJ	P,
	PUSHJ	P,GETMOD		;SET UP MODE BYTES
	TRNE	S,IO.BYP	;IF SPECIAL - CHECK PRIVS
	PUSHJ	P,PRVJ##	;...
	AOSA	0(P)		;ALL SO FAR OKAY
	JRST	SETIPM		;ERROR - GIVE IPM RETURN
	TRNN	S,IO.BYP	;NEED TO SKIP RDYCHK
	PUSHJ	P,RDYCHK	;CHECK EP UP

;PSACT MAKE DEVICE PSEUDO ACTIVE

PSACT:	NULL
	MOVEI	T1,ZAPACT	;CLEAR ACTIVITY CODE
	EXCH	T1,(P)		;AND GET RETURN ADDRESS
	PUSH	P,T1		;AND STORE ADDRESS OF CALLER
	HRROI	T1,ACTTIM	;GET PSEUDO HUNG TIME
	MOVEM	T1,DVXPAC(F)	;SET THE COUNT
	AOS	XKBPAC##(W)	;FLAG THAT CONTROL HAS PSEUDO ACTIVE ONE
	AOS	XUBPAC(U)	;AND COUNT IN UNIT BLOCK
	AOS	PSMAKE		;ACCOUNT
	CONO	PI,PI.OFF	;NO INTERFERENCE
	JRST	MAKAC0		;AND BECOME ACTIVE

;FALL INTO MAKACT CODE
;MAKACT MAKE A JOB UNDISTURBED IO ACTIVE

MAKACT:	NULL			;SUBROUTINE TO MAKE JOB I/O ACTIVE
	CONO	PI,PI.OFF	;SILENCE
	SKIPN	DVXPAC(F)	;PSEUDO ACTIVE??
	JRST	MAKAC0		;NOPE NORMAL STUUF
	SETZM	DVXPAC(F)	;REMOVE THE FLAG
	SOSGE	XUBPAC(U)	;ACCOUNT IN UDB
	STOPCD	.,DEBUG,TC5,
	SOSGE	XKBPAC##(W)	;AND IN KDB
	STOPCD	.,DEBUG,TC6,
	SALL
MAKAC0:	MOVE	S,DEVIOS(F)	;THIS IS UNIQUE!!
	TLZ	S,IOBEG		;ONLY ONCE
	PUSHJ	P,SETACT##	;MAKE IT ACTIVE
	JRST	ONPOPJ##	;AND RETURN ACTIVE

SUBTTL	I/O UUO SUBROUTINES -- IFDMP, XTCBTL, ZAPACT, XTCIPM, XFRRST, SETIPM
;IFDMP CPOPJ BUFFERED MODE CPOPJ1 DUMP MODE SAVES ALL ACCS

IFDMP:	PUSH	P,T1		;GET SCRATCH
	LDB	T1,PIOMOD	;GET I/O MODE
	CAIL	T1,DR		;DUMP MODE
	PJRST	TPOPJ1##	;YAP SKIP
	PJRST	TPOPJ##		;NO NORMAL
;ROUTINE TO RETURN BLOCK-TOO-LARGE ERROR TO USER

XTCBTL:	NULL
	PUSHJ	P,MAKBTL		;BLOCK TOO LARGE TO SWALLOW
	PUSHJ	P,SENDW		;MAKE SURE IT GETS THERE
XBTLRG:	NULL
	MOVEI	S,IOBKTL	;LITE A BIT
XTCRTE:	NULL
	IORB	S,DEVIOS(F)
	PJRST	SETIOD##	;EXIT AFTER SETTING DONE

;ANY CALLER TO OFF PSACT WILL COME HERE BEFORE RETURNING TO 
;THE CALLER, THIS ALLOWS ACCOUNTING OF PAC JOBS

ZAPACT:	NULL
	CONO	PI,PI.OFF	;NO INTERRUPTS!
	SKIPN	DVXPAC(F)	;PSEUDO ACTIVE
	JRST	ZAPAC0		;NOPE
	SETZM	DVXPAC(F)	;NO LONGER
	SOSGE	XUBPAC(U)	;ACCOUNT
	STOPCD	.,DEBUG,TC3,
	SOSGE	XKBPAC##(W)	;IN UDB AND XKB
	STOPCD	.,DEBUG,TC4,
	SALL
ZAPAC0:	MOVE	S,DEVIOS(F)	;GET I/O STATUS
	PUSHJ	P,CLRACT##	;AND QUIETLY UPDATE S
	SETZM	DVXPST(F)	;NO HERITAGE
	JRST	ONPOPJ##	;ALL IS SAFE AGAIN

;ROUTINE TO SET IMPROPER MODE

XTCIPM:	NULL
	PUSHJ	P,MAKIDM		;IMPROPER DATA MODE
	PUSHJ	P,SENDW		;SEND IT AND WAIT
	MOVEI	S,IOIMPM	;LITE A BIT
	JRST	XTCRTE		;AND RETURN ERROR

;ROUTINE TO RESET INFO REGARDING THIS XFER ON AN I/O ERROR

XFRRST:	NULL
	SETZM	DVXPST(F)	;ZAP THE PROTOCOL STATUS
	POPJ	P,		;RETURN TO UUOCON

SETIPM:	NULL
	MOVEI	S,IOIMPM	;SET SPECIAL BIT
	IORB	S,DEVIOS(F)
	POPJ	P,		;ERROR RETURN
SUBTTL	I/O UUO SUBROUTINES -- DMPSET, SETIOW, NXTIOW
;SUBROUTINE TO COMPUTE THE NUMBER OF WORDS IN A DUMP MODE
; COMMAND LIST. AND TO BUILD IOWD LIST
;CALLED ON 2 LEVELS: UUO OR INT LEVEL
;ON INTERRUPT LEVEL DO NOT CALL COMCHK , AS T2, T3 AND M ARE SET UP
;FOR NXCMR CALL
;CALLED WITH:
;	MOVEI	M,ADDRESS-OF-LIST (UVA)
;	PUSHJ	P,LSTSIZ
;	RETURN HERE IF THERE IS AN ERROR
;	RETURN HERE ANSWER IN T1

DMPSET:	NULL
	PUSHJ	P,SAVE2##	;SAVE P1
	SETZM	P1		;NO WORDS YET
	MOVEI	P2,DVXIWD(F)	;START ADDRESS OF LIST
	MOVEM	P2,DVXCUR(F)	;REMEMBER THE START
	SETZM	DVXIWA(F)	;AND ASSUME ALL IN LIST
	CONSZ	PI,PI.IPA	;AT INTERRUPT LEVEL
	PUSHJ	P,NXCMR##	;(YES) CONTINUE
	CONSO	PI,PI.IPA	;AT INTERRUPT LEVEL
	PUSHJ	P,COMCHK##	;(NO) LOOK AT FIRST IOWD
DMPSE0:	JUMPE	T1,DMPSE2	;ALL IOWDS GOTTEN
	JUMPN	S,CPOPJ##	;A LOSER
;***NOTE ANY CHANGE TO THE NEXT INSTRUCTION SHOULD REFLECT ITSELF
;IN THE ADDI INSTRUCTION IN SETIOW
	SUBI	T1,-1(R)	;UNDO COMCHK ADDITION
				;AND MAKE ADDRESS THE START ADDRESS
	MOVEM	T1,(P2)		;STORE THE IOWD
	HLRE	T1,T1		;GET POSITIVE WC
	MOVN	T1,T1		; ..
	JUMPLE	T1,CPOPJ##	;A LOSING IOWD
	ADD	P1,T1		;ADD INTO TOTAL
	CAIE	P2,DVXILS(F)	;IS LIST FULL NOW?
	JRST	DMPSE1		;MAYBE WILL SEE LATER
	MOVEM	M,DVXIWA(F)	;REMEMBER M
	MOVEM	T2,DVXULM(F)	;SAVE UPPER LIMIT
	MOVEM	T3,DVXLLM(F)	;SAVE LOWER LIMIT
	JRST	DMPSE2		;ALL DONE NOW
DMPSE1:	PUSHJ	P,NXCMR##	;GET THE NEXT COMMAND
	AOJA	P2,DMPSE0	;DO NEXT WORD
DMPSE2:	CONSO	PI,PI.IPA	;AT INTERRUPT LEVEL DON'T UPDATE 
	HRRM	P1,DVXBSZ(F)	;REMEMBER THE TRANSFER SIZE
	CAIGE	P2,DVXILS(F)	;A TERMINATOR NEEDED
	SETZM	(P2)		;ZAP IT NIL
	MOVE	S,DEVIOS(F)	;RESTORE S IT WAS CLOBBERED
	PJRST	CPOPJ1##
	COMMENT	%

I/O IS DONE BY USING THE FOLLOWING MECHANISM:
STARTING AT LABEL DVXIWD IS AN IOWD WHIBH HAS TO BE USED
FOR THE FIRST TRANSFER. FOR OTHER TRANSFERS A LIST OF OTHER POINTERS
MAY FOLLOW TERMINATED EITHER BY A ZERO OR TERMINATING
AT LABEL DVXILS, IN WHICH CASE DVXIWA CONTAINS THE VALUE TO BE USED
ON NXCMR CALLS
%

;SETIOW CALLED BY BUFFERED I/O

SETIOW:	NULL
	TLNN	S,IO		;DOING INPUT?
	SKIPA	T1,DEVIAD(F)	;GET UVA OF BUFFER
	MOVE	T1,DEVOAD(F)	;GET UVA OF OUTPUT BUFFER
;****ANY UPDATE TO THE FOLLOWING INSTRUCTION MUST KEEP IN MIND
;THAT AT DMPSE0+2 DUMPMODE IOWDS ARE UPDATED
	ADDI	T1,2		;ONE MORE FOR ADDRESS
	HRRZ	T2,DVXBSZ(F)	;GET XFER SIZE
	MOVNS	T2		;IN A NEGATIVE WAY
	HRL	T1,T2		;MAKE THE IOWD
	MOVEM	T1,DVXIWD(F)	;STORE THE IOWD
	SETZM	DVXIWD+1(F)	;TERMINATE THE LIST
	SETZM	DVXIWA(F)	;INDICATE NO MORE THERE
	MOVEI	T2,DVXIWD(F)	;GET START ADDRESS
	MOVEM	T2,DVXCUR(F)	;AND REMEMBER THAT
	POPJ	P,

;NXTIOW GENERATE THE NEXT DA28 IOWD OR WARN THAT THE BUFFER IS EMPTY
;CPOPJ ALL I/O IS READY
;CPOPJ1 NEXT IOWD IS IN  T1

NXTIOW:	NULL
	MOVE	T1,DVXCUR(F)	;GET ADDRESS OF CURRENT IOWD REMAINDER
	CAIE	T1,DVXILS+1(F)	;IF AT THE END OF THE LIST
	JRST	NXTIO0		;NO GET IOWD
	SKIPN	M,DVXIWA(F)	;GET OLD M BACK
	POPJ	P,		;ALL SET NOW
	MOVE	T2,DVXULM(F)	;GET THE UPPER LIMIT
	MOVE	T3,DVXLLM(F)	;GET THE LOWER LIMIT
	PUSHJ	P,DMPSET		;DO DUMB STUFF
	PJRST	NXTERR		;IOLIST GOT CLOBBERED
	JRST	NXTIOW		;RESTART THE CALL 
NXTIO0:	NULL
	MOVE	T1,@DVXCUR(F)	;GET CURRENT IOWD
	JUMPGE	T1,CPOPJ##	;ALL HAS BEEN DONE
	PUSHJ	P,SBINIO		;LEAVE IF BINARY I/O
	PUSHJ	P,MPIOWD		;MAP THE IOWD
	MOVEM	T2,@DVXCUR(F)	;UPDATE IOWD
	JUMPL	T2,CPOPJ1##	;ALL IS OKAY
	AOS	DVXCUR(F)	;POINT TO NEXT IOWD
	PJRST	CPOPJ1##	;ALL IS OJAY NOW
SUBTTL	I/O UUO SUBROUTINES -- SBINIO
;SBINIO IS USED TO SPLIT BINARY AND NON BINARY MODES
;IN BINARY MODE ALL DATA IS XFERRED VIA A MONITOR BUFFER IN THE
;CONTROLLER DATA BLOCK.THIS MODE IS RATHER SLOW AS IT HAS TO 
;UNPACK AND PACK BYTES . MOREOVER ITRUNS ON INTERRUPT LEVEL

SBINIO:	NULL
	LDB	T2,DVYIOM	;SEE IF A BINARY STREAM
	CAIE	T2,11		;SLOW OR 
	POPJ	P,		;FASTER!
	PUSH	P,P1		;NO SENSE TO CALL SAVE1
	PUSHJ	P,GXFSIZ		;T2_# OF WORDS ; P1_-# OF WORDS
	TLNN	S,IO		;IF INPUT AND
	TLZN	S,FRSTIN	;FIRST SEGMENT IS NOT TRUE
	JRST	BINOLD		;THEN COMMON LOGIC
	MOVSI	S,FRSTIN	;ELSE
	ANDCAB	S,DEVIOS(F)	;CLEAR THE FLAG
	JRST	GBNIOW		;AND GET THE IOWD
BINOLD:	NULL
	HRLS	T2		;GET THE IOWD UPDATE
	ADDM	T2,@DVXCUR(F)	;UPDATE THE OLD VALUE
	HRLI	T1,(POINT 12,0)	;BUILD POINTER TO USER AREA
	HRRZ	T3,T2		;AND GET THE BYTE COUNT
	IMULI	T3,3		;3 BYTES PER WORD
	MOVE	T2,[POINT 18,XKBMBF##(W)]	;INTERMEDIATE AREA
	TLNE	S,IO		;IF OUTPUT THEN
	JRST	SBNOUT		;USE OTHER WAYS
SBNINP:	NULL
	ILDB	T4,T2		;GET A BYTE
	EXCTXU	<IDPB T4,T1>	;STORE IN USER AREA
	SOJG	T3,SBNINP	;ALL BYTES
	SKIPGE	T1,@DVXCUR(F)	;SEE IF DONE
	JRST	[ CALL  GXFSIZ	;GET  TRANSFER SIZE
		  JRST  GBNIOW ] ;GET NEXT IOWD
	POP	P,P1		;GET P1 BACK
	AOS	DVXCUR(F)	;ADVANCE IOWD POINTER
	POP	P,T1		;GET RID OF CALL RETURN
	PJRST	NXTIOW		;TRY AGAIN
SBNOUT:	NULL
	EXCTUX	<ILDB T4,T1 >	;GET THE USERS BYTE
	IDPB	T4,T2		;AND STORE IT IN MONITOR BUF.
	SOJG	T4,SBNOUT	;EMPTY ALL
GBNIOW:	NULL
	LSH	P1,CNTLSH	;SHIFT COUNT IN PLACE
	HRRI	P1,XKBMBF##(W)	;INTERMEDIATE STORE
	MOVE	T1,P1		;EREIS RESULT EXPECTED
	POP	P,P1		;GET THE COW BACK
	POP	P,T2		;ZAP RETURN
	POPJ	P,

GXFSIZ:	NULL
	HLRE	P1,T1		;GET THE AREA SIZE
	MOVN	T2,P1		; plus
	CAILE	T2,MAXBSZ	;TOO BIG
	MOVEI	T2,MAXBSZ	;(YES) THAN LESS
	MOVN	P1,T2		;UPDATE HIM TOO
	POPJ	P,
SUBTTL	I/O UUO SUBROUTINES -- MPIOWD
;MPIOWD MAP THE IOWD IN T1 INTO A DA28 POINTER
;ON A KI10 RETURN THE REMAINDER OF THE IOWD IN T2
;AND THE DA28 IOWD IN T1
;CALL:
;	.T1=IOWD WORD TO BE MAPPED
;	DEVICE IS IOACTIVE
;	USER'S UPMP IS SET UP ON A KI10

MPIOWD:	NULL
	PUSHJ	P,SAVE2##	;GET SAME ARM SPACE
	PUSH	P,T1		;SAVE THE IOWD
	HRRZS	T1		;GET RID OF EXTRA BITS

	EXCTUX	<MAP T2,(T1)>	;GET PHYSICAL ADDRESS
	TLZ	T2,(MP.NAD)	;CLEAR JUNK KL-PAGING BITS
	MOVE	T4,(P)		;GET ADDRESS BACK @GAIN
	ANDI	T4,PG.BDY	;GET OFFSEP IN PAGE

	MOVEI	T3,PAGSIZ	;GET THE PAGE SIZE
	SUBI	T3,(T4)		;GET THE CAPACITY IN THIS PAGE
	HLRE	T4,(P)		;NUMBER OF WORDS GOING OUT
	MOVNS	T4		;GET THE POSITIVE NUMBER
	TDZA	P2,P2		;# OF WORDS IN THIS TRANSFER
IOWSIZ:	MOVEI	T3,PAGSIZ	;THIS MUCH IN THE PAGE
	ADD	P2,T3		;NUMBER GOING NOW
	CAML	P2,T4		;ENOUGH SPACE
	PJRST	IOWDON		;ALL IS DONE

	MOVE	P1,T2		;GET PHYSICAL ADDRESS
	ADDI	P1,PAGSIZ	;NEXT PHY PAGE
	ADDI	T1,PAGSIZ	;NEXT VIRT PAGE
	EXCTUX	<MAP T3,(T1)>	;GTE NEW PHYSICAL ADDRESS
	TLZ	T3,777760	;CLEAR RANDOM KL-PAGING BITS
	CAMN	T3,P1		;NEXT PHY PAGE MATCH NEXT VRTUAL PAGE?

	JRST	IOWSIZ		;(YES) KEEP ADDING
IOWDON:	CAMLE	P2,T4		;MORE THAN REQUIRED?
	MOVE	P2,T4		;THEN GET THE RIGHT AMOUNT
	MOVN	T1,P2		;negative NUMBER GOING OUT
	LSH	T1,CNTLSH	;SHIFT IN RIGHT PLACE
	IOR	T1,T2		;COMPLETE IOWD
	SOS	T1		;MAKE AN IOWD
	POP	P,T2		;GET OLD IOWD
	ADD	T2,P2		;AND UPDATE
	SUBM	P2,T4		;NUMBER FOR NEXT TIME
	HRL	T2,T4		;FOR NEXT TIME
	POPJ	P,
SUBTTL	I/O UUO SUBROUTINES -- RDYCHK
;SUBROUTINE TO WAIT FOR A RESTART FROM THE SMALL CPU
;CALL WITH:
;	PUSHJ	P,RDYCHK
;	RETURN HERE WHEN READY
;
RDYCHK:	NULL			;CHECK IF SMALL COMPUTER HAS SENT RESTART
	SKIPGE	XUBRDY(U)	;IS HE READY
	POPJ	P,0		;YES--JUST RETURN
	PUSHJ	P,MAKREL		;GET RESTART
	PUSHJ	P,SENDW		;AND GET IT ACROSS
	PUSHJ	P,DOZE0		;WAIT A WHILE [7136]
	SKIPGE	XUBRDY(U)	;is he ready now [7136]
	POPJ	P,0		;yes -- just return [7136]
	PUSH	P,U		;SAVE U
	PUSHJ	P,HNGSTP##	;GENERATE OPR MESSAGE
	POP	P,U		;RESTORE U
	MOVEI	S,RHERR		;CLEAR OUT ANY ERRORS
	ANDCAB	S,DEVIOS(F)
	JRST	RDYCHK		;MAKE SURE IT IS READY NOW
SUBTTL CLOSE AND RELEAS UUOS

;CLOSE INPUT

XTCLSI:	NULL

;	MOVEI	S,IODEND	;ASSUME DUMP MODE
;	PUSHJ	P,IFDMP		;IS THAT TRUE?
;	MOVSI	S,IOEND		;NO SO CHANGE OUR MIND
;	IORB	S,DEVIOS(F)	;SET GOOD  BITS
	POPJ	P,

;CLOSE OUTPUT

XTCLSO:	NULL
	HRRZ	U,DVXUDB(F)	;GET THE UDB ADDRESS
	SKIPL	XUBRDY(U)	;IS UNIT REALLY READY
	JRST	XTCLS0		;NO DO NOT SEND ANYTHING
	PUSHJ	P,IFDMP		;ONLY IF NOT DUMP MODE
	PUSHJ	P,OUT##		;TERMINATE OUTPUT
	PUSHJ	P,WSYNC##		;WAIT FOR I/O TO COMPLETE
	PUSHJ	P,SETACS		;GETA LL ACCS
	TRNN	S,IO.BYP	;BYPASS?
	PUSHJ	P,XMTEOF	;SEND EOF
XTCLS0:	MOVSI	T1,IORRFI!IORWFI!IOXRFO
	ANDCAB	T1,DVXPST(F)	;CLEAR THE BITS
	PJRST	WTQEMP		;AND WAIT FOR SEND QUEUE TO EMPTY

;XTCREL RELEASE A DEVICE IS EQUIVALENT TO SENDING A RESTART TASK

XTCREL:	NULL
	PUSHJ	P,SETACS		;WE NEED MORE DATA
	SKIPGE	XUBRDY(U)	;TO CHECK FOR READY
	TRNE	S,IO.BYP	;BYPASSING
	JRST	XTCRE0		;DO NOT TOUCH THE INTERFACE
IFE FTCMP1,<	;SEND RESTART TASK IF 0
	PUSHJ	P,MAKRTK		;MAKE RESTART TASK
	PUSHJ	P,SENDW		;AND GET IT ACROSS
>;END IFE FTCMP1
XTCRE0:	SETZM	DVXPST(F)	;ALL SET
	PJRST	WTQEMP		;WAIT FOR AN EMPTY SEND QUEUE
SUBTTL	INTERRUPT SERVICE -- XTCINT, CLRERR, SETSCN

;HERE ON AN INTERRUPT WITH THE ACS SAVED AND W POINTING
; TO THE CONTROLLER DATA BLOCK.
;P IS THE PUSH DOWN POINTER ALL ELSE IS RANDOM

XTCINT::NULL
	XCT	XTSCNI##(W)	;GET CONI DAS,
	MOVEM	T1,XKBDAS##(W)	;STORE THEM
	XCT	XTCCNI##(W)	;GET CONI DAC,
	MOVEM	T1,XKBDAC##(W)	;ALWAYS THE LATEST ONE
	TRNE	T1,XC.BSY	;IS THE DA28-C BUSY?
	STOPCD	CPOPJ##,DEBUG,BSY,	;*++DA28 BUSY
	SALL
;	SKIPGE	XKBLOK##(W)	;DO WE BELIEVE THAT IT IS IN USE? [7136]
;	TRNN	T1,XC.SRQ	;NO AND A SELECT REQUEST? [7136]
	TRNE	T1,XC.SRQ	;NO SELECT REQUESTS
	PJRST	REMINT		;ELSE IT IS A REMOTE INTERRUPT
	SKIPE	F,XKBDDB##(W)	;IS THERE A DDB WAITING FOR DONE
	JRST	DDBINT		;YES--HANDLE THAT CASE
	SKIPE	U,XKBIUN##(W)	;RECEIVE CONTROL WORD?
	JRST	UNIINT		;YES--GO WORRY ABOUT THAT
	TRNE	T1,XC.SCN!XC.TST!XC.JAM!XC.ERI!XC.FT!XC.EOT
	STOPCD	.+1,DEBUG,SCB,	;*++SPURIOUS CONI BIT
	SALL
CLRERR:	NULL
	MOVEI	T1,XS.CLR+XTCCHN##
	XCT	XTSCNO##(W)	;WE LOST, CLEAR DEVICE

SETSCN:	NULL
	SETOM	XKBLOK##(W)	;FREE THE CONTROL VARIABLE
	MOVEI	T1,XC.SCN
	XCT	XTCCNO##(W)	;TURN ON SCANNER
	POPJ	P,
SUBTTL	INTERRUPT SERVICE -- REMINT, DOINP
;HERE WHEN SMALL COMPUTER ASKS FOR AN INTERRUPT
;COME HERE WITH RESULT OF  CONI DAC,T1

REMINT:	NULL
	PUSHJ	P,IDLE28		;SEE IF REALLY IDLE!!
	STOPCD	.+1,DEBUG,TC2,	;SHOULD NOT HAPPEN
	TRNE	T1,XC.ERR	;CHECK ERRORS
	STOPCD	.+1,DEBUG,RIE,	;*++REMOTE INTERUPT ERROR
	MOVEI	T1,0
	XCT	XTCCNO##(W)	;CLR COMMAND REG
	SKIPL	XKBLOK##(W)	;IS THE CONTROL FREE?
	STOPCD	.+1,STOP,KNF,	;*++CONTROL NOT FREE, SOFTWARE BUG
	SETZM	XKBLOK##(W)	;NOW CLAIM CONTROL
	LDB	T2,[POINT 4,XKBDAS##(W),21]	;GET UNIT ADR FROM STATUS WORD
	MOVSI	T1,(1B0)	;T1 USED FOR TESTING REQ STATUS
	MOVN	T3,T2		;T2 HAS NUMBER OF SHIFTS FOR T1
	LSH	T1,(T3)		;POSITION REQ STATUS TEST WORD
	TDNN	T1,XKBDAS##(W)	;REQ BIT CORRESPONDING TO CODE SHOULD BE ON
	PJRST	CLRERR		;WE WAS HERE, BUT YOU WASN'T
				;NOW YOU IS HERE, BUT WE ISN'T
	MOVE	T3,W		;START WITH FIRST UNIT
	PUSHJ	P,FNDUNI	;FIND UNIT
	STOPCD	CPOPJ##,DEBUG,NUI, ;*++NON EX UNIT INTERRUPTING(NO UDB)
	SALL
	SKIPE	F,XUBLOK(U)	;WAITING FOR THIS?
	JRST	DOINP		;YES: GO START INPUT
	HRRZM	U,XKBIUN##(W)	;UNIT DOING XFR
	MOVEI	T1,RECUCW	;WHERE TO GO ON DONE
	HRRZM	T1,XUBIPC(U)	; INTERRUPT
	MOVEI	T1,XUBRCW-1(U)	;ADDRESS OF PLACE TO GET WORD
	HRLI	T1,WC(1)	;1 WORD XFER
	PUSHJ	P,SETKCW	;LOAD UP THE CONTROL WORD
	MOVEI	T1,XUBRCW(U)	;ADDR OF CONTROL WORD
	PUSHJ	P,OUCHE##	;GET IT OUT OF CACHE
	MOVEI	T1,XC.CON!XC.BSY!XC.FST!DM.BIN!XC.MEM
	XCT	XTCCNO##(W)
	POPJ	P,
;ROUTINE TO START INPUT XFER FOR DDB FOUND IN F

DOINP:	NULL
	SETZM	XUBLOK(U)	;NOW FREE
	PUSHJ	P,SETACI		;GET INTERRUPT ACCS
	MOVE	T1,DVXPST(F)	;GET PROTOCOL STATUS
	TLNN	T1,IOXWFI	;AND GUARANTEE A WFI LEFT
	STOPCD	.,STOP,TC1,
	SALL
IFN	FTKL10,<	;FLUSH CACHE
	PUSHJ	P,CSDMP##	;TO CORE
>
	PJRST	DDBIO		;START @/O FOR THE DDB
PLM
;+
;.LM 0
;.hl 1 Interrupt Service
;^^
;.subtitle Interrupt Service
; The DA28C generates an interrupt under three circumstances:
;.list
;.le;if the small computer raises "select request" (i.e. wants to
;output something to the -10), known as a "remote" interrupt.
;.le;when a DMA data transfer (either to or from the -10)
;completes, known as a "done" interrupt.
;.le;if any of the hardware error bits set (e.g. timing error), known
;as an "error" interrupt.
;.end list
;The very beginning of the interrupt code is in COMDEV; there are
;the instructions which form part of the skip chain for
;the PI channel that the DA28C is on. If the skip chain test
;succeeds (i.e.#the DA28C really has interrupt-causing
;bits on) this code loads W with the address of the KDB and jumps
;to XTCINT.
;.lm 0
;.hl 2 XTCINT
;^^
;.subtitle XTCINT
; XTCINT is the common interrupt routine for all DA28C's
;on the system (it keeps them straight by the value of W).
;If the interrupt is a select request from the
;small computer, control passes to the routine REMINT.  If the
;XKBDDB word is non-zero it means that we expect a done interrupt
;for the transfer of actual data (as opposed to protocol words) and
;control passes to the routine DDBINT (which tries to continue the
;data transfer by calling DDBIO to process the next IOWD). Otherwise the interrupt
;should be a done interrupt for a control word transfer, either
;to or from the small computer.  In both cases
;XTCSER had placed the UDB address (and DDB address if applicable)
;into XKBIUN, as well as the PC of the routine to process the done interrupt
;into XUBIPC. (XTCSER did this when it started the DMA transfer request
;on the DA28C hardware.)
;If XKBIUN is non-zero, control passes to
;UNIINT, which in turn jumps to the address in XUBIPC.
;This will be one of four routines:
;.list
;.le;RECUCW if we were reading a control word from the
;small computer.  REMINT sets it up.
;RECUCW then dispatches (based on the function code of the control word)
;to the appropriate routine (usually called RECxxx where "xxx" is a mnemonic
;for the type of control word received) to extract the information from
;the control word and process it.
;.le;XDNDDB if we were sending a control word and we had a DDB.
;The routine PHS2F0 sets it up.
;.le;XDNXUB if we were sending a control word, the DA28C was available  and we had no DDB.
;The routine PHS2NF sets it up.
;.le;XDNXU0 if we were sending a control word that came from the UDB
;queue.  This is set up when SCNQUE on a previous interrupt finds
;that something has been queued and calls PHS2N0 to send it out.
;.end list
;All the interrupt routines exit by calling SCNQUE which looks for
;control word transfers which were queued because the DA28C was busy at
;the time SENDW was called. These can be related to a DDB (in which case
;DVXQUE is non-zero) or only to a unit (in which case XUBQUE points to a
;chain of 4-word free core blocks containing all the information about the
;request).  If there are no queued control words to send, SCNQUE calls CLRERR
;to reset the DA28C hardware which falls into SETSCN which
;starts the DA28C scanning all the small computers for select requests.
;.lm 0
;.hl 2 DDBIO
;^^
; Most of the work of actual data transfer (as opposed to control
;word transfer) is done by the routine DDBIO.
; The first call to DDBIO comes about in one of two ways:
;.list
;.le;If we are doing input, we store the DDB address in XUBLOK when
;we send the WFI.  A subsequent select request should be for
;the output of the data.  REMINT checks XUBLOK, and if it is non-zero
;it goes to DOINP which jumps to DDBIO to do the first IOWD.
;.le;If we are doing output, the routine RECWFI transfers control to
;DDBIO to start outputting the first IOWD.
;.end list
;The input and output UUO processing code stores user virtual
;address IOWDs in the DDB at DVXIWD to describe the data transfer to
;be accomplished.  DDBIO processes these IOWD's successively
;(it keeps a pointer to which it is working on in DVXCUR) by
;calling NXTIOW. If NXTIOW indicates
;that there are no IOWD's left, DDBIO goes to IOREDY which clears
;XKBDDB and finishes up the I/O processing. If NXTIOW finds another
;IOWD it returns it (converted to physical addresses by MPIOWD) and
;DDBIO stores F in XKBDDB (so no-one can interrupt the transfer)
;and starts this IOWD going.
;-
MLP
SUBTTL	INTERRUPT SERVICE -- UNIINT
;HERE WHEN WE GET AN INTERRUPT FOR A UNIT
;AC U POINTS TO UNIT DATA BLOCK, W POINTS TO THE CONTROLLER DB
;  NO OTHER ACS CONTAIN USEFUL INFORMATION (EXCEPT P).

UNIINT:	NULL
	SETZB	T1,XKBIUN##(W)	;WE NO LONGER USE IT
	XCT	XTCCNO##(W)	;DISCONNECT (RELEASES SMALL COMPUTER)
	MOVE	T1,XKBDAC##(W)	;GET CONI DAC BITS
	TRNE	T1,XC.DUN	;IS DONE SET?
	TRNE	T1,XC.ERR	;ANY ERROR BITS?
	PJRST	UNIERR		;(YES) A UNIT ERROR
	HLRZ	F,U		;GET THE DDB ADDRESS IF ANY
	SKIPE	F		;IF A DDB THEN
	MOVE	S,DEVIOS(F)	;THEN GET THE STATUS
	HRRZS	U		;AND CLEAN UP U

;TRANSFER TO EITHER:
;	RECUCW
;	XDNXUB
;	XDNDDB

	PJRST	@XUBIPC(U)	;GO TO EITHER RECUCW OR XDNXUB OR XDNDDB
SUBTTL	INTERRUPT SERVICE -- RECUCW
;HERE TO RECEIVE A CONTROL WORD FROM A UNIT

RECUCW:NULL
IFE LIVE,<
	SETZ	T1,
IFE FTKL10 <
	DATAI	APR,T1		;READ CONSOLE
	HRR	T1,.TRCF	;AND TRACE FLAGS
>;end IFE FTKL10
IFN FTKL10<HRRZ T1,.TRCF>	;TRACE FLAGS
	TDNN	T1,[40,,1]	;TRY EITHER
	PUSHJ	P,TRCRCW	;PRINT CW
>;end IFE LIVE
IFN FTKL10,<
	MOVEI	T1,XUBRCW(U)	;ADDRESS OF RECEIVED CONTROL WORD
	PUSHJ	P,OUCHE##	;MAKE SURE WE GET THE NEW VALUE
>;end IFN FTKL10
	LDB	T1,XUYMFC	;GET MAJOR FUNCTION CODE
	SETOM	F		;GET ALL ONES
	CAIE	T1,FN.DST	;IS IT DEAD-START
	CAIN	T1,FN.RST	;IS IT A RESTART
	SETCMM	F		;ZAP NO DDB
	LDB	T1,XUYTIF	;GET TASK ID
	SKIPE	F		;DO NOT LOOK FOR DDB
	PUSHJ	P,FNDTSK	;FIND THE DDB
	SETZM	F		;NO DDB FOR TASK
IFN .DBLEN,<
	PUSHJ	P,RCPUT		;LEAVE TRACES
>
	JUMPE	F,RCUCW2	;JUMP IF NO DDB
	PUSHJ	P,SETACI		;SET INTERRUPT ACCUS
	MOVE	T1,XUBRCW(U)	;GET DATA FROM UNIT STORAGE
	MOVEM	T1,DVXCTL(F)	;AND SET IT IN DDB
RCUCW2:	LDB	T1,XUYMFC	;GET MAJOR FUNCTION CODE
	HRRZ	T2,UNIFTB(T1)	;GET DISPATCH TABLE ENTRY
	SKIPE	F		;OKAY IF NO DDB
	HLRZ	T2,UNIFTB(T1)	;GET DDB ADDRESS
	PUSHJ	P,(T2)		;CALL THE SERVICE BUREAU
	PUSHJ	P,CHKPRC	;CHECK FOR COROUTINES AND SKIP!
	PJRST	SCNQUE		;SCAN THE WORK LOAD

;TABLE OF WHAT TO DO FOR VARIOUS FUNCTIONS

UNIFTB:	XMTFNE,,XMTFNE		;(00)ILLEGAL FUNCTION
	XMTFNE,,TTYFUN		;(01)TTY FUNCTION
	RECREJ,,RECREJ		;(02)REJECT
	RECACK,,XMTNOT		;(03)UNDEFINED
	RECCLS,,XMTNOT		;(04)CLOSE
	RECATB,,XMTNOT		;(05)MANIPULATE ATTRIBUTE BYTE
	XMTFNE,,RECRST		;(06)RESTART
	XMTFNE,,RECDST		;(07)DEAD-START
	XMTFNE,,XMTFNE		;(10)FUNCTION NOT IMPLEMENTED
	XMTFNE,,XMTFNE		;(11)UNDEFINED
	XMTFNE,,XMTFNE		;(12)UNDEFINED
	XMTFNE,,XMTFNE		;(13)UNDEFINED
	RECRFI,,XMTNOT		;(14)READY FOR INPUT
	RECRFO,,XMTNOT		;(15)READY FOR OUTPUT
	RECWFI,,XMTNOT		;(16)WAITING FOR INPUT
	RECWFO,,XMTNOT		;(17)WAITING FOR OUTPUT

PLM
;+
;.lm 0
;.hl 2 RECUCW
;^^
;.subtitle RECUCW
; This routine processes the received protocol words.  If the type
;code from the control word is "dead start"
;or "restart", it assumes it doesn't need a DDB; otherwise
;it calls FNDTSK to find a DDB corresponding to the task ID in
;the control word. It then looks up the word corresponding to
;that function in a table (UNIFTB) which has the routine
;which processes the control if you have a DDB in the LH, and
;the routine which processes the function when you do
;not have a DDB (which includes all restarts) in
;the RH.
; The following list contains which routines are executed for
;the receipt of which control words:
;.list
;.le;TTY function -- with a DDB only sends back a "reject function error"; without a DDB goes to TTYFUN to process it.
;TTYFUN then dispatches on the subtype code:
;.list
;.le;character -- TTYCHR checks if the line number specified is
;an XTCSER line and if it is, calls RECINT in SCNSER
;with the character.
;.le;character acknowledge -- TTYACK checks the line
;and then calls XMTINT in SCNSER.  This will ship out the next
;character (if any) via the ISR dispatch to XTCTYP.
;.le;get a TTY line -- TTYGET send a TTY NAK if the line
;is already in use or not an XTCSER line; otherwise it marks the
;line as in use and sends a TTY ack (TTY more).
;.le;TTY nak -- ignores by going to CPOPJ.
;.le;Free a TTY line -- sends a TTY Nak if line isn't ours, frees
;line if it is.
;.end list
;.le;reject -- both with and without DDB go to RECREJ; however if the
;DDB is not there, this exits to CPOPJ.  If the DDB is there it uses
;the sub-function reason code to index into a table of error
;bits (RJBTTB), ORs the bit into DEVIOS and clears IOACT.
;.le;ack -- if there is no DDB it goes to XMTNOT to send a "reject no task" to the
;small computer.  Otherwise goes to RECACK which simply sets IO.ACK in DEVIOS.
;.le;close -- if there is no DDB goes to XMTNOT to send a "reject no task"; if there is a DDB goes to RECCLS which checks the sub-function
;code to make sure its "close eof" (if not it sends a "reject function error").
;Then it clears IORRFO, IORWFO and IOXRFI (have received RFO,
;have received WFO and have sent RFI) bits in the protocol status
;word (DVXPST) and set IODEND (dump mode) or IOEND (buffered mode) for UUOCON.
;.le;attribute byte -- goes to XMTNOT if no DDB; goes to
;RECATB if there is a DDB which dispatches on the sub-function
;into table ATBDTB to perform the following functions:
;.list
;.le;transmit ATB -- goes to XMTXAB to send the "here is attribute byte"
;control word.
;.le;here is ATB -- goes to ATBSTO which extracts the 8-bit
;attribute from the control word and stores it in DVXDSC.
;.le;set ATB bits -- goes to ATBSET which gets the 8-bit
;mask of bits to set from the control word and ORs them into DVXDSC.
;.le;clear ATB bits -- goes to ATBCLR which gets the 8-bit
;mask of bits to clear from the control word and ANDCs it into DVXDSC.
;.end list
;.le;restart -- always goes to RECRST (DDB or no DDB) which dispatches
;on the sub-function code via table RSTTAB as follows:
;.list
;.le;restart -8, -11, -5 -- go to RSTUNI which sets the
;XUBRDY word to -1 (to signal that small computer is
;alive) and then calls DDBRST to terminate I/O for each DDB on
;the unit. After this, it also clears all XTCSER TTY lines on the unit.
;.le;restart REP -- goes to RSTREP which exits if there is no
;DDB, and then calls DDBRST to terminate I/O on all DDB's that
;have the same REP field.
;.le;restart -10 -- goes to XMTOPE to send a "reject operation error" control word back to small computer.
;.le;restart task -- goes to RSTTSK which tries to find the DDB
;corresponding to the task ID. If there is none it responds with
;a reject no task. If there is one, it calls DDBRST to terminate I/O
;on this DDB.
;.le;restart status -- goes to RSTSTS; if the code from the small
;computer indicates that it has gone down it calls RSTUNI
;to terminate I/O on all DDB's and free all XTCSER TTY lines.
;In either case, it gets its opinion of the small computer's state from
;XUBRDY and sends it back in a restart status control word.
;.end list
;.le;dead start -- always goes to RECDST; this looks for a DDB with
;a task ID of -1 and exits if not found. Then it points
;to the appropriate UDB (based on the DDB) and examines the XUBDST
;word. If it is non-zero (i.e. a previous dead start is
;pending) it exits.  Otherwise it stores the
;received control word in XUBDST so that a program may read it (with
;the appropriate XTTSK. function).
;.le;RFI -- goes to XMTNOT if no DDB and RECRFI if there is a DDB.
;This routine extracts the word count, makes it positive and stores
;it in DVXRFI; then it sets the IORRFI bit in DVXPST.
;.le;RFO -- goes to XMTNOT or RECRFO depending upon DDB; RECRFO
;merely sets IORRFO (have received RFO) in DVXPST.
;.le;WFO -- goes to XMTNOT if no DDB and RECWFO if there is a DDB.
;This routine checks if IOXWFO (have transmitted WFO) set, and if so sets IOIMPM error in DEVIOS and also sends a "reject operation error" to the small computer.
;Otherwise it sets IORWFO (have received WFO) in DVXPST, gets the word
;count, makes it positive in the RH of DVXWFO, gets the mode and stores
;it in the LH of DVXWFO.
;.le;WFI -- goes to XMTNOT if no DDB, RECWFI if DDB; this 
;routine checks for IOXWFI and if it is one sets IOIMPM error
;in DDB and sends a "reject operation error" to the small computer.
;Otherwise it sets IORWFI (have received WFI) in DVXPST and tests
;if we have sent WFO yet (IOXWFO); if not, it merely exits. If so,
;it flushes the cache (KL10 only) and goes to DDBIO to
;start transferring data.
;.end list
;-
MLP
SUBTTL	INTERRUPT SERVICE -- CHKPRC, CHKWAK
;CHKPRC CALLED TO VERIFY WHETHER A COROUTINE SHOULD RUN
;OR THE JOB HAS TO BE WAKED. THIS ROUTINE ALWAYS SKIPS
;SO SKIP RETURNS CAN BE PROPAGATED

CHKPRC:	NULL
	JUMPE	F,CPOPJ##	;NO BUSINESS HERE
	MOVEM	S,DEVIOS(F)	;STORE S NOW
IFN FTCMP3,<			;MANY EXTRA WAKES
	PJRST	XTWAKA		;ALWAYS WAKE
>;END IFN FTCMP3
IFE FTCMP3,<			;WAKE SELECTIVELY NOT UNNEEDED
	PUSHJ	P,CHKWAK		;SEE IF A WAKE IS REQUIRED
	SKIPN	DVXCOR(F)	;ANYONE WAITING?
	POPJ	P,		;NOPE JUST GO BACK
	MOVE	T1,DVXMSK(F)	;GET THE SYNC MASK
	PUSHJ	P,IFEBTS		;SEE WHAT IS SET
	SKIPA			;IN THAT CASE CONTINUE PROCES
	POPJ	P,		;NOTHING TO DO
	MOVE	S,DEVIOS(F)	;USE THE LATEST COPY
	PJRST	@DVXCOR(F)	;YES MAKE PROGREESS
>	;END OF FTCMP3=0


;ROUTINES TO CHECK EVENTS FOR A DDB
;IFEBTS VERIFY IF ANY OF THE EVENT FLAGS IN T1 IS SET
;T2 IS DESTROYED AND CONTAINS THE CURRENT SET OF EVENT FLAGS

IFEBTS:	NULL
	MOVE	T2,DEVIOS(F)	;GET DEVIOS
	TLZ	T2,^-IOEND	;BUT ONLY THIS IN LEFT HALF
	IOR	T2,DVXPST(F)	;AND ADD PROTOCOL STATUS
	TDNN	T2,T1		;IF NO BIT IS SET THEN
	AOS	(P)		;GIVE A SKIP RETURN
	POPJ	P,

IFE	FTCMP3,<	;IF STANDARD VERSION
;CHKWAK CHECK IF A WAKE SHOULD BE DONE FOR A DEVICE

CHKWAK:	NULL
	JUMPE	F,CPOPJ##	;ONLY FOR DDB'S
	SKIPN	T1,DVXWAK(F)	;ANY WAKE REQUESTS
	POPJ	P,		;NO JUST POPJ	P,
	PUSHJ	P,IFEBTS		;ALLREADY ANY EVENT THERE
	SKIPA			;(YES) TAKE A CLOSER LOOK
	POPJ	P,		;(NO) LATER MAYBE
	SETZM	DVXWAK(F)	;ONCE IS ENOUGH
	PJRST	XTWAKA		;ALWAYS WAKE
>	;END OF IFE FTCMP3
SUBTTL	INTERRUPT SERVICE -- DDBINT, IOREDY, BUFDON, DDBRST
;HERE ON AN INTERRUPT FOR A DDB

DDBINT:	NULL
	SETZM	XKBDDB##(W)	;FORGET THE PAST ASAP
	PUSHJ	P,SETACI		;SET UP INTERRUPT ACCUS
	SKIPE	XKBIUN##(W)	;MAKE SURE THIS IS A UNIQUE INT
	STOPCD	.+1,DEBUG,UIP,	;*++NOT A UNIQUE INT
	SALL
	MOVE	T1,XKBDAS##(W)	;GET STATUS BITS
	MOVEM	T1,DEVSTS(F)	;STORE FOR DEVSTS UUO
	MOVE	T1,XKBDAC##(W)	;GET THE CONI BITS
	TRNE	T1,XC.EOT!XC.DUN	;CHECK FOR DONE OR EOT
	TRNE	T1,XC.ERR!XC.SRQ ;UNEXPECTED CONDITION
	JRST	DDBERR		;YES--PONDER THE ERROR
	XCT	XTCDTI##(W)	;GET THE W.C.
IFN	FTCMP2,<	;IF CLEMENT THEN
	PUSHJ	P,IFDMP		;SKIP SHORT TRANSFER IN DUMP MODE
>				;SKIPS WHEEN DUMP
	JUMPL	T1,CKDINP	;JUMP IF TOO SHORT
DDBIO:	NULL
	PUSHJ	P,SVEUF##		;MAKE USER ADDRESSABLE
	MOVEM	S,DEVIOS(F)	;SAVE S FOR PROBLEMS
DDBIO0:	MOVEM	F,XKBDDB##(W)	;TO DDBINT
	PUSHJ	P,NXTIOW		;GET NEXT I/O WORD
	PJRST	IOREDY		;ALL IS DONE
	MOVE	S,DEVIOS(F)	;RELOAD S
	TLNN	S,IO		;DOING INPUT?
	PJRST	STINPT		;YES GO ON WITH THE BUSINESS
	PJRST	STOUTP		;NO CONTINUE THE OUTPUT

;IOREDY CALLED WHEN ANY I/O TRANSACTION IS READY

IOREDY:	NULL
IFN .DBLEN,<
	TLNN	S,IO		;OUTPUT?
	JRST	IOR000		;NO INPUT
	PUSHJ	P,IFDMP		;DUMP MODE
	PUSHJ	P,XDPUT		;NORMAL SKIPS!!
	PUSHJ	P,XDDPUT		;DUMP DOESNOT SKIP
	JRST	IOR001		;SKIP OTHER TRACE
IOR000:	PUSHJ	P,IFDMP		;IF NOT DUMP MODE
	PUSHJ	P,RDPUT	;THEN HERE AND SKIP RETURN
	PUSHJ	P,RDDPUT		;DUMP MODE INPUT
IOR001:
>
	SETZB	T1,XKBDDB##(W)	;DISCONNECT REMOTE
	XCT	XTCCNO##(W)	;BY THIS
	PUSHJ	P,FINDDB		;FINISH ALL FOR THE DDB
	PJRST	SCNQUE		;ALL SET

;BUFDON SPECIALS FOR BUFFRED MODES

BUFDON:	NULL
	TLNE	S,IO		;DOING INPUT?
	PJRST	ADVBFE##	;NO JUST ADVANCE
IFN	FTKL10,<	;FOR THE CACHE
	PUSHJ	P,CSDMP##	;FLUSH CORE
>
	PJRST	ADVBFF##	;(YES) GO BACK VIA ADVANCE BUFFERS
;DDBRST CLEAN UP A DDB

DDBRST:	NULL
	MOVEI	T1,ASSCON!ASSPRG	;SEE IF BUSY
	TDNN	T1,DEVMOD(F)	;CHECK THE BITS
	POPJ	P,		;NO
	PUSHJ	P,SETACS		;GET THE ACCS SET UP
	TRO	S,IOIMPM!IODTER	;SET ERROR FLAGS

;FALL INTO FINDDB
;CONTINUED ON NEXT PAGE
SUBTTL	INTERRUPT SERVICE -- FINDDB, FINUNI
;CONTINUED FROM PREVIOUS PAGE

;FINDDB FINISHES ALL FOR A DDB AND ENSURES THAT THE JOB
;WILL RUN AGAIN REGARDLESS OF ITS STATE. THIS CODE IS CALLED
;ON INTERRUPT LEVEL WITH A POSSIBLE ERROR FLAG SET IN S

FINDB0:	NULL
	MOVEM	S,DEVIOS(F)	;UPDATE S FOR CALLER

FINDDB:	NULL
	PUSHJ	P,SVEUF##		;MAKE USER ADDRESSABLE
IFE	FTCMP3,<
	PUSHJ	P,CHKWAK		;SEE IF HE IS INTERESTED IN ERRORS
>	;END OF IFE FTCMP3
	PUSHJ	P,XTWAKE		;WAKE ONLY IF SLEEPING
	MOVE	S,DEVIOS(F)	;GET STATUS
	SKIPN	DVXCOR(F)	;IS THERE A COROUTINE ACTIVE
	JRST	FINDD0		;(NO) PLAIN VANILLA
	PUSHJ	P,@DVXCOR(F)	;CALL THE GHOST	
	SETZM	DVXCOR(F)	;DAWN KILLS HIM
FINDD0:	SKIPN	DVXPAC(F)	;PSEODO ACTIVE?
	JRST	FINDD1		;NO FORGET IT
	SETZM	DVXPAC(F)	;YOU WERE IT
	SOS	XKBPAC##(W)	;ONE LESS TO BOTHER ABOUT
	SOS	XUBPAC(U)	;SO SPEED UP
FINDD1:	MOVE	T1,DVXPST(F)	;GET THE STATUS
	TRNE	S,IO.BYP	;IF IO ACTIVE AND
	TRNN	S,IOACT		;BYPASSING
	TLNE	T1,ANYACT	;OR ACTIVE IN NORMAL MODE
	SKIPA			;THEN DO BUFFER DONE LOGIC
	JRST	FINDD2		;ELSE SO NO BUFFER STUFF
	PUSHJ	P,IFDMP		;IF DUMP MODE
	PUSHJ	P,BUFDON		;THEN FINISH BOFFERS
	JFCL			;2 RETURNS MORE OR ALL DONE
	PUSHJ	P,SETIOD##	;IN CASE IN IOW STATE
FINDD2:	SETZM	DVXPST(F)	;ZAP THE PROTOCOL
	SETZM	DVXQUE(F)	;FORGET THE HISTORY
	PJRST	CLRACT##	;FINISH THE LAST TRACES
;FINUNI FINISH ALL FOR A UNIT

FINUNI:	NULL
	SETZM	XUBRDY(U)	;UNIT IS NOT READY
;ADD UNIT CLEAN UP HERE
	PUSH	P,F		;SAVE CURRENT F
CLNDDB:	NULL
	HLRZ	F,XUBDDB(U)	;GET FIRST DDB
	JUMPE	F,DDBDUN	;DONE WITH DDB'S
CLNDD0:	NULL
	PUSHJ	P,SETACS		;SET THE ACCS RIGHT
	PUSHJ	P,FINDDB		;FINISH THE DDB
	HLRZ	F,DVXUDB(F)	;GET NEXT DDB
	JUMPN	F,CLNDD0	;AND RELEASE THE TASK
DDBDUN:	NULL
	POP	P,F		;GET F BACK
	MOVE	S,DEVIOS(F)	;RESTORE S
	POPJ	P,
;!!ADD ERROR BIT TO S
SUBTTL	ERROR ROUTINES -- UNIERR, DWNUNI
;UNIERR CALLED WHEN A UNIT ERROR HAS BEEN DETECTED

UNIERR:	NULL
	MOVE	T1,XKBDAS##(W)	;GET LAST CONI DAS,
	MOVE	T2,XKBDAC##(W)	;AND LAST CONI DAC,
	TRNN	T2,XC.EOT	;CHECK EOT'S
	TRNE	T1,XS.NRD!XS.TER!XS.REM!XS.PAR!XS.NXM ;CHECK ERRS
	JRST	[PUSHJ P,DWNUNI		;REPORT LOSAGE
		 PJRST	SCNQUE]		;D28CLR WAS CALLED BY DWNUNI
	TRNE	T1,XS.CON		;IF NOT CONNECT - IGNORE
	PUSHJ	P,CHKCER		;REPORT CONNECT ERROR
	PUSHJ	P,D28CLR		;ZAP DA28 ERRORS
	PUSHJ	P,FINUNI		;FINISH THE UNIT
	PJRST	SCNQUE			;AND RESTART IT

;HERE ON A HARDWARE ERROR

DWNUNI:	NULL			;HERE TO PRINT ERROR MESSAGE
	PUSHJ	P,CHKTYP	;CAN WE SAFELY TYPE OUT?
	  JRST	DWNUN1		;NO--GO CLEAR ERRORS
	PUSH	P,U		;SAVE XUB ADDRESS
	PUSHJ	P,ERRSTS	;PRINT ERROR STATUS
	POP	P,U		;RESTORE POINTER TO XUB
DWNUN1:	MOVEI	T1,XS.CLR+XTCCHN##
	XCT	XTSCNO##(W)	;CLEAR ERRORS
	SETZM	XUBRDY(U)	;UNIT IS OFFLINE
	PJRST	FINUNI


;PRINT ERROR STATUS
ERRSTS:	MOVEI	T1,OPM.SO!OPM.CT ;SEND TO ORION OR CTY IF NO ORION
	PUSHJ	P,OPRMSG##	;WE WANT AN OPERATOR MESSAGE
	  POPJ	P,		;NO CORE OR NO ORION--PUNT
	PUSHJ	P,INLMES##	;ADD TEXT
	  ASCIZ	/DA28 Hardware Error/
	PUSHJ	P,OPRHDR##	;BIND OFF THE HEADER
	PUSHJ	P,INLMES##	;PRINT TEXT
	  ASCIZ	/	Status:  /
	MOVE	T1,XKBDAS##(W)	;GET THE STATUS
	PUSHJ	P,HWDPNT##	;PRINT AS HALF-WORDS
	PUSHJ	P,PCRLF##	;END LINE
	PUSHJ	P,INLMES##	;PRINT TEXT
	  ASCIZ	/	Command: /
	MOVE	T1,XKBDAC##(W)	;GET COMMAND STATUS
	PUSHJ	P,HWDPNT##	;PRINT AS HALF-WORDS
	PUSHJ	P,PCRLF##	;END LINE
	PUSHJ	P,INLMES##	;PRINT TEXT
	  ASCIZ	/	IOWD:    /
	XCT	XTCDTI##(W)
	PUSHJ	P,HWDPNT##	;PRINT AS HALF-WORDS
	PUSHJ	P,PCRLF##	;END LINE
	PUSHJ	P,INLMES##
	  ASCIZ	/	Data:    /
	XCT	XTSDTI##(W)
	PUSHJ	P,HWDPNT##	;PRINT AS HALF-WORDS
	PJRST	PCRLF##		;END LINE AND PRINT STATUS
SUBTTL	ERROR ROUTINES -- CHKCER, DDBERR, NXTERR
;SUBROUTINE TO MAKE SURE WE HAVE A CONNECT ERROR
;CALL WITH:
;	PUSHJ	P,CHKCER
;	NEVER RETURNS
;
CHKCER:	NULL
	PUSHJ	P,CHKTYP	;CAN WE SAFELY TYPE?
	  JRST	CHKCE1		;NO
	PUSH	P,U		;SAVE POINTER TO XUB
	PUSHJ	P,CERSTS	;PRINT CONNECT ERROR STATUS
	POP	P,U		;RESTORE XUB
CHKCE1:	PUSHJ	P,FRCOFL	;FORCE UNIT OFFLINE
	PJRST	SCNQUE		;AND LOOK FOR WORK

CERSTS:	MOVEI	T1,OPM.SO!OPM.CT ;SEND TO ORION OR CTY IF NO ORION
	PUSHJ	P,OPRMSG##	;WE WANT AN OPERATOR MESSAGE
	  POPJ	P,		;NO CORE OR NO ORION--PUNT
	PUSHJ	P,INLMES##	;ADD TEXT
	  ASCIZ	/DA28 Connect Error/
	PUSHJ	P,OPRHDR##	;BIND OFF THE HEADER
	PUSHJ	P,INLMES##	;PRINT TEXT
	  ASCIZ	/	Status: /
	MOVE	T1,XKBDAS##(W)	;GET UNIT NUMBER
	PUSHJ	P,HWDPNT##	;PRINT AS HALF-WORDS
	PUSHJ	P,PCRLF##	;END LINE
	PUSHJ	P,INLMES##	;PRINT TEXT
	  ASCIZ	/	Forced unit offline /
	PJRST	PCRLF##		;END LINE AND PRINT MESSAGE


;HERE ON AN ERROR

DDBERR:	NULL
				;T1 CONTAINS CONI DAC,
	TRNE	T1,XC.SCN!XC.TST!XC.JAM!XC.SRQ!XC.ERI
	STOPCD	.+1,DEBUG,DA28B, ;*++DA28 IS BROKEN
	SALL
	TRO	S,IODERR	;LIGHT A BIT FOR USER
	MOVE	T1,DEVSTS(F)	;REFETCH ERROR BITS
	TRNE	T1,XS.NRD!XS.TER!XS.REM!XS.PAR!XS.NXM
	JRST	[PUSHJ P,DWNUNI	;REPORT THE LOSSAGE
		 PJRST SCNQUE ] ;TRY YOUR LUCK
	PUSHJ	P,CHKCER	;MAKE SURE WE HAVE A CONNECT ERR
	TRO	S,IOIMPM	;MARK THE ERROR
	PUSHJ	P,FINDB0		;STOP ALL DDB STUFF
	PJRST	SCNQUE		;LOOK FOR NEXT REQUEST

;HERE ON A TRANSFER WITH THE WRONG NUMBER OF WORDS TRANSFERED

NXTERR:	NULL
	POP	P,T1		;GET RID OF CALL RETURN
	TRO	S,IOBKTL	;FLAG THAT ERROR IN DEVIOS
SETERR:	NULL
	PUSHJ	P,D28CLR	;RECOVER
	PUSHJ	P,FINDB0	;FINISH DDB
	PJRST	SCNQUE		;AND SCAN AGAIN
CKDINP:	NULL
	TRO	S,IOBKTL	;BLOCK TOO LARGE
	JRST	SETERR		;SET THE FLAG


;SUBROUTINE TO CHECK ON THE SAFETY OF TYPING OUT XTCSER MESSAGES.
;CALL IS:
;
;	PUSHJ	P,CHKTYP
;	  NOT-SAFE
;	SAFE
;
;SINCE SOME ROUTINES WANT TO TYPE OUT AT INTERUPT LEVEL WHICH
;CAN RESULT IN A SCNSER/NETSER DEADLOCK (IF SCNSER OR NETSER IS
;RUNNING WITH SCNSER INTERLOCK SET (FONDLING CHUNKS FOR EXAMPLE)
;AND XTCSER INTERRUPTS AND TRIES TO TYPE THEN THE SYSTEM HANGS)
;THEY SHOULD CALL CHKTYP FIRST. THE "NOT-SAFE" RETURN SAYS TO
;***NOT*** TYPE OUT (SYSTEM WILL HANG), THE "SAFE" RETURN SAYS
;IT IS PROBABLY OK.

CHKTYP:
IFN FTMP,<
	CONSZ	PI,PI.IPA	;AT INTERRUPT LEVEL?
	SKIPGE	SCNLOK##	;AND WITH SCNSER INTERLOCK?
> ;END IFN FTMP
	AOS	(P)		;NO, SAFE TO TYPE
	POPJ	P,		;RETURN AS APPROPRIATE
SUBTTL	DEBUGGING CODE -- CONSOLE CONTROL WORD TRACE
;ROUTINE TO PRINT CONTENTS OF XUBRCW(U)

IFE LIVE,<
TRCRCW:	PUSH	P,T1
	MOVEI	T1,"R"
	MOVE	T2,XUBRCW(U)	;GET INFO TO PRINT IN T2
	JRST	TRACWD

TRCXCW:	PUSH	P,T1
	MOVEI	T1,"X"
	MOVE	T2,XUBXCW(U)	;INFO TO PRINT
	SKIPE	F		;MAY BE IN DDB
	MOVE	T2,DVXXCW(F)
TRACWD:	PUSHJ	P,CHKTYP	;DARE WE TYPE?
	  JRST	TPOPJ#		;NO - DISCARD TYPEOUT
	PUSH	P,U		;SAVE UDB POINTER
	PUSH	P,T2		;SAVE INFO
	PUSH	P,T1		;SAVE DIRECTION
	MOVE	U,OPRLDB##	;FETCH LDB POINTER
	PUSHJ	P,INLMES##
	ASCIZ	/UNIT: /
	LDB	T3,[POINT 6,XKBNAM##(W),17]
	ADDI	T3,40		;CONTROLLER ID IN ASCII
	PUSHJ	P,COMTYO##	;PRINT IT
	MOVE	T1,-2(P)	;GET UDB POINTER
	MOVE	T1,XUBUNO(T1)	;UNIT # IN T1
	PUSHJ	P,PRTDI8##	;PRINT IT IN OCTAL
	PUSHJ	P,PRSPC##	;PRINT A SPACE
	POP	P,T3		;PUT CHAR IN T3
	PUSHJ	P,COMTYO##	;PRINT IT
	PUSHJ	P,INLMES##
	ASCIZ	/CW: /
	POP	P,T1		;RESTORE INFO
	PUSHJ	P,HWDPNT##	;PRINT AS HALF-WORDS
	PUSHJ	P,CRLF##	;EOL
	POP	P,U		;RESTORE U
	JRST	TPOPJ##		;restore T1 and return

	$LOW
.TRCF:	BLOCK	1		;tracing flags
				;RH 1 (bit 35) disables receive CW console trace
				;RH 4 (bit 33) disables xmit CW console trace

	$HIGH
; ...still in IFE LIVE
SUBTTL	DEBUGGING CODE -- EXECUTION TRACE
IFN FTETR <				;if execution trace enabled

;Subroutines to implement execution trace.  Always give skip
; returns, even if not tracing.  ETRCON turns on software trace
; bit, ETRCOF turns off software trace bit, and ETRACE does
; trace.

ETRCON:					;subroutine to turn on trace bit
	AOS	0(P)			;set skip return
	PUSH	P,T1			;get register to use
	MOVSI	T1,ETR.ON		;get trace bit
	IORM	T1,ETRFLG		;and turn it on
	JRST	TPOPJ##			;and exit

ETRCOF:					;turn off trace bit
	AOS	0(P)			;set skip return
	PUSH	P,T1			;get register to use
	MOVSI	T1,ETR.ON		;get trace bit
	ANDCAM	T1,ETRFLG		;turn it off
	JRST	TPOPJ##			;and exit

ETRACE:					;subroutine to trace PC's
	AOS	0(P)			;set skip return
	SKIPL	ETRFLG			;only trace if sign bit on
	POPJ	P,			;return if not
;here to store caller's PC and PI state
	PUSH	P,T1			;save T1
	PUSH	P,T2			;save T2 also
	MOVE	T1,-2(P)		;get PC of caller
	SUBI	T1,2			;back it up to address of PUSHJ
	CONI	PI,T2			;get PI status
	PUSHJ	P,TRCINS		;insert both into trace table
	POP	P,T2			;restore T2
	JRST	TPOPJ			;and exit

TRCINS:					;subroutine to insert entry into trace table
	SETZM	EPIFLG			;assume interrupts not off
	CONSO	PI,PI.ON		;check if PI system on
	SETOM	EPIFLG			;already off, don't turn on later
	CONO	PI,PI.OFF		;this may be redundant
	MOVEM	T1,@EPNT		;put PC into trace buffer
	HRLM	T2,@EPNT		;put PI status into trace buffer
	AOS	EPNT			;adjust pointer
	MOVEI	T2,EBUFE		;get address of end of buffer
	CAMLE	T2,EPNT			;check if there
	JRST	TRCINE			;no, exit
	MOVE	T1,ETRFLG		;get flag bits
	TLNE	T1,ETR.ST		;check if stop (no wraparound) bit on
	TLZ	T1,ETR.ON		;if yes, turn off trace
	MOVEM	T1,ETRFLG		;update flags
	MOVEI	T2,EBUF			;get address of beginning of trace buffer
	MOVEM	T2,EPNT			;and store as new pointer
TRCINE:					;here when done inserting trace entry
	SKIPL	EPIFLG			;skip if interrupts were off at entry
	JRST	ONPOPJ			;turn on interrupts and return
	POPJ	P,			;else just return

	$LOW
ETRFLG:	Z				;software flag bits for ex. trace
; LH bits
	ETR.ON==(1B0)			;enable tracing (must be sign)
	ETR.ST==(1B1)			;disallow wraparound

EPIFLG:	Z				;switch to indicate whether or not
					;to turn on PI system at exit
					;  0=turn on, -1=do nothing

EPNT:	EBUF				;pointer to next entry in trace table
EBUF:	BLOCK	ENMENT			;trace buffer
EBUFE=.					;one word past end
	$HIGH

>;end IFN FTETR
>;end IFE LIVE
SUBTTL	RECEIVE CONTROL WORDS -- ATTRIBUTE BYTE

;HERE WHEN WE RECEIVE MAJOR FUNCTION FN.ATB

RECATB:	NULL
	LDB	T1,DVYFSC	;GET THE SUBFUNCTION CODE
	CAILE	T1,SF.AAB	;IN RANGE?
	PJRST	XMTFNE		;NO--SEND A REJECT
	PJRST	@ATBDTB(T1)	;DISPATCH ON SUBFUNCTION

ATBDTB:	XMTFNE			;(0)ILLEGAL
	XMTXAB			;(1)SEND OUT THE ATB
	ATBSTO			;(2)HERE IS THE BYTE
	ATBSET			;(3)SET SETECTED BITS
	ATBCLR			;(4)CLEAR SELECTED BITS

;HERE TO SET A NEW ATB
ATBSTO:	NULL
	LDB	T1,DVYSFI	;GET THE NEW BYTE
	DPB	T1,DVYTAT	;STORE THE NEW BYTE
	POPJ	P,

;HERE TO SET SELECTED BITS
ATBSET:	NULL
	SKIPA	T3,[IOR T1,T2]	;INSTRUCTION FOR SETTING BITS

;HERE TO CLEAR SELECTED BITS
ATBCLR:	NULL
	MOVE	T3,[ANDCA T1,T2] ;INSTRUCTION FOR CLEARING BITS
	LDB	T1,DVYTAT	;GET THE OLD BYTE
	LDB	T2,DVYSFI	;GET THE MASK
	XCT	T3		;MODIFY T1
	DPB	T1,DVYTAT	;STORE UPDATED BYTE
	POPJ	P,
SUBTTL	RECEIVE CONTROL WORDS -- CLOSE

;HERE ON A CLOSE

RECCLS:	NULL
	LDB	T1,DVYFSC	;GET SUB-FUNCTION
	CAIE	T1,SF.EOF	;GRNTEE CORRECT CODE
	PJRST	XMTFNE		;SEND REJECT
	MOVSI	T1,IORRFO!IORWFO!IOXRFI
	ANDCAM	T1,DVXPST(F)	;AND ZAP THE CRAP
	LDB	T1,PIOMOD	;GET THE IOMOD
	CAIL	T1,DR		;IF NOT DUMP MODE
	TROA	S,IODEND	;THE SET THE LAST WORD FLAG
	TLO	S,IOEND		;SET END OF FILE BIT
	POPJ	P,
SUBTTL	RECEIVE CONTROL WORDS -- REJECT

;SUBROUTINE TO RECEIVE A REJECT COMMAND
;CALL WITH:
;	PUSHJ	P,RECREJ
;	RETURN HERE
;
;NOTE: REJECTS CAN NEVER SEND THE SMALL COMPUTER ANYTHING (ESPECIALY
; A REJECT) SINCE THAT COULD CAUSE AN ENDLESS LOOP. SO WHATEVER,
; WE DO WE MUST DO IT QUIETLY
;
RECREJ:	NULL
	JUMPE	F,CPOPJ##	;RETURN IF NO DDB
	LDB	T1,DVYFSC	;GET THE FUNCTION SUB CODE
	CAIG	T1,RJVMAX	;TOO BIG?
	IOR	S,RJBTTB(T1)	;NO GET ERROR BIT
	TRZ	S,IOACT		;NO HUNG DEVICES
	POPJ	P,

RJBTTB:	0			;(0)ERROR
	IOIMPM			;(1)EXTERNAL TASK DOES NOT EXIST
	IODERR			;(2)HUNG
	IOIMPM			;(3)FUNCTION ERROR
	IOIMPM			;(4)IMPROPER MODE
	IODTER			;(5)IMPROPER DATA MODE
	IOBKTL			;(6)BLOCK TOO LARGE
	IODTER			;(7)DATA ERROR
	IOIMPM			;(10)OPERATION ERROR
RJVMAX==.-RJBTTB-1
SUBTTL	RECEIVE CONTROL WORDS -- READY FOR INPUT

;SUBROUTINE TO PROCESS A READY FOR INPUT

RECRFI:	NULL
	LDB	T1,DVYWDC	;GET THE WORD COUNT
	HRROI	T1,770000(T1)	;NEGATIVE
	MOVMM	T1,DVXRFI(F)	;STORE POSITIVE FOR XOSYNC
	MOVSI	T1,IORRFI	;GOT A RFI
	JRST	SETBIT		;AND SETTHE BIT

;FALL IN RECRFO EXIT

;SUBROUTINE TO PROCESS A READY FOR OUTPUT
RECRFO:	NULL
	MOVSI	T1,IORRFO	;I GOT A RFO

SETBIT:	NULL
	IORM	T1,DVXPST(F)	;SET IT
	POPJ	P,

;SUBROUTINE TO PROCESS A ACK FROM AN EXTERNAL TASK
;JUST FIND TASK AND WAKE HIM UP

RECACK:	NULL
	TRO	S,IO.ACK	;SET BIT FOR HIM
	POPJ	P,
SUBTTL	RECEIVE CONTROL WORDS -- WAITING FOR INPUT

;SUBROUTINE TO PROCESS A WAITING FOR INPUT
;CALL WITH:
;	PUSHJ	P,RECWFI
;	RETURN HERE
;
RECWFI:	NULL
	MOVE	T1,DVXPST(F)	;GET THE STATUS
	TLNE	T1,IOXWFI	;DEADLY EMBRACE?
	JRST	[TRO S,IOIMPM	;YES--LIGHT AN ERROR BIT
		 PJRST XMTOPE]	;SEND A REJECT
	TLO	T1,IORWFI
	MOVEM	T1,DVXPST(F)	;STORE THE UPDATED VALUE
	TLNN	T1,IOXWFO	;SEND WFO YET?
	POPJ	P,		;NO- GO BACK
IFN	FTKL10,<	;FLUSH THE CACHE
	PUSHJ	P,CSDMP##	;NOW
>
	PJRST	DDBIO		;START UP I/O
SUBTTL	RECEIVE CONTROL WORDS -- WAITING FOR OUTPUT

;SUBROUTINE TO PROCESS A WFO FROM AN EXTERNAL TASK
;CALL WITH:
;	PUSHJ	P,RECWFO
;	RETURN HERE
;
RECWFO:	NULL
	MOVE	T1,DVXPST(F)	;GET THE PROTOCOL STATUS
	TLNE	T1,IOXWFO	;ARE WE ALSO WAITING?
	JRST	[TRO S,IOIMPM	;YES-- SET IMPROPER MODE
		 PJRST XMTOPE]	;SEND A REJECT
	TLO	T1,IORWFO
	MOVEM	T1,DVXPST(F)	;STORE IT
	LDB	T1,DVYWDC	;GET THE WORD COUNT
	HRROI	T1,770000(T1)	;SIGN EXTEND
	MOVM	T1,T1		;MAKE POSITIVE
	HRRM	T1,DVXWFO(F)	;STORE IN DDB
	LDB	T1,DVYMOD	;GET MODE
	HRLM	T1,DVXWFO(F)	;SAVE FOR LATER
	POPJ	P,
SUBTTL	RECEIVE CONTROL WORDS -- RESTART

;SUBROUTINE TO PROCESS A RESTART MESSAGE
;CALL WITH:
;	PUSHJ	P,RECRST
;	RETURN HERE
;
RECRST:	NULL
	LDB	T1,XUYFSC	;GET SUB-FUNCTION
	CAILE	T1,SF.LNG	;IN RANGE
	PJRST	XMTFNE		;NO - ERROR
	PJRST	@RSTTAB(T1)	;DO FUNCTION

RSTTAB:	XMTFNE			;(00) ILLEGAL
	RSTUNI			;(01) UNIT RESTART PDP-11
	RSTUNI			;(02) UNIT RESTART PDP-15
	RSTUNI			;(03) UNIT RESTART PDP-8
	RSTREP			;(04) RESTART REP
	XMTOPE			;(05) RESTART PDP-10 IMPOSSIBLE
	RSTTSK			;(06) RESTART A TASK
	RSTSTS			;(07) RECEIVE UP STATUS
SF.LNG==.-RSTTAB		;LENGTH OF TABLE

RSTUNI:	SETOM	XUBRDY(U)	;FLAG AS READY
	HLRZ	F,XUBDDB(U)	;GET POINTER TO FIRST DDB
RSTUN1:	NULL
	JUMPE	F,RSTUN2	;DONE IF NO DDB
	PUSHJ	P,DDBRST	;RESTART EACH DDB
	HLRZ	F,DVXUDB(F)	;STEP TO NEXT DDB
	JRST	RSTUN1		;LOOP BACK

RSTUN2:	MOVE	T1,[MTTD28##,,TTLTAB##]
	HRL	U,W		;FOLD POINTERS
	CAMN	U,0(T1)		;ON THIS UNIT?
	SETZM	0(T1)		;YES - FLUSH
	AOBJN	T1,.-2		;LOOP UNTIL DONE
	POPJ	P,

RSTTSK:	NULL
	LDB	T1,XUYTIF	;GET TASK ID
	PUSHJ	P,FNDTSK	;SEE IF IT EXISTS
	  PJRST	XMTNOT		;NOPE!
	PUSHJ	P,DDBRST	;YES - RESTART
	POPJ	P,

RSTSTS:	NULL
	LDB	T1,[POINT 16,XUBRCW(U),31]	;GET STATUS
	PUSH	P,XUBRDY(U)	;SAVE THE CURRENT STATUS
	SKIPE	XUBRDY(U)	;IF DOWN OR
	JUMPN	T1,RSTST0	;UP ACCORDING TO 10 AND DOWN ACCORDING TO EP
	PUSHJ	P,RSTUNI	;THEN JUST DO RESTART
RSTST0:	POP	P,T1		;GET OLD STATUS
	MOVSI	T4,316000	;RESTART STATUS
	DPB	T1,[POINT 16,T4,31]	;TRANSMIT OUR OLD OPINION
	PJRST	SENDW		;GET IT ACROSS
RSTREP:	NULL
	PUSHJ	P,SAVE1##	;SAVE P1
	LDB	P1,XUYUNI	;GET UNIT ID
	HLRZ	F,XUBDDB(U)	;GET DDB LIST
RSTRP1:	JUMPE	F,CPOPJ##	;DONE WHEN NO MORE
	LDB	T1,DVYUNI
	CAMN	T1,P1		;CHECK SAME UNITS
	PUSHJ	P,DDBRST	;YES - RESTART
	HLRZ	F,DVXUDB(F)	;GET NEXT
	JRST	RSTRP1
SUBTTL	RECEIVE CONTROL WORDS -- DEAD-START

;SUBROUTINE TO PROCESS A DEAD-START MESSAGE
;FIND TASK OWNING TASK WITH 7777 ID
;THE WAKE IT UP AND STORE INFO FROM INTERUPTING UNIT

RECDST:	NULL
	MOVEI	T1,7777		;GET DEFAULT TASK ID
	PUSHJ	P,FNDTSK	;LOCATE OWNING JOB
	POPJ	P,		;IGNORE NO TASK
	PUSHJ	P,SETACS	;SET UP S , J AND R
	SKIPN	T1,XUBDST(U)	;IGNORE IF ONE PENDING
	MOVE	T1,XUBRCW(U)	;FETCH NEW CTL WORD
	MOVEM	T1,XUBDST(U)	;AND SAVE AS DEAD-START INFO
	PJRST	XTWAKA		;WAKE JOB
SUBTTL	RECEIVE CONTROL WORDS -- TTY FUNCTION

;SUBROUTINE TO PROCESS A TTY FUNCTION
;CALL WITH:
;	PUSHJ	P,TTYFUN
;	RETURN HERE
;
TTYFUN:	NULL
	LDB	T1,XUYFSC	;GET FUNCTION SUB CODE
	CAILE	T1,SF.TTR	;FUNCTION IN RANGE?
	PJRST	TTYNAK		;NO--SEND A REJECT
	PUSH	P,U		;PRESERVE U
	PUSH	P,W		;AND W
	PUSHJ	P,@TTFTAB(T1)
	POP	P,W
	JRST	UPOPJ##

TTFTAB:	TTYNAK			;(0) ERROR
	TTYCHR			;(1) CHAR IN SFI
	TTYMOR			;(2) XMIT DONE
	TTYGET			;(3) GET A TTY
	CPOPJ##			;(4) JUST SWALLOW
	TTYRET			;(5) RETURN A TTY
;SUBROUTINE TO GET A PROCESS A TTY CHAR FROM SMALL COMPUTER
;CALL WITH:
;	PUSHJ	P,TTYCHR
;	RETURN HERE
;
TTYCHR:	NULL
	PUSHJ	P,CHKLIN	;CHECK LINE GOODNESS
	  PJRST	TTYNAK		;SEND REJECT
	LDB	T3,XUYSFI	;GET THE CHAR
	MOVE	U,T1		;COPY LINE # IN U
	PUSHJ	P,RECINT##	;CALL SCNSER
	SETZ	F,		;NO TRACE VALUES
	POPJ	P,

;SUBROUTINE TO PROCESS A TTY MORE
;CALL WITH:
;	PUSHJ	P,TTYMOR
;	RETURN HERE
;
TTYMOR:	NULL
	PUSHJ	P,CHKLIN	;CHECK LINE GOODNESS
	  PJRST	TTYNAK		;SEND REJECT
	MOVE	U,T1		;COPY LINE # INTO U
	PUSHJ	P,XMTINT##
	SETZ	F,		;ZAP SCNSER DDB
	POPJ	P,

;SUBROUTINE TO CHECK IF LINE # BELONGS TO THIS UNIT
;CALL:
;	PUSHJ	P,CHKLIN
;	RETURN HERE IF NOT CORRECT #
;	RETURN HERE WITH LINE # IN T1

CHKLIN:	NULL
	LDB	T1,XUYTIF	;GET TASK ID FIELD
	PUSHJ	P,XTCTTY	;CHECK IF ON DA-28
	  POPJ	P,		;INACTIVE
	  SKIPA			;TRY THIS
	POPJ	P,		;NOT DA-28 LINE
	HRL	U,W		;FOLD POINTERS
	CAMN	U,T2		;T2 CONTAINS TTLTAB ENTRY
	AOS	(P)		;SKIP RETURN
	POPJ	P,		;RETURN
;ROUTINE TO CHECK IF LINE # IN T1 IS ON DA28
;RETURN IN T1 - ORIGINAL LINE #
;	   T2 - TTLTAB ENTRY IF VALID LINE #
;	   T3 - ADJUSTED TTLTAB INDEX
;CALL:
;	PUSHJ	P,XTCTTY
;	RETURN HERE IF INACTIVE XTC LINE
;	RETURN HERE IF ACTIVE XTC LINE
;RETURN HERE IF NOT XTC LINE

XTCTTY::NULL
	MOVE	T3,T1		;COPY LINE #
	SUBI	T3,D28OFS##	;REMOVE OFFSET
	JUMPL	T3,CPOPJ2##	;NOT XTC LINE IF NEG
	CAIL	T3,TTD28N##	;CHECK UPPER BOUND
	JRST	CPOPJ2##
	SKIPE	T2,TTLTAB##(T3)	;CHECK IF ACTIVE LINE #
	AOS	0(P)		;SKIP IF ACTIVE
	POPJ	P,		;RETURN

;SET UP T4 WITH TTY # AND SEND NAK

TTYNAK:	NULL
	LDB	T4,XUYTIF	;SET UP REC'D LINE #
	PUSHJ	P,MAKTTN		;GET XCW
	HRRZS	U		;GET RID OF LEFT HALF
	PJRST	SENDW		;THERE IT GOES


;SUBROUTINE TO PROCESS A TTY RETURN
;CALL WITH:
;	PUSHJ	P,TTYRET
;	RETURN HERE
TTYRET:	NULL
	PUSHJ	P,CHKLIN	;IS IT OURS?
	  PJRST	TTYNAK		;NO--SEND A REJECT
	SETZM	TTLTAB##(T3)	;RETURN THE LINE NUMBER
	POPJ	P,
SUBTTL	RECEIVE CONTROL WORDS -- TTY SUBROUTINES

;XTCOFL IS XTCSER OFF LINE

XTCOFL:	NULL
	PUSHJ	P,XTCTTY		;CHECK THE LINE
	POPJ	P,		;AN INACTIVE XTC LINE
	JRST	CPOPJ1##	;THIS IS A GOOG XTC LINE
	POPJ	P,		;NOT MY BUSINESS

;SUBROUTINE TO PROCESS A REQUEST FOR TTY LINE NUMBER
;CALL WITH:
;	PUSHJ	P,TTYGET
;	RETURN HERE
;
TTYGET:	NULL
	LDB	T1,XUYTIF	;GET LINE # FIELD
	JUMPN	T1,TTYGLN	;HANDLE SPECIAL IF NON-ZERO
	MOVE	T1,[MTTD28##,,TTLTAB##]
	SKIPE	(T1)		;SKIP IF FREE
	AOBJN	T1,.-1		;LOOP OVER ALL LINES
	JUMPG	T1,TTYNAK	;JUMP IF NO FREE LINES
	HRLM	W,(T1)		;STORE POINTERS INTO
	HRRM	U,(T1)		; TABLE ENTRY
	MOVNI	T4,TTLTAB##	;SET UP LINE
	ADDI	T4,D28OFS##(T1)	; NUMBER
TTYG1:	PUSH	P,T4		;SAVE LINE NUMBER
	PUSH	P,U		;AND UNIT NUMBER
	PUSH	P,W		;AND KDB ADDRESS
	LDB	T1,XUYSFI	;GET LDB INFO
	HRRZ	T2,LINTAB##(T4)	;GET LDB POINTER
	DPB	T1,[POINT 6,LDBDCH##(T2),17]
	LSH	T1,-6		;SHIFT OVER
	DPB	T1,[POINT 2,LDBBYT##(T2),2]
	MOVEI	T3,LNTDHC##	;TURN OFF IRMA CATCHER
	MOVE	U,T4		;LNCREC LIKES LINE #'S
	PUSHJ	P,LNCREC##	;...
				;U NOW POINTS TO LDB
	LDB	T1,XUYMOD	;GET ADDITIONAL INFO BITS
	TRNE	T1,10		;SHOULD WE RESET?
	JRST	TTYG2		;NO
	PUSHJ	P,TSETBI##	;RESET LINE BUFFERS
	PUSHJ	P,TSETBO##	;...
	SETZM	LDBXNP##(U)	;CLEAR XON POINTER
	SETZM	LDBFLP##(U)	;CLEAR FILL POINTER
	MOVSI	T1,(1B0)	;LDLOIP
	ANDCAM	T1,LDBDCH##(U)
TTYG2:	SETZ	F,		;GET RID OF F IF SET
	POP	P,W		;GET KDB ADDRESS BACK
	POP	P,U		;AND UDB ADDRESS
	POP	P,T3		;GET LINE NUMBER
	PUSHJ	P,MAKTTM		;TELL THE NAME
	PJRST	SENDW		;AND LET IT BE KNOWN
TTYGLN:	PUSHJ	P,XTCTTY	;CHECK IF OK TO HAVE THIS ONE
	  JRST	TTYGL1		;YES - PROCEED
	JRST	TTYNAK		;ALREADY ACTIVE
	JRST	TTYNAK		;NOT AN XTC LINE

TTYGL1:	HRLM	W,TTLTAB##(T3)	;STORE KDB
	HRRM	U,TTLTAB##(T3)	;  AND UDB INFO
	MOVE	T4,T1		;COPY LINE # INTO T4
	JRST	TTYG1		;AND EXIT

;LDB INFORMATION IN SFI FIELD DEFINED AS FOLLOWS:
;
;BIT  8 & 9 - FILLER CLASS CODE
;     10 - THIS TTY IS A SLAVE
;     11 - THIS TTY HAS LOWER CASE
;     12 - THIS TTY HAS HARDWARE TABS
;     13 - THIS TTY HAS LOCAL COPY
;     14 - THIS TTY HAS HARDWARE FF & VT
;     15 - NO AUTOMATIC CRLF
;     16 - DON'T RESET I/O BUFFERS
;     17 - NO ECHO ANYTHING!
SUBTTL	RECEIVE CONTROL WORDS -- DA28 SCHEDULING SUBROUTINES
;SUBROUTINE TO FIND THE NEXT THING TO DO
;CALL WITH:
;	PUSHJ	P,SCNQUE
;	RETURN HERE

SCNQUE:	NULL
	PUSHJ	P,IDLE28		;IS 28 IDLING?
	POPJ	P,		;(NO) WAIT FOR IT TO BECOME FREE
	SKIPE	T1,XKBREQ##(W)	;A GRAB CONTROL REQUEST ACTIVE?
	PJRST	ZAPCTL		;(YES) HIDE CONTROL AND WAKE USER
	MOVE	T3,W		;START WITH FIRST UNIT
	JRST	SCNQL3		;GET FIRST UNIT

SCNQL1:	SKIPE	T1,XUBQUE(U)	;UNIT IN QUEUE?
	PJRST	PHS2N0		;TRANSMIT FOR NON F PROCES
	HLRZ	F,XUBDDB(U)	;POINT TO FIRST UNIT
	JUMPE	F,SCNQL3	;JUMP IF NO TASKS ON THIS UNIT
SCNQL2:	SKIPE	T1,DVXQUE(F)	;IS THIS DDB WAITING?
	JRST	[PUSHJ P,SETACS	;CONTEXT SWITCH
		 JRST (T1)]	;GIVE IT CTL
	HLRZ	F,DVXUDB(F)	;STEP TO NEXT DDB
	JUMPN	F,SCNQL2	;LOOP FOR NEXT DDB
SCNQL3:	HRRZ	U,XKBUDB##(T3)	;POINT TO NEXT UNIT
	JUMPE	U,CLRERR	;RETURN IF NO MORE UDB'S
	SKIPE	XUBLOK(U)	;OK IF UNIT FREE
	AOJA	T3,SCNQL3	;  IF LOCKED SKIP IT
	AOJA	T3,SCNQL1	;ELSE TRY NEXT


;IDLE28 CALLED TO FIND OUT WHETHER THE DA28C IS FREE TO USE OR NOT
;NO ACCS ARE CHANGED , W SHOULD POINT TO 
;CONTROLLER BLOCK

IDLE28:	NULL
	SKIPN	XKBDDB##(W)	;I/O BUSY
	SKIPE	XKBIUN##(W)	;OR PROTOCOL BUSY
	POPJ	P,		;THEN DA28C IS NOT IDLE
	SKIPE	XKBGRB##(W)	;DID SOME ONE GRAB THE CONTROL
	POPJ	P,		;THEN IT CANNOT BE USED
	PJRST	CPOPJ1##	;IT IS FREE
SUBTTL	TTY FUNCTION SCNSER INTERFACE

;ISR DISPATCH TABLE FOR XTCSER TTY'S

XTTDSP::JRST	XTCTYP		;(0) SEND CHAR IN T3
	POPJ	P,		;(1) NO MODEM CONTROL
	POPJ	P,		;(2) NO ONCE A SEC CHECK
	POPJ	P,		;(3) NO ISR INIT (YET)
	POPJ	P,		;(4) CHANGE HDW PARAMS
	POPJ	P,		;(5) SEND LINE CONTROL MSG
	POPJ	P,		;(6) SET ELEMENT #
	POPJ	P,		;(7) REMOTE STUFF
	JRST	XTCOFL		;(10) OFFLINE

;SUBROUTINE TO SEND A TTY CHARACTER

XTCTYP:	NULL
	LDB	T1,LDPLNO##	;GET LINE # IN T1
	PUSH	P,T3		;SAVE THE CHAR
	PUSHJ	P,XTCTTY	;SEE IF A GOOD LINE
	  JRST	T3POPJ##	;INACTIVE LINE
	  SKIPA	T3,T1		;COPY LINE NUMBER INTO T3
	JRST	T3POPJ##	;NOT AN XTC TTY
	POP	P,T4		;RESTORE CHAR
	PUSH	P,U		;SAVE SCANNER WORLD
	PUSH	P,W
	PUSH	P,F
	HRRZ	U,T2		;SET UP XTCSER WORLD
	HLRZ	W,T2		;XTCTTY SET UP T2
	MOVE	T2,T4		;GET CHAR IN THECRIGHT ACC
	MOVEI	F,0		;NO DDB
	PUSHJ	P,XMTTTC	;PUT OUT CHAR
	  JFCL			;WE TRIED
	POP	P,F		;RESTORE ETC...
	POP	P,W
	JRST	UPOPJ##		;AND RETURN
SUBTTL	TRANSMITTERS OF CONTROL WORDS

	DEFINE	XMT(FUN),<
	XLIST
XMT'FUN:	PUSHJ	P,MAK'FUN		;;GET PROTOCOL WORD IN T4
	PJRST	SENDW			;;WAIT ONLY ON UUO LEVEL!!
	LIST
>	;END OF XMT

	XMT(EOF)			;TRANSMIT EOF
	XMT(NOT)			;TRANSMIT NOT A JOB
	XMT(XAB)			;ATTRIBUTE BYTE
	XMT(TTC)			;GET CHARACTER OUT
	XMT(OPE)			;BAD OPERATION

;SPECIAL TRANSMITTERS

XMTFNE:	NULL
	SETZM	F			;NO DDB NO MATTER WHO CALLS
	PUSHJ	P,MAKFNE			;MAKE THE CODE
	PJRST	SENDW			;SEND IT
SUBTTL	MAKE CONTROL WORDS -- MAKxxx

IF2,<	.XCREF	..AA,..BB,..CC>

	DEFINE	MAK(MFC,FSC,SFI),<
MAK'FSC:NULL
	MOVSI	T4,<<<FN.'MFC>_4+<SF.'FSC>>_^D10>	;GET OPCODES
..AA==0
..BB==0
..CC==0
IFDIF <SFI><I>,<..AA==1>
IFDIF <MFC><TTY>,<..BB==1>
IFIDN <MFC>,<REJ>,<..CC==1>
	IFE	<..AA+..BB+..CC>,<
	PJRST	FINMSG		;SEND THE CONTROL WORD
>
	IFN	<..AA&..BB>,<
	IFN	..CC,<
	PJRST	FINMS0	;;ZERO T2,T3 AND LOAD DATA
>	;END OF IFN ..CC
	IFE	..CC,<
	PJRST	FINMS2		;;ZERO T2,T3 ONLY
> >	;END OF IFE..CC AND ..AA AND ..BB
	IFE	<..AA&..BB>,<
	IFN	<..AA+..BB>,<
	IFN	..AA,<	SETZ	T2,	> ;;NO SUB FUNCTION
	IFN	..BB,<  SETZ	T3,	> ;;TASK ID IS IN DDB
	IFN	..CC,<  PJRST	FINMS1	>;;GET T3 FROM DDB
	IFE	..CC,<  PJRST	FINMSG	>;;TERMINATE THE THING
>	;END OF IFN <..AA+..BB>
> ;END OF IFE <..AA&..BB>
	LIST
>
	XALL			;LIST EXPANSION

	MAK	TTY,TTC,I,	;TTY CHARACTER
	MAK	TTY,TTN,	;TTY REJECT
	MAK	TTY,TTM,	;TTY MORE
	MAK	RFI,RFI,	;SEND AN RFI
	MAK	RFO,RFO,	;SEND AN RFO
	MAK	WFO,WFO,	;SEND A WFO
	MAK	WFI,WFI,	;SEND A WFI
	MAK	REJ,NOT,	;NO DDB FOR TASK
	MAK	REJ,FNE,	;FUNCTION ERROR
	MAK	REJ,IMP,	;IMPROPER MODE
	MAK	REJ,IDM,	;IMPROPER DATA MODE
	MAK	REJ,BTL,	;BLOCK TOO LARGE
	MAK	REJ,DTE,	;DATA ERROR
	MAK	REJ,OPE,	;OPERATION ERROR
	MAK	CLS,EOF,	;END-OF-FILE
	MAK	RST,REL,	;RELEASE
	MAK	RST,RTK,	;RESTART TASK
	MAK	ATB,XAB,I,	;XMT ATTRIBUTE BYTE

	SALL			;NO MORE LISTING OF EXPANSION
SUBTTL	MAKE CONTROL WORDS -- FINISH UP COMMON CODE
IF2,<	PURGE	MAK,..AA,..BB,..CC>

;SUBROUTINE TO FINISH A PROTOCOL WORD IN T4
;CALL WITH:
;	MOVEI	T4,MAJOR-FUNCTION-CODE+SUBFUNCTION CODE
;	MOVEI	T2,SUPP.-FUNCTION-INFORMATION
;	MOVEI	T3,TASKID [OR 0 TO GET FROM DDB]
;	PUSHJ	P,FINMSG
;	RETURN HERE

FINMS0:	NULL
	SETZB	T2,T3		;ZAP BOTH
FINMS1:	NULL
	PJUMPN	F,FINMSG	;GET IT FROM DDB
	LDB	T3,XUYTIF	;GET RECEIVED WORD'S DATA
	SKIPA			;JUMP PAST ZAPPING T3
FINMS2:	NULL
	SETZB	T2,T3		;ZONK
FINMSG:	NULL
	DPB	T2,[POINT 8,T4,15];STORE SUPP. FUNCTION INFORMATION
	SKIPE	T1,F		;SKIP IF NO DDB
	LDB	T1,DVYIOM	;GET THE I/O MODE
	DPB	T1,[POINT 4,T4,19]	;STORE THE MODE
	JUMPE	F,[JUMPN T3,.+1	;PROCEDE IF WE CAN GET TASK ID
		  POPJ	P,	];DONE
	SKIPN	T3		;SKIP IF ALREADY KNOW TASK ID
	LDB	T3,DVYTID	;GET THE TASK ID
	DPB	T3,[POINT 12,T4,31]	;STORE IN CONTROL WORD
	POPJ	P,
SUBTTL	MAKE CONTROL WORDS -- SUBROUTINES ADDSIZ, GETMOD, CHKMOD
;ADDSIZ ADD THE SIZE OF THE TRANSFER TO THE PROTOCOL WORD

ADDSIZ:	NULL
	HRRZ	T1,DVXBSZ(F)	;GET THE CURRENT SIZE
	MOVNS	T1		;GET THE MINUS AMOUNT
	DPB	T1,[POINT 12,T4,15]	;STORE THE SIZE
	POPJ	P,		;THAT'S ALL
;SUBROUTINE TO GET THE HARDWARE MODE FROM THE DDB
;CALL WITH:
;	MOVE	F,ADDRESS-OR-DDB
;	PUSHJ	P,GETMOD
;	RETURN HERE MODE IN T1

GETMOD:	NULL
	LDB	T1,PIOMOD	;GET DATA MODE
	IDIVI	T1,^D9		;DIVIDE BY BYTES/WORD
	MOVN	T2,T2		;CALCULATE THE BIT POSITION
	ADDI	T2,10		; ..
	ROT	T2,-4		; ..
	IOR	T2,[POINT 4,DVXMOD(F),35] ;MAKE INTO A BYTE POINTER
	ADDI	T2,(T1)		;THROW IN REMAINDER
	LDB	T1,T2		;GET THE MODE
	DPB	T1,DVYIOM	;SAVE THE I O MODE
	IDIVI	T1,^D9		;GET WA AND BYTE AD
	MOVE	T1,HDWDPM(T1)	;GET THE MODE WORD
	IMULI	T2,4		;NUMBER OF BITS
	LSH	T1,777740(T2)	;AND SHIFT THE BYTE IN PLACE
	ANDI	T1,17		;MASK OUT THE HDW MODE
	DPB	T1,DVYHWM	;STORE IT
	POPJ	P,

;BYTES CORRESPOND TO THE SEQUENCE MODE 0,1,2,.....
HDWDPM:	BYTE	(4) MD.ASC,MD.ASC,MD.ASC,MD.ASC,MD.ASC,MD.ASC,MD.ASC,MD.ASC,MD.IMI
	BYTE	(4) MD.PKI,MD.PKI,MD.PKI,MD.BIN,MD.IMI,MD.ASC,MD.BIN


;ROUTINE TO CHECK IF DATA MODE RECEIVED FROM EP IS REASONABLE

CHKMOD:	NULL
	LDB	T1,DVYHWM	;GET THE HARDWARE MODE
	HLRZ	T2,DVXWFO(F)	;GET MODE REC'D
	CAMN	T2,MODTAB(T1)	;SEE IF WE LIKE IT
	AOS	(P)		;MODE ARE THE SAVE GIVE SKIP
	POPJ	P,		;RETURN

MODTAB:	EXP	2		;(0) IMAGE
	EXP	0		;(1) ASCII
	EXP	3		;(2) PACKED IMAGE
	EXP	1		;(3) BINARY
SUBTTL	MAKE CONTROL WORDS -- SETACS
;EP SENDS
; 0 FOR ASCII
; 1 FOR BINARY
; 2 IMAGE
; 3 PACKED IMAGE
;SUBROUTINE TO SET UP ALL THE AC'S IN SIGHT
;CALL WITH:
;	MOVE	F,ADDRESS-OF-DDB
;	PUSHJ	P,SETACS
;	RETURN HERE WITH S,J,R,U AND W SETUP
SETACI:
SETACS:	NULL
	HRRZS	F		;CLEAR LH OF F
	HRRZ	U,DVXUDB(F)	;U = ADDRESS OF UDB
	HRRZ	W,XUBKDB(U)	;W = ADDRESS OF KDB
	MOVE	S,DEVIOS(F)	;SET UP S
	LDB	J,PJOBN##	;J = JOB NUMBER
	POPJ	P,0		;RETURN
SUBTTL	MAKE CONTROL WORDS -- RING BUFFER CONTROL WORD TRACE
;ROUTINES TO SUPPORT GIANT RING BUFFER TRACE

IFN .DBLEN,<
RCPUT:	MOVSI	T1,(1B0)
	MOVE	T2,XUBRCW(U)	;CW IN T2
	JRST	CPUT

XCPUT:	MOVEI	T1,0		;FLAGS
	MOVE	T2,XUBXCW(U)
	SKIPE	F
	MOVE	T2,DVXXCW(F)	;MAYBE IN DDB
	JRST	CPUT

RDPUT:	AOS	(P)		;SKIP DUMP TRACE
	TDZA	T2,T2
RDDPUT:	MOVSI	T2,-1		;MARK DUMP MODE
	MOVSI	T1,(3B1)	;FLAGS
	JRST	CPUT

XDPUT:	AOS	(P)		;SKIP DUMP TRACE
	TDZA	T2,T2
XDDPUT:	MOVSI	T2,-1
	MOVSI	T1,(1B1)

CPUT:	SKIPE	F
	HLR	T1,DEVIOS(F)	;INCLUDE DEVIOS IF THERE
	IOR	T2,XUBUNO(U)	;ADD UNIT #
	LDB	T3,[POINT 3,XKBNAM##(W),17]
	DPB	T3,[POINT 3,T1,17] ;INCLUDE CONTROLLER ID
	MOVE	T3,.DBUFP	;GET POINTER
	MOVEM	T1,(T3)
	MOVEM	T2,1(T3)	;STASH INFO
	ADDI	T3,1
	AOBJN	T3,.+2
	MOVE	T3,[-.DBLEN,,.DBUF]
	MOVEM	T3,.DBUFP
	POPJ	P,		;RETURN

	$LOW			;LOW DATA
.DBUFP::-.DBLEN,,.DBUF
.DBUF::	BLOCK	2*.DBLEN
	$HIGH
>
SUBTTL	MAKE CONTROL WORDS -- SENDW
	COMMENT	\
SEND ROUTINE FOR PROTOCOL WORDS.

PROTOCOL WORDS CAN BE GENERATED BY 2 TYPES OF PROCESSES:
1  PROCESSES ASSOCIATED WITH A DDB
2  PROCESSES WITHOUT A DDB
THE GENERATION CAN MOREOVER TAKE PLACE AT 2 LEVELS:
A  INTERRUPT LEVEL
B  UUO LEVEL
THE SENDING PROCESS CONSISTS OF 2 PHASES:
P1 GETTING THE CLEARANCE TO SEND
P2 INITIATION OF THE HARDWARE PROCESS
P3 COMPLETION OF THE HARDWARE PROCESS
THE GOAL IS THAT EVERYBODY CALLS THE SAME ROUTINE AND THAT
AUTOMATICALLY ALL THE RIGHT THINGS WILL HAPPEN
IN ORDER TO DO THIS PHASE 2 WILL BE DESCRIBED FIRST:

PHASE 2:

IF .F 'NEQ' 0
 THEN (DVXXCW[.F]_.T4;DVXIPC[.F]_XDNDDB;XMTADR_DVXXCW[.F])
 ELSE (XUBXCW[.U]_.T4;XUBIPC[.U]_XDNXUB;XMTADR_XUBIPC[.U];XKBIUN[.W]_.U);
XKBDDB[.W]_.F; FOR INTERRUPT CODE
D28OUT(XMTADR,"1 WORD");

;END OF PHASE 2

PHASE 2 HAS THE FOLLOWING PROPERTIES:
1 NO ASSUMPTION FOR THE PROCESS LEVEL IS MADE
2 FOR EACH PROCESS TYPE THE ACCESS RIGHT HAS TO BEACQUIRED TO
  THE DATA BASE OF THE TYPE
3 THE RIGHT TO USE THE HARDWARE HAS TO BEACQUIRED
4 THE UNIT MUST BE UNLOCKED, THIS MEANS WE EXPECT TO DO DATA INPUT
  ONLY FROM THIS UNIT.IT IS POSSIBLE FOR SCNQUE TO FIND WORK FOR A UNIT
  WHICH IS IN THE LOCKED STATE.UNIT ERRORS AND REJECTS SHOULD UNLOCK
  THE UNIT!!

GIVEN THIS THE LOGIC FOR PHASE 1 IS:
IF "AT UUO LEVEL"
 THEN ( IF 'NEQ' .F THEN XIOWA0;  !!!WAIT FOR UUO USER TO STOP USING THE DDB
!!!!!*****START OF CRITICAL SECTION VULNERABLE TO:
!!!!!*****1. INTERRUPTS
!!!!!*****2. GRANTED INTERRUPTS
	IF 'NOT' "GET DA28 CONTROL" 'AND' "UNIT UNLOCKED" THEN
	   IF .F 'EQL' 0 THEN (Q FUNCTION;EXIT(DOZE0)!REVIVES WORLD)
			ELSE (SAVE FUNCTION;SET DVXQUE[.F];RETURN))

;END OF PHASE 1

EXCEPT FOR MINOR DETAILS THIS IS THE COMPLETE CONTENT OF PHASE 1

NOTE THAT PHASE 1 STARTS A CRITICAL SECTION, TERMINATED BY EITHER:
 THE DOZE0 CALL OR THE RETURN.  IN PHASE 2 THE HARDWARE INITIATION 
  REVIVES THE WORLD
\
SENDW:	NULL
	CONSO	PI,PI.IPA	;IS A INTERRUPT PROCES HERE
	JRST	PHASE1		;NO START PHASE 1
	JUMPE	F,PHS2NF	;PHASE 2 AND NO DDB
	JRST	PHS2F		;PHASE 2 AND A DDB
PHASE1:	NULL
	JUMPE	F,NODDB		;NO DDB IN THIS CASE
	PUSH	P,T4		;SAVE PROTOCOL WORD
	PUSHJ	P,XIOWA0		;WAIT TILL DDB SPACE IS AVAILABLE
	MOVE	T4,(P)		;RESTORE T4
	POP	P,DVXST4(F)	;USE DDB NOW AS STORAGE
NODDB:	PUSHJ	P,D28GET		;TRY TO GET CONTROL AND UNIT
	JRST	SWAIT		;WE HAVE TO WAIT
	JUMPE	F,PHS2NF	;PHASE 2 STARTED
	JRST	PHS2F		;HERE TOO IF THERE IS A DDB

;COME HERE IF DA28 IN USE , UNIT IS LOCKED OR UDB IN USE

SWAIT:	NULL
	JUMPE	F,D28WNF	;WAIT THERE IS NO DDB
XYXY:	NULL
	PUSHJ	P,D28WTF	;WAIT WITH A DDB
	SETZM	DVXQUE(F)	;NO MORE WAITING

;HERE START THE PHASE 2 ROUTINES AND THE PHASE 3 ROUTINES
;IT IS MANDATORY THAT PHS2F STARTS IMMEDIATELY AFTER THE CALL
;TO D28WTNF
;COME HERE AT INTERRUPT LEVEL FROM SCNQUE FOR A DELAYED SEND
;THIS CODE IS UNLABELED , BUT PRINTX WILL CATCH PROBLEM MAKERS
	MOVE	T4,DVXST4(F)	;GET THE CW BACK

;COME HERE WHEN THE TRANSFER WAS INITIATED AT INTERRUPT LEVEL
;DUE TO AN EVENT CREATED BY A RECEIVED CTLWD

PHS2F:	NULL
	MOVEM	T4,DVXXCW(F)	;STORE THE PROTOCOL WORD
	MOVE	T1,[ IOEND,,IODEND] ;END OF FILE STATUS
	TDNN	T1,DEVIOS(F)	;FOR DDB
	JRST	PHS2F0		;NOPE
	LDB	T1,DVYXMF	;GET MAJOR FUNCTION
	CAIE	T1,FN.RFI	;AND IF IT IS AN RFI
	JRST	PHS2F0		;NO LET IT GO
	PUSH	P,U		;SAVE UNIT
	PUSH	P,F		;AND DDB
	PUSHJ	P,SCNQUE	;SO ALL WILL BE BACK
	POP	P,F		;GET IT BACK IN LINE
	JRST	UPOPJ##		;SO WORD DOES NOT CHANGE FOR UUO LEVEL
PHS2F0:	NULL
	MOVEI	T2,XDNDDB	;DONE CODE ADDRESS
	MOVEI	T1,DVXXCW-1(F)	;MAKE IT EASY FOR D28OUT
	PJRST	D28XCW		;XMIT A CONTROL WORD

XDNDDB:	NULL
	IFN	.DBLEN,<
	PUSHJ	P,XCPUT		;TRACE IT
>
	LDB	T1,DVYXMF	;WHAT WAS SENT OUT
	CAIN	T1,FN.WFI	;A WFI
	MOVEM	F,XUBLOK(U)	;LOCK THE UNIT
	MOVE	T1,MSBTTB(T1)	;GET THE BIT
	IORM	T1,DVXPST(F)	;AND FLAG IT
	SKIPE	DVXQUE(F)	;IF THERE IS A QUEUE THEN
	PJRST	SCNQUE		;LOOK FOR WORK
	MOVSI	T1,WAKTSK	;ELSE A WAKE ON AN EMPTY Q ACTIVE
	TDNN	T1,DEVIOS(F)	;CHECK IT
	PJRST	SCNQUE		;NO GET THE INTERFACE GOING
	ANDCAM	T1,DEVIOS(F)	;WE DID THE WAKE AND ONCE WILL DO
	PUSHJ	P,XTWAKE		;WORKTIME
	PJRST	SCNQUE		;LOOK AROUND

MSBTTB:	0		;(0) UNDEFINED
	0		;(1) TTY FUNCTION
	0		;(2) REJECT
	0		;(3) ACK
	0		;(4) CLOSE
	0		;(5) MODIFY ATTRIBUTE BYTE
	0		;(6) RESTART
	0		;(7) UNDEFINED
	0		;(10) UNDEFINED
	0		;(11) UNDEFINED
	0		;(12) UNDEFINED
	0		;(13) UNDEFINDE
	IOXRFI,,0	;(14) READY FOR INPUT
	IOXRFO,,0	;(15) READY FOR OUTPUT
	IOXWFI,,0	;(16) WAITING FOR INPUT
	IOXWFO,,0	;(17) WAITING FOR OUTPUT
;PHS2NF DO CONTROL WORD TRANSMISSION FOR NON F PROCESSES

PHS2NF:	NULL
	MOVEI	T2,XDNXUB	;NO Q TO BOTHER ABOUT
PHS2N1:	NULL
	MOVEM	T4,XUBXCW(U)	;STORE THE PROTOCOL
	MOVEI	T1,XUBXCW-1(U)	;MAKE IT EASY
	PJRST	D28XCW		;SEND THE WORD

;COME HERE WHEN A QUEUE ENTRY WAS SERVICED

XDNXU0:	NULL
	MOVE	T1,XUBQUE(U)	;GET THE 4 WORD BLOCK ADDRESS
	PUSH	P,3(T1)		;SAVE THE LINK ADDRESS
	PUSH	P,1(T1)		;SAVE THE JOB NUMBER
	MOVEI	T2,4		;WORDS USED
	EXCH	T1,T2		;SWAP
	PUSHJ	P,GIVWDS##	;GIVE THE FREE CORE BACK
	POP	P,T1		;GET THE JOB NUMBER
	JUMPE	T1,XDNXU1	;NUL JOB SO DON'T WAKE
	PUSH	P,W		;ELSE IT EVAPORATES
	PUSHJ	P,WAKJOB##	;BACK TO WORK
	POP	P,W		;GET XKB ADDRESS BACK
XDNXU1:	POP	P,T1		;GET NEXT XUB REQUEST
	MOVEM	T1,XUBQUE(U)	;STORE NEXT WORK REQUEST
	JUMPN	T1,PHS2N0	;MISUSE OUR PRILIGES
	SETZM	XUBEND(U)	;ZAP THE END POINTER

;COME HERE TO TRACE AND NOT DEQUE AS SCNQUE WILL DO THIS

XDNXUB:	NULL
	IFN	.DBLEN,<
	PUSHJ	P,XCPUT
>
	PJRST	SCNQUE		;SCHEDULE WORK


PHS2N0:	NULL
	MOVE	T4,(T1)		;GET CONTROL WORD
	MOVEI	T2,XDNXU0	;A Q ENTRY WAS PROCESSED
	PJRST	PHS2N1		;MISUSE OUR POSITION
PLM
;+
;.lm 0
;.hl 1 Send Control Words
;^^
;.subtitle SENDW
; XTCSER must be able to send protocol words to
;different processes running on different small computers all at
;the same time, and also be able to do so both at UUO level and at
;interrupt level.  It simplifies the code a great deal if there
;exists a single routine to call which correctly
;determines the state of the DA28C hardware and which either
;immediately initiates the transfer if the DA28C is free or queues
;the request to be initiated later.
; This routine is called SENDW and is divided into two parts.
;The first is called PHASE1 and its purpose is to get permission to
;use the DA28 hardware (and wait if we cannot). This part is
;only used at UUO level since we only run at interrupt level when
;the DA28 has just completed some transfer and is therefore known
;to be idle.  The second part is called PHASE2 and has as
;its purpose the starting of the hardware to do the transfer.  Then
;there is also a PHASE3, which consists of executing the proper
;termination code when the hardware transfer has finished.
; As this is a reasonably crucial routine in XTCSER, I will
;give the logic in quite some detail:
;.list
;.le;SENDW: -- this is the only entry; the protocol word to be
;sent is in T4. If it is for a DDB F must have the DDB address
;and if it is not for a DDB F must be 0.
;If the caller is executing at interrupt level, skip phase1
;entirely and go to PHS2F if there is a DDB and PHS2NF if there is
;no DDB.
;.le;PHASE1: -- here only at UUO level. (Note that there are two possibilities
;concerning the DA28C hardware:  it may be busy or it may not be busy.
;There are also two situations in which we may find ourselves -- with
;a DDB or without.  If the DA28C is busy we must queue up the request
;somehow and ensure that the UUO waits long enough for completion.)
;If there is a DDB call XIOWA0. This routine returns immediately if DVXQUE
;is zero, i.e. this DDB does not already
;have a control word queued to go out. Otherwise it calls DOZE0 and
;tries again later. Thus control only passes through this point in
;the DDB case when DVXQUE is free. (Note that the check is made
;with interrupts turned off, but that after we see that it is free
;we turn interrupts back on again. This does not hurt because only
;UUO level can put anything into DVXQUE and we are the only
;ones running at UUO level.)
;When we have ensured our ability to queue the DDB we store the
;protocol word in it (at DVXST4). If we do have to wait, we will
;continue at interrupt level with none of our old context, so this
;is essential.
;.le;NODDB: -- here either with F=0 or with (F .NE. 0) .AND. (DVXQUE = 0).
;Here we call D28GET to attempt to get the DA28C hardware.  This routine
;turns off interrupts and returns non-skip if the DA28C is not
;available (with interrupts still off).
;If we get the hardware (skip return) we are finished PHASE1 and
;do precisely what SENDW: did if it was at interrupt level -- namely
;go to PHS2F if we have a DDB and PHS2NF if we do not.
;If we cannot get the hardware, that means we must queue the request.
;In this case we go to D28WNF if we have no DDB, and to XYXY: if we
;have a DDB.
;.le;XYXY: -- here we call D28WTF which pops the return PC off
;the stack into DVXQUE, turns on interrupts and returns to
;the caller of SENDW.  The non-zero nature of DVXQUE will cause
;the SCNQUE call at some later interrupt to continue the code at the
;PC in DVXQUE. At this point we clear DVXQUE (we will be the next
;control word out because the hardware is idle because we are at
;interrupt level), copy the saved protocol word (DVXST4) back into
;T4 and fall into PHS2F.
;.le;PHS2F: -- we get here either at UUO level if we got the hardware
;or at interrupt level to actually ship out the control word.
;The code first copies it from T4 into DVXXCW, then tests for the
;special combination of sending RFI when EOF bits are set.
;If this is not the case, the code goes to PHS2F0 to set the
;address to continue with this when the control word is done to
;XDNDDB and calls D28XCW to actually start the hardware transfer and
;return to the caller (of SENDW if at UUO level or of SCNQUE if at interrupt level).
;If we are sending an RFI when we already have EOF bits set we simply
;call SCNQUE to try to select something else to do and avoid sending the control word.
;There are only two times we will be in this situation -- if we are
;doing an INPUT UUO and the EOF came in between the time we tested
;for it at XISYNC and the time we decided to send the RFI. The
;EOF condition will eventually give an error return to the IN
;UUO and in this case we do not want to send the RFI because
;it would be misleading to the small computer.
;Similarly, the XTTSK function to send an RFI checks
;for error bits and gives an error return, and similarly there
;is a race if the EOF comes in at the inappropriate moment.
;By throwing away the RFI in this case, however, we must
;ensure that we do not leave the DA28 neither doing a transfer
;nor scanning, hence the call to SCNQUE.
;.le;PHS2F0: -- here we actually send the control word on the
;behalf of a DDB.  Put address of control word (DVXXCW) minus 1
;into T1, address of where to pass control when the done
;interrupt (XDNDDB) into T2, call D28XCW to start the
;output, and return to caller (either of SENDW at UUO level
;or SCNQUE at interrupt level).
;.le;PHS2NF: -- here to send out control word not for a DDB. Same
;as PHS2F except that the address for resuming after an interrupt
;is XDNXUB and the source of the control word (saved from T4 value)
;is XUBXCW.
;.le;PHS2N0: -- this routine is only entered by SCNQUE when it
;finds there is something to send in the XUBQUE.
;This routine gets the control word from the 4-word block, sets up
;the interrupt done address as XDNXU0, calls D28XCW and returns.
;.le;XDNDDB: -- this is where we come at interrupt level when the transfer
;of a control word for the DDB is finished.  This code inserts the
;transmitted control word in the control-word trace buffer, then
;checks if we have just transmitted a WFI and if so, stores
;the DDB address in XUBLOK (indicating that the next transfer
;on this unit must be data and not some control word for another
;task-to-task transfer).
;In any case, the bit corresponding to the control word
;function code is gotten from MSBTTB and ORed into DVXPST.
;Then if DVXQUE is zero (i.e. we have shipped all that is queued
;for this DDB) and WAKTSK bit is set in DEVIOS (only set up by XIOWA0 before
;its call to DOZE0) it calls XTWAKE to wake up UUO level.
;Finally, this routine (in all cases) calls SCNQUE to either find another
;transfer to do or to set the scanner going, then exits the interrupt.
;.le;XDNXU0: -- this is the done interrupt routine when we got
;the control word from the XUBQUE queue of 4-word blocks.  This routine
;gets the address of the 4-word block we just finished,
;copies the link to the next four word block and the job number,
;frees the 4-word block, calls WAKJOB in UUOCON to wake up the job (if
;the job number is non-zero) and copies the link to the next
;four-word block into XUBQUE. If this is zero (i.e. there are
;no more requests) it clears the XUBEND pointer to
;the last queue entry as well and falls into XDNXUB to trace the
;control word and exit via SCNQUE. If there is another
;entry into the queue it saves some time by not calling SCNQUE but
;instead jumping directly to PHS2N0 (where SCNQUE would go if
;it selected the same unit to work on).
;.le;XDNXUB: -- this is the interrupt routine executed on the done
;interrupt of a control word that was not associated
;with a DDB and had not been queued, as well as the exit
;of the queued case.  This routine simply calls XCPUT to
;trace the control word we finished sending, and exits via SCNQUE.
;.end list
;-
MLP
SUBTTL	MAKE CONTROL WORDS -- WAIT ROUTINES
;D28WTF WAIT PRIMITIVE FOR A UUO PROCESS WITH A DDB
;NO WAIT WILL BE DONE IF NOT DESIRED

D28WTF:	NULL
	POP	P,DVXQUE(F)	;CODE TO RUN
	CONO	PI,PI.ON+PI.TNP+XTCBIT##	;HEAR AGAIN
	POPJ	P,


;D28WNF WAIT ON UUO LEVEL FOR A UUO PROCESS WHEN THE CONTROLLER IS NOT
;FREE THIS USES A LIST OF 4 WORD DATA BLOCKS:
;WORD 0 PROTOCOL WORD
;WORD 1 JOB NUMBER WAITING
;WORD 2 SPARE (ZERO)
;WORD 3 LINK TO NEXT TASK BLOCK OR NIL
;THE LIST HEAD IS IN XUBTSK AND THE END OF THE LAST TASK BLOCK IN 
;XUBEND

D28WNF:	NULL
	PUSH	P,T4		;SAVE THE PROTOCOL WORD
	MOVEI	T2,4		;WE WISH A FOUR WORD BLOCK
	PUSHJ	P,GETWDS##	;GET CORE
	SKIPA			;NO ONE FREE YET
	JRST	GOTCOR		;WE GOT IT
	CONO	PI,PI.ON+PI.TNP+XTCBIT##	;REVIVE
	PUSHJ	P,DOZE1		;SLEEP A BIT
	POP	P,T4		;GET CTLW BACK
	PUSHJ	P,D28GET		;SEE IF CONTROL IS FREE NOW?
	JRST	D28WNF		;(NO) WAIT SOME MORE
	PJRST	PHS2NF		;(YES) START PHASE 2 OF SEND NOW
GOTCOR:	NULL
	POP	P,(T1)		;LOAD PROTOCOL WORD
	MOVEM	J,1(T1)		;STORE JOB NUMBER
	SETZM	2(T1)		;SPARE
	SETZM	3(T1)		;AND LINK ARE ZERO
	MOVE	T2,T1		;COPY OUR ADDRESS
	CONO	PI,PI.OFF	;NO PROBLEMS
	EXCH	T2,XUBEND(U)	;GET END POINTER OR ZERO
	SKIPE	T2		;BE CAREFUL
	MOVEM	T1,3(T2)	;LINK IN THE CHAIN
	SKIPN	XUBQUE(U)	;IF THERE IS NO Q THEN
	MOVEM	T1,XUBQUE(U)	;MAKE ONE
	PJRST	DOZE0		;RETURN AFTER SLEEPING
;XIOWAT USED TO WAIT UNTIL ALL PREVIOUS ACTIVITIES FOR THE
;DDB ARE FINISHED

XIOWAT:	NULL
	PUSHJ	P,WAIT1##		;WAIT FOR I/O TOCOMPLETE

;ENTRY FOR ACTIVE (I/O) JOBS

XIOWA0:	NULL
	CONO	PI,PI.OFF	;SEE IT THE SAFE WAY
	SKIPN	DVXQUE(F)	;IS DDB READY FOR USE
	PJRST	ONPOPJ##	;(YES) USE IT
;GET PI'S ON IN DOZE0
	MOVSI	T1,WAKTSK	;SET THE WAKE REQUEST
	IORM	T1,DEVIOS(F)	;SO WE WILL WAKE AGAIN
	PUSHJ	P,DOZE0		;SLEEP TILL ALL IS READY
	JRST	XIOWA0		;MAKE SURE ALL IS OKAY


;XIOWT1 WAIT AND SAVE T1

XIOWT1:	NULL
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,XIOWAT		;WAIT TILL ALL FREE
	PJRST	TPOPJ##		;GO BACK WITH GOOD T1


;CODE TO WAIT UNTIL ALL SENDING OF CONTROL WORDS IS COMPLETED
;THERE ARE 2 STEPS 
;1 GUARANTEE THAT THE QUE IS EMPTY (CALL TO XIOWAT)
;2 GUARANTEE THAT NO WORD IS IN THE DA28C PIPELINE

WTQEMP:	NULL
	PUSHJ	P,XIOWAT		;GET THE AUTHORITY OVER DVXQUE
	AOS	CNTQWT		;NUMBER OF WAITS DONE
	HRRZS	F		;GURANTEE  A UNIQUE VALUE
WTLOP0:	HRLZ	T1,XTCPAR	;GET THE WAIT PARAMETER
WTLOP1:	HLRZ	T2,XKBIUN##(W)	;GET THE DDB IF ANY
	CAME	T2,F		;IS IT US
	CAMN	F,XKBDDB##(W)	;USING THE DA28C
	SKIPA			;IN USE BY US
	POPJ	P,		;WE ARE NOT USING IT
	AOBJN	T1,WTLOP1	;TRY ONCE MORE
	JUMPL	T1,CPOPJ##	;ALL DONE
	AOS	CNTWTQ		;SLEEPING FOR THE Q
	PUSHJ	P,DOZE1		;SLEEP SORTLY
	JRST	WTLOP0		;TRY AGAIN
SUBTTL	MAKE CONTROL WORDS -- ROUTINES TO GET ACCESS TO DA28 HARDWARE
;GRBCTL GRAB THE CTL FOR A JOB UNTIL HE GIVES IT BACK

GRBCTL:	NULL
	PUSHJ	P,D28GET		;GET THE CONTROL
	SKIPA	T1,XKBREQ##(W)	;SEE IF OTHER REQUESTORS
	JRST	PACIFY		;REALLY REMOVE IT
	JUMPE	T1,GRBCT0	;NONE GET IT
	PUSHJ	P,DOZE1		;JUST KEEP TRYING
	JRST	GRBCTL		;UNTIL YOU GET IT
GRBCT0:	MOVEM	J,XKBREQ##(W)	;SET THE JOB NUMBER
	PUSHJ	P,DOZE0		;WAIT A WHILE
	SKIPL	XKBLOK##(W)	;SEE IF WE REALLY GOT IT
	STOPCD	.,STOP,TC7,	;WE LOST
	SALL
	POPJ	P,		;USE IT

;GIVCTL GIVE THE CONTROLLER BACK

GIVCTL:	NULL
	SETZM	XKBGRB##(W)	;NO LONGER GRABBED
	MOVEI	T1,XKBSKP##	;SKIP CONDITION
	HRRM	T1,XKBINT##(W)	;RESTORE THE SKIP CHAIN
	SETOM	XKBLOK##(W)	;MAKE THE CONTROL FREE
	PJRST	SCNQUE		;AND GET LIVE GOING AGAIN

;ZAPCTL IS CALLED TO ALLOCATE THE CONTROL TO THE JOB IN T1

ZAPCTL:	NULL
	SETZM	XKBREQ##(W)	;REQUEST IS OVER
	PUSH	P,W		;SAVE ADDRESS
	PUSHJ	P,WAKJOB##	;WAKE THE JOB
	POP	P,W		;GET ADDRESS BACK
	PUSHJ	P,D28GEI		;GET AT INTERRUPT LEVEL

PACIFY:	NULL
	HLLZS	XKBINT##(W)	;TAKE IT OUT OF THE SKIP CHAIN
	SETOM	XKBGRB##(W)	;MARK IT AS GRABBED
	POPJ	P,
;D28GET THIS BOOLEAN FUNCTION CAN BE CALLED AT UUO AND INTERRUPT
;LEVEL AND WILL TRY TO CLAIM THE INTERFACE.
;NOTE THAT WHEN TRUE IS RETURNED THEN THE DA28 IS DEACTIVATED
;	ON UUO LEVEL AND ON A FALSE RETURN THE DA28 IS SILENCED
;THE LOGIC IS :
;D28GET_IF ON INTERRUPT LEVEL THEN TRUE
;			       ELSE
;		(SILENCE THE WHOLE WORLD;
;		IF CONTROL BUSY THEN FALSE ELSE ("DEACTIVATE" CONTROL;TRUE)

D28GET:	NULL
	CONSZ	PI,PI.IPA	;AT INTERRUPT LEVEL
	JRST	D28GE0		;YES
	CONO	PI,PI.OFF+PI.TFP+XTCBIT##
	SKIPGE	XKBLOK(W)	;IS CONTROL FREE
	SKIPE	XUBLOK(U)	;AND UNIT UNLOCKED
	POPJ	P,		;NO FALSE!!
	JUMPN	F,D28GEI	;ALL OKAY FOR DDB STUFF
	SKIPE	XUBQUE(U)	;ARE ANY REQUESTS FORGOTTEN
	STOPCD	.,DEBUG,TC0,	;SEE IF IT OCCURRED
	SALL
D28GEI:	MOVEI	T1,XS.CLR	;CLEAR DAC BIT
	XCT	XTSCNO##(W)	;ZAP DAC
	SETZ	T1,		;ZAP T1 NOW
	XCT	XTCCNO##(W)	;TO CLEAR REMOTE INTERRUPT
	CONO	PI,PI.ON+PI.TNP+XTCBIT##
D28GE0:	SETZM	XKBLOK##(W)	;NO COMPETETION
	PJRST	CPOPJ1##	;YOU GOT IT
SUBTTL	DATA TRANSFER BEGIN -- STOUTP, STINPT
;SUBROUTINE TO START UP AN OUTPUT TRANSFER
;CALL WITH:
;	MOVE	T1,<IOWD>
;	PUSHJ	P,STOUTP
;	RETURN HERE
;
STOUTP:	NULL

IFE FTKL10,<
	HLRZ	T2,T1		;FIXUP FOR HARDWARE FORMAT
	LSH	T2,4
	HRL	T1,T2
>;END IFE FTKL10
	PUSHJ	P,SETKON	;SET UP HARDWARE
	LDB	T1,DVYHWM	;GET HARDWARE MODE
	LSH	T1,MODLSH	;GET IT IN PLACE
	IORI	T1,XC.CON!XC.OUT!XC.BSY!XC.MEM!XC.FST	;START THE TRANSFER
	XCT	XTCCNO##(W)
	POPJ	P,0		;RETURN


;SUBROUTINE TO START AN INPUT TRANSFER
;CALL WITH:
;	MOVE	T1,<IOWD>
;	PUSHJ	P,STINPT
;	RETURN HERE
;

STINPT:	NULL

IFE FTKL10,<
	HLRZ	T2,T1		;ADJUST WC FOR HARDWARE
	LSH	T2,4
	HRL	T1,T2
>;END IFE FTKL10
	MOVEI	T2,0		;SET TO CLEAR OUT DR
	XCT	XTSDTO##(W)	;...
	PUSHJ	P,SETKON	;SET UP HARDWARE
	LDB	T1,DVYHWM	;GET THE HARDWARE MODE
	LSH	T1,MODLSH	;SHIFT MODE IN THE RIGHT PLACE
	IORI	T1,XC.CON!XC.BSY!XC.MEM!XC.FST	;START THE TRANSFER
	XCT	XTCCNO##(W)
	POPJ	P,0		;RETURN
SUBTTL	DATA TRANSFER BEGIN -- D28XCW TO START CONTROL WORD
;D28XCW XMIT A CONTROL WORD
;.T1 IS THE CW ADDRESS
;.T2 IS THE XMIT DONE CODE ADDRESS

D28XCW:	NULL
	HRLI	T1,WC(1)	;ONE WORD GOES
	HRL	U,F		;COPY DDB OR NO DDB
	MOVEM	U,XKBIUN##(W)	;REMEMBER THE UNIT
	HRRZM	T2,XUBIPC(U)	;SET COMPLETION ADDRESS
	SETZ	T2,
IFE LIVE,<
IFE FTKL10 <
	DATAI	APR,T2		;READ CONSOLE
	HRR	T2,.TRCF	;AND TRACE FLAGS
>;end IFE FTKL10
IFN FTLK10 <HRRZ T2,.TRCF>	;AND TRACE FLAGS
	TDNN	T2,[10,,4]	;TRY EITHER SWITCH
	PUSHJ	P,TRCXCW	;call trace routine
>;end IFE LIVE

;FALL INTO D28OUT

;D28OUT GET OUT DATA

D28OUT:	NULL
	PUSH	P,T1		;SAVE ADDRESS OF CONTROL WORD
	ANDI	T1,-1		;JUST ADDRESS
	PUSHJ	P,OUCHE##	;GET OUT INTO PHYSICAL MEMORY
	POP	P,T1		;RESTORE IOWD
	PUSHJ	P,SETKCW	;SET CONTROL
	MOVEI	T1,XC.CON!XC.OUT!XC.BSY!DM.BIN!XC.MEM!XC.FST
	XCT	XTCCNO##(W)	;GO
	POPJ	P,
SUBTTL	DATA TRANSFER BEGIN -- SETUP SUBROUTINES SETKON, D28CLR, FRCOFL
;SUBROUTINE TO LOAD DA28 REGS FOR DATA XFER
;CALL WITH:
;	MOVE	T1,<IOWD FOR DAC>
;	PUSHJ	P,SETKCW/SETKON
;	RETURN HERE

;CALL SETKCW FOR CONTROL-WORD DATA TRANSFER (NO NEED TO SET T1 WITH
;AN IOWD) OR SETKON FOR A TRUE DATA TRANSFER (NEEDS IOWD AND WILL
;FLUSH THE CACHE ON A KL-10.
SETKON:	NULL
IFN FTKL10 <
	PUSHJ	P,CSDMP##	;FLUSH OUT CACHE FOR DMA DA28-C
>;END IFN FTKL10
SETKCW:	NULL			;NON-FLUSH ENTRY
	XCT	XTCDTO##(W)	;LOAD DAC
	MOVE	T1,XUBUNO(U)	;PICK UP NEW UNIT NUMBER
	LSH	T1,UNILSH	;SHIFT THE UNIT NUMBER
	IORI	T1,XS.ETI+XTCCHN## ;SET TIMING ERRORS AND PIA
;THE FOLLOWING CODE IS TO HANDLE THE DA28-C HARDWARE BUG FIXED BY
;ECO 7. DA28-C'S PRIOR TO THIS ECO WOULD CAUSE THE SMALL COMPUTER
;TO SEE AN ERROR ON THE RE-SELECTING OF THE SAME UNIT IN THE CODE
;FIELD (THE DA28-C INTERNALLY WENT THROUGH A 0-CODE STATE SETTING
;THE NEW CODE, WHICH 0-CODE STATE WAS PERCEIVED BY THE SMALL COM-
;PUTER INTERFACE, WHICH THOUGHT IT HAD BEEN DISCONNECTED). THIS
;PROBLEM WAS ONLY VISIBLE ON UNITS OTHER THAN UNIT 0, AND TYPICALLY
;ONLY UNDER HEAVY SYSTEM LOAD. IF THE DA28-C IS PRE-ECO 7 THEN
;SET ECO7=0.

IFE	ECO7,<
	PUSH	P,T1		;SAVE DESIRED UNIT/PIA
	XCT	XTSCNI##(W)	;READ CURRENT DA28-C STATUS
	IORI	T1,XS.ETI	;TURN ON THIS FLAG
	ANDI	T1,<17_UNILSH>!XS.ETI!7	;REDUCE TO IMPORTANT BITS
	CAMN	T1,(P)		;RE-SELECTING SAME UNIT?
	JRST	TPOPJ##		;YES, THEN DO NOTHING
	POP	P,T1		;NO, RESTORE NEW UNIT DESIRED
> ;END OF DA28-C PRE-ECO 7 HANDLER

	XCT	XTSCNO##(W)	;LOAD UNIT CODE & PIA
	POPJ	P,		;RETURN

;D28CLR CLEAR ALL DA28 ERRORS

D28CLR:	NULL
	MOVEI	T1,XS.CLR+XTCCHN##
	XCT	XTSCNO##(W)	;CLR ERRORS
	POPJ	P,
;FRCOFL IS CALLED WITH W AND U SET UP IN THE PROPER WAY
;THERE ARE 2 RETURNS YOU LOSE OR YOU WIN

FRCOFL:	NULL
	PUSHJ	P,GRBCTL		;FIRST GET THE CONTROL
	MOVE	T1,XUBUNO(U)	;GET THE UNIT NUMBER
	LSH	T1,UNILSH	;IN THE RIGHT PLACE
	XCT	XTSCNO##(W)	;AND SET THE UNIT FIELD
	MOVEI	T1,XC.CON	;NEXT 
	XCT	XTCCNO##(W)	;CONNECT SO FORCE SET BY AN EP
	SETZ	T1,		;WILL DISAPPEAR NEXT
	XCT	XTCCNO##(W)	;WHEN WE DISCONNECT
	DELAYY	T1		;DELAY FOR DA28Y'S
	MOVE	T1,XUBUNO(U)	;GET THE UNIT NUMBER
	LSH	T1,UNILSH	;IN THE RIGHT PLACE
	IORI	T1,XS.FRC	;GET FORCE BIT
	XCT	XTSCNO##(W)	;AND DRIVE IT HOME
	DELAYY	T1		;WAIT FOR THE Y
	MOVEI	T1,XC.CON	;CONNECT NEXT
	XCT	XTCCNO##(W)	;BACK TO UNIT
	XCT	XTCCNI##(W)	;GET THE STATUS
	TLNE	T1,XC.DRD	;IS IT NOT READY
	AOS	-1(P)		;(YES) SO SET WIN RETURN
	SETZ	T1,		;ZAP T1 AS SCNQUE WILL CLEAR
	XCT	XTCCNO##(W)	;DISCONNECT
	PJRST	GIVCTL		;GIVE IT BACK
SUBTTL	COROUTINE SUPPORT ROUTINES $COROUT, SYNC$, CPOPJx
;$COROUT ENABLES A SIMPLE COROUTINE MECHANISM BETWEEN
;UUO AND INTERRUPT LEVEL.THE ESSENTIAL THING IS THAT NOTHING IS LEFT
;ON THE STACK ON A COROUTINE EXIT.THE BENEFIT IS THE LACK OF THE
;NEED TO HAVE STACK SPACE IN THE DDB

$COROUT:NULL
	CONSZ	PI,PI.IPA	;IF AT INTERRUPT LEVEL THEN
	POPJ	P,		;IGNORE AS ALL IS SETUP
	MOVEM	T1,DVXMSK(F)	;RESET MASK
	EXCH	T1,(P)		;GET RETURN ADDRESS AND SAVE T1
	EXCH	T1,-1(P)	;REMOVE RETURN TO COROUT CALLER
	MOVEM	T1,DVXPRC(F)	;REMEMBER THE CALLER
	PJRST	TPOPJ##		;RESTORE T1 AND FALL IN COROUTINE


;SYNC$ WAIT FOR ACTION AT INTERRUPT LEVEL
;THIS ROUTINE DEPENDS ON THE RACE FREE OPERATION OF THE WAKE
;HIBER MECHANISM
;IT WILL SUSPEND OPERATIONS AND RETURN TO THE CALL POINT
;NEEDED AGAIN
;CAN BE CALLED AT UUO AND INTERRUPT LEVEL

SYNC$:	NULL
	MOVEM	T1,DVXMSK(F)	;REDEFINE THE MASK
	CONSZ	PI,PI.IPA	;AT INTERRUPT LEVEL
	JRST	SYNC30		;A DIFFERENT STORY
SYNC10:	HRLZ	T3,XTCPAR	;RETRY COUNT
SYNC20:	PUSHJ	P,IFEBTS		;SEE IF ANYTHING CAME
	POPJ	P,		;WAITING IS OVER
	AOBJN	T3,SYNC20	;TRY IT THIS MANY TIMES
	CONO	PI,PI.OFF	;DON'T BOTHER ABOUT DA28
	PUSHJ	P,IFEBTS		;ANY BITS SET
	PJRST	ONPOPJ##	;YES TURN ON PI AND RETURN
	POP	P,DVXCOR(F)	;HERE INTERRUPT LEVEL SHOULD GO ON
	PUSHJ	P,DOZE0		;SLEEP A WHILE
	SKIPN	DVXCOR(F)	;ANY COROUTINE STILL ACTIVE?
	PJRST	@DVXPRC(F)	;(NO) JUMP BACK
	PUSH	P,DVXCOR(F)	;put co-routine address back on stack [7136]
	JRST	SYNC10		;JUST TRY IT AGAIN 
SYNC30:	NULL
	PUSHJ	P,IFEBTS		;IF ANY  BITS THEN
	POPJ	P,		;ALL SET SO GO BACK
	POP	P,DVXCOR(F)	;NO CONTINUE HERE
	POPJ	P,		;THE COROUTINE


;ESCAPE CODE FROM INTERRUPT LEVEL
;CPOPJ$ IF ON UUO LEVEL THEN GO TO CPOPJ ELSE WAKE JOB
;CPOJ1$ IF ON UUO LEVEL THEN GO TO CPOPJ1 ELSE GO TO <.DVXIPC+1>
;CPOJ2$ IF ON UUO LEVEL THEN GO TO CPOPJ2 ELSE GO TO <.DVXIPC+2>
;

CPOJ2$:	NULL
	AOS	DVXPRC(F)	;SKIP ONE MORE
CPOJ1$:	NULL
	AOS	DVXPRC(F)	;AND ONE MORE
CPOPJ$:	NULL
	SETZM	DVXCOR(F)	;NO MORE WATING
	CONSO	PI,PI.IPA	;AT UUO LEVEL
	PJRST	@DVXPRC(F)	;ALL SET
	PUSHJ	P,XTWAKE		;WAKE THE JOB
	POPJ	P,
SUBTTL	SLEEP AND WAKE ROUTINES
;SLEEPY CODE

DOZE0:	NULL
	JUMPE	F,DOZE00	;NO F SO FORGET
	MOVSI	S,HIBTSK	;HIBERNATE FLAG
	IORB	S,DEVIOS(F)	;SET THE FLAG
	AOS	CNTHIB		;COUNT HIBERS
DOZE00:	TDZA	T1,T1		;SLEEP VERY LONG
DOZE1:	MOVEI	T1,2		;SLEEP SHORTLY
	CONO	PI,PI.ON+PI.TNP+XTCBIT## ;START LIFE AGAIN
	PUSH	P,W		;SAVE THE KDB
	PUSHJ	P,HIBER##		;THERE YOU GO [7136]
	POP	P,W		;GET CONTROLLER ADDRESS BACK
	MOVE	S,DEVIOS(F)	;GET THE CHANGED VALUE
	POPJ	P,

;SUBROUTINE TO WAKE UP A SLEEPING JOB
;CALL WITH:
;	MOVEI	F,ADDRESS-OF-DDB [OR 0]
;	PUSHJ	P,XTWAKE
;	RETURN HERE
;
XTWAKE:	NULL
	JUMPE	F,CPOPJ##	;NO-OPERATION IF NO DDB
	MOVSI	S,HIBTSK!WAKTSK	;IT WILL BE RESET!!
	TDNN	S,DEVIOS(F)	;CHECK IT
	JRST	XTWAK0		;NO LEAVE JOB ALONE
	ANDCAB	S,DEVIOS(F)	;ZAP THE HIBER FLAG

;XTWAKA WAKE ALWAYS ENTRY FOR REC DST

XTWAKA:	NULL
	PUSH	P,T1		;SAVE T1
	LDB	T1,PJOBN##	;GET JOB NUMBER
	JUMPE	T1,TPOPJ##	;NOP IF JOB 0
	PUSH	P,W		;SAVE W
	AOS	CNTWAK		;COUNT THE WAKES
	PUSHJ	P,WAKJOB##	;WAKE THE JOB
	POP	P,W		;RESTORE W
	POP	P,T1		;GET T1 BACK
XTWAK0:	MOVE	S,DEVIOS(F)	;FOR CALLER
	POPJ	P,
SUBTTL	EVENT COUNTERS
	$LOW			;STORE IN LOW


;DATA STORAGE FOR STATISTICS

CNTHIB:BLOCK	1		;NUMBER OF HIBERS
CNTWAK:BLOCK	1		;NUMBER OF WAKES
CNTINP:BLOCK	1		;NUMBER OF INPUTS
CNTOUT:BLOCK	1		;NUMBER OF OUTPUTS
PSZERO:BLOCK	1		;# OF LOOSING PSEUDO ACTS
PSMAKE:BLOCK	1		;# OF PSEUDO ACTIVE MAKES
CNTWTQ:BLOCK	1		;#OF HIBERS IN WTQEMP
CNTQWT:BLOCK	1		;# OF HIBERS FOR WTQEMP
DBGPAR:	IFE	.DBLEN,< Z>	;NO TRACE BUFFER
IFN .DBLEN,< .DBUFP,,.DBLEN> ;ADDRESS AND LENGTH OF TRACE BUFFER
XTCPAR::ACTTIM,,-QLPCNT	;PARAMETERS
			;ACTTIM IS # OF PSEUDO ACTIVE SECONDS
			;QLPCNT IS # OF TRIES BEFORE A HIBER STARTS
	XALL
	$LIT			;LITERALS
	SALL
PLM
;+
;.lm 0
;.chapter Debugging Aids
;^^\\
;	^THERE ARE THREE DEBUGGING FEATURES AVAILABLE WITH
;^^XTCSER\\:
;.SKIP
;.LIST
;.LE;AN IN-CORE TRACE OF PROTOCOL WORDS TRANSFERRED IN BOTH DIRECTIONS
;(NORMALLY ENABLED) TOGETHER WITH A CATEGORY ^C PROGRAM (CALLED ^^XTDUMP\\)
;TO PRINT THE CONTENTS OF THIS TABLE;
;.LE;A DYNAMIC TRACE OF PROTOCOL MESSAGES ON THE CONSOLE ^^TTY\\  AS THEY ARE SENT
;OR RECEIVED AND
;.LE;AN IN-CORE TRACE OF EXECUTION FLOW WITHIN ^^XTCSER\\
;.END LIST
;.HL 1 ^^XTDUMP\\
;.SUBTITLE ^^XTDUMP\\
; ^THE ^^XTDUMP\\ PROGRAM READS THE PROTOCOL WORD TRACE
;TABLE OF EITHER A RUNNING MONITOR, OR FROM AN ^^EXE\\ FILE
;DUMP OF A CRASH.
;^IT PRINTS THE CONTENTS ON DEVICE ^^LPT:\\ IN A SEMI-FORMATTED
;FASHION.
;^^XTDUMP\\ MAY BE ASSEMBLED BY ASSEMBLING ^^MACROS.MAC\\ TO
;PRODUCE A UNIVERSAL FILE ^^MACROS.UNV\\, THEN ASSEMBLING
;^^XTDUMP\\ AND ^^EXESUB\\, AND FINALLY LINKING THESE TWO
;MODULES TOGETHER WITH ^^HELPER\\ AND ^^SCAN\\.
; ^TO DUMP THE TRACE TABLE OF A RUNNING
;MONITOR, THE USER NEED ONLY START THE PROGRAM; IT DETERMINES
;THE LOCATION AND SIZE OF THE TRACE TABLE BY ISSUING AN
;^^XTTSK\\ ^^UUO\\.
; ^TO DUMP THE TRACE TABLE FROM A CRASH FILE, THE USER MUST
;START THE PROGRAM BY TYPING A LINE OF THE FORM
;.SKIP
;.INDENT 10
;^^RU XTDUMP\\-FILESPEC
;.SKIP
;WHERE "FILESPEC" CONTAINS THE NAME OF THE FILE CONTAINING
;THE CRASH.
;^IN THIS CASE, ^^XTDUMP\\ WILL ASK THE USER TO ENTER
;THE ADDRESS OF THE TRACE TABLE (VALUE OF ^^.DBUFP\\ IN
;^^XTCSER\\) AND ITS LENGTH (USUALLY 400, WHICH IS
;VALUE OF ^^DBLEN\\ IN ^^XTCSER\\).
; ^THE FOLLOWING IS AN EXAMPLE OF THE OUTPUT OF ^^XTDUMP\\:
;.SKIP.NOFILL.NOJUSTIFY
;^^
;030734/  400001,,000200  777570,,200020        _<-- A0  WFO (1)
;030736/  000001,,000201  737573,,600020        --_> A0  WFI (1)
;030740/  600001,,000201  777777,,000000  _<  D
;030742/  400001,,000200  202000,,200020        _<-- A0  CLSEOF (1)
;030744/  000001,,000200  314003,,600020        --_> A0  RSTRTK (1)
;030746/  400001,,000202  202000,,200020        _<-- A0  CLSEOF (1)
;030750/  000001,,000202  314003,,600020        --_> A0  RSTRTK (1)
;030752/  400001,,000000  314000,,200020        _<-- A0  RSTRTK (1)
;030754/  000001,,000000  102000,,000020        --_> A0  REJNOT (1)
;030756/  400001,,000002  777764,,200020        _<-- A0  WFO (1)
;030760/  000001,,000201  737767,,600020        --_> A0  WFI (1)
;030762/  600001,,000201  777777,,000000  _<  D
;030764/  400001,,000200  637570,,200020        _<-- A0  RFI (1)
;030766/  000001,,000221  677573,,600020        --_> A0  RFO (1)
;030770/  000001,,000221  777573,,600020        --_> A0  WFO (1)
;030772/  400001,,000221  737570,,200020        _<-- A0  WFI (1)
;030774/  200001,,000221  777777,,000000  _>  D
;.SKIP.FILL.JUSTIFY
;\\
;^THE COLUMN ON THE LEFT IS THE ADDRESS (IN THE MONITOR) OF THE
;TRACE BUFFER ENTRY. ^IT IS FOLLOWED BY THE TWO WORDS AT THAT ADDRESS
;IN OCTAL.  ^THE FIRST WORD INDICATES WHAT TYPE OF TRACE ENTRY IT
;IS (DATA OR CONTROL WORD), THE DIRECTION, THE CONTROLLER AND THE UNIT.
;(^FOR MORE DETAIL, SEE THE ROUTINES ^^XCPUT\\ AND ^^RCPUT\\ IN THE
;LISTING OF ^^XTCSER\\.)
;^THE NEXT WORD IS THE ACTUAL CONTROL WORD TRANSFERRED.
;^THE FINAL PORTION OF THE LINE IS AN "INTERPRETATION" OF THIS
;DATA, GIVING THE DIRECTION (VIA THE ARROW, TO THE LEFT MEANS
;TO THE -10), THE CONTROLLER AND UNIT (^A0), THE
;TYPE OF CONTROL WORD (^^RFI, RFO\\, ETC.) AND THE TASK ^^ID\\
;(IN PARENTHESES).
; ^^NOTE\\: ^^XTDUMP\\ IS NOT A SUPPORTED PROGRAM; IT IS
;SUPPLIED WITH ^^XTCSER\\ BECAUSE OF ITS USEFULNESS IN TRACKING
;DOWN PROTOCOL PROBLEMS FOR CUSTOMERS IMPLEMENTING ^^LIPS\\
;ON A SMALL COMPUTER.
;.HL 1 ^CONSOLE AND ^EXECUTION ^TRACE
;.SUBTITLE ^CONSOLE ^TRACE
; ^THE OTHER TWO DEBUGGING FEATURES OF ^^XTCSER\\ REQUIRE
;RE-ASSEMBLING ^^XTCSER\\ WITH SOME DEBUGGING SWITCHES
;ON.
;^BOTH ARE UNDER THE CONTROL OF THE FEATURE TEST
;SWITCH "^^LIVE\\", WHICH IS NORMALLY ENABLED
;(-1) AND WHICH IS DISABLED BY SETTING ITS VALUE TO 0.
;(^THE RATIONALE BEHIND THIS NAME IS:
;IF THE SYSTEM IS "LIVE" IT IS NOT DEBUGGING, AND IF IT IS
;DEBUGGING IT IS NOT "LIVE".)
;.HL 2 ^CONSOLE ^TRACE OF ^PROTOCOL ^WORDS
;.SUBTITLE ^CONSOLE ^TRACE
; ^THIS FEATURE ALLOWS THE DYNAMIC TRACING OF PROTOCOL 
;MESSAGES ON THE SYSTEM CONSOLE.
;^EACH DIRECTION OF MESSAGE CAN BE INHIBITED FROM THE TRACE BY
;EITHER SETTING A SWITCH IN THE SWITCH REGISTER (^^KA\\ AND
;^^KI\\) OR BY SETTING A SOFTWARE BIT IN THE WORD
;"^^.TRCF\\".
;^THIS FEATURE IS MOSTLY USEFUL WHEN DEBUGGING A ^^DA28\\
;DRIVER ON A SMALL COMPUTER WITH SOMETHING LIKE ^^DDT\\, WHICH
;IMPLIES THAT THE CONTROL WORDS TO BE TRACED ON THE CONSOLE APPEAR
;RELATIVELY INFREQUENTLY.  ^IF THE PROTOCOL IS RUNNING AT FULL SPEED
;THE CONSOLE WON'T BE ABLE TO KEEP UP, AND DATA (IN THE
;TRACE) WILL BE LOST.
;BECAUSE OF THIS, IN CURRENTLY DISTRIBUTED ^^XTCSER\\S THIS TRACE IS
;DISABLED BY ASSEMBLING THE APPROPRIATE TWO BITS IN THE
;WORD ^^.TRCF\\ (TO INHIBIT CONSOLE TRACE OF RECEIVE AND TRANSMIT
;CONTROL WORDS) AS ONES.
;.HL 2 ^EXECUTION ^TRACE
;.SUBTITLE ^EXECUTION ^TRACE
; ^THE THIRD DEBUGGING FEATURE IS GOVERNED BY THE
;FEATURE TEST SWITCH ^^FTETR\\.
;^THIS IS NORMALLY SET ON (-1) BY DEFAULT IF
;^^LIVE\\ IS ON (0) AND MAY BE TURNED OFF BY
;SETTING ^^FTETR\\ TO 0.
;^THIS CAUSES EVERY ^^NULL\\ MACRO CALL (USUALLY AT EVERY LABEL)  IN ^^XTCSER\\ TO GENERATE A
;TWO-WORD CALL TO AN EXECUTION TRACE ROUTINE.
;^THIS ROUTINE DOES NOTHING IF THE SIGN BIT OF
;THE WORD "^^ETRFLG\\" IS NOT ON; HOWEVER, IF IT IS
;ON, IT STORES THE ^^RH\\ OF THE CURRENT ^^CONI PI\\
;STATE IN THE ^^LH\\ OF THE TRACE TABLE ENTRY, AND
;THE CURRENT ^^PC\\ IN THE ^^RH\\ OF THE TRACE TABLE
;ENTRY.
;^THE TRACE BUFFER BEGINS AT ^^EBUF\\, AND IS "^^ENMENT\\"
;ENTRIES LONG (CURRENT DEFAULT IS 4000 OCTAL).
;^ANOTHER BIT IN ^^ETRFLG\\ (NAMELY ^^ETR.ST\\) INHIBITS
;THE TRACE CODE FROM WRAPPING AROUND THE BUFFER (THEREFORE
;DESTROYING PREVIOUS ENTRIES).
;^THIS IS USEFUL WHEN YOU WANT TO START COLLECTING TRACE
;INFORMATION FROM A GIVEN POINT FOR AS LONG AS POSSIBLE.
;^IF THIS BIT IS CLEAR, THE TRACE WILL WRAP AROUND, AND THE
;WORD ^^EPNT\\ WILL INDICATE THE NEXT WORD TO USE
;IN THE TRACE BUFFER.
;^THIS MODE OF OPERATION IS USEFUL IF YOU WANT TO
;TRACE AS MUCH INFORMATION AS POSSIBLE ENDING AT A CERTAIN
;POINT.
; ^A CALL TO THE TRACE ROUTINE MAY BE MODIFIED
;BY THE USER (VIA ^^EDDT\\) FOR SEVERAL REASONS:
;.LIST
;.LE;TO ELIMINATE A TAG FROM ANY TRACING, REPLACE THE
;^^PUSHJ P,ETRACE\\ WITH A ^^SKIPA\\
;(IF YOU WISH TO ELIMINATE A TAG FROM TRACING PERMANENTLY,
;YOU MAY EDIT THE ^^NULL\\ MACRO TO HAVE THE WORD "^^NOTRACE\\"
;AS AN ARGUMENT)
;.LE;TO START TRACING AT A SPECIFIED TAG,
;REPLACE THE ^^PUSHJ P,ETRACE\\ WITH A ^^PUSHJ P,ETRCON\\
;(WHICH SETS THE SIGN BIT OF THE ^^ETRFLG\\ WORD TO ENABLE
;TRACING)
;.LE;TO STOP TRACING AT A SPECIFIED TAG,
;REPLACE THE ^^PUSHJ P,ETRACE\\ WITH A ^^PUSHJ P,ETRCOF\\
;(WHICH CLEARS THE SIGN BIT OF THE ^^ETRFLG\\ WORD TO
;PREVENT FURTHER TRACING)
;.END LIST
;^^NOTE:\\ THAT THE TRACE ROUTINE IS CODED TO PROPERLY
;HANDLE ONLY SINGLE SKIPS BEFORE A ^^NULL\\ MACRO
;CALL; DOUBLE SKIPS (SUCH AS SUBROUTINE RETURNS) WILL
;NOT WORK.
; ^THE EXECUTION TRACE BUFFER IS SUITABLE FOR EXAMINING
;WITH AND MONITOR ^^DDT\\, I.E.#^^EDDT\\ IF STAND-ALONE
;OR ^^FILDDT\\ IF IN A CRASH OR DURING TIMESHARING.
; ^THE FOLLOWING IS AN EXCERPT FROM THE ^^FILDDT\\ OUTPUT OF
;THE TRACE BUFFER FROM A RUNNING MONITOR (HOWEVER THE TRACE
;BIT HAD AT THIS POINT BEEN TURNED OFF). IT WAS DONE WITH THE
;_<^^ALT\\_>^Y COMMAND (SO THE OUTPUT WOULD GO TO
;^^LPT:\\) WITH ^^LPT:\\ ASSIGNED TO ^^DSK:\\. ^THE CONTENTS OF THE
;^^.DDT\\ FILE WAS MERELY A NOT-WORD SEARCH OF THE TRACE BUFFER FOR
;0.
;^THE COMMENTS AT THE END OF EACH LINE ARE A RUNNING COMMENTARY ^I ADDED
;TO SHOW WHAT IS GOING ON. ^THE TRACE SHOWS WHAT HAPPENS DURING
;A SINGLE DATA TRANSFER FROM THE -10 TO THE 11.
;.NOFILL.NOJUSTIFY.SKIP
;^^
;30236/	JBTJLT+53,,XTCINT_#	interrupt occured
;30237/	JBTJLT+53,,REMINT_#	it was select request
;30240/	JBTJLT+53,,IDLE28_#	DA28 hdw idle?
;30241/	JBTJLT+53,,FNDUNI_#	yes, so look for UDB
;30242/	JBTJLT+53,,SETKON_#	unit not locked, set up read CW
;30243/	JBTJLT+53,,XTCINT_#	another interrupt
;30244/	JBTJLT+53,,UNIINT_#	done and XKBDDB=0, so CW done
;30245/	JBTJLT+53,,RECUCW_#	done for read of CW
;30246/	JBTJLT+53,,FNDTSK_#	find DDB for task ID
;30247/	JBTJLT+53,,SETACS_#	trace word and set ACs from DDB
;30250/	JBTJLT+53,,RECRFI_#	dispatch on CW type=RFI
;30251/	JBTJLT+53,,SETBIT_#	##set IORRFI in DVXPST and return
;30252/	JBTJLT+53,,CHKPRC_#	can we further co-routine
;30253/	JBTJLT+53,,CHKWAK_#	no, see if we need to wake job
;30254/	JBTJLT+53,,SCNQUE_#	no, look for work
;30255/	JBTJLT+53,,IDLE28_#	##check if DA28 idle
;30256/	JBTJLT+53,,CLRERR_#	yes, but no work so clear it
;30257/	JBTJLT+53,,SETSCN_#	set it scanning and exit
;30260/	DBS_#+43,,XTCIOS_#	someone did GETSTS or something
;30261/	DBS_#+43,,XTCDEV_#	##which looks at DEVIOS
;30262/	DBS_#+43,,XTCDOU_#	dump mode OUT UUO
;30263/	DBS_#+43,,OUTSET_#	set IO bit in DEVIOS
;30264/	##DBS_#+43,,SETACS_#	##and ACs from DDB info
;30265/	##DBS_#+43,,GETMOD_#	##set up hdw mode based on softw mode
;30266/	##DBS_#+43,,RDYCHK_#	##check if unit believed up
;30267/	##DBS_#+43,,PSACT_#	##yes, make us pseudo-active
;30270/	DBS_#+43,,DMPSET_#	copy user IOWDs into DVXIWD
;30271/	DBS_#+43,,OUTCOM_#	common code dump/buffered OUT
;30272/	DBS_#+43,,XOSYNC_#	start synchronization co-routine
;30273/	DBS_#+43,,$COROU_#	##save co-rout return in DVXPRC
;30274/	DBS_#+43,,MAKRFO_#	##no errors, must send RFO
;30275/	DBS_#+43,,FINMS2_#	##make it in T4
;30276/	DBS_#+43,,FINMSG_#	##and finish it
;30277/	DBS_#+43,,ADDSIZ_#	##add transfer size
;30300/	DBS_#+43,,SENDW_#		##try to output it
;30301/	DBS_#+43,,PHASE1_#	##at UUO level
;30302/	DBS_#+43,,XIOWA0_#	##wait for DVXQUE to be zero
;30303/	DBS_#+43,,D28GET_#	##it was, try to get DA28
;30304/	DBS_#+43,,PHS2F_#		##it was idle, start output
;30305/	DBS_#+43,,PHS2F0_#	##not RFI when EOF, so put it out
;30306/	DBS_#+43,,D28XCW_#	##send it; done will be XDNDDB
;30307/	DBS_#+43,,D28OUT_#	##set up hardware for output
;30310/	DBS_#+43,,SETKON_#	##and controller, flush cache
;30311/	DBS_#+43,,XOSYN1_#	##back in synch co-routine
;30312/	DBS_#+43,,CPOJ1$_#	##all done, RFI already seen
;30313/	DBS_#+43,,CPOPJ$_#	##increment DVXPRC, exit co-routine
;30314/	DBS_#+43,,XTCOU0_#	check if counts agree
;30315/	DBS_#+43,,XTCOU1_#	yes, check if bypassing
;30316/	DBS_#+43,,MAKACT_#	make job IO active
;30317/	DBS_#+43,,XTCOU2_#	not bypassing, use WFO
;30320/	DBS_#+43,,MAKWFO_#	build it
;30321/	DBS_#+43,,FINMS2_#	finish it off
;30322/	DBS_#+43,,FINMSG_#	...
;30323/	JBTUPM+103,,XTCINT	####interrupt!!
;30324/	JBTUPM+103,,UNIINT_#	####done for CW output
;30325/	JBTUPM+103,,XDNDDB_#	####where we told it to go
;30326/	JBTUPM+103,,SCNQUE_#	####set bit, and check for work
;30327/	JBTUPM+103,,IDLE28_#	####hardware idle
;30330/	JBTUPM+103,,CLRERR_#	####nothing to do, so clear hdw
;30331/	JBTUPM+103,,SETSCN_#	####set scanner going
;30332/	DBS_#+43,,ADDSIZ_#	add size to CW
;30333/	DBS_#+43,,SENDW_#		try to send it
;30334/	DBS_#+43,,PHASE1_#	at UUO level
;30335/	DBS_#+43,,XIOWA0_#	DVXQUE 0
;30336/	DBS_#+43,,D28GET_#	yes, hdw free
;30337/	DBS_#+43,,PHS2F_#		yes, start it
;30340/	DBS_#+43,,PHS2F0_#	CW send
;30341/	DBS_#+43,,D28XCW_#	send it
;30342/	DBS_#+43,,D28OUT_#	set up hardware
;30343/	DBS_#+43,,SETKON_#	and flush cache and go
;30344/	JBTUPM+103,,XTCINT	my, another interrupt
;30345/	JBTUPM+103,,UNIINT_#	done for CW
;30346/	JBTUPM+103,,XDNDDB_#	where we told it to go
;30347/	JBTUPM+103,,SCNQUE_#	set bit, exit looking for work
;30350/	JBTUPM+103,,IDLE28_#	hdw free
;30351/	JBTUPM+103,,CLRERR_#	yes, no work, clear hdw
;30352/	JBTUPM+103,,SETSCN_#	set up scanner
;30353/	JBTUPM+103,,XTCINT_#	another interrupt
;30354/	JBTUPM+103,,REMINT_#	select request
;30355/	JBTUPM+103,,IDLE28_#	check if we really were idle
;30356/	JBTUPM+103,,FNDUNI_#	find UDB
;30357/	JBTUPM+103,,SETKON_#	XUBLOK 0 (so not data) so read CW
;30360/	JBTUPM+103,,XTCINT_#	interrupt
;30361/	JBTUPM+103,,UNIINT_#	done for CW
;30362/	JBTUPM+103,,RECUCW_#	which we read
;30363/	JBTUPM+103,,FNDTSK_#	get DDB from task ID
;30364/	JBTUPM+103,,SETACS_#	got one, set up other ACs
;30365/	JBTUPM+103,,RECWFI_#	dispatch for CW type
;30366/	JBTUPM+103,,DDBIO_#	start data transfer
;30367/	JBTUPM+103,,NXTIOW_#	get next (really 1st) IOWD
;30370/	JBTUPM+103,,NXTIO0_#	...
;30371/	JBTUPM+103,,SBINIO_#	got one, do we need to copy
;30372/	JBTUPM+103,,STOUTP_#	no, map it and start output
;30373/	JBTUPM+103,,SETKON_#	flush cache and do it
;30374/	JBTUPM+103,,CHKPRC_#	look for progress on co-routines
;30375/	JBTUPM+103,,CHKWAK_#	none, look for wake requests
;30376/	JBTUPM+103,,SCNQUE_#	none, look for work
;30377/	JBTUPM+103,,IDLE28_#	##check if idle
;30400/	JBTUPM+103,,XTCINT_#	no, leave things alone till interrupt
;30401/	JBTUPM+103,,DDBINT_#	DDBIO set XKBDDB so we get here
;30402/	JBTUPM+103,,SETACS_#	set up all ACs
;30403/	JBTUPM+103,,DDBIO_#	continue data transfer
;30404/	JBTUPM+103,,NXTIOW_#	look for IOWD
;30405/	JBTUPM+103,,NXTIO0_#	...
;30406/	JBTUPM+103,,IOREDY_#	no more, we are finished
;30407/	JBTUPM+103,,FINDDB_#	finish I/O for DDB
;30410/	JBTUPM+103,,CHKWAK_#	see if UUO level needs to wake
;30411/	JBTUPM+103,,XTWAKE_#	yes, do it
;30412/	JBTUPM+103,,SCNQUE_#	look for work
;30413/	JBTUPM+103,,IDLE28_#	##are we idle
;30414/	JBTUPM+103,,CLRERR_#	##yes but no work, clear hdw
;30415/	JBTUPM+103,,SETSCN_#	set up scanner and exit
;30416/	DBS_#+43,,XTCIOS_#	someone else
;30417/	DBS_#+43,,XTCDEV_#	##trying to look at DEVIOS
;.FILL.JUSTIFY.SKIP
;\\
; ^WHEN USING THE EXECUTION TRACE, REMEMBER THAT ^^XTCSEC\\ IS
;CALLED ONCE A SECOND; IF YOU DO NOT PROMPTLY TURN OFF TRACING
;(BY CLEARING THE SIGN BIT OF ^^ETRFLG\\ WITH
;^^FILDDT\\ OR WITH AN ^^ETRCOF\\ CALL) THIS WILL GRADUALLY WIPE
;OUT ALL INFORMATION IN THE CIRCULAR BUFFER (UNLESS
;THE NO-WRAP BIT IN ^^ETRFLG\\ WAS SET).
;-
MLP
XTCEND::END