[mod.computers.vax] OBSERVE.MAR Part 1 of 1

todd@CINCOM.UMD.EDU ("TODD AVEN") (12/17/86)

Following the -*- cut here -*- is the VAX/MACRO program
OBSERVE.MAR.  I didn't write it, so I can't answer any
questions about it (gasp! I haven't even looked at the code).

Use in good taste, please.

-? send(message(following),from(todd),to(Netlandiers)).
			-*- cut here -*-
	.TITLE		OBSERVE

	.LIBRARY	/SYS$LIBRARY:LIB.MLB/

	.PAGE
	.SUBTITLE	DEFINITIONS

	$CRBDEF		GLOBAL
	$DDBDEF		GLOBAL
	$DVIDEF		GLOBAL
	$IDBDEF		GLOBAL
	$IODEF		GLOBAL
	$IPLDEF		GLOBAL
	$IRPDEF		GLOBAL
	$PRDEF		GLOBAL
	$PRIDEF		GLOBAL
	$RSNDEF		GLOBAL
	$SSDEF		GLOBAL
	$TTYDEF		GLOBAL
	$TTDEF		GLOBAL
	$TT2DEF		GLOBAL
	$UBADEF		GLOBAL
	$UCBDEF		GLOBAL
	$VECDEF		GLOBAL
	$TTYMACS	
	$TTYDEFS	GLOBAL

	.PAGE
	.SUBTITLE	PARAMETERS

TERM_LENGTH     =  64
RESPONSE_LENGTH =   1
HEADER          =  12
DYN_C_CODE      = 120

GREATER_THAN_ZERO = ^B1100
NEGATIVE          = ^B1000
ZERO              = ^B0100

	.PAGE
	.SUBTITLE	BUFFERS

CHANNEL:
	.BLKW		1

SYS_INPUT:
	.ASCII		/SYS$INPUT/
SYS_INPUT_LENGTH        = .- SYS_INPUT

TERM_PROMPT:
	.ASCII		/enter target terminal /
TERM_PROMPT_LENGTH           = .- TERM_PROMPT

PROMPT_BUFFER:
	.BLKB		TERM_LENGTH

TARGET_TERMINAL:
	.BLKB		TERM_LENGTH

MY_TERMINAL:
	.BLKB		TERM_LENGTH


;I need to substitute tests for 'X' in the terminal name with a test of
;this byte (MY_TERM_TYPE).  I should also validate the target terminal
;type (DT$_DZ11 or DT$_DMF32).

TARGET_TERM_TYPE:
	.BYTE		0

MY_TERM_TYPE:
	.BYTE		0	

TARGET_PID:
	.BLKL		1

TARGET_CLASS:
	.BLKL		1

TARGET_UCB_ADDRESS:
	.BLKL		1

TARGET_UCB_PRTCTL:
	.BLKW		1

NPP_ADDRESS:
	.BLKL		1

ALLOCATED_SIZE:
	.BLKL		1

RESPONSE_BUFFER:
	.BLKB		RESPONSE_LENGTH

EXIT_MESSAGE_BUFFER:
	.BYTE		27
	.BYTE		91
	.BYTE		72
	.BYTE		27
	.BYTE		91
	.BYTE		74
	.ASCII		?enter CTRL/Y to exit?
	.BYTE		13
	.BYTE		10
EXIT_MESSAGE_LENGTH = .- EXIT_MESSAGE_BUFFER

ROW:	.LONG	24
COLUMN:	.LONG	1

MY_UCB_ADDRESS:
	.LONG		0

PUTNXT_ADDRESS:
	.LONG		0

GETNXT_ADDRESS:
	.LONG		0

PORT_ADDRESS:
	.LONG		0

NEW_PUTNXT_ADDRESS:
	.BLKL		1

NEW_GETNXT_ADDRESS:
	.BLKL		1

NEW_PORT_ADDRESS:
	.BLKL		1

USER_RUNDOWN_ADDRESS:
	.BLKL		1

CONTROL_Y_MASK:
	.LONG		^X02000000

QIO_IOSB:
	.BLKQ		1

TERMINAL_CHAR:
	.BLKQ	1


	.PAGE
	.SUBTITLE	GETDVI ITEM LIST

GETDVI_ITEM_LIST:
	.WORD		TERM_LENGTH
	.WORD		DVI$_TT_PHYDEVNAM
DVI_TERM_ADDR:
	.ADDRESS	TARGET_TERMINAL
	.LONG		0

	.WORD		4
	.WORD		DVI$_PID
	.ADDRESS	TARGET_PID
	.LONG		0

	.WORD		4
	.WORD		DVI$_DEVCLASS
	.ADDRESS	TARGET_CLASS
	.LONG		0

	.LONG		0


	.PAGE
	.SUBTITLE	DESCRIPTORS


SYS_INPUT_DESCR:
	.WORD		SYS_INPUT_LENGTH
	.BLKW		1
	.ADDRESS	SYS_INPUT

TERM_PROMPT_DESCR:
	.WORD		TERM_PROMPT_LENGTH
	.BLKW		1
	.ADDRESS	TERM_PROMPT

TARGET_TERM_DESCR:
	.WORD		TERM_LENGTH
	.BLKW		1
	.ADDRESS	TARGET_TERMINAL


	.PAGE
	.SUBTITLE	OBSERVE

	.ENTRY		OBSERVE, ^M<>

	BSBW		INITIAL
	CMPL		#SS$_NORMAL, R0
	BEQLU		10$
	BRW		EXIT
10$:
	$CMKRNL_S	ROUTIN = INITIALIZE_UCBS
	BLBS		R0, 20$
	BRW		EXIT
20$:
	;disable CTRL/Y

	PUSHAL		CONTROL_Y_MASK
	CALLS		#1, G^LIB$DISABLE_CTRL
	BLBS		R0, 30$
	BRW		EXIT
30$:
	;clear screen with write

	$QIOW_S		FUNC   = #IO$_WRITEVBLK,-
			CHAN   = CHANNEL,-
			IOSB   = QIO_IOSB,-
			P1     = EXIT_MESSAGE_BUFFER,-
			P2     = #EXIT_MESSAGE_LENGTH
	BLBC		R0, EXIT
	BLBC		QIO_IOSB, EXIT

	;modify target UCB

	$CMKRNL_S	ROUTIN = MODIFY_TARGET_UCB
	BLBC		R0, EXIT

	;establish CTRL/Y AST to execute termination routine

	$QIOW_S		FUNC   = #IO$_SETMODE!IO$M_CTRLYAST,-
			CHAN   = CHANNEL,-
			IOSB   = QIO_IOSB,-
			P1     = TERMINATION
	BLBC		R0, EXIT
	BLBC		QIO_IOSB, EXIT

	$HIBER_S

EXIT:
	PUSHL		R0
	PUSHAL		CONTROL_Y_MASK
	CALLS		#1, G^LIB$ENABLE_CTRL

	BBS		#TT$V_NOBRDCST, TERMINAL_CHAR, 10$

	$QIOW_S		FUNC = #IO$_SETMODE,-
			CHAN = CHANNEL,-
			P1   = TERMINAL_CHAR
10$:
	$DASSGN_S	CHAN = CHANNEL

	$EXIT_S		(SP)+


	.PAGE
	.SUBTITLE	INITIAL


INITIAL:

	PUSHL		#0			;prompt only if string absent
	PUSHAL		TARGET_TERM_DESCR	;don't need out length
	PUSHAQ		TERM_PROMPT_DESCR
	PUSHAQ		TARGET_TERM_DESCR

	;obtain target terminal name

	CALLS		#4, G^LIB$GET_FOREIGN
	BLBS		R0, 10$

	BRW		INITIAL_EXIT

10$:
	;make sure it's a valid device

	$GETDVIW_S	DEVNAM = TARGET_TERM_DESCR,-
			ITMLST = GETDVI_ITEM_LIST
	BLBS		R0, 12$
11$:
	BRW		INITIAL_EXIT
12$:
	CMPL		#SS$_NOSUCHDEV, R0
	BEQL		11$

	;make sure the device is being used
15$:
	TSTB		TARGET_PID
	BNEQU		20$

	MOVL		#SS$_NONEXPR, R0
	BRW		INITIAL_EXIT

20$:
	;assign a channel to my terminal

	$ASSIGN_S	DEVNAM = SYS_INPUT_DESCR,-
			CHAN   = CHANNEL
	BLBS		R0, 25$
	BRW		INITIAL_EXIT

	;get my terminal name
25$:
	MOVAL		MY_TERMINAL, DVI_TERM_ADDR
	MOVL		#0, DVI_TERM_ADDR + 4

	$GETDVIW_S	CHAN   = CHANNEL,-
			ITMLST = GETDVI_ITEM_LIST
	BLBC		R0, INITIAL_EXIT

	MOVL		TARGET_TERMINAL + 1, TARGET_TERMINAL
	MOVL		MY_TERMINAL + 1, MY_TERMINAL

	;make sure I'm not observing my terminal

	CMPL		MY_TERMINAL, TARGET_TERMINAL
	BNEQU		30$

	MOVL		#SS$_NONEXPR, R0
	BRB		INITIAL_EXIT

	;set my terminal to no-broadcast
30$:
	$QIOW_S		FUNC = #IO$_SENSEMODE,-
			CHAN = CHANNEL,-
			P1   = TERMINAL_CHAR
	BLBC		R0, INITIAL_EXIT

	BBS		#TT$V_NOBRDCST, TERMINAL_CHAR, INITIAL_EXIT

	MOVQ		TERMINAL_CHAR, QIO_IOSB
	BISL2		#TT$M_NOBRDCST, QIO_IOSB + 4

	$QIOW_S		FUNC = #IO$_SETMODE,-
			CHAN = CHANNEL,-
			P1   = QIO_IOSB

INITIAL_EXIT:
	RSB


	.PAGE
	.SUBTITLE	INITIALIZE UCBS


	.ENTRY		INITIALIZE_UCBS, ^M<R2, R3, R4, R5, R6, R7, R8, R9>

	BSBW		FIND_UCBS

	;check to see if this terminal is already OBSERVEd

	MOVL		MY_UCB_ADDRESS, R1
	CMPL		UCB$L_TT_PUTNXT(R1), PUTNXT_ADDRESS
	BEQLU		10$
5$:
	MOVL		#SS$_ILLIOFUNC, R0
	BRB		20$
10$:
	MOVL		TARGET_UCB_ADDRESS, R0
	CMPB		UCB$W_TT_SPEED(R1), UCB$W_TT_SPEED(R0)
	BLSSU		5$
15$:
	BSBW		PUT_ROUTINE_IN_NPP
20$:
	RET

	.PAGE
	.SUBTITLE	FIND_UCBS

FIND_UCBS:

	MOVL		G^IOC$GL_DEVLIST, R6

10$:
	CMPC3		#3, DDB$T_NAME+1(R6), TARGET_TERMINAL
	BNEQU		30$

	CLRL		R7
	CLRL		R8
	SUBB3		#48, TARGET_TERMINAL + 3, R7

	MOVL		DDB$L_UCB(R6), R9
	BRB		25$

20$:
	MOVL		UCB$L_LINK(R9), R9
25$:
	AOBLEQ		R7, R8, 20$

;	MOVL		UCB$L_CRB(R9), R10
;	MOVB		CRB$B_TT_TYPE(R10), TARGET_TERM_TYPE

	MOVL		UCB$L_TT_PUTNXT(R9), PUTNXT_ADDRESS
	MOVL		UCB$L_TT_GETNXT(R9), GETNXT_ADDRESS
	MOVL		UCB$L_TT_PORT(R9), PORT_ADDRESS
	MOVW		UCB$W_TT_PRTCTL(R9), TARGET_UCB_PRTCTL

	MOVL		R9, TARGET_UCB_ADDRESS

	TSTL		MY_UCB_ADDRESS
	BNEQU		FIND_EXIT

30$:
	CMPC3		#3, DDB$T_NAME+1(R6), MY_TERMINAL
	BNEQU		60$

	CLRL		R7
	CLRL		R8
	SUBB3		#48, MY_TERMINAL + 3, R7

	MOVL		DDB$L_UCB(R6), R9
	BRB		45$

40$:
	MOVL		UCB$L_LINK(R9), R9
45$:
	AOBLEQ		R7, R8, 40$

	MOVL		R9, MY_UCB_ADDRESS

;	MOVL		UCB$L_CRB(R9), R10
;	MOVB		CRB$B_TT_TYPE(R10), MY_TERM_TYPE

	TSTL		TARGET_UCB_ADDRESS
	BNEQU		FIND_EXIT

60$:
	MOVL		DDB$L_LINK(R6), R6
	BEQLU		FIND_EXIT
	BRW		10$

FIND_EXIT:
	RSB

	.PAGE
	.SUBTITLE	PUT_ROUTINE_IN_NPP

PUT_ROUTINE_IN_NPP:

	CMPB		#^A/X/, MY_TERMINAL + 1
	BNEQU		10$

	MOVL		#DMF_ROUTINE_LENGTH, R1
	BRB		20$
10$:
	MOVL		#DZ_ROUTINE_LENGTH, R1
20$:
	MTPR		IPL_TWO, S^#PR$_IPL
	JSB		G^EXE$ALONONPAGED
	MTPR		#0, S^#PR$_IPL

	;establish image rundown routine

	MOVL		G^CTL$GL_USRUNDWN, USER_RUNDOWN_ADDRESS

	MOVAL		RESET_UCBS, G^CTL$GL_USRUNDWN

	BRB		AROUND

IPL_TWO:
	.BYTE		2

AROUND:
	BLBS		R0, 2$
	BRW		PUT_EXIT
2$:
	MOVL		R2, NPP_ADDRESS

	MOVL		PUTNXT_ADDRESS, (R2)+
	MOVL		MY_UCB_ADDRESS, (R2)+

	;mark block for easy deallocation

	MOVW		R1, (R2)+
	MOVW		#DYN_C_CODE, (R2)+

	;move GETNXT address and port address

	MOVL		GETNXT_ADDRESS, (R2)+

	MOVL		@PORT_ADDRESS, (R2)+

	;save start of vector table in R8 for modifying UCB

	MOVL		R2, NEW_PORT_ADDRESS

	;calculate address of PORT_STARTIO vector and move into vector table

	CMPB		#^A/X/, MY_TERMINAL + 1
	BNEQU		3$

	ADDL3		NPP_ADDRESS, #DMF_STARTIO_DISPLACEMENT, (R2)+
	BRB		4$
3$:
	ADDL3		NPP_ADDRESS, #DZ_STARTIO_DISPLACEMENT, (R2)+
4$:
	;loop to move the other port vectors

	MOVL		#1, R0
5$:
	MOVL		@PORT_ADDRESS[R0], (R2)+
	AOBLSS		#14, R0, 5$

	;move address of PUTNXT code into R6 for modifying UCB

	MOVL		R2, NEW_PUTNXT_ADDRESS

	;move code into system buffer,  calculate GETNXT address (in R7)

	CMPB		#^A/X/, MY_TERMINAL + 1
	BNEQU		10$

	MOVC3		#DMF_CODE_LENGTH, DMF_PUTNXT_ROUTINE, (R2)
	ADDL3		#DMF_GETNXT_DISPLACEMENT, NEW_PUTNXT_ADDRESS,-
			NEW_GETNXT_ADDRESS
	BRB		20$

10$:
	MOVC3		#DZ_CODE_LENGTH, DZ_PUTNXT_ROUTINE, (R2)
	ADDL3		#DZ_GETNXT_DISPLACEMENT, NEW_PUTNXT_ADDRESS,-
			NEW_GETNXT_ADDRESS
20$:
	MOVL		#SS$_NORMAL, R0

PUT_EXIT:
	RSB

	.PAGE
	.SUBTITLE	MODIFY TARGET UCB

	.ENTRY		MODIFY_TARGET_UCB, ^M<>

	MOVL		TARGET_UCB_ADDRESS, R2

	MTPR		IPL_21, S^#PR$_IPL

	MOVL		NEW_PUTNXT_ADDRESS, UCB$L_TT_PUTNXT(R2)
	MOVL		NEW_GETNXT_ADDRESS, UCB$L_TT_GETNXT(R2)
	MOVL		NEW_PORT_ADDRESS, UCB$L_TT_PORT(R2)

	;clear DMA bit to force single character and burst output

	BICW2		#TTY$M_PC_DMAENA, UCB$W_TT_PRTCTL(R2)

	MTPR		#0, S^#PR$_IPL

	MOVL		#SS$_NORMAL, R0
	RET

IPL_21:
	.BYTE		21


	.PAGE
	.SUBTITLE	START OF DMF ROUTINE


START_OF_DMF_ROUTINE:

DMF_PUTNXT_ADDRESS:
	.BLKL		1

DMF_MY_UCB_ADDRESS:
	.BLKL		1

	.BLKL		1	;holds position of 3rd longword of header

DMF_GETNXT_ADDRESS:
	.BLKL		1	;moved to system buffer via MOVL

DMF_PORT_VECTOR:
	.BLKL		1

DMF_PORT_VECTOR_TABLE:
	.BLKL		14	;new vector table

DMF_PUTNXT_ROUTINE:

	PUSHR		#^M<R6, R7, R8, R9, R10>

	MOVL		DMF_MY_UCB_ADDRESS, R6

	MOVL		UCB$L_CRB(R6), R7
	MOVL		@CRB$L_INTD + VEC$L_IDB(R7), R7

	PUSHAL		DMF_START_IO			;return to output rtn
	JMP		@DMF_PUTNXT_ADDRESS		;perform code

DMF_GETNXT_ROUTINE:
DMF_GETNXT_DISPLACEMENT = .-DMF_PUTNXT_ROUTINE

	PUSHR		#^M<R6, R7, R8, R9, R10>

	MOVL		DMF_MY_UCB_ADDRESS, R6

	MOVL		UCB$L_CRB(R6), R7
	MOVL		@CRB$L_INTD + VEC$L_IDB(R7), R7

	JSB		@DMF_GETNXT_ADDRESS		;perform routine
DMF_START_IO:
	BLEQ		10$				;none or string output

	BISW3		#^X4040, UCB$W_UNIT(R6), (R7)	;select silo transmit
	MOVB		R3, 6(R7)			;output character

	BICPSW		#GREATER_THAN_ZERO		;reset CC
	BRB		91$

10$:
	BEQL		91$				;no output
	MOVW		UCB$W_TT_OUTLEN(R5), UCB$W_TT_OUTLEN(R6)
	MOVL		UCB$L_TT_OUTADR(R5), UCB$L_TT_OUTADR(R6)
	BISW3		#^X4040, UCB$W_UNIT(R6), (R7)
	MOVZBL		6(R7), R8			;get silo depth
	SUBL3		R8, #32, R8			;convert to # of slots
	MOVZWL		UCB$W_TT_OUTLEN(R6), R9		;get length of transfer
	CMPW		R9, R8				;compare slots and size
	BLEQU		50$
	MOVZBL		R8, R9				;maximize with slots
50$:
	MOVL		UCB$L_TT_OUTADR(R6), R10	;autoincrement R10
	ADDL		R9, UCB$L_TT_OUTADR(R6)		;update pointer
	SUBW		R9, UCB$W_TT_OUTLEN(R6)		;and count
	BEQL		60$
	BISW		#TTY$M_TANK_BURST,-
			UCB$W_TT_HOLD(R6)
60$:
	BLBC		R9, 70$				;branch if even
	MOVB		(R10)+, 6(R7)			;output single byte
	DECL		R9
	BEQL		90$
70$:
	ASHL		#-1, R9, R9			;convert to word count
75$:
	MOVW		(R10)+, 6(R7)
	NOP
	NOP
	NOP
	SOBGTR		R9, 75$
90$:
	TSTL		DMF_MY_UCB_ADDRESS		;reset CC negative
91$:
	POPR		#^M<R6, R7, R8, R9, R10>

	RSB

DMF_STARTIO_ROUTINE:
DMF_STARTIO_DISPLACEMENT = .-START_OF_DMF_ROUTINE

	BEQL		90$

	;save PSL on stack

	MOVPSL		-28(SP)

	;load return address for RSB in above routine

	PUSHL		DMF_PORT_VECTOR

	PUSHR		#^M<R6, R7, R8, R9, R10>

	;save condition codes and set branch address to above routine (REI)

	TSTL		-(SP)
	PUSHAL		DMF_START_IO

	MOVL		DMF_MY_UCB_ADDRESS, R6

	MOVL		UCB$L_CRB(R6), R7
	MOVL		@CRB$L_INTD + VEC$L_IDB(R7), R7

	;restore condition codes and branch

	REI

90$:
	JMP		@DMF_PORT_VECTOR


DMF_CODE_LENGTH = .-DMF_PUTNXT_ROUTINE
DMF_ROUTINE_LENGTH = .- START_OF_DMF_ROUTINE


	.PAGE
	.SUBTITLE	START OF DZ ROUTINE


START_OF_DZ_ROUTINE:

DZ_PUTNXT_ADDRESS:
	.BLKL		1

DZ_MY_UCB_ADDRESS:
	.BLKL		1

	.BLKL		1	;holds position of 3rd longword of header

DZ_GETNXT_ADDRESS:
	.BLKL		1	;moved to system buffer via MOVL  DMF_GETNXT...

DZ_PORT_VECTOR:
	.BLKL		1

DZ_PORT_VECTOR_TABLE:
	.BLKL		14

DZ_PUTNXT_ROUTINE:

	PUSHR		#^M<R6, R7, R8>

	MOVL		DZ_MY_UCB_ADDRESS, R6

	MOVL		UCB$L_CRB(R6), R7
	MOVL		@CRB$L_INTD + VEC$L_IDB(R7), R7

	PUSHAL		DZ_START_IO			;return to output rtn
	JMP		@DZ_PUTNXT_ADDRESS		;perform routine


DZ_GETNXT_ROUTINE:
DZ_GETNXT_DISPLACEMENT = .-DZ_PUTNXT_ROUTINE

	PUSHR		#^M<R6, R7, R8>

	MOVL		DZ_MY_UCB_ADDRESS, R6

	MOVL		UCB$L_CRB(R6), R7
	MOVL		@CRB$L_INTD + VEC$L_IDB(R7), R7

	JSB		@DZ_GETNXT_ADDRESS		;perform routine

	TSTB		UCB$B_TT_OUTYPE(R5)		;anything to output??
DZ_START_IO:
	BLEQ		10$				;none or string output

	MOVB		R3, UCB$W_TT_HOLD(R6)		;save character in tank
	BISW		#TTY$M_TANK_HOLD,-
			UCB$W_TT_HOLD(R6)		;signal char in tank
	BISW		UCB$W_TT_UNITBIT(R6), 4(R7)	;enable line

	BICPSW		#GREATER_THAN_ZERO		;reset CC positive
	BRW		90$				;exit

10$:
	BEQL		90$				;no character - exit
	MOVL		UCB$L_TT_OUTADR(R5), UCB$L_TT_OUTADR(R6)	;addr
	MOVW		UCB$W_TT_OUTLEN(R5), UCB$W_TT_OUTLEN(R6)	;len
	BISW		#TTY$M_TANK_BURST,-
			UCB$W_TT_HOLD(R6)		;signal burst
	BISW		UCB$W_TT_UNITBIT(R6), 4(R7)	;enable line

	TSTL		DZ_MY_UCB_ADDRESS		;reset CC negative
90$:
	POPR		#^M<R6, R7, R8>
	RSB

DZ_STARTIO_ROUTINE:
DZ_STARTIO_DISPLACEMENT = .-START_OF_DZ_ROUTINE

	;save PSL on stack

	MOVPSL		-20(SP)

	;push return address of above routine

	PUSHL		DZ_PORT_VECTOR

	PUSHR		#^M<R6, R7, R8>

	;save condition codes and set branch address to above routine (REI)

	TSTL		-(SP)
	PUSHAL		DZ_START_IO

	MOVL		DZ_MY_UCB_ADDRESS, R6		;get my UCB
	MOVL		UCB$L_CRB(R6), R7		;find my
	MOVL		@CRB$L_INTD + VEC$L_IDB(R7), R7	;CSR

	;restore condition codes and branch

	REI

DZ_CODE_LENGTH = .-DZ_PUTNXT_ROUTINE
DZ_ROUTINE_LENGTH = .- START_OF_DZ_ROUTINE



	.PAGE
	.SUBTITLE	TERMINATION ROUTINE

	.ENTRY		TERMINATION, ^M<>

	PUSHAL		CONTROL_Y_MASK
	CALLS		#1, G^LIB$ENABLE_CTRL

	pushal		column
	pushal		row
	calls		#2, G^lib$set_cursor

	BBS	#TT$V_NOBRDCST, TERMINAL_CHAR, 10$

	$QIOW_S		FUNC = #IO$_SETMODE,-
			CHAN = CHANNEL,-
			P1   = TERMINAL_CHAR
10$:
	$DASSGN_S	CHAN = CHANNEL

	;force immediate image rundown

	$EXIT_S		R0

	RET

	.PAGE
	.SUBTITLE	RESET UCBS

RESET_UCBS:

	MOVL		TARGET_UCB_ADDRESS, R2

	MOVL		NPP_ADDRESS, R0

	MTPR		IPL_TWENTY_ONE, S^#PR$_IPL

	MOVL		PUTNXT_ADDRESS, UCB$L_TT_PUTNXT(R2)
	MOVL		GETNXT_ADDRESS, UCB$L_TT_GETNXT(R2)
	MOVL		PORT_ADDRESS, UCB$L_TT_PORT(R2)
	MOVW		TARGET_UCB_PRTCTL, UCB$W_TT_PRTCTL(R2)

	MTPR		#2, S^#PR$_IPL

	JSB		G^EXE$DEANONPAGED

	MTPR		#0, S^#PR$_IPL

	;clear specified rundown routine

	MOVL		USER_RUNDOWN_ADDRESS, G^CTL$GL_USRUNDWN

	BRB		AROUND_1

IPL_TWENTY_ONE:
	.BYTE		21

AROUND_1:
	RSB
	.END		OBSERVE
------

LEICHTER-JERRY@YALE.ARPA.UUCP (12/18/86)

		WARNING!!!  This program can crash your system!

OBSERVE is a clever little piece of code that interposes itself between the
port and class drivers of a target terminal and copies all outgoing characters
directly to the terminal it was run on.  For OBSERVE to work, it must under-
stand the kind of port driver being used, and further the same port driver
must be used on both the target and observing terminals.  In practice, the
program understands the DZ11 and DMF32 port drivers.  Unfortunately, it makes
a rather simple test to determine which of the two it is dealing with:  It
looks at the second byte of the terminal's device name.  If that byte is "X",
the DMF32 code is used; otherwise, the DZ11 code is used.  For example, if you
try it out using a VAXStation emulated window - device name WTAn: - you'll get
a quick crash.  (At least I did.)  I'm willing to bet that the same thing will
happen with LAT terminals (LTAn) or a DECnet remote terminal (RTAn).  I don't
know what will happen with other terminal hardware, such as the DZ32, though I
think the port drivers for the DZ32 and DZ11 are the same, so that particular
one should work.  It's also not obvious that the code will work if virtual
terminals are enabled.  Since it WON'T run on my VAXStation - which has no
"real" terminals - I can't test any of this out; I'm not willing to crash our
8600 just for the heck of it.  So, I can only guess based on a quick reading
of sparsely-commented code.

Other things to know about OBSERVE:

	- I suspect that typing CTRL/S while observing a terminal that's
		producing a lot of output can cause a crash as various buffers
		overflow.
	- It is hard-wired to assume VT100-compatible terminals, only, though
		nothing really terrible will happen on others.
	- It has hard-coded in a variety of assumptions about the inards
		of the terminal driver.  Hence, it stands a good chance of
		dying as new versions of VMS come out.  Further, given its
		nature, any time OBSERVE dies, it is almost certain to take
		the system with it.
	- Some of the coding isn't quite as defensive as it might be; there
		are some timing windows during initialization that could leave
		the system in a strange state.  Don't type CTRL/Y while the
		program is starting up!
	- The program never bothers to lock down the kernel-mode, elevated-IPL
		code it runs during initialization; a page fault in this code
		will cause a crash.  This is quite unlikely, but possible.
	- If you start it via a foreign command, it will take a single argu-
		ment, the name of the target terminal.  Otherwise, it will
		prompt you.
	- Don't bother thinking about using OBSERVE to RECORD what a terminal
		is doing, rather than just displaying it - that would involve
		a whole new approach.

Take all this as a warning to be careful.  Given its simplicity, it's probably
the case that if OBSERVE works on a particular configuration at all, it will
continue to work - i.e., if you can run it for a couple of minutes without
crashing the system you should be safe.  But don't make your test run during
production!

BTW, OBSERVE needs CMKRNL - which it will NOT enable - and must be linked
against the system symbol table.  (I'm being brief deliberately:  If you
don't know what this means, you have no business playing with this program.)

							-- Jerry
-------

CP.PAVER@MCC.COM.UUCP (12/18/86)

Yup.  It doesn't like LAT's either.  Fortunately it was late at night...
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Bob Paver	(512) 338-3316
Microelectronics and Computer Technology Corp. (MCC)
3500 West Balcones Center Drive
Austin, TX  78759

ARPA:  paver@mcc.com
UUCP:  {ihnp4,seismo,harvard,gatech}!ut-sally!im4u!milano!paver
-------