Google
 

Trailing-Edge - PDP-10 Archives - BB-J724B-SM_1982 - sources/xdte10.p11
There are 27 other files named xdte10.p11 in the archive. Click here to see a list.
	.SBTTL	XDTE10 - driver for a DECsystem-10 through a DTE-20

; This module replaces the DL10 module in the DN60 front-end
; program to use the DTE-20 on a 1090 configuration rather
;  than the DTE-20 on the 2040 or the DL10 on a 1070.
;
; Note that the hardware is the same for TOPS-10 and TOPS-20, but
;  the TOPS-10 version is driven by D60SER/D6SINT, which interface
;  to the TOPS-10 DTESER module for the DN60.  The TOPS-20 version
;  is driven by the TOPS-20 module FESRV which interfaces to
;  DTESRV.  FESRV was enhanced for the DN60 project, but
;  is not special-purpose as D60SER/D6SINT is.
;
;  This module conditionally assembles to interface to FESRV on
;   TOPS-20 by setting the switch FTFEDV to a nonzero value.
;
; XDTE10.P11 is a replacement for the old HDTE10.P11 to use the
;common protocol module XTENCM and its standard interface.

.REPT 0

Things still to do, loose ends:

o	separate common code for XDTE10 and XDTE20 (and perhaps XDMC20)

o	move DLGONE to driver

o	change DLACKF to be .WORD 0

o	move DTE save code to TRPINT

.ENDR;.REPT 0

.REPT 0


                          COPYRIGHT (c) 1982,1981,1980, 1979
            DIGITAL EQUIPMENT CORPORATION, maynard, mass.

THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH  LICENSE AND WITH THE
INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR  ANY  OTHER
COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
TRANSFERRED.

THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE  WITHOUT  NOTICE
AND  SHOULD  NOT  BE  CONSTRUED  AS  A COMMITMENT BY DIGITAL EQUIPMENT
CORPORATION.

DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR  RELIABILITY  OF  ITS
SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.

.ENDR;.REPT 0
VDTE10=033				;XDTE10 edit number

VEDIT=VEDIT+VDTE10			;DN60 total edit number

.REPT 0

Revision History

Edit	Who	Date		What

5(31)	KR	13-Oct-80	Strip out all common code, implement standard interface
				This new module is (very) loosely based on 4(30) of
				HDTE10.
5(32)	RLS	28-JAN-81	Insert FTFEDV condtional code to create a TOPS-20/FESRV
				protocol driver. Primary difference is that the DN60
				header comes as an indirect message and any data
				comes as a separate FE header,indirect transfer pair.
				Also, each indirect part must be explicitly ack'd.

5(33)	RLS	12-JUN-81	Insert FTP5 conditional code to create TOPS-20
				release 5 protocol.  Primary differences are an
				expanded header(up to 8 words) and the exclusive
				use of direct mode transfers.  The response 
				header includes a 2 word device status and a 2
				word line status.  TENTSK may elect to return
				no data on a read dta fcn - handled by setting
				the queue size to zero and ringing the 10 doorbell.
				Similarly the deposit fcn doesn't even return a
				header...no header returned => no data returned.
.ENDR;.REPT 0
.REPT 0

This section contains the DTE-20 driver and the queued protocol
interface conforming to the RSX-20F specifications for
communication between the PDP-11 and DECsystem-10.

This module contains device-dependent code for talking to
the TOPS-10 modules D60SER/D6SINT and DTESER.  It calls a common
protocol module, XTENCM.P11, via the standard interface, namely
calling either WAKTEN to wake up the DL10/DTE task if the -10
has had some sort of error, or WAKFNC to provide a function and
wake up the task if it has work to do.


The following symbols defined in this module are referred to by the
rest of the DN60 code:

DLSTCS		routine to store stopcode value
DSPDLT		once/tick timer code
DSPDLS		once/second timer code
INITDL		initialize -10 interface hardware
DLRESP		send back response to -10
BLECHI		block transfer of input data
BLECHO		block transfer of output data
BYTCHI		byte transfer of input data
BYTCHO		byte transfer of output data

DT10DS		two word device status - FTP5
DT10LS		two word line status   - FTP5

The following symbols defined elsewhere are used by this module:

T.HDR		displacement of header in DL10/DTE task block
  T.FN		  function code
  T.RES		  result code
  T.DEV		  device number
  T.LIN		  line number
  T.LNG		  (word) length of data

WAKTEN		routine to wake DL10/DTE task
WAKFNC		routine to give a function to DL10/DTE task and wake it
TENSLP		routine to put DL10/DTE task to sleep waiting for EBTENI
DLGONE		cell set to -1 when -10 interface is dead, 0 when it is alive
		note, driver alone can set or clear it

 This module implements the DN60-DTE interaction as a single state
machine, pieces of which are executed at both interrupt and non-interrupt
level.  The subroutine NXTPRT does the next part of the state machine;
it has one of six interrupt conditions (I..xxx) set in cell INTCND. Each
state examines interrupt conditions in a fixed order, and decides upon
a new state to enter.

 The interrupt conditions are generated by both the DTE hardware and the
DN60 software; the hardware conditions are to-10 done interrupt, to-11 done
interrupt and doorbell interrupt.  The interrupt handler generates another
condition, TGHA doorbell, if valid examine is not on in the status word from
the -10 on a doorbell.  The remaining two interrupt conditions are 1) response
ready (generated by DLRESP which the common module calls when it has finished
building the reply to a request) and 2) TGHA timer expired, which means the
once a second code has decremented the TGHA timer to zero.

.ENDR;.REPT 0
	.SBTTL		Symbol definitions

;Parameters

.IIF NDF,FTP5,FTP5=0			;default to version 4 rpotocol

.IIF NE,FTP5,FTFEDV=0			;if version 5 protocol, can't have 4

.IIF NDF,FTFEDV,FTFEDV=0		;default to no FE device interface

.IIF NE,FTFEDV,MAXDAT=376		;FE device will only xfer small amount

.IIF NDF,MAXDAT,MAXDAT=^D5*CHDATL 	;max data transferred in a single request

.IIF NDF,TGHMAX,TGHMAX=5.		;max number of seconds to wait for TGHA

.IIF NDF,DLYPRM,DLYPRM=0		;make no DTE delay default


;Define more mnemonic interrupt bits

I..10D=TS.XNT				;-10 done
I..11D=TS.ETD				;-11 done
I..DBL=TS.XEE				;-11 doorbell
I..TGH=TS.MPE				;TGHA doorbell (software bit)
I..RSP=TS.EPE				;DLRESP (software bit)
I..TMO=TS.XER				;TGHA timer expire (software bit)

;(The hardware error bits used to define the software interrupt conditions
;are guaranteed never to be on during the state machine, as the interrupt
;code traps them before dispatching to the state machine.)

;DN60 function definitions

DF.RED=1.				;READ DATA INTO THE PDP-10
DF.WRT=2.				;WRITE DATA FROM THE PDP-10
DF.RDS=3.				;READ DEVICE STATUS
DF.WDC=4.				;WRITE DEVICE COMMAND
DF.RLS=5.				;READ LINE STATUS
DF.WLC=6.				;WRITE LINE COMMAND
DF.RPS=7.				;READ PORT STATUS
DF.WPC=8.				;WRITE PORT COMMAND
DF.EXA=9.				;examine function
DF.DEP=10.				;deposit function

DF.MAX=DF.DEP				;max fcn code

;NOTE:	Even valued functions have indirect data from the ten and odd valued
;	functions do not(they send indirect data to the ten). This fact is used
;	in FE device service to determine whether anything follows the FEH from
;	the ten. Non-FE service just tests the indirect data flag in DT11FN.

;The driver needs to know DF.EXA and DF.DEP, since it fulfills them at interrupt
;level instead of dispatching to the task.
.SBTTL		DTE20 HARDWARE BITS

TE.BRL=	5		;(?)DTE bus request level
TE.LVL=	PR.TEN		;PROCESSOR LEVEL FOR DTE20 INTERRUPTS
TE.VEC=774		;VECTOR FOR DTE20 INTERRUPTS

TE.DYC=0		;DELAY COUNTER
TE.XW3=2		;DEPOSIT OR EXAMINE WORD 3
TE.XW2=4		;DEPOSIT OR EXAMINE WORD 2
TE.XW1=6		;DEPOSIT OR EXAMINE WORD 1
TE.XA1=10		;TEN ADDRESS WORD 1

TS.DEP=B12		;DEPOSIT
TS.POF=B11		;EXAMINE/DEPOSIT PROTECT OFF
TS.PEX=B15		;PHYSICAL EXAMINE

TE.XA2=12		;TEN ADDRESS WORD 2
TE.XBC=14		;TO-10 BYTE COUNT (?)
TE.EBC=16		;TO-11 BYTE COUNT

TS.IFB=B15		;I FLIPFLOP BIT
TS.ZST=B14		;ZSTOP
TS.EBM=B13		;TO 11 BYTE MODE

TE.XAD=20		;TO-10 PDP-11 MEMORY ADDRESS
TE.EAD=22		;TO-11 PDP-11 MEMORY ADDRESS
TE.XDT=24		;TO-10 PDP-11 DATA WORD
TE.EDT=26		;TO-11 PDP-11 DATA WORD
TE.DG1=30		;DIAGNOSTIC WORD 1
TE.DG2=32		;DIAGNOSTIC WORD 2
TS.RST=B6		;RESET DTE20


TE.STW=34		;STATUS WORD

TS.XNT=B15		;TO-10 NORMAL TERMINATION
TS.XTS=B14		;TO-10 NORMAL TERMINATION STATUS
TS.XER=B13		;TO-10 ERROR TERMINATION (AND STATUS)
TS.XEC=B12		;CLEAR TO-10 ERROR TERMINATION
TS.XEE=B11		;10 REQUESTED -11 INTERRUPT
TS.RES=B11		;REQUEST -11 STATUS
TS.EIS=B10		;10 REQUESTS 11 INTERRUPT STATUS
TS.MPE=B9		;11 MEMORY PARITY ERROR
TS.EEX=B8		;11 REQUESTED 10 INTERRUPT
TS.ETD=B7		;TO-11 TRANSFER DONE
TS.ENT=B6		;TO-11 NORMAL TERMINATION
TS.EEE=B5		;11 INTERRUPT ENABLE
TS.EPE=B4		;E-BUS PARITY ERROR
TS.RM=B3		;RESTRICTED MODE
TS.DEI=B3		;DISABLE -11 INTERRUPT
TS.XDN=B2		;DEPOSIT/EXAMINE DONE
TS.EET=B1		;TO-11 ERROR TERMINATION (AND STATUS)
TS.IEN=B0		;INTERRUPTS ENABLED
TS.CET=B0		;CLEAR TO-11 ERROR TERMINATION

TE.DG3=36		;STATUS WORD 3
TS.TBM=B0		;TO TEN BYTE MODE
	.SBTTL		RSX-20F queued protocol definitions

;THIS DEFINES THE DEVICE QUEUE POINTERS AND FUNCTION CODES
; FOR THE RSX-20F QUEUED PROTOCOL.

;	DEVICE QUEUE POINTERS

DLDCTY	=1	;DEVICE CODE FOR CTY
DLDL11	=2	;DEVICE CODE FOR DL11
DLDH11	=3	;DEVICE CODE FOR DH11 (1)
DLDDLS	=4	;DEVICE CODE FOR DATA LINE SCANNER (1)
DLDLPT	=5	;DEVICE CODE FOR LPT
DLDCDR	=6	;DEVICE CODE FOR CDR
DLDCLK	=7	;DEVICE CODE FOR CLOCK
DLDPFE	=10	;PSEUDO DEVICE FOR FE
DLDDAS	=12	;DN61 DEVICE CODE 

DLDCPU	=200	;PSEUDO DEVICE PDP10 CPU
DLDKLE	=201	;KL ERROR PSEUDO DEVICE

; TO ELEVEN QUEUE ENTRY

;	FUNCTION CODE DEFINITIONS

DTFRQD	=1	;REQUEST DEVICES
DTFHAD	=2	;HERE ARE DEVICES
DTFSTR	=3	;STRING DATA
DTFLNC	=4	;LINE/CHARACTER DATA
DTFRDS	=5	;RETURN DEVICE STATUS
DTFSDS	=6	;SET DEVICE STATUS
DTFHDS	=7	;HERE IS DEVICE STATUS
DTFDES	=10	;DEVICE ERROR STATUS
DTFRTD	=11	;RETURN TIME OF DAY
DTFHTD	=12	;HERE IS TIME OF DAY
DTFFOD	=13	;FLUSH OUTPUT DEVICE QUEUE
DTFSNA	=14	;SEND ALL 
DTFTDU	=15	;DEVICE DIAL UP
DTFTHU	=16	;DEVICE HANG UP
DTFSAK	=17	;ACKNOWLEDGE DEVICE DONE
DTFXOF	=20	;X-OFF (TTY ONLY)
DTFXON	=21	;X-ON (TTY ONLY)
DTFSTS	=22	;SET TTY SPEED
DTFSLA	=23	;set line allocation
DTFBTP	=24	;11 REBOOT WORD
DTFAKA	=25	;ACK ALL
DTFSPT	=26	;START/STOP LINE
DTFEDR	=27	;ENABLE/DISABLE REMOTES
DTFLDR	=30	;LOAD LP RAM
DTFLDV	=31	;LOAD LP VFU
DTFDAS	=32	;DN60 FUNCTION DATA
DTFFNM	=33	;1 GREATER THAN MAX FUNCTION
	.SBTTL		DTE20 COMMUNICATION AREA OFFSETTS (WORD NAMES)

;The comm region consists of a circular list of blocks - one for each processor
;communicating with each other. Each block is composed of a base area which has
;some info about the "owning" processor and a series of "TO" blocks, one for 
;each processor to which the owning processor communicates. In theory, the size
;of each area may vary but only in 8 36-bit word units.
;A processor sends status info to another processor by setting the data in
;his owned "TO" block for that processor and,similarly, reads info for himself
; from that processor by looking at that processor's "TO" block for himself.
;The 11 addresses data in the comm region relative to an address space that
;is individually relocated for the particular dte through which the 11 examines
;the 10's memory. Immediately preceeding the comm region is a series of single
;words, one for each connected processor.  The relative address zero points at
;the particular word associated with the processor who is looking at 10 memory.
;This word contains the processor's own identifying number and the offset,
;relative to the beginning of the comm region, of the processor's own area.
;The beginning of the comm region is located in the processor's address space
; at <processor number>+1. Thus the address of the processor's own area is 
;located at "offset"+<processor number>+1.
;The 11 examines/deposits 36 bit words in 10 memory - these are formatted in
;the 11 as three consective 16 bit words:
;	word 0 - low order 4 bits	- 10 word bits 0-3
;	word 1				- 10 word bits 4-19
;	word 2				- 10 word bits 20-35

