.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 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 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 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 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 ;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 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 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 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 ;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