From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 30-AUG-1989 16:13
To:	MRGATE::"ARISIA::EVERHART"
Subj:	SNAP part 7 of 8

Message-Id:  <8908302003.AA19213@crdgw1.ge.com>
Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Wed, 30 AUG 89 12:18:18 PDT
Received: from drcvax.af.mil by KL.SRI.COM with TCP; Wed, 30 Aug 89 11:50:43 PDT
Date: 30 Aug 89 14:33:00 EST
From: "Daniel J. Graham" <graham@drcvax.af.mil>
Subject: SNAP part 7 of 8
To: "info-vax" <info-vax@kl.sri.com>

-+-+-+-+-+-+-+-+ START OF PART 7 -+-+-+-+-+-+-+-+
X`009`009MOVL`009#KERN_SIZE, R1`009`009; Size of pool to get
X`009`009JSB`009G`094EXE$ALONONPAGED`009; Get the pool
X`009`009BLBS`009R0, 10$`009`009`009; Skip if OK
X`009`009ENBINT
X`009`009RET`009`009`009`009; Can't get it!
X10$:`009`009MOVW`009R1, CODE_SIZE`009`009; Store size
X`009`009MOVL`009R2, CODE_PTR`009`009; Store pointer
X`009`009MOVC3`009#KERN_SIZE,-
X`009`009`009KERNEL_CODE,-
X`009`009`009(R2)`009`009`009; Store the code in the block
X`009`009MOVL`009CODE_PTR, R0`009`009; Point to code block
X`009`009MOVAL`009SETUP-KERNEL_CODE(R0), R0 ; Get SETUP address
X`009`009JSB`009(R0)`009`009`009; Go to it
X`009`009ENBINT
X`009`009RET
X`012
X`009`009.SBTTL SETUP_TERM_AST - Setup the terminal mailbox AST
XSETUP_TERM_AST:`009$QIOW_S`009CHAN=USER_MBX,-`009`009; Using user's terminal
V mailbox
X`009`009`009FUNC=#IO$_SETMODE!IO$M_WRTATTN,- ; Write attention AST
X`009`009`009P1=TERM_AST`009`009; AST routine
X`009`009STATUS
X`009`009RSB
X
X`009`009.ENTRY`009TERM_AST, `094M<R2,R3>
X`009`009$QIOW_S`009`009CHAN=USER_MBX,-
X`009`009`009`009IOSB=USER_IOSB,-
X`009`009`009`009FUNC=#IO$_READVBLK,-
X`009`009`009`009P1=INPUT_MBX_BUF,P2=#512
X`009`009STATUS
XLOOP:`009`009$QIOW_S`009CHAN=INPUT_CHAN,-
X`009`009`009EFN=INPUT_EF,-
X`009`009`009FUNC=#IO$_READVBLK!IO$M_TIMED!IO$M_NOECHO,-
X`009`009`009IOSB=INPUT_IOSB,-
X`009`009`009P1=INPUT_BUF,-
X`009`009`009P2=#80,-
X`009`009`009P3=#0`009`009`009; Zero second timeout
X`009`009STATUS
X`009`009MOVZWL`009INPUT_IOSB, R0`009`009; Check status
X`009`009CMPW`009R0, #SS$_TIMEOUT`009; Timed out?
X`009`009BEQL`00910$`009`009`009; Yup, that's OK.
X`009`009STATUS
X10$:`009`009MOVW`009INPUT_IOSB+2, R2`009; Get offset to terminator
X`009`009ADDW`009INPUT_IOSB+6, R2`009; Plus terminator size
X`009`009BNEQ`00920$`009`009`009; Something there
X`009`009BSBW`009SETUP_TERM_AST`009`009; Reset the AST
X`009`009RET`009`009`009`009; Nothing there
X20$:`009`009MOVZWL`009R2, R2`009`009`009; Extend to word
X`009`009MOVAL`009INPUT_BUF, R3`009`009; And buffer pointer
X30$:`009`009MOVZBL`009(R3)+, SEND_CHAR`009; Get character
X;`009`009BRB`00960$
X`009`009CMPB`009SEND_CHAR,#`094A/\/-`094A/@/`009; `094\?
X`009`009BNEQ`00950$`009`009`009; Not the flag char
X`009`009BLBS`009FLAGS, 40$`009`009; If was set, clear it
X`009`009BISB`009#1, FLAGS`009`009; Set the flag
X`009`009PUSHAL`009ENABLED`009`009`009; Say input is enabled
X`009`009CALLS`009#1,G`094LIB$PUT_OUTPUT
X`009`009BRB`00960$`009`009`009; Try next char
X40$:`009`009BICB`009#1, FLAGS`009`009; Clear the input flag
X`009`009PUSHAL`009DISABLED
X`009`009CALLS`009#1,G`094LIB$PUT_OUTPUT`009; Say input disabled
X50$:`009`009BLBC`009FLAGS, 60$`009`009; Input mode disabled
X`009`009$CMKRNL_S`009ROUTIN=SEND_ONE,ARGLST=SEND_ARGS
X`009`009STATUS
X`009`009BRB`00970$`009`009`009; Done character
X60$:`009`009CMPB`009SEND_CHAR,#`094A/Z/-`094A/@/`009; Control-Z?
X`009`009BNEQ`00970$`009`009`009; Nope, ignore it.
X`009`009$EXIT_S`009#SS$_NORMAL`009`009; Exit now.
X70$:`009`009SOBGTR`009R2, 30$`009`009`009; Loop back
X`009`009BRW`009LOOP`009`009`009; Any more input?
X80$:`009`009RET
X`012
X`009`009.SBTTL`009SEND_ONE - Send a character to user terminal
X`009`009.ENTRY`009SEND_ONE, `094M<R2, R3, R4, R5>
X`009`009MOVL`009CODE_PTR, R0`009`009; Point to code block
X`009`009MOVAL`009SEND_IT-KERNEL_CODE(R0), R0 ; Get SEND CHARACTER address
X`009`009JSB`009(R0)`009`009`009; Call it
X`009`009RET
X`012
X`009`009.SBTTL`009KERNEL_CODE
X`009`009.PSECT`009LOADED`009RD, WRT, PIC, NOSHR, EXE, PAGE
XKERNEL_CODE:
XFKB_LIST:`009.BLKQ`0091`009`009`009; Fork block list
XCODE_SIZE:`009.BLKW`0091`009`009`009; Size
X`009`009.WORD`009DYN$C_FRK`009`009; Type
XCODE_PTR:`009.LONG`0090`009`009`009; Pointer to loaded code
XTERM_UCB:`009.LONG`0090`009`009`009; Terminal UCB
XMBX_UCB:`009.LONG`0090`009`009`009; Mailbox UCB
XPORT_TABLE:`009.BLKB`009PORT_LENGTH`009`009; Copied/munged port vector
XCLASS_LENGTH = CLASSS_CLASS_DEF`009`009`009; Hack since it's not there..
XCLASS_TABLE:`009.BLKB`009CLASS_LENGTH`009`009; Copied/munged class vector
XPORT_START_VEC:`009.LONG`0090`009`009`009; Gets original UCB PORT STARTIO
XPORT_DS_VEC:`009.LONG`0090`009`009`009; Gets original UCB PORT modem`032
XCLASS_GETNXT_VEC:.LONG`0090`009`009`009; Gets original UCB Class GETNXT
XCLASS_PUTNXT_VEC:.LONG`0090`009`009`009; ... class driver put char
XCLASS_DS_VEC:`009.LONG`0090`009`009`009; ... class driver dataset trans
XPORT_DIS_VEC:`009.LONG`0090`009`009`009; ... port driver disconnect
XCLASS_DIS_VEC:`009.LONG`0090`009`009`009; ... class driver disconnect
XSAVED_PORT:`009.LONG`0090`009`009`009; Saved port driver pointer
XSAVED_CLASS:`009.LONG`0090`009`009`009; Saved class driver pointer
X`009`009.ALIGN`009QUAD
XFKB_COUNT = 20
XFKB_1:
X`009`009.REPT`00940
X`009`009.BLKQ`0091`009`009`009; Flink/Blink
X`009`009.WORD`009FKB$K_LENGTH`009`009; Size
X`009`009.BYTE`009DYN$C_FRK`009`009; Type
X`009`009.BYTE`0096`009`009`009; Fork IPL
X`009`009.BLKL`0093`009`009`009; FPC/FR3/FR4
X`009`009.ENDR
XRING_SIZE = 1024`009`009`009`009; Size of buffer
XBUF_2:`009`009.BLKB`009RING_SIZE`009`009; Fork level buffer
XRING_BUFFER:`009.BLKB`009RING_SIZE`009`009; Buffer for mailbox
XRING_PTR:`009.BLKL`0091`009`009`009; Pointer to data storage
XRING_FREE:`009.LONG`009RING_SIZE`009`009; Free in mailbox
XWRITE_SIZE:`009.BLKL`0091`009`009`009; Characters in alt buffer
X`012
X`009`009.SBTTL`009SETUP - Set up hook
XSETUP:`009`009MOVAL`009RING_BUFFER, RING_PTR`009; Set up pointer to buffer
X`009`009MOVAL`009FKB_LIST, FKB_LIST`009; Set up queue header
X`009`009MOVL`009FKB_LIST, FKB_LIST+4
X`009`009MOVAL`009FKB_1, R0`009`009; Set up FKB queue
X`009`009MOVL`009#FKB_COUNT, R1`009`009; Number of fork blocks
X10$:`009`009INSQUE`009(R0), @FKB_LIST+4`009; Insert onto queue at tail
X`009`009MOVAL`009FKB$K_LENGTH(R0), R0`009; Point to next
X`009`009SOBGTR`009R1, 10$`009`009`009; Do next
X
X`009`009MOVL`009TERM_UCB, R2`009`009; Get UCB pointer
X`009`009MOVL`009UCB$L_TT_PORT(R2), R0`009; Point to port vectors
X`009`009MOVL`009R0, SAVED_PORT`009`009; Save port vector pointer
X`009`009BLSS`00920$`009`009`009; Branch if legal system VA
X`009`009MOVL`009#SS$_IVDEVNAM, R0`009; Indicate an invalid device
X`009`009RSB`009`009`009`009; And return
X
X20$:`009`009MOVAL`009PORT_TABLE, R1`009`009; Point to internal table
X`009`009PUSHR`009#`094M<R0,R1,R2,R3,R4,R5>`009; Save across MOVC
X`009`009MOVC3`009#PORT_LENGTH, (R0),(R1)`009; Copy port vector to internal
X`009`009POPR`009#`094M<R0,R1,R2,R3,R4,R5>
X`009`009MOVL`009PORT_STARTIO(R1),-`009;
X`009`009`009PORT_START_VEC`009`009; Save old port startio
X`009`009MOVAL`009GRAB_STARTIO,-`009`009;
X`009`009`009PORT_STARTIO(R1)`009; Point to hook code
X`009`009MOVL`009PORT_DS_SET(R0),-`009;
X`009`009`009PORT_DS_VEC`009`009; Save old port dataset vector
X`009`009MOVAL`009GRAB_PORT_DS,-`009`009;
X`009`009`009PORT_DS_SET(R1)`009`009; Set new dataset transition
X`009`009MOVL`009PORT_DISCONNECT(R0),-`009; Save old port disconnect
X`009`009`009PORT_DIS_VEC`009`009;
X`009`009MOVAL`009GRAB_PORT_DIS,-`009`009;
X`009`009`009PORT_DISCONNECT(R1)`009;
X`009`009MOVL`009UCB$L_TT_CLASS(R2), R0`009; Point to class vectors
X`009`009MOVL`009R0, SAVED_CLASS`009`009; Save class table pointer
X`009`009BLSS`00930$`009`009`009; Branch if legal system VA
X`009`009MOVL`009#SS$_IVDEVNAM, R0`009; Indicate an invalid device
X`009`009RSB`009`009`009`009; And return
X
X30$:`009`009MOVAL`009CLASS_TABLE, R1`009`009; Point to saved table
X`009`009PUSHR`009#`094M<R0,R1,R2,R3,R4,R5>`009; Save registers
X`009`009MOVC3`009#CLASS_LENGTH, (R0),(R1); Copy class vector
X`009`009POPR`009#`094M<R0,R1,R2,R3,R4,R5>`009; Restore regs
X`009`009MOVL`009CLASS_GETNXT(R0),-`009; Save original getnxt vector
X`009`009`009CLASS_GETNXT_VEC`009;
X`009`009MOVAL`009GRAB_GETNXT,-`009`009;
X`009`009`009CLASS_GETNXT(R1)`009; Point to hook code
X`009DEVICELOCK -`009`009`009`009; lock the device
X`009`009LOCKADDR=UCB$L_DLCK(R2),-
X`009`009SAVIPL=-(SP)
X
X`009`009MOVAL`009GRAB_GETNXT,-`009`009; Plus point UCB
X`009`009`009UCB$L_TT_GETNXT(R2)`009;
X`009`009MOVL`009CLASS_PUTNXT(R0),-
X`009`009`009CLASS_PUTNXT_VEC`009; Save original PUTNXT vector
X`009`009MOVAL`009GRAB_PUTNXT,-`009`009; Set up copied class vector
X`009`009`009CLASS_PUTNXT(R1)
X`009`009MOVAL`009GRAB_PUTNXT,-`009`009; Plus device UCB
X`009`009`009UCB$L_TT_PUTNXT(R2)
X`009DEVICEUNLOCK -
X`009`009LOCKADDR=UCB$L_DLCK(R2),-
X`009`009NEWIPL=(SP)+,-
X`009`009CONDITION=RESTORE,-
X`009`009PRESERVE=YES
X`009`009MOVL`009CLASS_DS_TRAN(R0),-`009; Save original dataset trans
X`009`009`009CLASS_DS_VEC`009`009;
X`009`009MOVAL`009GRAB_CLASS_DS,-`009`009; Point to hook code
X`009`009`009CLASS_DS_TRAN(R1)`009;
X`009`009MOVL`009CLASS_DISCONNECT(R0),-`009; Save class disconect
X`009`009`009CLASS_DIS_VEC`009`009;
X`009`009MOVAL`009GRAB_CLASS_DIS,-`009; Point to hook code
X`009`009`009CLASS_DISCONNECT(R1)`009;
X`009DEVICELOCK -
X`009`009LOCKADDR=UCB$L_DLCK(R2),-
X`009`009SAVIPL=-(SP)
X`009`009MOVAL`009CLASS_TABLE,-`009`009;;; Point UCB to my class
X`009`009`009UCB$L_TT_CLASS(R2)`009;;;   table copy
X`009`009MOVAL`009PORT_TABLE,-`009`009;;; Plus point to my port
X`009`009`009UCB$L_TT_PORT(R2)`009;;;   table copy
X`009DEVICEUNLOCK -
X`009`009LOCKADDR=UCB$L_DLCK(R2),-
X`009`009NEWIPL=(SP)+,-
X`009`009CONDITION=RESTORE,-
X`009`009PRESERVE=YES
X`009`009MOVZBL`009#SS$_NORMAL, R0`009`009; Set normal status
X`009`009RSB`009`009`009`009; All done
X`012
X`009`009.SBTTL`009GRAB_CLASS_DS - Hook to notice dataset hangups
XGRAB_CLASS_DS:`009BSBB`009RESET_IT`009`009;;; Remove hooks
X`009`009JMP`009@CLASS_DS_VEC`009`009;;; Call the class driver
X
X`009`009.SBTTL`009GRAB_PORT_DS - Hook to notice dataset hangups
XGRAB_PORT_DS:`009BSBB`009RESET_IT`009`009;;; Remove hooks
X`009`009JMP`009@PORT_DS_VEC`009`009;;; Call the port driver
X
X`009`009.SBTTL`009GRAB_PORT_DIS - Hook to notice disconnects
XGRAB_PORT_DIS:`009BSBB`009RESET_IT`009`009;;; Reset device
X`009`009JMP`009@PORT_DIS_VEC`009`009;;; Call port driver
X
X`009`009.SBTTL`009GRAB_CLASS_DIS - Hook to notice disconnects
XGRAB_CLASS_DIS:`009BSBB`009RESET_IT`009`009;;; Reset device
X`009`009JMP`009@CLASS_DIS_VEC`009`009;;; Call class driver
X
XRESET_IT:`009MOVQ`009R0, -(SP)`009`009;;; Save registers
X`009`009CALLS`009#0, RESET`009`009;;; Reset terminal
X`009`009MOVQ`009(SP)+, R0`009`009;;; Restore...
X`009`009RSB`009`009`009`009;;; And return
X`012
X`009`009.SBTTL`009GRAB_STARTIO - Hook to send data to mbx
X;+
X;`009This routine is called at device IPL to send
X;`009the data to the port driver. The value in R3 contains
X;`009the data; either a character or a pointer to a burst string.
X;`009(r2 contains the size.) An IPL 6 fork is created to send the data
X;`009to the mailbox.
X;-
XGRAB_STARTIO:`009TSTL`009R3`009`009`009;;; Any work to do?
X`009`009BEQL`00910$`009`009`009;;; Nope, tell the startio.
X`009`009PUSHR`009#`094M<R0,R1,R2,R3,R4,R5>`009;;; Store volatile regs
X`009`009BSBB`009GET_DATA`009`009;;; Get terminal data
X`009`009POPR`009#`094M<R0,R1,R2,R3,R4,R5>`009;;; Restore registers
X`009`009TSTL`009R3`009`009`009;;; Reset condition codes
X10$:`009`009JMP`009@PORT_START_VEC`009`009;;; Call port routine
X`012
X`009`009.SBTTL`009GRAB_GETNXT - Hook to send data to mbx
X;+
X;`009This routine is called at device IPL to send
X;`009the data to the port driver. The value in R3 contains
X;`009the data; either a character or a pointer to a burst string.
X;`009(r2 contains the size.) An IPL 6 fork is created to send the data
X;`009to the mailbox.
X;-
X`009`009.ENABLE LSB
XGRAB_GETNXT:`009JSB`009@CLASS_GETNXT_VEC`009;;; Call the class driver
X10$:`009`009TSTB`009UCB$B_TT_OUTYPE(R5)`009;;; Any work to do?
X`009`009BEQL`00920$`009`009`009;;; Nope.
X`009`009PUSHR`009#`094M<R0,R1,R2,R3,R4,R5>`009;;; Store volatile regs
X`009`009BSBB`009GET_DATA`009`009;;; Check for data type...
X`009`009POPR`009#`094M<R0,R1,R2,R3,R4,R5>`009;;; Restore regs
X`009`009TSTB`009UCB$B_TT_OUTYPE(R5)`009;;; Reset cond codes
X20$:`009`009RSB`009`009`009`009;;; Return to caller
X`012
X`009`009.SBTTL`009GRAB_PUTNXT
X;+
X;`009This routine is used to grab echoes of input characters
X;-
XGRAB_PUTNXT:`009JSB`009@CLASS_PUTNXT_VEC`009;;; Call the class driver
X`009`009BRB`00910$`009`009`009;;; Common code.
X`009`009.DISABLE LSB
X`012
X`009`009.SBTTL GET_DATA - Copy the output data to the buffer
X;+
X;`009This routine copies the output data to the buffer.
X;`009When the buffer is full, DUMP_BUFFER is called
X;`009to output it to the mailbox.
X;-
XGET_DATA:`009TSTL`009R3`009`009`009;;; Character or pointer?
X`009`009BLSS`00920$`009`009`009;;; Pointer
X`009`009MOVB`009R3, @RING_PTR`009`009;;; Copy to buffer
X`009`009INCL`009RING_PTR`009`009;;; And bump it
X`009`009DECL`009RING_FREE`009`009;;; Less this much free
X`009`009BGTR`00910$`009`009`009;;; Still room left
X`009`009BSBW`009DUMP_BUFFER`009`009;;; Dump the buffer
X10$:`009`009RSB`009`009`009`009;;; Done sending message
X;
X;`009Handle multi-byte messages
X;
X20$:`009`009MOVZWL`009R2, R2`009`009`009;;; Size of message
X`009`009CMPL`009R2, #RING_SIZE`009`009;;; Is it too big?
X`009`009BLSS`00930$`009`009`009;;; Skip if not
X`009`009MOVL`009#RING_SIZE, R2`009`009;;; Limit to this size
X30$:`009`009CMPL`009R2, RING_FREE`009`009;;; Room for this one?
X`009`009BLEQ`00940$`009`009`009;;; Yup, add it in.
X`009`009MOVQ`009R2,-(SP)`009`009;;; Save R2 and R3
X`009`009BSBW`009DUMP_BUFFER`009`009;;; First, dump the buffer
X`009`009MOVQ`009(SP)+, R2`009`009;;; Restore R2 and R3
X40$:`009`009PUSHR`009#`094M<R0,R1,R2,R3,R4,R5>`009;;; Store registers
X`009`009MOVC3`009R2, (R3), @RING_PTR`009;;; Move to buffer
X`009`009POPR`009#`094M<R0,R1,R2,R3,R4,R5>`009;;; Restore registers
X`009`009ADDL`009R2, RING_PTR`009`009;;; Point to next byte
X`009`009SUBL`009R2, RING_FREE`009`009;;; Drop free counter
X`009`009RSB
X`012
X`009`009.SBTTL DUMP_BUFFER - Dump buffer to mailbox
X;+
X;`009Routine to write the buffer to the mailbox.
X;`009First calls EXE$FORK to wait for IPL 6 interrupt;
X;`009Returns to caller to proceed until IPL drops.
X;`009Fork routine takes the text and writes it to the mailbox.
X;-
XDUMP_BUFFER:`009SUBL3`009RING_FREE, #RING_SIZE,-`009;;; Free-original gives.
V.
X`009`009`009WRITE_SIZE`009`009;;;  Size to move
X`009`009MOVAL`009RING_BUFFER, RING_PTR`009;;; Reset pointer
X`009`009MOVL`009#RING_SIZE,RING_FREE`009;;; And free
X`009`009TSTL`009WRITE_SIZE`009`009;;; Anything to write?
X`009`009BLEQ`00910$`009`009`009;;; Nothing to do
X`009`009REMQUE`009@FKB_LIST, R5`009`009;;; Get a FKB to use
X`009`009BVS`00910$`009`009`009;;; No entry to get
X`009`009PUSHR`009#`094M<R0,R1,R2,R3,R4,R5>`009;;; Save regs cross MOVC
+-+-+-+-+-+-+-+-  END  OF PART 7 +-+-+-+-+-+-+-+-