;11's processor word - relative address 0
;	xam word 1			;must be zero
;	xam word 2
;	 high byte			;processor number for me
;	 low  byte			; unused
;	xam word 3			; offset to my area relative to beg of
					; comm region
;processor's own area

;	base block offsets

PBPID=0		;PROCESSOR IDENTIFICATION WORD
 ;	XAM WORD 1
  PB.TEN=10	;this processor is a 10
  PB.VER=7	;mask for comm version number
 ;	xam word 2
 ;	high byte = protocol version being used
 ;	low  byte
  PB.NPR=370	;mask for number of processors in this area
  PB.SIZ=7	;mask for size of base area(in 8 word units)
 ;	xam word 3
 ;	word = processor name

PBPNA=1		;POINTER TO COMM AREA OF NEXT PROCESSOR (CIRC LIST)
PBCPS=2		;CLOCK CPS COUNT
PBTOD=3		;TIME OF DAY
PBDAT=4		;DATE
PBPW1=5		;keepalive count
PBPW2=6		;PROCESSOR STATUS WORD2
PBPW3=7		;PROCESSOR STATUS WORD3
PBPW4=10	;PROCESSOR STATUS WORD4
PBPW5=11	;PROCESSOR STATUS WORD5
PBPW6=12	;PROCESSOR STATUS WORD6
PBPW7=13	;PROCESSOR STATUS WORD7
PBPW10=14	;PROCESSOR STATUS WORD10
PBPW11=15	;PROCESSOR STATUS WORD11
PBPW12=16	;PROCESSOR STATUS WORD12
PBPW13=17	;PROCESSOR STATUS WORD13

PBASIZ=20	;size of base area = offset to 1st TO block

;	TO block offsets

TOPID=0		;FOR PROCESSOR IDENTIFICATON WORD
 ;	xam word 1
  TO.TEN=10		;this connection is to a 10
  TO.DTE=4		;a DTE connects these two processors
  TO.DTN=3		;mask for the DTE number
 ;	xam word 2
 ;	high byte unused
 ;	low  byte
  TO.PRO=370		;mask for protocol in use: 0=RSX20F(TOPS-20 version 4
			;			   1=MCB
			;			   2=DN60(TOPS-20 version 5)
  TO.SIZ=7		;mask for size of this TO block
 ;	xam word 3
 ;	word = processor number that this block is "TO"

TOPCA=1		;POINTER TO COMM AREA OF THE PROCESSOR ASSOC WITH THIS BLOCK
 ;	xam word 1 - unused
 ;	xam wrod 2 - unused
 ;	xam word 3
 ;	word = offset to "TO" processor's own area relative to beginning of comm region

TOSTAT=2	;COMMUNICATION STATUS WORD
 ;	xam word 1
  TO.PFL=10		;power fail indicator
  TO.REL=4		;reload 11 indicator
  TO.INI=2		;MCB,DN60 protocol initializing flag
  TO.VEX=1		;valid examine flag - guaranteed to be set
 ;	xam word 2
  TO.QP=100		;queued protocol in use
  TO.FWD=4		;do a word mode xfer(16 bit)
  TO.IND=2		;indirect transfer
  TO.IT=1		;xfer in progress from me to him
 ;	xam word 3
 ;	high byte = 10 queue count
 ;	low  byte = 11 queue count

TOXFSZ=3	;queue size word
 ;	xam word 1 - unused
 ;	xam word 2 - unused
 ;	xam word 3
 ;	word(12 bits) = numbers of bytes in this transfer

		;remaining 4 words are not relavent to the 11
	.SBTTL		Macro definitions

;Macros to disable and enable interrupts from the dte

	.MACRO	DTEOFF
	MOV	#TS.DEI,TE.STW(R5) ;disable dte interrupts
	.ENDM
	.MACRO	OFFDTE
	MOV	DTEBAD,-(SP)
	ADD	#TE.STW,(SP)
	MOV	#TS.DEI,@(SP)+ ;disable dte interrupts
	.ENDM

	.MACRO	DTEON
	MOV	#TS.EEE,TE.STW(R5) ;enable dte interrupts
	.ENDM
	.MACRO	ONDTE
	MOV	DTEBAD,-(SP)
	ADD	#TE.STW,(SP)
	MOV	#TS.EEE,@(SP)+ ;enable dte interrupts
	.ENDM

;Macro to declare next state in state machine

;Call	NXTINT			to define following code as next state
;or	NXTINT	#name		to define "name" as next state
;or	NXTINT	cell		to define contents of cell as next state

.MACRO NXTINT ADR,?TAG
.IF B,<ADR>
	MOV	#TAG,NXTPC
	GOBACK

TAG:
.IFF;.IF B,<ADR>
	MOV	ADR,NXTPC
.ENDC;.IF B,<ADR>
.ENDM NXTINT

;Macro to go back to state dispatch level

.MACRO GOBACK
.IF NE,DTBUG
	JMP	NXTCN1			;try to schedule another condition
.IFF;.IF NE,DTBUG
	JMP	NXTCND
.ENDC;.IF NE,DTBUG
.ENDM GOBACK

;Macro to define state entry block for a state -- must be used at state entry point

;Contains the interrupt bits that cause 11err state, the bits that cause
;10err state, followed by pairs of masks and dispatch addresses (terminated
;by a zero word).

.MACRO INTTYP	ERR11,ERR10,ARG,?TAG
STBDSP=.
E10DSP=.-STBDSP
	.WORD	ERR10			;means -10 has done protocol wrong and
					; should be considered down
STBDSP=.-STBDSP
.IRP DISP,<ARG>
	DSPENT	DISP			;generate bit mask, dispatch address
.ENDR;.IRP DISP,<ARG>
	.WORD	0
TAG:
.ENDM INTTYP

;Macro to define dispatch entries within state entry block

.MACRO DSPENT BITS,ADR
	.WORD	BITS,ADR
.ENDM DSPENT

;Macro for call that only stores PC (i.e. is really a JMP)

.MACRO XCALL ADR
	CALL	ADR
.ENDM XCALL

;Macro to test carry and XCALL an error routine if set

.MACRO IFCRY WHERE,?TAG
	BCC	TAG
	XCALL	WHERE
TAG:
.ENDM IFCRY

;Macro to test equal and XCALL an error routine if not set

.MACRO IFNE WHERE,?TAG
	BEQ	TAG
	XCALL	WHERE
TAG:
.ENDM IFNE

.MACRO IFEQ WHERE,?TAG
	BNE	TAG
	XCALL	WHERE
TAG:
.ENDM IFEQ

;Macro to do DTE examine

;Call	EXAM	disp for examine,dest		to examine and copy to dest
;	EXAM	disp for examine,,		to examine and leave in TE.XW1-3

.MACRO EXAM LOWADR,DEST,TAG,?TAG1
	CLR	TE.XA1(R5)		;set examine EVA, protectin off, bits 13-19 0
	MOV	LOWADR,TE.XA2(R5)	;set low order address, start examine
	CALL	DLWEDN			;wait for examine done to set
	BCC	TAG1
	CLR	TE.XA1(R5)		;set examine EVA, protectin off, bits 13-19 0
	MOV	LOWADR,TE.XA2(R5)	;set low order address, start examine
	CALL	DLWEDN			;wait for examine done to set
	BCS	TAG			;is timeout, don't store value
TAG1:
.IF NB,<DEST>
	MOV	TE.XW1(R5),DEST		;store first word of result (KL bits 0-3
					; right justified)
	MOV	TE.XW2(R5),DEST+2	;store bits 4-19
	MOV	TE.XW3(R5),DEST+4	;store bits 20-35
.ENDC;.IF NB,<DEST>
.IIF NE,FTRACE,	MFPS	-(SP)
	TRACE	TRCDTE,<TE.XW1(R5),TE.XW2(R5),TE.XW3(R5)>
.IIF NE,FTRACE,	MTPS	(SP)+
.ENDM EXAM


;Macro to do DTE deposit

;Call	DEPO	disp for deposit,source		to copy source and deposit
;	DEPO	disp for deposit,,		to use contents of TE.XW1-3

.MACRO DEPO LOWADR,SRC,TAG,?TAG1
.IF NB,<SRC>
	MOV	SRC,TE.XW1(R5)		;get first word (KL bits 0-3)
	MOV	SRC+2,TE.XW2(R5)	;get second word (bits 4-19)
	MOV	SRC+4,TE.XW3(R5)	;get third word (bits 20-35)
.ENDC;.IF NB,<SRC>
	TRACE	TRCDTE,<TE.XW1(R5),TE.XW2(R5),TE.XW3(R5),LOWADR>
	MOV	#TS.DEP,TE.XA1(R5)	;set deposit EVA, protection on, bits 13-19 0
	MOV	LOWADR,TE.XA2(R5)	;move low order address and start deposit
	CALL	DLWEDN			;wait for done flag
	BCC	TAG1
	MOV	#TS.DEP,TE.XA1(R5)	;set deposit EVA, protection on, bits 13-19 0
	MOV	LOWADR,TE.XA2(R5)	;move low order address and start deposit
	CALL	DLWEDN			;wait for done flag
	BCS	TAG			;carry will be set if -10 times out
TAG1:
.ENDM DEPO
	.SBTTL		Data storage

; THE DTE DATA BASE.


DTIDBL:	.WORD	0	;KEEP DOORBELL INTERRUPT COUNT HERE
DTIXDN:	.WORD	0	;KEEP TEN DONE INTERRUPT COUNT HERE
DTIEDN:	.WORD	0	;ELEVEN DONE INTERRUPT COUNT HERE
DTEPCA:	.WORD	0	;ADDRESS OF PRIV OFFSET TABLE ENTRY
DTPSTA:	.WORD	0	;OUR DTE20 STATUS WORD AND
DTEBAD:	.WORD	0	; DTE ADDRESS (INITTED AT STARTUP)
DTEDTO:	.WORD	0	;DEPOSIT/EXAMINE  TIMEOUT
			;ALSO USED FOR STORING
			;INTERRUPT VECTOR LOCATION
			;IN CHK11.P11 MODULE
DLACKF:	.WORD	0	;NON-ZERO WHEN IN PRIMARY PROTOCOL
DTQSTA:			;ZEROED AT STARTUP
DT11ST:	.BYTE	0	;STATE OF TO-11 MECHANISM
DT10ST:	.BYTE	0	;AND OF TO-10

DT10AK:	.WORD	0	;IF NON-ZERO, ED DATA EXPECTED AND MUST BE ACKED
DTPTCT:	.WORD	0	;COUNT OF MESSGES PUNTED

;	POINTERS TO COMMUNICATIONS AREA

DLCMBS:	.WORD	0	;BASE OF COMMUNICATION AREA
DLMYPN:	.WORD	0	;MY PROCESSOR NUMBER
DLDPOF:	.WORD	0	;DEPOSIT OFFSET FROM EXAMINE


;	PROCESSOR IDENTIFICATION TABLE

;	DTPIDT FORMAT:

;	5 WORDS/ENTRY
;	16 ENTRYS IN THE TABLE ONE FOR EACH PROCESSOR IN COMMUNICATION 
;	COMMUNICATION NUMBERS ARE LIMITED TO THE RANGE 0-15.

;	(PROCESSOR 0) DTPIDT:	ADDRESS OF DTE20 TO ACCESS THIS PROCESSOR
DTENM=0
;	(PROCESOR 0)		ADDRESS TO COMMUNICATE TO PROCESSOR 0
DTEMYN	=2
;	(PROCESSOR 0)		ADDRESS TO COMMUNICATE TO PROCESSOR 0 (WRITE)
DTDMYN	=4
;	(PROCESSOR 0)		ADDRESS FROM GENERAL 
DTEHSG	=6
;	(PROCESSOR 0)		ADDRESS FROM SPECIFIC
DTEHSM	=10

;	(PROCESSOR 1)	ADDRESS OF DTE20 TO USE TO ACCESS THIS PROCESSOR
;	...........

DTPIDT:	
	.NLIST
	.REPT	16.*5.
	.WORD	0
	.ENDR
	.LIST

DTXTM3:	.WORD	0		;EXAMINE WORD 3 (TEMP STORAGE) TO BE
DTXTM2:	.WORD	0		;EXAMINE WORD 2 -USED ONLY BECAUSE EXAMINE
DTXTM1:	.WORD	0		;EXAMINE WORD 1 - OR DEPOSIT 
				;		MAY FAIL AND 
				;		MUST BE REDONE
DTSTT:	.WORD	0		;TO 10 STATUS
	.WORD	0
	.WORD	0
DTQCNT	=DTSTT+4		;BOTH OF BELOW
DT10QC	=DTSTT+4		;TO 10 QUEUE COUNT
DT11QC	=DTSTT+5		;TO 11 QUEUE COUNT

DTKPLV:	.WORD	0		;last successful 11 keep alive
NXKPLV:	.WORD	0		;next time we really want to do one

.IF NE,DEBUG
DTESAV:
	.NLIST
	.REPT	20		;FOR SAVING DTE20 REGISTERS
	.WORD	0
	.ENDR
	.LIST
.ENDC ;.IF NE,DEBUG


;Queued protocol header input buffer

DT11HD:
.IF EQ,FTP5
	.WORD	0			;count of bytes in this message
DT11FN:	.WORD	0			;queued protocol function code
DT11DV:	.WORD	0			;queued protocol device number
	.WORD	0			;unused
.IF NE,FTFEDV
DT11UC:	.WORD	0			;FE#,,BYTE COUNT TO FOLLOW
.ENDC					;DEFINED ONLY FOR FE DEVICES
.ENDC	;.IF EQ,FTP5
D11HDL=.-DT11HD				;length of to 11 direct header

DT11DF:	.WORD	0			;DN60 function code
DT11AD:	.WORD	0			;address (exam/depo) or DN60 line,,dev
DT11DT:	.WORD	0			;data (deposit) or length of indirect msg
.IF NE,FTP5
DT11A3:	.WORD	0			;arg3 - unused
DT11A4:	.WORD	0			;arg4 - unused
DT11A5:	.WORD	0			;arg5 - unused
DT11A6:	.WORD	0			;arg6 - unused
DT11A7:	.WORD	0			;arg7 - unused
.ENDC	;IF NE,FTP5
D11DFL=.-DT11DF				;length of to 11 DN60 header

.IF NE,FTFEDV

DTACKR:	.WORD	0			;ack flag - nonzero => ack must be sent

; THIS HEADER IS FOR SENDING "ACK" TO THE TEN
;  EACH TIME 11 RECEIVED INDIRECT DATA.

DTAKHD:	.WORD	0			;NO OF BYTES IN THIS HEADER
DTAKFN:	.WORD	0			;ACK FUNCTION CODE
DTAKDV:	.WORD	0			;FE DEVICE CODE
	.WORD	0			;unused
DTAKUC:	.WORD	0			;HAS FE# RIGHT JUSTIFIED
.ENDC ;.IF NE,FTFEDV

;Queued protocol header output buffer

.IF NE,FTP5
RSPSIZ:	.WORD	0			;size of response header
.ENDC	;IF NE,FTP5

DT10HD:
.IF EQ,FTP5
	.WORD	0			;count of bytes in this message
DT10FN:	.WORD	0			;queued protocol function code (must be 32)
DT10DV:	.WORD	0			;queued protocol device number (must be DLDDAS)
	.WORD	0			;unused
.IF NE,FTFEDV				;DEFINED ONLY FOR FE DEVICES
DT10UC:	.WORD	0			;FE#,,BYTE COUNT TO FOLLOW
.ENDC ;NE FTFEDV
.ENDC	;.IF EQ,FTP5
D10HDL=.-DT10HD				;length of to ten direct header

DT10DF:	.WORD	0			;DN60 function code
DT10AD:	.WORD	0			;address (exam/depo) or DN60 line,,dev
DT10DT:	.WORD	0			;data (deposit) or length of indirect msg
.IF NE,FTP5
DT10A3:	.WORD	0			;return val3 - unused
DT10DS:	.WORD	0,0			;device status
DT10LS:	.WORD	0,0			;line status
.ENDC	;IF NE,FTP5

D10DFL=.-DT10DF				;length of to ten dn60 header

;Queued protocol comm-region status

TCSTFX:	.BLKW	3			;status word from -10

;Queued protocol data buffers (indirect part)

INBUF:					;input data buffer

OUTBUF:					;output data buffer
	.BLKB	MAXDAT

;Buffer control cells (used by BLECHI, BLECHO, BYTCHI, BYTCHO)

OUTPTR:	.WORD	0			;current output pointer
OUTCTR:	.WORD	0			;bytes left to go till output overflow

INPPTR:	.WORD	0			;current input pointer
INPCTR:	.WORD	0			;bytes left to go till input runs out

;TGHA Control cells

TGHCNT:	.WORD	0			;0 means TGHA not running, > 0 means seconds
					; before TGHA timer expires

;State machine dispatch information

NXTPC:	.WORD	0			;next state address
TNXTPC:	.WORD	0			;copy of NXTPC while TGHA is running

.IF NE,DTBUG
WITHIN:	.WORD	0			;indicate we are within the state machine
.ENDC;.IF NE,DTBUG

;State machine interrupt conditions

INTCND:	.WORD	0			;interrupt conditions active at current
					; entry into state machine
;State machine stack

.IIF NDF,STKLEN,STKLEN=40.		;default number of words of stack

INTGW:	.WORD	0			;guard word for overwriting stack
	.BLKW	STKLEN			;body of stack
INTSTK:					;address for start of stack + 2

STATSP:	.WORD	0			;current state machine stack pointer
INTSP:	.WORD	0			;current caller (of state machine) stack pointer

;-10 link state information

;DLGONE:	.WORD	0			;0 when talking, -1 when down
					;actually defined elsewhere
PROTER:	.WORD	0			;when DLGONE = -1, 0=ten down, 1=protocol
					; error
;Debugging information

.IF NE,DTBUG

LSTTWC:	.BLKW	STKLEN			;copy of stack for last caller of TENDWN
SAVSTK:	.WORD	0			;tag for start of saved stack and pointer
					; save area
LSTINT:	.WORD	0			;interrupt conditions on last running of state
					; machine
INTFLG:	.WORD	0			;flag that we are within DTE interrupt
.ENDC;.IF NE,DTBUG
	.SBTTL		DTE initialization

INITDL:					;initialize DTE communications
	SAVE	<R5>			;save standard hardware register
	PIOFF
	MOV	DTEBAD,R5		;get hardware address
	TST	DLACKF			;are we in primary protocol?
	BEQ	14$			;no, just try to start it
	MOV	#50,R2			;number of tries
	MOV	#TS.RST,TE.DG2(R5)	;yes, reset DTE-20
10$:	CALL	CHKTEN			;check on -10's health
	BCS	14$			;dead, go try to start it up again
	SOB	R2,10$			;keep trying till count exhausted
.IF NE,DTBUG
	INC	#0
.ENDC;.IF NE,DTBUG
99$:	PION
	RESTOR	<R5>			;restore registers
	RETURN
14$:	CLR	DLACKF			;indicate out of primary protocol
	MOV	#TS.EEX,TE.STW(R5)	;ring -10 doorbell to wake it up
	MOV	#50,R2			;times to try
15$:	CALL	CHKTEN			;see if up now
	BCC	19$			;yes, mark it up
	SOB	R2,15$			;keep trying
.IF NE,DTBUG
	INC	#0
.ENDC;.IF NE,DTBUG
	BR	99$			;give up if takes too long
19$:	TRACE	TRCPRO,<R2,JIFCLK>
	MOV	#-1,DLACKF		;mark primary protocol runnning
	CLR	DLGONE			;mark -10 up
	CALL	DLINDB			;setup DTE block(s)
	BCS	21$			;if error, die
	CALL	INISTA			;initialize state machine
	BR	99$			;return
21$:					;here because -10 looked up but was
					; really down
	CLR	DLACKF			;flag primary protocol not running
	MOV	#-6,DLGONE		;note ten is down
	BR	99$			; and exit
	.SBTTL		Stopcode processing

DLSTCS:					;here on stopcode to ask -10 to reload us
	TST	DLGONE			;see if -10 alive
	BNE	99$			;no, no chance at asking him to reload either
.IF NE,DTBUG
	TST	STPFLG			;have we been here once?
	BEQ	5$			;no, continue
	HALT				;just die
5$:
	MOV	#-1,STPFLG
.ENDC;.IF NE,DTBUG
	SAVE	<R2,R3,R5>
	MOV	DTEBAD,R5
	MOV	DTEPCA,R3
	PIOFF
	CALL	SAVDTE			;save DTE registers on stopcode
	BIS	#TO.REL,DTSTT		;set reload bit
	CALL	SETSTS			;send status to -10
	BCS	90$
	MOV	#TS.EEX,TE.STW(R5)	;and ring -10 doorbell
90$:	PION
	RESTOR	<R5,R3,R2>
99$:	RETURN
.IIF NE,DTBUG,STPFLG:	.WORD	0
	.SBTTL		DTE-20 interrupt

.REPT 0

  This routine runs a single-valued state machine (instead of one for input
and one for output as the old code did) at interrupt level; any incorrect
interrupt causes the driver to inform the common code that the -10 is down.

The events that may trigger a change of state are:

1) receipt of a normal doorbell interrupt (i.e. with valid examine set)
2) receipt of a to-11 done interrupt
3) receipt of a to-10 done interrupt
4) receipt of a TGHA doorbell interrupt (i.e. with valid examine not set)
5) call to DLRESP by DL10/DTE task to send a response back to the -10
6) TGHA timer expiration

