TITLE DNSNUP DECnet-10 Message Trace program SUBTTL Tarl Neustaedter SEARCH DCN,SNUP,D36PAR,S .REQUI REL:SNUP SALL .DIRECT MACMPD XP $ONLY,I.LUO!I.PRM!I.GTT $INIT MSG ;Revision history. ;1 Write the program. ;2 Add code to make sure program is running on same type of processor ; it was assembled for. XBLT vs BLT data structures can look different. ;3 Search DCN. ;4 Don't call WAKJOB with the interlock set. ;5 Avoid trashing T1 before calling SAVT. ;6 Add entry point for local messages ;7 Add checks for monitor skew, add error (^C) trapping. ;10 Update for DECnet Phase IV monitor. ;11 Update for DECnet in Section 7. ;12 Croque for the KS to get DN section right, would be unnecessary ; if LOCK could allocate EVM mapped in DN space... ;13 Undo much of edit 11, we've kroque'd the monitor till SNOOP can ; deal with section 7. ;14 Update for 7.03 field test #1. ;15 Add routine SVEUD for KS10 now that it isn't in KSSER anymore. ;Check for right version of SNUP. IFN V.SNUP-6,< PRINTX ?Wrong version of SNUP. Please obtain the latest version. > ;Make version global so we get a multiply defined if wrong version ;rel file is loaded after using the right universal. V.SNUP==:V.SNUP XP BUFSIZ,5000 ;Buffer size. XP BPTN,30 ;Number of breakpoints we will ; ask SNUP to handle. DEFINE POINTS,< ZZ=. AT RTROTR,[PUSHJ %P,ORECVD] ;Output message received. AT RTRITR,[PUSHJ %P,IRECVD] ;Input message received AT RTRLTR,[PUSHJ %P,LRECVD] ;local message. AT BP$000,[PUSHJ %P,INITAL] ;Initialization AT BP$001,[PUSHJ %P,DESTRO] ;Destroy TOTBPT=.-ZZ > ;To flag a word as 'needs to be relocated' DEFINE .R.(SYM),< SYMCNT==SYMCNT+1 GENSYM(M,\SYMCNT)==.-1 GENSYM(A,\SYMCNT)==LOKADR > DEFINE .M.(SYM),<0 SYMCNT==SYMCNT+1 GENSYM(M,\SYMCNT)==.-1 GENSYM(A,\SYMCNT)== > SYMCNT==0 ;To generate a symbol given a numeric argument DEFINE GENSYM(PRE,NUM), ;To delete symbol defined above DEFINE DELSYM(PRE,NUM), ;to define a symbol for SNOOP. DEFINE SYMDEF(SYM), VRSN.(0,1,0,15) SUBTTL Monitor code $LOSEG %MB==%J ;Define the message block pointer IFE FTXMON,< ;We get here in Monitor context (otherwise this code (EVM) is not mapped) ;However, the data we want to reference is in DECnet context. To prevent ;catch-36, we deviously map the NULL job, and make it's address space the ;DECnet context. This lets various PXCTs touch DECnet context data, such as ;MBs. To make it clear what's happening, and to let the same code work for ;extended monitors, the .DN. macro is defined below. DEFINE .DN.(INST),)> >;IFE FTXMON IFN FTXMON,< DEFINE .DN.(INST), >;IFN FTXMON ;Input and output message breakpoint receivers. ORECVD: CAIE %T1,DF.XMT ;Output? POPJ %P, ;no, ignore this one. PUSHJ %P,.M.(SAVT) ;Save our ACs MOVSI %T1,IOL.OT_9!TYP.MH ;Flag this is an output message JRST .R.(RECVD) ;Join common code LRECVD: PUSHJ %P,.M.(SAVT) ;Save acs MOVSI %T1,IOL.LO_9!TYP.MH ;Flag this as a local message JRST .R.(RECVD) ;join common code IRECVD: PUSHJ %P,.M.(SAVT) ;Save acs MOVSI %T1,IOL.IN_9!TYP.MH;Flag this is an input message RECVD: IFN FTXMON,< JSP %R,.M.(D36PIF) ;Call d36pif to turn avoid races >;FTXMON IFE FTXMON,< MOVEM %P,.R.(DNSVP) ;Save Monitor stack, which may be in PP space MOVEI %P,.R.(DNPDL) ;Get our, small one PUSHJ %P,.R.(RECVD1) ;Call message processor MOVE %P,.R.(DNSVP) ;Restore monitor stack POPJ %P, ;Return RECVD1: PUSHJ %P,.R.(SVEUD) ;Set up DECnet as previous context, PIOFF >;FTXMON MOVEI %T2,*4;Length of the entry block. (in bytes) XMOVEI %T4,UD.DAT(%MB) ;Get possible pointer to user data .DN. ;Compare against real pointer .DN. < ADD %T2,MD.ALL+UD.MSD(%MB)> ;Get number of bytes we have allocated ADDI %T2,3 ;Round up to nearest word. ASH %T2,-2 ;Convert to words MOVEI %T3,.M.(%DLBSZ) ;Get largest default buffer size ADDI %T3,.M.(%RTEHS) ;Add in ethernet overhead bytes ASH %T3,-2 ;Convert into words ADDI %T3,MB.LEN+MH.LEN ;Add overhead words CAMLE %T2,%T3 ;Enough room in buffer? JRST .R.(FULLBF) ;No, pretend buffer is full SKIPN %T3,.R.(DEPADR) ;Next address to store stuff in JRST .R.(CONTIN) ;Must be unwinding. Ignore message. MOVE %T4,%T3 ;Copy address ADD %T4,%T2 ;point to where our block would end. CAMGE %T3,.R.(EXMADR) ;Is start above reader's current pointer? CAMGE %T4,.R.(EXMADR) ;no, would this stomp on the reader's data? SKP ;We won't overwrite the user's message JRST .R.(FULLBF) ;Would destroy un-read message. drop it. CAMGE %T4,.R.(TOPADR) ;Would we go past the end of the buffer? JRST .R.(HAVADR) ;no, our pointer is good. SETOM (%T3) ;We have to wrap around. Flag the fact. MOVE %T3,.R.(ORGADR) ;Get start of buffer pointer MOVE %T4,%T3 ;copy address ADD %T4,%T2 ;Point to end of block CAML %T4,.R.(EXMADR) ;Make sure I am below taker's address. JRST .R.(FULLBF) ;Would destroy un-read message. Drop it. HAVADR: MOVEM %T2,MH.LNG(%T3) ;save length of this entry HRR %T1,.R.(LSTMSG) ;Get cumulative number of lost messages MOVEM %T1,MH.FLG(%T3) ;save flags for this entry MOVE %T1,.M.(UPTIME) ;Get system uptime as of this message MOVEM %T1,MH.UPT(%T3) ;save in time stamp for this entry MOVE %T1,.M.(DATE) ;Get udt of right now. MOVEM %T1,MH.UDT(%T3) ;save current date/time .DN. ;Get input circuit pointer .DN. < MOVE %T1,RC.LID(%T1)> ;Get the line ID for this circuit MOVEM %T1,MH.ILN(%T3) ;Store input circuit circuit id .DN. ;Get output circuit pointer .DN. < MOVE %T1,RC.LID(%T1)> ;Get the line ID for this circuit MOVEM %T1,MH.OLN(%T3) ;Store output circuit circuit id MOVEM %MB,MH.OMB(%T3) ;save original message block pointer ADDI %T3,MH.LEN ;Point past header part of message MOVE %T2,%MB ;Copy source pointer MOVEI %T1,MB.LEN ;Number of words to copy JSP %R,.R.(BLTR..) ;Copy the data XMOVEI %T2,UD.DAT(%MB) ;generate a possible pointer to user data .DN. ;Was the user data within the MB? JRST .R.(GIVUSR) ;yes, just give current stuff to the user .DN. ;Pointer to user data block SUB %T4,%T3 ;number of words to copy MOVE %T1,%T4 ;Put where xblt can find it JSP %R,.R.(BLTR..) ;And copy the data GIVUSR: MOVEM %T3,.R.(DEPADR) ;Save new deposit address AOS %T1,.R.(PENMSG) ;Bump count of pending messages TRNE %T1,3 ;Wake up every 4th message JRST .R.(CONTIN) ;Not 4th message, continue SKP ;Don't increment overflow count FULLBF: AOS .R.(LSTMSG) ;Bump count of lost messages IFN FTXMON,< JSP %R,.M.(D36PIN) ;Turn interrupts back on > MOVE %T1,.R.(MYJOB) ;Get job to wake up PUSHJ %P,.M.(WAKJOB) ;Wake him up. IFN FTXMON,< SKP ;don't try to turn them on twice. > CONTIN: IFN FTXMON,< JSP %R,.M.(D36PIN) ;Turn interrupts back on. > POPJ %P, ;Return to user ;UUO-level initialization and termination code. INITAL: MOVEI %T2,BUFSIZ ;No, get some core to use as buffer XMOVEI %T1,.R.(BUFFER) ;*Get pointer to our buffer MOVEM %T1,.R.(ORGADR) ;set up start of buffer MOVEM %T1,.R.(EXMADR) ;Initialize user's pointer. XMOVEI %T2,BUFSIZ(%T1) ;Get pointer to end of buffer MOVEM %T2,.R.(TOPADR) ;save as top address of buffer MOVEI %T2,FH.LEN ;Size of this entry MOVEM %T2,FH.LNG(%T1) ;Save as first entry in buffer MOVSI %T2,TYP.FH ;message type HRRI %T2,MB.LEN ;Message block length. MOVEM %T2,FH.FLG(%T1) ;Save as second word in header MOVE %T2,.M.(UPTIME) ;Get current uptime MOVE %T3,.M.(DATE) ;Universal date/time DMOVEM %T2,FH.UPT(%T1) ;say what time we started to trace MOVE %T2,.R.(.JBVER) ;Get program's version number MOVE %T3,.JBVER ;Get the monitor's real version DMOVEM %T2,FH.PVR(%T1) ;Save as version numbers XMOVEI %T3,FH.CFG(%T1) ;Where to copy config string to XMOVEI %T2,.M.(CONFIG) ;Where the config string is MOVEI %T1,^D5 ;Number of words to copy IFE FTXMON,< ;Do BLTR.. by hand, can't touch DECnet context on job PDL EXCH %T1,%T3 ;Put length in a safe place HRL %T1,%T2 ;Source of BLT data ADDI %T3,(%T1) ;point to first word after data BLT %T1,-1(%T3) ;Copy the data ; HLRZ %T2,%T1 ;Point to first word we didn't copy ; SETZ %T1, ;and say zero words left to copy > IFN FTXMON,< JSP %R,.R.(BLTR..) ;and copy the data > MOVEM %T3,.R.(DEPADR) ;And save deposit address, starting trace up. AOS .R.(PENMSG) ;Increment number of messages pending. AOS (%P) ;Bump return PC. POPJ %P, ;And return success. DESTROY: ;Entry to return freecore. SETZM .R.(DEPADR) ;Stop the trace. SETZM .R.(EXMADR) ;Wipe examine address. SETZM .R.(ORGADR) ;Clear start of freecore address SETZM .R.(TOPADR) ;Clear end of freecore address POPJ %P, ;And return ;Routine to simulate an XBLT BLTR..: IFN FTXMON,< EXTEND %T1,.R.(.+2) ;do a real xblt JRST (%R) ;and return XBLT ;extend opcode > IFE FTXMON,< EXCH %T1,%T3 ;Put length in a safe place HRL %T1,%T2 ;Source of BLT data ADDI %T3,(%T1) ;point to first word after data XCT 1,.R.(<[BLT %T1,-1(%T3)]>) ;Copy the data HLRZ %T2,%T1 ;Point to first word we didn't copy SETZ %T1, ;and say zero words left to copy JRST (%R) > IFE FTXMON,< ;Coroutine to set up DECnet context SVEUD: EXCH %J,(%P) ;Save J, get caller's PC PUSH %P,%J ;Save caller's PC ;Assume some job is addressable MOVE %J,.UPMP+SECTAB+0 ;Get current section pointer EXCH %J,-1(%P) ;Get J back, save section pointer CONO PI,PI.OFF ;Disable interrupts PUSH %P,.M.(.E0DMP) ;Section pointer to DECnet context POP %P,.UPMP+SECTAB+0 ;Make it the user map WREBR @.M.(.CPEBR) ;Flush page table ADJSP %P,-1 ;Get caller's PC off stack PUSHJ %P,@1(%P) ;Call caller CAIA AOS -1(%P) ;Caller skipped POP %P,.UPMP+SECTAB+0 ;Restore UPMP WREBR @.M.(.CPEBR) ;Flush page table CONO PI,PI.ON ;Reenable interrupts POPJ %P, ;Return >;END IFE FTXMON SUBTTL General program variables ADVANC BPTN,BPTN ;Number of symbols to set SNUP up for. ;^C intercept block CCBLOK: XWD 4,CCEXIT ;Length,,where to go ER.EIJ!ER.TLX!ER.QEX!ER.FUL!ER.OFL!ER.ICC!ER.IDV ;All errors trap EXP 0 ;Place for monitor to store PC. EXP 0 ;Place for monitor to store reason ;Filop argument list to do dump mode O OUTFIL: .FOOUT ;Argument block for FILOP ;To expand POINTS macro into radix50 names. DEFINE AT(NAME,STUFF),< RADIX50 0,NAME > LOCS: POINTS ;Define breakpoint symbols ZZ=. ;Define other symbols we need SYMDEF(SAVT) ;Coroutine to save t1-t4. SYMDEF(WAKJOB) ;Routine to wake myself up. IFN FTXMON,< SYMDEF(D36PIF) ;Routine to turn off interrupts SYMDEF(D36PIN) ;Routine to turn interrupts back on > IFE FTXMON,< SYMDEF(.E0DMP) ;DECnet context mapping SYMDEF(.CPEBR) ;EBR for CPU > SYMDEF(%DLBSZ) ;Default largest buffer size in bytes SYMDEF(%RTEHS) ;Ethernet header size in bytes SYMDEF(UPTIME) ;System uptime. SYMDEF(DATE) ;Universal date/time kept by monitor SYMDEF(CONFIG) ;Monitor name. HGHCNT==.-LOCS ;Number of symbols to relocate to section 7 CHKKLP: AT FTXMON ;Make sure we are run on a correct monitor IFN FTXMON,< CHKHGH: AT MS.HGH > CHKLEN: AT MB.LEN CHKDAT: AT UD.DAT CHKMSD: AT UD.MSD CHKALA: AT MD.ALA CHKALL: AT $MDALL CHKAT1: AT T1 ;Make sure the acs are correct CHKAMB: AT MB ;Another AC TOTADR=.-ZZ IFG , $BLOCK SNPARG,TOTBPT*2+2 ;Argument block for snoop uuo $BLOCK FOPBLK,.FOMAX $BLOCK SCBLK,.FXLEN $BLOCK LKBLK,.RBMAX $BLOCK PTBLK,.PTMAX $BLOCK BUFFER,BUFSIZ $BLOCK OBUF,3 ;Output buffer ring header IFE FTXMON,< $BLOCK DNPDL,30 ;A generous private stack $LVAR DNSVP ;A place to save the monitor's P > $LVAR LOKADR $LVAR MYJOB ;Words used to control buffer usage. $LVAR ORGADR ;Contains address of start of buffer $LVAR TOPADR ;Highest address in buffer. $LVAR DEPADR ;Next address to deposit into (Changed by EXEC) $LVAR EXMADR ;Next address to read from (Changed by USER) $LVAR LSTMSG ;number of lost messages $LVAR PENMSG ;Number of pending messages (Exec ups count ; when finished putting message, user ; decrements count when out to disk). $LVAR RELOFF ;Used to convert monitor buffer addresses to ; user buffer addresses. $LOSEG XLIST ;LIT LIT LIST SUBTTL Structure definitions $HISEG ;Note that these BEGSTRs are copied in DNTATL, the formatting program ; for this trace. BEGSTR FH ;File Header WORD LNG ;Length of this header FIELD FLG,9 ;Flags to indicate what kind of entry FIELD TYP,9 ;Entry Type XP TYP.FH,1 ; Entry type of header record HWORD MGL ;Length of a message block WORD UPT ;UPTIME corresponding to UDT below WORD UDT ;Universal Date/Time corresp to UPTIME WORD PVR ;Trace program version number (loc 137) WORD MVR ;Monitor Version (location 137) WORD CFG,5 ;CONFIG string from this monitor ENDSTR BEGSTR MH ;Message Header WORD LNG ;Length of the entire entry FIELD FLG,6 ;Flags to indicate what kind of entry FIELD IOL,3 ;Input, output, or local XP IOL.IN,1 ;Input XP IOL.OT,2 ;Output XP IOL.LO,3 ;locals FIELD TYP,9 ;Entry Type XP TYP.MH,2 ; Entry type of message record HWORD LST ;Cumulative number of messages lost WORD UPT ;UPTIME as of entry (reliable time stamp) WORD UDT ;Universal date/time (readable time stamp) WORD OMB ;Original MB pointer WORD ILN ;Input line ID (or zero if none) WORD OLN ;Output line ID (or zero if none) ENDSTR ;To expand POINTS macro into pointers to values DEFINE AT(NAME,STUFF), ;Define pointers VALS: POINTS ;Words which must have relocation added to them. ADDERS: ZZ=0 REPEAT SYMCNT,< ZZ=ZZ+1 XWD GENSYM(M,\ZZ),GENSYM(A,\ZZ) DELSYM(M,\ZZ) DELSYM(A,\ZZ) > XWD 0,0 ;End of list DEFINE .R., DEFINE .M., SUBTTL Startup code. Read filespec. DNSNUP: $SETUP ;Initialize the world MOVE T1,[.STDEF,,[1,,.STDSB 4]] ;Set default large buffers to 4 blocks SETUUO T1, ;While this program runs. $WARN CSL,,.TOCTW##,T1 GETFIL: MOVEI T1,[ASCIZ \Trace file:\] CALL .TSTRG## ;Type the prompt CALL .FILIN## ;Get a filespec back SKIPL T1 ;make sure we got a filespec $WARN FSR,,,,GETFIL MOVEI T1,SCBLK ;address of my scan block MOVEI T2,.FXLEN ;length of my scan block CALL .GTSPC## ;get the specification ;Default output extension to .MSG MOVE T1,.FXEXT+SCBLK ;Get extension user specified TLNN T1,-1 ;Anything in the mask? HRLOI T1,'MSG' ;No, use default MOVEM T1,.FXEXT+SCBLK ;Restore defaulted extension MOVE T1,[.FXLEN,,SCBLK] ;args for .STOPB MOVEI T2,FOPBLK+1 ;open block is hidden in the filop block MOVE T3,[.RBMAX,,LKBLK] ;lookup block MOVEI T4,PTBLK ;path block CALL .STOPB## ;create the lookup and open block stuff $ERROR BFS, MOVX T1,FO.ASC!.FOWRT ;Assign me a channel, for writing MOVX T2,.IOIMG ;Image buffered mode. DMOVEM T1,FOPBLK+.FOFNC ;save as function for filop MOVSI T1,OBUF ;And define output buffer ring header MOVSI T2,1 ;Set up 3 buffers DMOVEM T1,FOPBLK+.FOBRH ;Point to the ring headers MOVEI T1,LKBLK ;Pointer to the lookup block MOVEM T1,FOPBLK+.FOLEB ;Now open our file MOVE T1,[.FOMAX,,FOPBLK] FILOP. T1, ;do the enter on the file $ERROR FEF,,,t1 HLL T1,FOPBLK ;Get channel number HLLM T1,OUTFIL ;save in output block ;Get our monitor symbols. MOVE T1,[TOTBPT+TOTADR,,LOCS] ;Pointer to our symbol names CALL GETADR## ;ask snup what the symbol values are ;Initialize pointers and counters here **&&** MOVE T1,CHKKLP ;Check the monitor we are running on CAXE T1,FTXMON ;specifically, whether or not kl paging is on. JSP T2,ERRMVS ;Skew, complain MOVE T1,CHKLEN CAXE T1,MB.LEN JSP T2,ERRMVS ;Skew, complain MOVE T1,CHKDAT CAXE T1,UD.DAT JSP T2,ERRMVS ;Skew, complain MOVE T1,CHKMSD CAXE T1,UD.MSD JSP T2,ERRMVS ;Skew, complain MOVE T1,CHKALA CAXE T1,MD.ALA JSP T2,ERRMVS ;Skew, complain MOVE T1,CHKALL CAXE T1,MD.ALL JSP T2,ERRMVS ;Skew, complain MOVE T1,CHKAT1 CAXE T1,%T1 ;Do we agree on AC definitions? JSP T2,ERRMVS ;Skew, complain MOVE T1,CHKAMB ;Check other AC, message block pointer CAXE T1,%MB JSP T2,ERRMVS ;Skew, complain IFN FTXMON&0,< ;Relocate stuff to section 7 MOVE T1,CHKHGH ;Get section portion of address CAXE T1,MS.HGH ;Check for expected value JSP T2,ERRMVS ;Skew, complain MOVEI T2,HGHCNT ;Get count of symbols to relocate ADDM T1,LOCS(T2) ;Relocate next symbol SOJG T2,.-1 ;Relocate all symbols >; END IFN FTXMON PJOB T1, ;Find out what job I am MOVEM T1,MYJOB ;save it for later wakes. MOVEI T1,1 ;An HPQ to put us into HPQ T1, ;WHAM! $WARN HPQ, SUBTTL Relocate and insert breakpoints ;Following code must be nailed down. MOVX T1,5 ;Lock us in EVM, don't bother with contiguous LOCK T1, ;Lock! $ERROR CNL,,.TOCTW##,T1 LSH T1,^D9 ;make it an address, rather than a page HRRZM T1,LOKADR ;save as displacement into the monitor ;Now we are starting to be dangerous. Trap errors. MOVEI T1,CCBLOK ;Point to ^C intercept block MOVEM T1,.JBINT ;And set up trapping. ;Relocate address MOVEI T4,ADDERS ;Pointer to list of addresses RELADR: SKIPN T1,(T4) ;Get a word JRST SNPBPT ;do snoop breakpoints MOVE T2,(T1) ;Get relocation MOVSS T1 ;pointer to word itself ADDM T2,(T1) ;add in the relocation AOJA T4,RELADR ;and go do another SNPBPT: MOVEI T4,TOTBPT ;number of addresses to transfer MOVEI T1,1+TOTBPT*2 ;Size of argument block we are feeding it MOVE T2,CHKSUM ;Get the checksum that GETADR left us DMOVEM T1,SNPARG ;Save double word in argument list MOVEI T1,TOTBPT ;Number of breakpoints XFRBPT: SOJL T1,INSBPT ;After done copying points, insert them. MOVE T2,LOCS(T1) ;Get a breakpoint location MOVE T3,@VALS(T1) ;Get this breakpoint's value ADD T3,LOKADR ;relocate it. MOVE T4,T1 ;Copy breakpoint number ASH T4,1 ;multiply by 2.. DMOVEM T2,SNPARG+2(T4) ;Store in breakpoints part of argument block JRST XFRBPT ;Transfer another breakpoint INSBPT: MOVE T1,[.SODBP,,SNPARG] ;Argument to define breakpoints SNOOP. T1, ;define them! $ERROR BDF,,.TOCTW##,T1 MOVSI T1,.SOIBP ;Insert the breakpoints! SNOOP. T1, $ERROR BIF, SUBTTL Setup buffer. ;Now to set up the buffer MOVE T1,[.SONUL,,SNPARG] ;Execute null snoop function SNOOP. T1, ;To grab freecore. JSP T1,QUIT ;Failed, get out of here quick. SKIPE T2,ORGADR ;Get address buffer starts at. SKIPN T3,TOPADR ;Get address buffer ends in. JSP T1,QUIT ;A bad address, quit. MOVE T1,ORGADR ;Get monitor address of buffer SUBI T1,BUFFER ;subtrace user address of buffer MOVEM T1,RELOFF ;Save as relocation offset $INFORM TIS,,.TDATN## SUBTTL Main loop. LOOP: SKIPE P2,PENMSG ;Any messages pending? JRST REDMSG ;Yes, read them out of the buffer INCHRS T1 ;Get a character if there is one JRST SNOOZE ;nope, sleep for a while CAIL T1,140 ;Are we in upper case range? SUBI T1,40 ;no, put us there. CAIN T1,"Q" ;Quit command? JRST ABORT ;yes, exit!!! CAIN T1,"Z"-100 ;^Z command? JRST ABORT ;yes, exit!!! CAIN T1,"E" ;Exit command? JRST ABORT ;yes, exit!!! CAIN T1,"D" ;is this a DDT command? JRST GODDT ;do to DDT. $WARN UNC,,.TCHAR##,T1 JRST LOOP GODDT: SKIPN .JBBPT ;Make sure we have a breakpoint address first $WARN NDL,,,,LOOP JSR @.JBBPT ;and go to DDT JRST LOOP SNOOZE: MOVX T1, HIBER T1, ;Go to sleep for a minute $ERROR HUF,,,,ABORT JRST LOOP ;Got woken up for something CCEXIT: $ERROR FEJ,,,,.+1 ABORT: CLOSE EXIT ;Implicit reset removes breakpoints QUIT: RESET ;First thing, clean up neat $ERROR FAE,,.TXWDW##,T1,.+1 EXIT ERRMVS: RESET ;First thing, clean up ; $ERROR MVS,,,,.+1;Production message $ERROR MVS,,.TXWDW##,T2,.+1;Handy for debugging DNSNUP EXIT SUBTTL Buffered mode I/O routine. REDMSG: MOVE P3,EXMADR ;Get address of next message SUB P3,RELOFF ;Relocate to user virtual address SKIPL T1,(P3) ;Get length of the entry JRST OUTMSG ;Length is good, send it out JUMPE T1,[$ERROR ZER,,,,ABORT] MOVE P3,ORGADR ;Get starting address of buffer MOVEM P3,EXMADR ;save as address for next buffer SUB P3,RELOFF ;Relocate to user virtual address MOVE T1,(P3) ;Length of message to copy OUTMSG: MOVE T2,P3 ;Pointer to message OUTMS1: SETZ T4, ;Number of words left over for next pass MOVE T3,OBUF+2 ;Get number of words left in buffer SUB T3,T1 ;Get number of words left after us JUMPGE T3,OUTMS2 ;If it fits, we are o.k. MOVN T4,T3 ;Number of words left for next pass SETZ T3, ;Number of words left in current buffer MOVE T1,OBUF+2 ;Number of words we can actually copy this time JUMPE T1,OUTMS4 ;If we can't copy anything, just do an out. OUTMS2: MOVEM T3,OBUF+2 ;set current number of words left HRRZ T3,OBUF+1 ;get current pointer-1 to disk buffer ADD T1,T3 ;make pointer to last word to copy AOJ T3, ;Point to first word to leave data in HRL T3,T2 ;Point to first word to take data from BLT T3,(T1) ;Copy the data HLRZ T2,T3 ;Get new source address HRRM T1,OBUF+1 ;and save updated byte pointer SKIPE OBUF+2 ;Are there any words left in the buffer? JRST OUTMS3 ;Yes, continue JUMPE T4,OUTMS3 ;Return to caller OUTMS4: MOVE T1,[1,,OUTFIL] ;Args for filop FILOP. T1, ;Do an out UUO $ERROR OUF,,.TOCTW##,T1 OUTMS3: SKIPE T1,T4 ;Any words left to do? JRST OUTMS1 ;and do the rest of this buffer ADD P3,(P3) ;Point to next message in sequence ADD P3,RELOFF ;Convert to exec vm address MOVEM P3,EXMADR ;Save as location for next message we look for SOSG PENMSG ;Decrement number of messages pending JRST LOOP ;none pending, go to sleep JRST REDMSG ;Messages pending, go read them XLIST LIT LIST END DNSNUP