The major states and their processing (in parenthesis) and state transitions
(F: means failure, S: means success) are:

idle	between transactions	4=>(set TGHA flag and timer)wfg-idle
				1=>(setup to read header)F:wfg-wfeh,S:wfeh
				2,3=>-10 error
				5,6=>-11 error
wfeh	waiting to read header	4=>(set TGHA flag and timer)wfg-wfeh
				2=>(test for indirect function)S:wfeb,F:(check for
				   examine/deposit)F:(wake DL10/DTE task)wftsk,
				   S:(build answer header, ring -10 doorbell,
				   send header)F:wsth,S:wfth
				1,3=>-10 error
				5,6=>-11 error
wfeb	waiting for indirect	4=>(set TGHA flag and timer)wfg-wfeb
	doorbell		1=>(setup to read data)F:wfg-wfeb,S:wfed
				2,3=>-10 error
				5,6=>-11 error
wfed	waiting to read data	4=>(set TGHA flag and timer)wfg-wfed
				2=>(wake DL10/DTE task)wftsk
				1,3=>-10 error
				5,6=>-11 error
wftsk	waiting for common	4=>(set TGHA flag and timer)wfg-wftsk
	module to respond	1,2,3=>-10 error
				5=>(ring -10 doorbell, send header)F:wsth,S:wfth
				6=>-11 error
wsth	waiting to send -10	4=>ignore
	doorbell again		1=>(abort response)wfeh
				6=>(ring -10 doorbell, send header)F:-10 down,S:wfth
				2,3=>-10 error
				5=>-11 error
wfth	waiting for -10 done	4=>(set TGHA flag and timer)wfg-wfth
	for header		3=>(check for indirect)F:idle,S:(ring -10 doorbell,
				   send data)F:wstd,S:wftd
				1=>(check for indirect)F:wfeh,S:-10 error
				2=>-10 error
				5,6=>-11 error
wstd	trying to resend -10	4=>ignore
	doorbell for data	1=>(abort response)wfeh
				6=>(ring -10 doorbell, send data)F:-10 down,S:wftd
				2,3=>-10 error
				5=>-11 error
wftd	waiting for -10 done	4=>(set TGHA flag and timer)wfg-wftd
	for data		3=>idle
				1=>(abort response)wfeh
				2=>-10 error
				5,6=>-11 error
wfg-xx	waiting for TGHA	1,2,3=>(clear TGHA flag and timer;pass interrupt on)xx
				4=>ignore
				6=>(clear TGHA flag and timer;check for valid examine)
				   F:-10 down,S:xx
				5=>-11 error
-10 err	illegal protocol	(set DLGONE to -1, wake DL10/DTE task)idle
-10 dwn	-10 not responding	(set DLGONE to -1, wake DL10/DTE task)idle
-11 err	logic error in FE	trap

.ENDR;.REPT 0

DT.INT:	INTSKD
	SAVE	<R0,R1,R2,R3,R4,R5>	;save a couple of registers
	CLKOFF				;turn off clock so it won't screw us
	MOV	DTEBAD,R5		;copy base address into standard register
	DTEOFF
	MTPS	#PR.TEN*40		;set ten interface priority level

.IF NE,DTBUG
	TST	INTFLG			;are we already within interrupt?
	BEQ	2$			;no, continue
	MOV	TE.STW(R5),#0		;yes, remember current status
	STOPCD	DTE			; and die
2$:
	MOV	#-1,INTFLG
.ENDC;.IF NE,DTBUG
	MOV	DTEPCA,R3		;get DTE table address
	MOV	TE.STW(R5),R0		;get interrupt bits
	TRACE	TRCDTE,R0
.IF NE,DTBUG
	MOV	R0,LSTINT		;save last interrupt
.ENDC;.IF NE,DTBUG
	BIT	#TS.XER!TS.MPE!TS.EPE!TS.EET,R0;check for hard errors
	BNE	20$			;yes, mark -10 down
	BIT	#TS.ETD!TS.XNT!TS.XEE,R0;check useful bits
.IF NE,DTBUG
	BNE	1$			;if some on, skip following
	INC	#0			;count how often it happens
	MOV	R0,#0			;and record status bits
	BR	99$			;ignore interrupt
1$:
.IFF;.IF NE,DTBUG
	BEQ	99$			;exit if none on
.ENDC;.IF NE,DTBUG
	MOV	R0,INTCND		;store interrupt conditions
	BIC	#^C<I..DBL!I..11D!I..10D>,INTCND;only leave on ones we handle
	BIT	#I..DBL,R0		;is it a doorbell?
	BEQ	10$			;no, just do normal dispatch
	CALL	GETSTS			;get status word from -10
	BCS	9$			;if no examine done, -10 is down
	TST	TCSTFX			;check valid examine
	BNE	10$			;yup, do normal dispatch
9$:	BIC	#I..DBL,INTCND		;no, call this TGHA doorbell
	BIS	#I..TGH,INTCND		; instead of normal doorbell
10$:	CALL	CLRINT			;clear hardware interrupt conditions
	CALL	NXTPRT			;do next part of state machine
99$:	MTPS	#BR7			;allow us to get out of here
	DTEON
	RESTOR	<R5,R4,R3,R2,R1,R0>	;restore registers
.IIF NE,DTBUG,	CLR	INTFLG			;no longer within interrupt

	CLKON				;turn the clock back on
	RTI				;dismiss interrupt

20$:	CALL	DTEDWN			;mark -10 down
	BR	99$			; and dismiss interrupt

DTEDWN:					;subroutine to declare -10 down when
					;not in state machine
	TRACE	TRCPRO,<(SP),NXTPC,JIFCLK>
.IF NE,DEBUG
	BIT	#TRCTER,TRCHLT
	BEQ	1$
	STOPCD	TER
1$:
.ENDC;.IF NE,DEBUG
	CALL	INISTA			;initialize state machine
	CLR	PROTER			;not due to protocol error
	MOV	#-1,DLGONE		;mark it down
	CALL	WAKTEN			;wake up DTE/DL10 task
	RETURN				;exit

CLRINT:					;subroutine to clear hardware conditions
	SAVE	R0
10$:	BEQ	99$			;if equal, all hardware bits cleared
	BIT	#I..11D,R0		;to -11 done?
	BEQ	20$			;no, try another
	MOV	#TS.ENT,TE.STW(R5)	;clear to -11 done
	BIC	#I..11D,R0		;clear flag bit
	BEQ	99$			;for speed
20$:	BIT	#I..10D,R0		;to -10 done?
	BEQ	30$			;no, try next
	MOV	#TS.XTS,TE.STW(R5)	;yes, clear it
	BIC	#I..10D,R0
	BEQ	99$
30$:	BIT	#I..DBL,R0		;doorbell?
	BEQ	99$			;no, finished
	MOV	#TS.EIS,TE.STW(R5)	;clear condition
	BIC	#I..DBL,R0
99$:	RESTOR	R0
	RETURN
	.SBTTL		dispatch for state machine

NXTPRT:					;subroutine to execute next part of
					; state machine code
	TRACE	TRCDTE,<(SP),PS>

.IF NE,DTBUG
	TST	WITHIN
	BEQ	1$
	STOPCD
 1$:
 .ENDC;.IF NE,DTBUG

	SAVE	<R0,R1,R2,R3,R4,R5>	;save caller regs
	MOV	SP,INTSP		; and stack pointer
	MOV	STATSP,SP		;get state machine stack pointer
	RESTOR	<R5,R4,R3,R2,R1,R0>	;restore state machine's regs
	MOV	(SP)+,NXTPC		;get entry point to state machine
	TRACE	TRCPRO,<NXTPC,JIFCLK>
.IF NE,DTBUG
	CMP	#INTSTK,SP		;make sure we are at appropriate point
	BEQ	77$
	STOPCD
77$:
	MOV	#-1,WITHIN
.ENDC;.IF NE,DTBUG

NXTCND:	CALL	FNDCND			;find an active condition
	BCC	ERRCHK			;if none, check for illegal interrupts
NXTCN0:
	TRACE	TRCDTE,<CNDINT,CNDHLD>
	JMP	@CNDHLD			;handle condition
.IF NE,DTBUG
NXTCN1:					;return here from state
	TRACE	TRCDTE,NXTPC
.IF NE,DEBUG
	CMP	#INTSTK,SP
	BEQ	78$
	STOPCD
78$:
.ENDC;.IF NE,DEBUG
	BR	NXTCND			; and go look for another
.ENDC;.IF NE,DTBUG

ERRCHK:					;here to see if error condition
	TST	INTCND			;any more interrupt conditions
	BEQ	DISMIS			;no, we are done
	CALL	PRTCHK			;go check for protocol error interrupts
	IFCRY	S.10ER			;if error, declare -10 down
	XCALL	S.11ER			;must be -11 logic error
DISMIS:					;when condition is finished, come here
	TRACE	TRCPRO,<NXTPC,JIFCLK>
	SAVE	<NXTPC,R0,R1,R2,R3,R4,R5>;save new state and registers
	MOV	SP,STATSP		;save stack pointer for state machine
	MOV	INTSP,SP		;restore caller's stack pointer
	RESTOR	<R5,R4,R3,R2,R1,R0>	;restore caller's registers
DISM0:					;here to exit from TENDWN
.IF NE,DTBUG
	TST	INTCND
	BEQ	5$
	INC	#0
5$:
	CLR	WITHIN
.ENDC;.IF NE,DTBUG
	CLR	INTCND			;make sure no unfinished business left
	RETURN				;return to caller of NXTPRT

FNDCND:					;find active condition
	SAVE	<R0,R1>			;need a couple of registers
	MOV	NXTPC,R0		;get pointer to current state block
	ADD	#STBDSP,R0		;point to dispatch part
10$:	MOV	(R0)+,R1		;get bit(s) to dispatch on
	BEQ	30$			;if none, return carry clear
	BIT	R1,INTCND		;a condition met?
	BEQ	20$			;no, advance to next
	MOV	(R0)+,CNDHLD		;yes, save dispatch address
	BIC	R1,INTCND		;mark conditions satisfied
	MOV	R1,CNDINT		;save last conditions (in case state
					; machine wants to know)
	RESTOR	<R1,R0>			;restore regs
	SEC				;indicate we got something
	RETURN
20$:	MOV	(R0)+,R1		;advance past dispatch address
	BR	10$			;try next entry
30$:	RESTOR	<R1,R0>			;restore regs
	CLC
	RETURN
CNDHLD:	.WORD	0			;dispatch address for condition
CNDINT:	.WORD	0			;conditions this dispatch

PRTCHK:	SAVE	R0			;save a register
	MOV	#E10DSP,R0		;displacement of -10 protocol error mask
	ADD	NXTPC,R0		;get address of mask bits
	CLC				;assume no error conditions
	BIT	(R0),INTCND		;check mask against conditions
	BEQ	99$			;exit if none match
	SEC				;flag error
99$:	RESTOR	R0
	RETURN
	.SBTTL		State machine

.IF NE,FTP5
	.ENABL	LSB
S.INI0:					;initial protocol start exchange
	INTTYP	<I..RSP!I..TMO>,<I..10D!I..11D>,<<I..TGH,5$>,<I..DBL,10$>>
5$:	CALL	TGHWAI
10$:	BIT	#TO.INI,TCSTFX		;check if 10 is initializing
	BNE	15$
	GOBACK
15$:
S.IN00:	BIS	#TO.INI,DTSTT		;yes - we are too
	CALL	SETSTS			;tell him we agree
	BCC	20$
	CALL	TGHWAI
	BR	15$
20$:	MOV	#TS.EEX,TE.STW(R5)	;ring -10 doorbell to wake it up
	NXTINT				;now he must agree that we agree
	.DSABL	LSB

S.INI1:					; we are agreeing that we are both starting
	INTTYP	<I..RSP!I..TMO>,<I..10D!I..11D>,<<I..TGH,5$>,<I..DBL,10$>>
5$:	CALL	TGHWAI
10$:	BIT	#TO.INI,TCSTFX		;does he agree that we agree with him?
	BNE	S.IN00			;no - then we don't agree about startup
15$:	BIC	#TO.INI,DTSTT		;yes - tell him we agree that he agrees that we agree
	CALL	SETSTS
	BCC	20$
	CALL	TGHWAI
	BR	15$
20$:	MOV	#TS.EEX,TE.STW(R5)	;ring -10 doorbell to wake it up
	NXTINT	#S.IDLE			;and we are started
	GOBACK
.ENDC	;.IF NE,FTP5


S.11ER:	STOPCD	S11			;-11 logic error

S.10ER:	MOV	#-1,PROTER		;indicate protocol error
XC:	XCALL	TENDWN			;flag -10 down

S.10DW:	CLR	PROTER			;no protocol error
	BR	XC			;flag it down

	.ENABL	LSB
TGHSTD:	CALL	TGHWAI	
99$:	GOBACK

S.IDLE:					;initial state (between messages)
	INTTYP	<I..RSP!I..TMO>,<I..10D!I..11D>,<<I..TGH,TGHSTD>,<I..DBL,10$>>
10$:
S.IDL0:	BIT	#TO.IND,TCSTFX+2	;doorbell for indirect?
	IFNE	S.10ER			;yes, -10 goofed

S.IDL1:	CMPB	DT10QC,TCSTFX+4		;compare our queue count with -10's
	BEQ	99$			;if same, ignore
20$:	CALL	SETHDR			;setup to read header
	BCC	30$
	CALL	TGHWAI
	BR	20$
30$:	NXTINT
	.DSABL	LSB

S.WFEH:					;waiting for -11 done of header

.IF	NE,FTFEDV

SAWFEH:					;substate: waiting for FEH for DN60 header
.ENDC	; .IF NE,FTFEDV
	INTTYP	<I..RSP!I..TMO>,<I..DBL!I..10D>,<<I..TGH,TGHSTD>,<I..11D,10$>>
10$:	MOV	#DT11HD,R0		;point to correct header
	CALL	SWPHDR			;swap header bytes
.IF EQ,FTP5
	TRACB	TRCPRO,DT11HD,D11HDL/2	;trace the FEH header
.IFF
	TRACB	TRCPRO,DT11DF,D11DFL/2	;trace the DN60 header
.ENDC	;.IF EQ,FTP5

	CALL	VALHDR			;check constant header info
.IF	NE,FTFEDV
	BCC	19$
.IIF NE,DTBUG,	INC	#0		;count these for the hell of it

12$:	NXTINT	#S.IDLE			;if illegal header - ignore it!
	GOBACK
.IFF
	IFCRY	S.10ER			;illegal header
.ENDC	; .IF NE,FTFEDV

19$:

.IF	NE,FTFEDV
	CMPB	DT11FN,#DTFSAK		;check for unexpected ack
	BEQ	12$			;20 sends another after transaction complete

15$:
	CALL	GETSTS			;try to get status
	BCS	30$			;if -10 timeout, declare it dead
	TST	TCSTFX			;check for valid examine
	BNE	20$			;no, assume TGHA running
30$:	CALL	TGHWAI			;go into TGHA wait
	BR	19$			;if timeout and -10 is up, read status again

20$:					;here for indirect - the DN60 header
	NXTINT

SAWFEB:					;wait for indirect doorbell - DN60 header
	INTTYP	<I..RSP!I..TMO>,<I..10D!I..11D>,<<I..TGH,TGHSTD>,<I..DBL,10$>>
10$:	BIT	#TO.IND,TCSTFX+2	;indirect doorbell?
	BNE	20$			;yes, continue
	INC	#0			;count how often this happens
	BIS	I..DBL,INTCND		;dummy up interrupt condition
	NXTINT	#S.IDLE			;change state immediately
	GOBACK				; and go to it
20$:	CALL	INPHD			;setup to read data
	BCC	25$
	CALL	TGHWAI
	BR	20$
25$:	NXTINT

SAWFED:					;wait for -11 done for indirect data - DN60 header
	INTTYP	<I..TMO!I..RSP>,<I..DBL!I..10D>,<<I..TGH,TGHSTD>,<I..11D,10$>>
10$:	MOV	#DT11HD,R0		;point at to-11 header
	CALL	SWPHDF			;swap the bytes
.ENDC	; .IF NE,FTFEDV

.IF EQ,FTP5
	TRACB	TRCPRO,DT11DF,D11DFL/2	;trace the DN60 header
.ENDC	;.IF EQ,FTP5

.IF	EQ,FTFEDV
	CALL	GETSTS			;try to get status
	BCS	30$			;if -10 timeout, declare it dead
	TST	TCSTFX			;check for valid examine
	BNE	21$			;no, assume TGHA running
	CALL	TGHWAI			;go into TGHA wait
	BR	19$			;if timeout and -10 is up, read status again
30$:	XCALL	TENDWN			;declare -10 down
.ENDC	;.IF EQ,FTFEDV
					;(never returns)


21$:	MOVB	DT11DF,R1		;get DN60 function code
	CMPB	#DF.EXA,R1		;is it examine
	BEQ	80$			;yes, special case
	CMPB	#DF.DEP,R1		;is it deposit?
	BEQ	80$			;yes, special case
.IF NE,FTFEDV+FTP5
	BIT	#1,DT11DF		;check DN60 function code for indirect dat
	BEQ	20$			;even function codes are writes from ten to eleven
.IFF
	TST	DT11FN			;is it indirect function?
	BMI	20$			;yes, go bring in data
.ENDC ;.IF NE,FTFEDV+FTP5
.IIF	NE,FTFEDV,	CALL	DTSACK		;send ack with FEH for response
	CLR	INPCTR			;no input data
	CALL	WKTSK			;wake up DL10/DTE task
	NXTINT	#S.WFTK			;declare next interrupt
99$:	GOBACK
80$:	CALL	DLTEXM			;build examine/deposit response
.IF NE,FTP5
	MOV	#DT10HD,R0		;point to the right header
	CALL	SWPHDF			;swap DN60 header for ten
.ENDC	;.IF NE,FTP5
.IIF	NE,FTFEDV,	CALL	DTSACK		;send ack with FEH for response
81$:	CALL	SNDHDR			;try to send it to -10
	BCS	75$			;if error ringing ten, try to repeat
.IF NE,FTP5
	TST	RSPSIZ			;if response size is zero
	BNE	70$
	JMP	SFAKDN			;there won't be any to 10 done
70$:
.ENDC	;IF NE,FTP5
	NXTINT	#S.WFTH			;declare next interrupt
	GOBACK
75$:	NXTINT	#S.WSTH			;next state is trying to send header
	CALL	TGHWAI			;but put ourselves into TGHA wait first
	BR	81$			;go try again to send
20$:					;here if indirect data coming
.IF NE,FTFEDV
	CALL	DTSAK			;send ack and wait for indirect data
	BR	81$			;go try again to send

SBWFEB:					;waiting for doorbell for FEH for data
	INTTYP	<I..RSP!I..TMO>,<I..10D!I..11D>,<<I..TGH,TGHSTD>,<I..DBL,10$>>
10$:	BIT	#TO.IND,TCSTFX+2	;doorbell for indirect?
	IFNE	S.10ER			;yes, -10 goofed
	CMPB	DT10QC,TCSTFX+4		;compare our queue count with -10's
	BEQ	11$			;if same, ignore
	CALL	SETHDR			;setup to read header
	BCC	15$
11$:	GOBACK				;don't leave state if it fails

15$:	NXTINT


SBWFEH:					;substate: waiting for FEH for DN60 data
	INTTYP	<I..RSP!I..TMO>,<I..DBL!I..10D>,<<I..TGH,TGHSTD>,<I..11D,10$>>
10$:	MOV	#DT11HD,R0		;point to correct header
	CALL	SWPHDR			;swap header bytes

	TRACB	TRCPRO,DT11HD,D11HDL/2	;trace the FEH header

	CALL	VALHDR			;check constant header info
	BCC	19$
.IIF NE,DTBUG,	INC	#0		;count these for the hell of it
12$:	NXTINT	#S.IDLE			;if illegal header - ignore it!
	GOBACK

19$:	CMPB	DT11FN,#DTFSAK		;check for unexpected ack
	BNE	15$
.IIF NE,DTBUG,	INC	#0		;count these for the hell of it
	BR	12$			;have seen this happen here, followed
					;by a non-fe header. seemed to be
					;associated with tgha event.
15$:	CALL	GETSTS			;try to get status
	BCS	30$			;if -10 timeout, declare it dead
	TST	TCSTFX			;check for valid examine
	BNE	20$			;no, assume TGHA running
30$:	CALL	TGHWAI			;go into TGHA wait
	BR	19$			;if timeout and -10 is up, read status again

20$:					;here for indirect - the DN60 data
.ENDC	; .IF NE,FTFEDV

	NXTINT	#S.WFEB
	GOBACK

S.WFEB:					;wait for indirect doorbell
	INTTYP	<I..RSP!I..TMO>,<I..10D!I..11D>,<<I..TGH,TGHSTD>,<I..DBL,10$>>
10$:	BIT	#TO.IND,TCSTFX+2	;indirect doorbell?
.IF NE,FTP5
	BEQ	20$			;no, continue
.IFF
	BNE	20$			;yes, continue
.ENDC	;IF NE,FTP5
	INC	#0			;count how often this happens
	BIS	I..DBL,INTCND		;dummy up interrupt condition
	NXTINT	#S.IDLE			;change state immediately
	GOBACK				; and go to it
20$:	CALL	SETDAT			;setup to read data
	BCC	21$
	CALL	TGHWAI
	BR	20$
21$:	NXTINT

S.WFED:					;wait for -11 done for indirect data
	INTTYP	<I..TMO!I..RSP>,<I..DBL!I..10D>,<<I..TGH,TGHSTD>,<I..11D,10$>>
10$:
.IF	NE,FTFEDV
	BIT	#1,DT11DF		;CHECK FOR WRITE FUNCTION
	BNE	11$
;for some mysterious reason write commands have to get their data from the
; indirect header byte count(WRITE DATA only but do it for all for consistency)
	CLR	DT11DT			;get length of msg
	MOVB	DT11UC,DT11DT		;from FEH of indirect msg
.ENDC	; .IF NE,FTFEDV

11$:	MOV	DT11DT,INPCTR		;get length of input data
	CMP	INPCTR,#MAXDAT		;limit to buffer size
	BLE	12$
	MOV	#MAXDAT,INPCTR
12$:	CALL	WKTSK			;wake up task
.IIF	NE,FTFEDV,	CALL	DTSACK	;set up ack of data read to go back with
					;FEH of response
	NXTINT

S.WFTK:					;wait for task to respond
	INTTYP	0,<I..10D!I..11D!I..DBL>,<<I..TGH,TGHSTD>,<I..RSP,10$>>
10$:
.IF NE,FTP5
	MOV	#DT10HD,R0		;point to the right header
	CALL	SWPHDF			;swap DN60 header for ten
.ENDC	;.IF NE,FTP5
	CALL	SNDHDR			;try to send header
	BCC	20$			;it went, go finish up
	NXTINT	#S.WSTH			;declare next state
	CALL	TGHWAI			;but as a TGHA state
	BR	10$			;try again
20$:	NXTINT				;success, we are in a new state

S.WFTH:					;waiting for to -10 done on header
	INTTYP	<I..RSP!I..TMO>,<I..11D>,<<I..TGH,TGHSTD>,<I..10D,20$>,<I..DBL,10$>>
10$:	BIT	#TO.IND,TCSTFX+2	;doorbell for indirect?
	IFNE	S.10ER			;yes, -10 error
	CALL	ABTXMT			;abort transmit in progress
.IIF	NE,FTFEDV,	CLR	DTACKR		;clear ack flag
	JMP	S.IDL1			;and wait for header from -10

20$:

SFAKDN:					;here when no to 10 done will happen

.IF NE,FTFEDV
	TST	DTACKR			;trace ack header if acking indirect data
	BEQ	21$
	TRACB	TRCPRO,DTAKHD,D10HDL/2	;length
21$:

	MOV	DTACKR,R0		;check for ack only
	BEQ	25$			;no ack at all
	CLR	DTACKR			;done with ack header
	CMP	R0,#D10HDL		;ack - check if FEH of response with it
	BGT	25$			;yes - go send the indirect data
	NXTINT	#SBWFEB			;no, just ack => expecting indirect data from 10
	GOBACK
25$:	TRACB	TRCPRO,DT10DF,D10DFL/2	;trace DN60 header returned
	MOV	#DT10HD,R0		;point to the right header
	CALL	SWPHDF			;swap DN60 header for ten
26$:	CALL	OUTHD			;send DN60 header to ten
	BCC	40$
	NXTINT	#S.WSTD
	CALL	TGHWAI
	BR	26$
40$:	NXTINT

SAWFTD:					; waiting for to-10 done on DN60 header
	INTTYP	<I..RSP!I..TMO>,<I..11D>,<<I..TGH,TGHSTD>,<I..10D,20$>,<I..DBL,10$>>
10$:	CALL	ABTXMT			;abort transmit
	CLR	DTACKR			;clear ack flag
	JMP	S.IDL0			;next state

20$:	BIC	#TO.IND!TO.FWD,DTSTT+2	;clear indirect in progress and byte mode
	NXTINT				;now wait for ack of indirect part sent

SAWFAK:					;waiting for ack header
	INTTYP	<I..RSP!I..TMO>,<I..10D!I..11D>,<<I..TGH,TGHSTD>,<I..DBL,10$>>
10$:	BIT	#TO.IND,TCSTFX+2	;doorbell for indirect?
	IFNE	S.10ER			;yes, -10 goofed
	CMPB	DT10QC,TCSTFX+4		;compare our queue count with -10's
	BNE	15$			;if same, ignore
	GOBACK
15$:	CALL	SETHDR			;setup to read header
	BCC	20$			;don't leave state if it fails
	CALL	TGHWAI
	BR	15$

20$:	NXTINT


SBWFAK:					;waiting for -11 done of ack header

	INTTYP	<I..RSP!I..TMO>,<I..DBL!I..10D>,<<I..TGH,TGHSTD>,<I..11D,10$>>
10$:	MOV	#DT11HD,R0		;point to correct header
	CALL	SWPHDR			;swap header bytes
	TRACB	TRCPRO,DT11HD,D11HDL/2	;trace the FEH header

	CALL	VALHDR			;check constant header info
	BCC	19$
.IIF NE,DTBUG,	INC	#0		;count these for the hell of it
	NXTINT	#S.IDLE			;if illegal header - ignore it!
	GOBACK


19$:
	CMPB	DT11FN,#DTFSAK		;check for expected ack
	BEQ	15$
	CALL	S.10ER			;ten is confused
15$:					;now time to think about sending response data
					;NOTE: DN60 header has been swapped at this point
	MOV	DT10DT,R0		;any data to go back ?
	BEQ	20$			;no - done with transaction
	CMPB	#DF.EXA,DT10DF+1	;maybe - check if it was examine/deposit response
	BEQ	20$			;yes - data is in DN60 header
	CMPB	#DF.DEP,DT10DF+1
	BEQ	20$			;yes - no data to return
	BITB	#1,DT10DF+1		;check for write function
	BNE	30$			;no - data returns to 10
					;yes - no data is returned to 10

20$:	NXTINT	#S.IDLE			;done - fall back to ground state(exhausted)
	GOBACK

30$:	SWAB	R0			;FE service can only handle a byte??
	MOVB	R0,DT10UC		;set no. bytes to follow
	CALL	SNDHDR			;try to send header
	BCC	40$			;it went, go finish up
	NXTINT	#S.WSTH			;declare next state
	CALL	TGHWAI			;but as a TGHA state
	BR	30$			;try again
40$:	NXTINT				;success, we are in a new state

SAWFTH:					;waiting for to -10 done on header for data
	INTTYP	<I..RSP!I..TMO>,<I..11D>,<<I..TGH,TGHSTD>,<I..10D,20$>,<I..DBL,10$>>
10$:	BIT	#TO.IND,TCSTFX+2	;doorbell for indirect?
	IFNE	S.10ER			;yes, -10 error
	CALL	ABTXMT			;abort transmit in progress
	JMP	S.IDL1			;and wait for header from -10

20$:
	TRACB	TRCPRO,DT10HD,D10HDL/2


.ENDC ;.IF NE,FTFEDV

.IF NE,FTP5
	CMPB	DT10DF+1,#DF.EXA	;check for examine/deposit
	BEQ	25$			;examine
	CMPB	DT10DF+1,#DF.DEP
	BEQ	25$			;deposit
	BITB	#1,DT10DF+1		;check for read data type function
	BNE	30$			;yes - have to respond
					;no - header is sufficient
.IFF
	TST	DT10FN			;check for indirect function
	BMI	30$			;yes, continue it
.ENDC	;IF NE,FTP5

25$:	BIC	#TO.IND!TO.FWD,DTSTT+2	;clear byte mode (and indirect for the hell of it)
	NXTINT	#S.IDLE			;next stop is idle
	GOBACK

30$:	CALL	SNDDAT			;send data
	BCC	40$			;continue if it worked
	NXTINT	#S.WSTD
	CALL	TGHWAI
	BR	30$

40$:	NXTINT

S.WFTD:					;waiting for to -10 done on data
	INTTYP	<I..RSP!I..TMO>,<I..11D>,<<I..TGH,TGHSTD>,<I..10D,20$>,<I..DBL,10$>>
10$:	CALL	ABTXMT			;abort transmit
.IIF	NE,FTFEDV,	CLR	DTACKR		;clear ack flag
	JMP	S.IDL0			;next state

20$:	BIC	#TO.IND!TO.FWD,DTSTT+2	;clear indirect in progress and byte mode
.IF NE,FTFEDV
	NXTINT				;now wait for ack of indirect part sent

SCWFAK:					;waiting for ack header
	INTTYP	<I..RSP!I..TMO>,<I..10D!I..11D>,<<I..TGH,TGHSTD>,<I..DBL,10$>>
10$:	BIT	#TO.IND,TCSTFX+2	;doorbell for indirect?
	IFNE	S.10ER			;yes, -10 goofed
	CMPB	DT10QC,TCSTFX+4		;compare our queue count with -10's
	BNE	15$			;if same, ignore
	GOBACK
15$:	CALL	SETHDR			;setup to read header
	BCC	20$			;don't leave state if it fails
	CALL	TGHWAI
	BR	15$

20$:	NXTINT


SDWFAK:					;waiting for -11 done of ack header

	INTTYP	<I..RSP!I..TMO>,<I..DBL!I..10D>,<<I..TGH,TGHSTD>,<I..11D,10$>>
10$:	MOV	#DT11HD,R0		;point to correct header
	CALL	SWPHDR			;swap header bytes
	TRACB	TRCPRO,DT11HD,D11HDL/2	;trace the FEH header

	CALL	VALHDR			;check constant header info
	BCC	19$
.IIF NE,DTBUG,	INC	#0		;count these for the hell of it
	NXTINT	#S.IDLE			;if illegal header - ignore it!
	GOBACK

19$:
	CMPB	DT11FN,#DTFSAK		;check for expected ack
	BEQ	15$
	CALL	S.10ER			;ten is confused
15$:
.ENDC ;.IF NE,FTFEDV
					;transaction complete - at last!!
	NXTINT	#S.IDLE
	GOBACK

S.WSTH:					;waiting to send header
	INTTYP	<I..RSP>,<I..10D!I..11D>,<<I..TGH,10$>,<I..DBL,20$>,<I..TMO,30$>>
20$:	CALL	ABTXMT
	JMP	S.IDL0
10$:	GOBACK
30$:	CALL	SNDHDR
	BCC	31$
	CALL	TGHWAI
	BR	30$
31$:
.IF NE,FTP5
	TST	RSPSIZ			;check if to 10 done will happen
	BNE	35$
	JMP	SFAKDN			;no - fake it
35$:
.ENDC	;IF NE,FTP5
	NXTINT	#S.WFTH
	GOBACK

S.WSTD:					;waiting to send data
	INTTYP	<I..RSP>,<I..10D!I..11D>,<<I..TGH,10$>,<I..DBL,20$>,<I..TMO,30$>>
20$:	CALL	ABTXMT
	JMP	S.IDL0
10$:	GOBACK
30$:	NXTINT	#S.IDLE
	GOBACK
	.SBTTL		Subroutines for state machine

TGHWAI:					;subroutine to wait for TGHA pause to
					; finish
	TRACE	TRCDTE!TRCPRO,<(SP),NXTPC,JIFCLK> ;trace caller and state coming from

;Call only at top level stack in state machine

;  This subroutine can only be called from the state machine; it assumes
; 10 will have turned off DTE for up to TGHMAX seconds. The TGHA state ends
; when: 1) the timer expires and -10 still doesn't have valid examine.  This
; means the -10 is down, and results in a call to S.10DW. 2) the timer expires
; and the -10 is alive. This returns to the caller of TGHWAI.  3) another
; interrupt condition occurs while timing.  This immediately terminates the
; TGHA state, and returns to the beginning of the state TGHWAI was called in
; with the interrupt condition set.
.IF NE,DTBUG
	TST	TGHCNT			;are we already in TGHA?
	BEQ	5$			;no, skip it
	STOPCD	RTC			;recursive TGHA call!
5$:
.ENDC;.IF NE,DTBUG
	MOV	(SP)+,TGHRET		;save return address
	MOV	NXTPC,TNXTPC		;save current state
	MOV	#TGHMAX,TGHCNT		;set timeout counter
	NXTINT				; and go into new state
WAITGH:	INTTYP	0,0,<<I..DBL,10$>,<I..11D,20$>,<I..10D,30$>,<I..TGH,99$>,<I..RSP,40$>,<I..TMO,50$>>
10$:	BIS	#I..DBL,INTCND		;re-iterate interrupt condition
11$:	NXTINT	TNXTPC			;force chance of state
99$:	GOBACK				;go do it
20$:	BIS	#I..11D,INTCND		;re-iterate condition
	BR	11$
30$:	BIS	#I..10D,INTCND
	BR	11$
40$:	BIS	#I..RSP,INTCND
	BR	11$
50$:	NXTINT	TNXTPC			;restore original state
	JMP	@TGHRET			;return to caller
TGHRET:	.WORD	0			;caller return for TGHWAI

WKTSK:					;subroutine to wake TENTSK

;The caller must set up INPCTR with the number of data bytes read

	MOV	DT11DT,OUTCTR		;maximum to transfer is requested amount
	CMP	OUTCTR,#MAXDAT		;check for buffer overflow
	BLE	5$			;no, use it
	MOV	#MAXDAT,OUTCTR		;yes, cut down to our buffer size
5$:	MOV	#OUTBUF,OUTPTR		; and where to start
	MOV	#INBUF,INPPTR		;when input starts
	CALL	CPYHDR			;copy header from input to output area
	MOV	#DT11DF,R0		;point to DN60 part of header
	CALL	WAKFNC			;wake up task
	SETSKD	TCDLDR			;force scheduling pass
	RETURN

INISTA:					;subroutine to initialize state machine
	SAVE	R5
	MOV	SP,R5			;copy stack pointer
	MOV	#INTSTK,SP		;reset stack pointer to state machine stack
.IF EQ,FTP5
	SAVE	#S.IDLE			;start idling
.IFF
	SAVE	#S.INI0			;startup exchange required
.ENDC	;.IF EQ,FTP5
	SAVE	<#0,#0,#0,DTEPCA,#0,DTEBAD>;initialize state regs and return
	MOV	SP,STATSP		;save state machine stack pointer
	MOV	#S.IDLE,NXTPC		;save current (and next) state
	CLR	TGHCNT			;assume TGHA not running
	CLR	INTCND			;make sure nothing left over
.IIF	NE,FTFEDV,	CLR	DTACKR		;clear ack flag
.IIF NE,DTBUG,	CLR	WITHIN
	MOV	R5,SP			;restore old stack pointer
	RESTOR	R5			;and register
	RETURN				;return to caller

TENDWN:					;subroutine for state machine to declare
					; -10 down
.IF NE,DTBUG
	CALL	STKSAV			;save state machine stack
.ENDC;.IF NE,DTBUG
.IF NE,DEBUG
	BIT	#TRCTER,TRCHLT
	BEQ	1$
	STOPCD	TER
1$:
.ENDC;.IF NE,DEBUG
	CALL	WAKTEN			;wake up DTE/DL10 task
	MOV	INTSP,SP		;restore caller's stack pointer
	CALL	INISTA			;initialize state machine
	MOV	#-1,DLGONE		;mark it down
	RESTOR	<R5,R4,R3,R2,R1,R0>	;restore caller's registers
	JMP	DISM0			;exit
	.SBTTL		Software-generated interrupt conditions

DLRESP:					;send response to -10

;NOTE: this code is called from DL10/DTE task to return the data
;length and result code and to initiate their return to the -10.
;It corresponds to the interrupt condition I..RSP in the state machine.

	MOVB	R0,DT10DF+1		;save result code
	MOV	R1,DT10DT		;and copy length
	TRACE	TRCTEN!TRCPRO,<R0,R1,JIFCLK> ;trace the results
.IF EQ,FTP5
.IF	EQ,FTFEDV
	TST	R1
	BEQ	6$			;if 0, leave indirect function bit clear
	BIT	#1,DT10DF		;was it a write function?
	BEQ	6$			;yes, never have data to send
	BIS	#100000,DT10FN		;else set indirect function bit
.ENDC	; .IF EQ,FTFEDV
.ENDC	;.IF EQ,FTP5

6$:	CLKOFF				;flush the clock
	OFFDTE				;disable dte interrupts

	BIS	#I..RSP,INTCND		;set the interrupt condition
	CALL	NXTPRT			;do next part of state machine

	PIOFF				;protect from clenches
	ONDTE				;allow dte interrupts
	CLKON				;also crocks
	PION				;unclench
	RETURN

TGHEXP:					;called from once per second code
					; when timer for TGHA expires
	PIOFF				;no interrupts
	CALL	GETSTS			;read status word
	BCS	10$			;if it timed out, -10 is dead
	CMP	NXTPC,#WAITGH		;make sure we are waiting for TGHA
	BEQ	4$			;yup, continue
	XCALL	S.11ER			;die
4$:
.IF NE,DTBUG
	TST	INTCND			;make sure no left-over interrupt conditions
	BEQ	5$
	STOPCD	INZ
5$:
.ENDC;.IF NE,DTBUG
	CLR	TGHCNT			;no longer timing tgha
	MOV	#I..TMO,INTCND
	CALL	NXTPRT
10$:	PION
	RETURN
	.SBTTL		Timer entry points

DSPDLT:					;tick timer
	TST	DLGONE
	BNE	99$
	TST	TGHCNT			;is TGHA timer running?
	BEQ	99$			;no, retire
	MOV	DTEBAD,R5		;point to hardware
	DTEOFF
	MOV	DTEPCA,R3		;get DTE block pointer
	CALL	CHKTEN			;check if ten is healthy
	BCS	98$			;if not - wait for tgha interval
	CALL	TGHEXP			;try TGHA expiration for size

98$:	DTEON
99$:	CLC
	RETURN


DSPDLS:					;second timer
	TRACE	TRCDTE,<DLGONE,TGHCNT>

	TST	DLGONE
	BEQ	1$
	DEC	DLGONE			;count it down
	RETURN
1$:	SAVE	<R3,R5>			;save standard hardware register
	MOV	DTEBAD,R5		;point to hardware
	DTEOFF
	MOV	DTEPCA,R3		;get DTE block pointer
	TST	TGHCNT			;is TGHA timer running?
	BEQ	50$			;no, test -10
	DEC	TGHCNT			;decrement timer
	BNE	99$			;if not up, we are done
70$:	CALL	DTEDWN			;if not, declare -10 down
99$:	DTEON
	RESTOR	<R5,R3>
	RETURN

50$:					;here if -10 needs to be up
	CALL	CHKTEN			;check that it is
	BCC	60$
	MOV	#I..TGH,INTCND		;no - set tgha state
	CALL	NXTPRT
	BR	99$

60$:	CALL	CRAML0 			;cram keepalive
	BCC	99$
	CALL	CRAML0
	BR	99$			;ignore error

CRAMLV:	MFPS	-(SP)			;preserve condition codes over this fcn
	CMP	JIFCLK,NXKPLV		;do this at odd times if not done recently
	BLO	10$
	CALL	CRAML0
10$:	MTPS	(SP)+
	RETURN

CRAML0:	CLR	TE.XW1(R5)
	CLR	TE.XW2(R5)
	MOV	JIFCLK,TE.XW3(R5)	;the count to -20
	MOV	#TS.DEP,TE.XA1(R5)	;set deposit flag
	MOV	#PBPW1,TE.XA2(R5)	;start xfer
	CALL	DLWEDN			;wait for exam/dep
	BCS	10$
	MOV	JIFCLK,DTKPLV		;save last successful keepalive
	MOV	DTKPLV,NXKPLV
	ADD	#JIFSEC,NXKPLV		;next time it becomes urgent to do it
	TRACE	TRCDTE,JIFCLK		;trace last successful keepalive
	CLC
10$:	RETURN

	.ENABL	LSB
CHKTEN:	CALL	DTECHK
	BCC	5$
	CALL	DTECHK
	BCS	9$			;branch if -10 down
5$:	TST	TE.XW3(R5)		;check for processor number
	BEQ	9$			;ten not up yet if zero
	TRACE	TRCDTE,<(SP),JIFCLK,TE.XW1(R5),TE.XW2(R5),TE.XW3(R5)>
CHKSUC:	CLC
	RETURN
9$:	TRACE	TRCDTE,<(SP),JIFCLK>
CHKFAL:
10$:	SEC
	RETURN
	.DSABL	LSB

DTECHK:	CLR	TE.XA1(R5)		;look at
DTEXAM:	CLR	TE.XA2(R5)		; out comm region header entry
	JMP	DLWEDN			;wait for examine done
	.SBTTL		DTE subroutines

;Turn on the DTE-20 and setup DTE table
;
; THIS ROUTINE WILL SET UP THE TABLES NECESSARY TO
;  INITIALIZE THE COMMUNICATIONS BETWEEN THE PDP-10
;  AND THE PDP-11.
;
; CALL: CALL	DLINDB
;
; ON RETURN:
;		C = 0: R0 = 1 TO INDICATE SUCCESS
;		C = 1: ERROR
;
; NOTE THAT THIS ROUTINE USES R5 IN A NON-STANDARD WAY.
;  THIS IS BECAUSE IT WAS TAKEN FROM THE DN87S CODE AND
;  WE WOULD PREFER NOT TO HAVE TO RE-WRITE IT TO MAKE IT
;  CONFORM TO THE DN60 CODING CONVENTIONS.
;
DLINDB:	MOV	R5,-(SP)
	CLR	-(SP)
	CLR	-(SP)
	MOV	DTEBAD,R0	;FIND THE COMMON DTE-20
	CLR	R1		;SET UP TO FIND PROCESSOR NUMBER
	CLR	R2		;START TRANSFER OF ABS WORD 0 OF EPT (MY PROCESSOR NUMBER
	MOV	#DTXTM3,R3	;SET UP ADDRESS TO STORE WORDS
	CLR	R4
	CALL	DLSWED		;WAIT FOR EXAMINE/DEPOSIT
	BCS	11$		;E BOX STOP
	MOV	@R3,R4		;YES --FIND OFFSET TO MY R/W AREA
	MOVB	@#DTXTM2+1,R2	;FIND THE PROCESSOR NUMBER
				; PROCESSOR NUMBER TO LOW ORDER BITS
	BIC	#177760,R2	;MASK OFF JUNK(0.-15. LEGAL)
	MOV	R2,DLMYPN	;SAVE PROCESSOR NUMBER
	INC	R2		;FIND COMMUNICATIONS VIRTUAL 2
	MOV	R2,DLCMBS	;SAVE BASE OF COMMUNICATIONS AREA
	ADD	R4,R2		;ADD OFFSET TO BASE OF COMM AREA
	MOV	R2,DLDPOF	;SET CORRECT OFFSETT
	TRACE	TRCDTE,<DTXTM1,DTXTM2,DTXTM3,DLMYPN,DLCMBS,DLDPOF>
	CALL	DLSWED		;WAIT FOR TRANSFER
	BCC	12$
11$:	JMP	DLINDR
12$:	TRACE	TRCDTE,<DTXTM1,DTXTM2,DTXTM3>
	MOV	@#DTXTM2,R5	;PICK UP THE NUMBER OF 8 TM BLOCKS
	BIC	#177770,R5	;FIND THE NUMBER OF 8 WORD BLOCKS IN MY AREA
	BEQ	33$		;die if none
	SUB	#2,R5		;ACCOUNT FOR MY GENERAL SECTION
.IIF	NE,FTP5,INC R5		;faker
	BGT	34$		;MCB uses 2 blocks,FE service 3

33$:	STOPCD	DTE
34$:	MOV	R2,2(SP)
	MOV	R5,0(SP)	;SAVE	COUNT OF BLOCKS
DLIND1:	ADD	#PBASIZ,2(SP)	;LOOK AT A COMMUNICATIONS AREA TO ANOTHER PROCESSOR
	MOV	2(SP),R2

	CLR	R4
	CALL	DLSWED		;WAIT FOR TRANSFER
	BCC	77$		; E BOX STOPPED
11$:	JMP	DLINDR
77$:	TRACE	TRCDTE,<DTXTM1,DTXTM2,DTXTM3>
	MOV	@R3,R4		;FIND PROCESSOR NUMBER
	MOV	#DTPIDT,R5	;SET INITIAL POINTER
	BIC	#177770,R4	;MASK OFF JUNK
	BEQ	13$		;YES -- CONTINUE
12$:	ADD	#5*2,R5		;NO -- LOOK AT NEXT ENTRY
	SOB	R4,12$		;TRY UNTIL ALL DONE

13$:	TRACE	TRCDTE,<DTXTM1,DTXTM2,DTXTM3,R4,R5>
	MOV	@#DTXTM2,R4	;FIND NUMBER OF 8 WORD BLOCS
	BIC	#177770,R4	;MASK OFF POSSIBLE GARBAGE
	SUB	R4,@SP		;UPDATE COUNT OF BLOCKS
	CLR	@R5		;SET UP TO CLEAR TABLE IF NO DTE
	MOV	@#DTXTM1,R4	;PICK UP DTE NUMBER
	TRACE	TRCDTE,<R4,R5>
	BIT	#TO.DTE,R4	;DTE HERE?
	BEQ	15$		;NO -- DON'T ENTER IN TABLE
	SWAB	R4		;MAKE MOD 40 (8)
	ROR	R4
	ROR	R4
	ROR	R4
	BIC	#177637,R4	;MASKOFF JUNK
	ADD	#174400,R4	;POINT TO FIRST BLOCK OF DTE'S
	CMP	R4,DTEBAD	;PRIMARY DTE?
	BNE	14$		;NO -- DON'T SET TABLE POINTER
	MOV	R5,DTEPCA	;SAVE TABLE OFFSET
	TRACE	TRCDTE,<R4,R5>
14$:	MOV	R4,@R5		;SET DTE ADDRESS IN TABLE
	MOV	#DLYPRM,@R4	 ;SET UP DELAY COUNTER
	MOV	#TS.EEE,TE.STW(R4) ;YES -- ENABLE INTERRUPT ON IT
15$:	MOV	R2,DTEMYN(R5) 	;SET THE ADDRESS OF EXAMINE MY AREA FOR N


;  MAKE ADDRESS OF THE ADDRESS OF DEPOSIT MY AREA FOR N
	MOV	R2,DTDMYN(R5) 	;STORE IT
	SUB	DLDPOF,DTDMYN(R5) ;RESTORE SUBRESS FOR EXAMINE OF THIS BLOCK
	TRACE	TRCDTE,<R2,DTDMYN(R5)>
	ADD	#TOPCA,R2 ;READ POINTER TO HIS COMM AREA
	CLR	R4
	CALL	DLSWED		;WAIT FOR EXAMINE/DEPOSIT
	BCS	DLINDR		;E BOX STOPPED
	MOV	@R3,R2		;FIND THE EXAMINE ADDRESS
	ADD	DLCMBS,R2	;ADD OFFSET TO COMMON AREA
	MOV	R2,DTEHSG(R5) 	;SET DTEHSG ADDRESS IN TABLE - ptr to his base area
	ADD	#PBASIZ,R2	;POINT TO HIS FIRST TABLE FOR OTHER PROCESSORS
	TRACE	TRCDTE,<DTXTM1,DTXTM2,DTXTM3,R2>
17$:	CLR	R4
	CALL	DLSWED		;WAIT FOR EXAMINE/DEPOSIT
	BCS	DLINDR
	TRACE	TRCDTE,<DTXTM1,DTXTM2,DTXTM3>
	CMPB	DLMYPN,@R3 	;SAME PROCESSOR NUMBER?
	BEQ	19$		;YES -- FOUND MY ENTRY
	MOV	@#DTXTM2,R4	;NO -- FIND NEXT ENTRY IN LIST
	BIC	#177770,R4	;IT IS IN 8 WORD INCREMENTS
;;++KR-FIX FOR TOPS-20 MONITOR PROBLEM
	BNE	20$		;;++KR-NON ZERO IS GOOD
	INC	R4		;;++KR-MAKE IT NON ZERO
20$:
;;++KR-END FIX
	ASL	R4		;SO IT MUST BE SHIFTED LEFT 3 BITS
	ASL	R4		;
	ASL	R4		;
	ADD	R4,R2		;READ NEXT BLOCK
	BR	17$		;AND TRY AGAIN

19$:
	TRACE	TRCDTE,R2
	MOV	R2,DTEHSM(R5)	;STORE DTEHSM ADDRESS - 10'S TO me area offset
	MOV	@SP,R5		;DONE ALL BLOCKS??
	BLE	96$
	JMP	DLIND1		;NO -- TRY NEXT BLOCK
96$:	MOV	#-1,TENALV		;let all know it has happened at least once
	CLR	DTQCNT		;RESET PROTOCOL COUNTERS
	CLR	DTQSTA		;INIT STATE MECHANISM, CLEAR CARRY
DLINDR:	MOV	(SP)+,R5	;RESTORE STACK 
	MOV	(SP)+,R5
	MOV	(SP)+,R5
	RETURN


; THIS SUBROUTINE STARTS A DEPOSIT/EXAMINE SEQUENCE AND WAITS FOR
;  ITS COMPLETION.  IT CHECKS TO SEE IF THE BOOTSTRAP
;  PROTOCOL IS NECESSARY BY CHECKING THE EXAMINE VALID BIT
;  AFTER EVERY EXAMINE/DEPOSIT.  IT IS NOT NECESSARY TO
;  CHECK MORE THAN ANY ONE RANDOM EXAMINE VAILD BIT
;  BECAUSE IF ONE IS 0 THEN THE PROCESSOR HAS
;  TO REVERT TO THE BOOTSTRAP PROTOCOL.
;
; CALL:	CALL	DLSWED
;
;	R0 -- ADDRESS OF DTE-20
;	R1 -- HIGH ORDER EXAMINE/DEPOSIT ADDRESS WORD (FOR TE.XA1)
;	R2 -- LOW ORDER EXAMINE/DEPOSIT ADDRESS WORD (FOR TE.XA2)
;	R3 -- ADDRESS TO XFER 3 WORD BLOCK TO OR FROM
;
; ON RETURN:
;
;	C = 0: SUCCESS, NO REGISTERS ALTERED.
;	C = 1: ERROR.

DLSWED:	MOV	R3,-(SP)	;SAVE REGISTERS
	SAVE	R5
	MOV	R0,R5
	BIT	#TS.DEP,R1	;CHECK FOR DEPOSIT
	BNE	12$		;YES -- GO TO DEPOSIT PART OF SUB
	CALL	30$
	BCC	10$
	CALL	30$
	BCS	14$		;COMPLAIN ABOUT E BOX STOPPED
10$:	MOV	TE.XW3(R0),(R3)+ ;STORE THE WORD XFERED
	MOV	TE.XW2(R0),(R3)+
	MOV	TE.XW1(R0),(R3)+
.IF NE,DTBUG
	CALL	TRCIT
.ENDC;.IF NE,DTBUG
11$:	TST	R4		;PRIV EXAMINE/DEP?
	BNE	14$		;YES -- DON'T DO CHECKS
	CLR	TE.XA1(R0)	;SEE IF WE CAN READ ANYTHING
	CLR	TE.XA2(R0)	;START TRANSFER
	CALL	DLWEDN		;WAIT FOR XFER
	BCC	9$
	CLR	TE.XA2(R0)	;START TRANSFER
	CALL	DLWEDN		;WAIT FOR XFER
	BCS	14$		;E BOX STOPPED
9$:	TST	TE.XW3(R0)	;VALID?
	BNE	14$		;YES -- PROCEED
	BR	13$		; NO - JUST SET CARRY AND RETURN

; HERE TO DO AN EXAMINE.

12$:	MOV	(R3)+,TE.XW3(R0) ;TRANSFER TO 10
	MOV	(R3)+,TE.XW2(R0) ;SET UP WORD IN DTE
	MOV	(R3)+,TE.XW1(R0)
.IF NE,DTBUG
	CALL	TRCIT
.ENDC;.IF NE,DTBUG
	CALL	30$
	BCC	11$		;GO TO COMMON EXAMINE VALID BIT CHECK
	CALL	30$
	BCC	11$		;GO TO COMMON EXAMINE VALID BIT CHECK

; HERE IF THE 'EXAMINE VALID' BIT IS OFF.  GIVE AN ERROR RETURN.

13$:
.IF NE,DTBUG
	STOPCD	DBG		;-10 STOPPED UNEXPECTEDLY
.ENDC;.IF NE,DTBUG
	SEC
14$:	RESTOR	R5
	MOV	(SP)+,R3	;RESTORE R3
	RETURN			;RETURN TO CALLER

30$:	MOV	R1,TE.XA1(R0)	;SET UP ADDRESS OF XFER IN DTE
	MOV	R2,TE.XA2(R0)	;START XFER
	JMP	DLWEDN		;WAIT FOR EXAMINE/DEPOSIT

.IF NE,DTBUG
TRCIT:
	TRACE	TRCDTE,<-2(R3),-4(R3),-6(R3)>
	RETURN
.ENDC;.IF NE,DTBUG
;	R3/DPTIDT block for this processor

GETSTS:					;subroutine to read comm region status word
	TRACE	TRCDTE,(SP)
	SAVE	R2
	MOV	#TOSTAT,R2	;calculate offset of status word from
					; beginning of to- section
	ADD	DTEHSM(R3),R2		;add in comm region offset of the
					; to- section for me in KL's area
	EXAM	R2,TCSTFX,69$		;examine it

69$:	RESTOR	R2
	RETURN				;return, carry will be set if timeout

SETSTS:					;subroutine to write comm region status word
	TRACE	TRCDTE,<(SP)>

	SAVE	R2
	MOV	#TOSTAT,R2	;get displacement of status within to- section
	ADD	DTDMYN(R3),R2		;convert to deposit offset
	DEPO	R2,DTSTT,20$		;store status
20$:	RESTOR	R2
	RETURN

SETQSZ:					;subroutine to store queued protocol
					;R0/ transfer size

	CLR	TE.XW1(R5)		;zero high
	CLR	TE.XW2(R5)		; order bits of -10 word
	MOV	R0,TE.XW3(R5)		;put size of transfer in low word
	TRACE	TRCDTE,R0
	MOV	#TOXFSZ,R0		;get offset of queue size
	ADD	DTDMYN(R3),R0		;make into deposit offset
	DEPO	R0,,69$			;deposit queue size
69$:	RETURN

ABTXMT:					;here to abort transmit already started
	INC	#0			;count how many times we are in this situation
	ATRACE	<(SP),INTCND>		;trace these always
	RETURN				;can't do it, DTE20 doesn't have a way
					;to cut down byte count.

SETHDR:					;setup to read header
.IF NE,FTP5
	MOV	#DT11HD,R1		;get address of where to put it

GETDAT:
.ENDC	;.IF NE,FTP5
	BIS	#TO.IT,DTSTT+2		;set queue in progress bit in status to -10
	INCB	DT10QC			;increment our counter
	CMPB	TCSTFX+4,DT10QC		;see if we match
	BEQ	10$			;ok, continue
.IF NE,DTBUG
	MOVB	DT10QC,#0
	MOVB	TCSTFX+4,#0
.ENDC;.IF NE,DTBUG
	DECB	DT10QC
	SEC
99$:	RETURN
10$:	CALL	SETSTS			;write status
	BCS	99$			;return on error
	CALL	GETQSZ			;get the xfer size
	BCS	99$
.IF NE,FTP5
	CMP	R0,#MAXDAT		;is it too big?
	BLE	11$			;no, continue
	MOV	#MAXDAT,R0		;yes, cut it down
	INC	#0			;count how often this happens
11$:
.ENDC	;.IF NE,FTP5
	TST	R0			;check size
	BNE	20$
.IF	NE,FTFEDV
	MOV	#D11HDL,R0		;else use default size
.IFF
	MOV	#D11HDL+D11DFL,R0	;else use default size
.ENDC	; .IF NE,FTFEDV

20$:	CALL	CRAMLV 			;cram keepalive

.IF EQ,FTP5
	MOV	#DT11HD,R1		;get address of where to put it
.ENDC	;.IF EQ,FTP5
	CALL	DTSTRT			;start input
	BIC	#TO.IT,DTSTT+2		;clear TOIT bit to indicate not indirect
	CALL	SETSTS			;set status
	RETURN				;return to caller

.IF	NE,FTFEDV
INPHD:					;get DN60 header - indirect data
	CALL	GETQSZ			;extract queue size word from dte
	BCC	5$
	RETURN				;return failure
5$:	CMP	R0,#D11DFL		;check max length dn60 header
	BLE	10$
	MOV	#D11DFL,R0		;use only this much
	INC	#0			;count these
10$:	MOV	#DT11DF,R1		;where to read the dn60 header
	BR	INPDAT			;do it
.ENDC	; .IF NE,FTFEDV

SETDAT:					;subroutine to setup to read indirect data
.IF NE,FTP5
	MOV	#INBUF,R1		;address to put it
	BR	GETDAT			;go get it
.IFF
	CALL	GETQSZ			;extract queue size from dte
	BCC	5$
	RETURN				;return failure
5$:	CMP	R0,#MAXDAT		;is it too big?
	BLE	10$			;no, continue
	MOV	#MAXDAT,R0		;yes, cut it down
	INC	#0			;count how often this happens
10$:	MOV	#INBUF,R1		;address to put it

INPDAT:	CALL	DTSTRT			;start input, R0/bytes to read, R1/buffer
	BIS	#TO.IT,DTSTT+2		;set TOIT bit to indicate indirect in progress
	CALL	SETSTS			;deposit status
10$:	RETURN
.ENDC	;.IF NE,FTP5

GETQSZ:					;extract queue size word from dte
	CLR	R0
	SAVE	R2
	MOV	#TOXFSZ,R2
	ADD	DTEHSM(R3),R2
	EXAM	R2,,69$
	MOV	TE.XW3(R5),R0		;get it into proper register
69$:	RESTOR	R2
	RETURN

DTSTRT:					;subroutine to start to-11 transfer
;R0 = byte count
;R1 = address to read to
;TCSTFX must have status word after last doorbell
	NEG	R0			;make byte count negative and set carry
	BIC	#170000,R0		;clear status bits at top of count word
	RORB	R0			;divide negative byte count by two
	BIT	#TO.FWD,TCSTFX+2	;was this supposed to be word mode?
	BNE	10$			;yes, skip setting byte flag
	ROLB	R0			;restore original negative byte count
	BIS	#TS.EBM,R0		;set byte mode
10$:	BIS	#TS.IFB,R0		;set to interrupt both on done
	MOV	R1,TE.EAD(R5)		;set address
	MOV	R0,TE.EBC(R5)		; and count (which starts transfer)
	CLC				;make sure this sucs
	RETURN

SNDHDR:					;subroutine to start sending header to -10
.IF NE,FTFEDV
	MOV	DTACKR,R0		;check if ack needed
	BEQ	10$			;no - just header
	MOV	#DTAKHD,R1		;yes - R0/size, get ack ptr
.IF NE,FTRACE
	CMP	R0,#D10HDL
	BLE	5$
	TRACB	TRCPRO,DTAKHD,D10HDL
	BR	20$
5$:
.ENDC	;.IF NE,FTRACE
	TRACB	TRCPRO,DTAKHD,D10HDL/2
	BR	20$
.ENDC ;.IF NE,FTFEDV

10$:
.IF EQ,FTP5
	MOV	#DT10HD,R1		;point to start address
	MOV	(R1),R0			;get size of header

.IF EQ,FTFEDV
	TRACB	TRCPRO,DT10DF,D10DFL/2
.IFF
	TRACB	TRCPRO,DT10HD,D10HDL/2	;trace the FEH header
.ENDC; .IF EQ,FTFEDV

.IFF
	MOV	#DT10DF,R1		;point to DN60 header
	MOV	RSPSIZ,R0		;and it's this big

	TRACB	TRCPRO,DT10DF,<<D10DFL>/2> ;trace the DN60 header
.ENDC	;.IF EQ,FTP5

20$:	MOV	R1,TE.XAD(R5)		;set up -10 address
	CALL	SETQSZ			;send queue size
	BCS	99$
	MOV	#TS.TBM,TE.DG3(R5)	;set byte mode (always for header)
	INCB	DT11QC			;increment queue count
	BIC	#TO.IT,DTSTT+2		;clear TOIT bit to indicate not indirect
	CALL	SETSTS			;deposit status word
	BCS	98$

	CALL	CRAMLV 			;cram keepalive

	MOV	#TS.EEX,TE.STW(R5)	;ring -10 doorbell
99$:	RETURN
98$:	DECB	DT11QC
	SEC
	RETURN

;THIS SUBROUTINE HAS TWO ENTRY POINTS . DTSACK TO SEND 
; AN ACK + FEH TO THE TEN AND DTSAK FOR SENDING THE 
; ACK ALONE TO THE TEN TO ACKNOWLEDGE RECEIPT OF DATA.

.IF NE,FTFEDV
DTSACK:	MOV	#D10HDL*2,R0		;SEND ACK + FEH TOGETHER
	BR	DTSAC			;SET UP ACK HEADER
DTSAK:	MOV	#D10HDL,R0		;SEND ONLY THE ACK TO-TEN
DTSAC:
	MOV	R0,DTACKR		;set ack flag with length of msg
	MOV	#D10HDL,DTAKHD		;LENGTH OF HEADER
	MOV	#DTFSAK,DTAKFN 		;ACK FUNCTION
	MOV	#DLDPFE,DTAKDV 		;FE DEVICE
	CLR	DTAKUC			;CLEAR BEFORE PUTTING FE#
	MOVB	DT11UC+1,DTAKUC	 	;FE# RIGHT JUSTIFIED
	RETURN
.ENDC ;.IF NE,FTFEDV

.IF	NE,FTFEDV
OUTHD:	MOV	#D10DFL,R0		;output DN60 header
	MOV	#DT10DF,R1
	BR	OUTDAT
.ENDC	; .IF NE,FTFEDV

SNDDAT:					;subroutine to start sending indirect data
.IF	NE,FTFEDV
	CLR	R0			;get no. bytes we said we would send
	BISB	DT10UC,R0
.IFF
	MOV	DT10DT,R0		;get size ready for deposit
.IF NE,FTP5
	SWAB	R0			;previously swapped
	BNE	5$			;check for zero length xfer
	INC	R0			;yes - xfer 1 fake byte
					;	DN60 header indicates truth
5$:
.ENDC	;IF NE,FTP5
.ENDC	; .IF NE,FTFEDV
	MOV	#OUTBUF,R1		;get big buffer ptr

OUTDAT:					;output data
					;R0/bytes to send
					;R1/buffer ptr
	CALL	SETQSZ			;set queued protocol transfer size
	BCS	99$
	MOV	R1,TE.XAD(R5)		;set output address
.IF NE,FTP5
	BIC	#TO.IND,DTSTT+2		;all version 5 xfers are direct
	INCB	DT11QC			;increment queue count
	BIC	#TO.IT,DTSTT+2		;clear TOIT bit to indicate not indirect
.IFF
	BIS	#TO.IND,DTSTT+2		;say we are doing indirect transfer
.ENDC	;IF NE,FTP5
	MOV	#TS.TBM,TE.DG3(R5)	;set byte mode in hardware
	CALL	SETSTS			;deposit status
.IF NE,FTP5
	BCS	98$
.IFF
	BCS	99$
.ENDC	;.IF NE,FTP5
	CALL	CRAMLV 			;cram keepalive
	MOV	#TS.EEX,TE.STW(R5)	;ring -10 doorbell
99$:	RETURN
.IF NE,FTP5
98$:	DECB	DT11QC
	SEC
	RETURN
.ENDC	;.IF NE,FTP5

;DLWEDN					;subroutine to wait for examine/deposit done
; THIS SUBROUTINE WAITS FOR EXAMINE/DEPOSIT TRANSFERS AND
;  CHECKS TO SEE THAT E BOX HAS NOT STOPPED.

; CALL:	CALL	DLWEDN

;	R5 -- ADDRESS OF DTE-20

; ON RETURN:
;	C = 0: SUCCESS
;	C = 1: ERROR

	.ENABL	LSB
DLWEDN:	MOV	#3000,DTEDTO	;SET UP TIMEOUT FOR TS.XDNE
11$:	BIT	#TS.XDN,TE.STW(R5) ;WAIT FOR TRANSFER TO COMPLETE
	BNE	12$		;DONE
	DEC	DTEDTO		;TIMEOUT?
	BNE	11$		;NO -- CONTINUE WAITING
	ATRACE	<(SP),TE.STW(R5)>;trace this if anything is traced
EXMFAL:	SEC			;YES, ERROR.
	RETURN

; HERE WHEN THE TRANSFER IS COMPLETE.

12$:	BIT	#TS.EPE,TE.STW(R5) ;CHECK FOR E BUS PARITY ERROR
	BNE	13$		;WE HAVE E-BUS PARITY
	TRACE	TRCDTE,TE.STW(R5)
EXMSUC:	CLC			;CLEAR CC-C
	RETURN

; WE HAVE AN E-BUS PARITY ERROR.  CALL THIS A FATAL ERROR.

13$:	STOPCD	DTE20		;E-BUS PARITY ERROR
	.DSABL	LSB


SAVDTE:					;subroutine to save DTE registers
	SAVE	<R2,R3,R5>		;save registers
	MOV	DTEBAD,R5		;point to DTE
	MOV	#-1,DTEMSK		;assume all registers NXM
	MOV	#DTERGS,R2		;point to table
	SAVE	NXMGO
	MOV	#10$,NXMGO
	MOV	#100000,R3		;mask bit for first register
5$:	MOV	@R5,(R2)		;save register (or cause NXM)
	BIC	R3,DTEMSK		;clear its bit
6$:	ADD	#2,R5			;point to next register
	ADD	#2,R2			;don't use auto-increment because
					; it is unpredictable around NXM
	CLC
	ROR	R3			;shift bit
	BNE	5$			; until shifted away
	RESTOR	NXMGO
	RESTOR	<R5,R3,R2>		;restore registers
	RETURN
10$:					;here on NXM
	MOV	#70707,@R2		;save distinctive pattern for NXM
	BR	6$			; and continue
DTEMSK:	.WORD	0			;B15=reg 0,B14=reg 1, etc.
DTERGS:	.BLKW	20			;copy sixteen words of DTE
	.SBTTL		Examine/Deposit functions

;The examine and deposit requests are handled completely at interrupt level,
;so that we can examine a DN60 that is looping at task level.

DLTEXM:					;subroutine to do examine/deposit
	CALL	CPYHDR			;setup output header
.IIF NE,FTP5,	MOV	#6,RSPSIZ	;default examine response size
	CMPB	DT10DF,#DF.DEP		;is this a deposit function?
	BNE	10$			;no, default length OK
.IF EQ,FTP5
	MOV	#D10HDL+2,DT10HD	;yes, deposit data is only 1st word of DN60 header
.IFF
	MOV	#2,RSPSIZ		;send only the 1st word of the DN60 header
.ENDC	;.IF EQ,FTP5
10$:

	SAVE	NXMGO			;save previous NXM trap
	MOV	#50$,NXMGO		;where to go on NXM
	CMPB	DT11DF,#DF.DEP		;is it deposit?
	BEQ	20$			;yes, go do it
	MOV	@DT11AD,DT10DT		;pick up word or NXM
11$:	RESTOR	NXMGO			;put back old NXM trap
	MOVB	#1,DT10DF+1		;put success result code
	RETURN				;return to caller
20$:	MOV	DT11DT,@DT11AD		;store data or get NXM
	BR	11$			;success, return OK
50$:					;here if examine/deposit NXM
	RESTOR	NXMGO			;restore old NXM trap
	MOVB	#3,DT10DF+1		;set reject code for result
	RETURN				; and exit
	.SBTTL		General subroutines

SWPHDR:					;routine to swap header pointed to by R0
.IF EQ,FTP5
	SWAB	DT11HD-DT11HD(R0)	;swap first word (queued protocol length)
	SWAB	DT11FN-DT11HD(R0)	;swap queud protocol function
	SWAB	DT11DV-DT11HD(R0)	;swap queued protocol device code
.IF	NE,FTFEDV
	SWAB	DT11UC-DT11HD(R0) 	;swap fe#,bytes
	RETURN
.ENDC	; .IF NE,FTFEDV
.ENDC	;.IF EQ,FTP5

SWPHDF:	SWAB	DT11DF-DT11HD(R0)	;swap DN60 function,,result
	SWAB	DT11AD-DT11HD(R0)	;swap address for dep/exam, or line,,dev
	SWAB	DT11DT-DT11HD(R0)	;swap dep data or indirect length
.IF NE,FTP5
	SWAB	DT11A3-DT11HD(R0)	;swap remaining args
	SWAB	DT11A4-DT11HD(R0)	;swap remaining args
	SWAB	DT11A5-DT11HD(R0)	;swap remaining args
	SWAB	DT11A6-DT11HD(R0)	;swap remaining args
	SWAB	DT11A7-DT11HD(R0)	;swap remaining args
.ENDC	;IF NE,FTP5
	RETURN				;exit

VALHDR:					;validate fe header pointed to by R0
.IF EQ,FTP5
.IF	NE,FTFEDV
	CMP	DT11DV-DT11HD(R0),#DLDPFE;make sure device is DN60 device
	BNE	10$			;if not, return error
	CMPB	DT11FN-DT11HD(R0),#DTFSAK	;check for ack FEH
	BEQ	99$			;yes - valid header, no indirect coming
	TST	DT11FN-DT11HD(R0)	;check if indirect
	BPL	10$			;this is not so pretty good
	CMPB	DT11FN-DT11HD(R0),#DTFSTR;make sure function is string data
	BEQ	99$			;if so, all is kosher
					;if not, this header is to be ignored!
					;unbelievable !!!!
.IFF
	CMPB	DT11FN-DT11HD(R0),#DTFDAS;make sure function is DN60
	BNE	10$			;if not, return error
	CMP	DT11DV-DT11HD(R0),#DLDDAS;make sure device is DN60 device
	BEQ	99$			;if so, don't set error
.ENDC	; .IF NE,FTFEDV
10$:	SEC
	RETURN
.ENDC	;.IF EQ,FTP5

99$:	CLC
	RETURN

CPYHDR:					;subroutine to copy input to output header
.IF EQ,FTP5
.IF	NE,FTFEDV
	MOV	#D10HDL,DT10HD		;size of output header
.IFF
	MOV	#D10HDL+D10DFL,DT10HD	;size of output header
.ENDC	; .IF NE,FTFEDV
	MOV	DT11DV,DT10DV		;copy queued protocol device
	MOV	DT11FN,DT10FN		;copy queued protocol function
.IF	NE,FTFEDV
	BIS	#100000,DT10FN		;set indirect bit
	MOVB	DT11UC+1,DT10UC+1	;xfer the FE #
	MOVB	#D10DFL,DT10UC		;set the bytes to follow to DN60 header size
.IFF
	BIC	#100000,DT10FN		;clear indirect bit
.ENDC	; .IF NE,FTFEDV

.IFF
	MOV	#D11DFL,RSPSIZ		;set response header size
.ENDC	;.IF EQ,FTP5

CPYDFL:	MOV	DT11DF,DT10DF		;copy DN60 function
	MOV	DT11AD,DT10AD		;copy address or line,,dev
	CLR	DT10DT			;clear data transferred
.IF NE,FTP5
	CLR	DT10A3			;precleen response header
	CLR	DT10DS
	CLR	DT10DS+2
	CLR	DT10LS
	CLR	DT10LS+2
.ENDC	;IF NE,FTP5
	RETURN				;done
	.SBTTL		Interface to read/write data part of message

.REPT 0

 This interface consists of 4 routines, BLECHI and BLECHO to
read and write blocks of data, and BYTCHI and BYTCHO to read
and write a single byte.  The first two have a byte count in
R0 and an address in R1, the latter two simply transfer the
single byte to/from R0.

.ENDR;.REPT 0

BLECHI:					;block transfer in
	TRACE	TRCTEN,<(SP),TCXLT(R5),R0,INPCTR>
	CLR	-(SP)			;assume 0 bytecount returned
	CMP	R0,INPCTR		;see if request too big
	BLE	10$			;no, assumption right so branch
	SUB	INPCTR,R0		;yes, calculate returned bytecount
	MOV	R0,(SP)			;save it for later
	MOV	INPCTR,R0		;change request to amount we have
10$:	SAVE	R2			;save source address register
	MOV	INPPTR,R2		;get source address
	SUB	R0,INPCTR		;update input count
	CLC				;ensure carry bit clear
	BIT	#1,R2			;source address odd?
	BNE	20$			;yes, go check for match
	BIT	#1,R1			;destination address even too?
	BNE	50$			;no, go do byte moves for mismatch
30$:	ROR	R0			;divide by two to get words
	BEQ	32$			;if none, go check for extra byte
31$:	MOV	(R2)+,(R1)+		;copy word
	SOB	R0,31$			;loop till count exhausted
32$:	BCC	33$			;if original count was not odd, go finish
	MOVB	(R2)+,(R1)+		;else copy odd byte
	CLC
33$:	MOV	R2,INPPTR		;update input pointer
	RESTOR	<R2,R0>			;restore work register and set count remaining
					;plus condition codes
	RETURN
20$:	BIT	#1,R1			;is destination address odd
	BEQ	50$			;no, go process mismatch
	MOVB	(R2)+,(R1)+		;copy preceding odd byte
	SOB	R0,30$			;update count and jump into loop if more
	BR	33$			;just exit if that was all
50$:	MOVB	(R2)+,(R1)+		;copy one byte
	SOB	R0,50$			;repeat till count exhausted
	BR	33$			;go finish up
BLECHO:				;block transfer out
	TRACE	TRCTEN,<(SP),TCXLT(R5),R0,R1>
	CLR	-(SP)			;assume 0 bytecount returned
	CMP	R0,OUTCTR		;see if request too big
	BLE	10$			;no, assumption right so branch
	SUB	OUTCTR,R0		;yes, calculate returned bytecount

	MOV	R0,(SP)			;save it for later
	MOV	OUTCTR,R0		;change request to amount we have
10$:	SAVE	R2			;save destination address register
	MOV	OUTPTR,R2		;get destination address
	SUB	R0,OUTCTR		;update remaining output count
	CLC				;ensure carry bit clear
	BIT	#1,R2			;destination address odd?
	BNE	20$			;yes, go check for match
	BIT	#1,R1			;source address even too?
	BNE	50$			;no, go do byte moves for mismatch
30$:	ROR	R0			;divide by two to get words
	BEQ	32$			;if none, go check for extra byte
31$:	MOV	(R1)+,(R2)+		;copy word
	SOB	R0,31$			;loop till count exhausted
32$:	BCC	33$			;if original count was not odd, go finish
	MOVB	(R1)+,(R2)+		;else copy odd byte
	CLC
33$:	MOV	R2,OUTPTR		;update output pointer
	RESTOR	<R2,R0>			;restore work register and set count remaining
					;plus condition codes
	RETURN
20$:	BIT	#1,R1			;is source address odd
	BEQ	50$			;no, go process mismatch
	MOVB	(R1)+,(R2)+		;copy preceding odd byte
	SOB	R0,30$			;update count and jump into loop if more
	BR	33$			;just exit if that was all
50$:	MOVB	(R1)+,(R2)+		;copy one byte
	SOB	R0,50$			;repeat till count exhausted
	BR	33$			;go finish up

BYTCHI:					;input one byte
	TST	INPCTR
	BGT	10$
	CLC
	SEZ
	RETURN
10$:	DEC	INPCTR
	CLR	R0
	BISB	@INPPTR,R0
	INC	INPPTR
	TRACE	TRCTEN,<(SP),TCXLT(R5),R0>
	CLRC	CZ
	RETURN

BYTCHO:					;output one byte
	TRACE	TRCTEN,<(SP),TCXLT(R5),R0>
	TST	OUTCTR			;any room?
	BGT	10$			;yes, continue
	CLC
	SEZ
	RETURN
10$:	DEC	OUTCTR
	MOVB	R0,@OUTPTR
	INC	OUTPTR
	CLRC	CZ
	RETURN
.IF NE,DTBUG
	.SBTTL		Debugging subroutines

STKSAV:					;subroutine to save state machine stack
	SAVE	<R0,R1,R2>		;save some registers
	MOV	#SAVSTK,R1		;point to source
	MOV	#INTSTK,R0		;address of source
	MOV	#STKLEN,R2		;get count
10$:	MOV	-(R0),-(R1)		;push onto save stack 
	SOB	R2,10$			;copy whole stack
	MOV	SP,R2			;copy current pointer
	SUB	#INTSTK,R2		;displacement
	ADD	#SAVSTK,R2		; into saved stack
	MOV	R2,SAVSTK		;save stack pointer
20$:	RESTOR	<R2,R1,R0>
	RETURN

.ENDC;.IF NE,DTBUG