.MCALL .MODULE .MODULE USR, VERSION=73, COMMENT= ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only 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 except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. ;++ ; Facility: User Service Routine ; ; Author: ; ; Abstract: ; ; Edit Who Date Description of modification ; ---- --- ---- --------------------------- ; 001 WLD 25-JAN-90 Expanded comments for routines ; at SPESHL. These routines build ; the argument block for the ; EMT 375 executed. The six word ; argument block identifies the ; EMT 375 as a .READx, although the ; the block is structurally that ; of a .SPFUNW. The byte at offset ; 11 is positive, containing a ; function code to support ; .ENTER, .DELETE, .LOOKUP, .RENAME ; .CLOSE, .PURGE, and .CLOSZ ; for special devices. ; ; (070) 22-Sep-90 MBG Change to .ENTER code to cause date to be corrected ; prior to use (including any month/year rollover) in ; directory entry for new file. Some format clean-up. ; ; (071) 15-Oct-90 MBG Code added during previous change should only be ; assembled if TIME$R is set. ; ;-- .NLIST CND .SBTTL ************************************** .SBTTL * User Service Routines For The * .IF NE MMG$T .IF NE SB .SBTTL * Extended Background (XB) Monitor * .IFF ;NE SB .SBTTL * Extended Memory (XM) Monitor * .ENDC ;NE SB .IF NE SUP$Y .IF NE SB .SBTTL * Multi-Mode Mapping Background (ZB) Monitor * .IFF ;NE SB .SBTTL * Multi-Mode Mapping (ZM) Monitor * .ENDC ;NE SB .ENDC ;NE SUP$Y .IFF ;NE MMG$T .IF NE RTE$M .SBTTL * RT-11 Emulator (RTEM) Monitor * .IFF ;NE RTE$M .IF NE VENU$C .SBTTL * VENUS (VAX 8600) Console Monitor * .IFF ;NE VENU$C .IF NE SB .SBTTL * Single Background (SB) Monitor * .IFF ;NE SB .SBTTL * Foreground/Background (FB) Monitor * .ENDC ;NE SB .ENDC ;NE VENU$C .ENDC ;NE RTE$M .ENDC ;NE MMG$T .SBTTL ************************************** .LIST CND .SBTTL Conditionalization Summary ;+ ;COND ; ; The USR has the following conditionals and conditional nesting: ; ; CSIBFL is the (default) CSI buffer length (but essentially fixed forever) ; ; CVT$NU 0 (RMON) Place to gen numeric conversion routines ; CVT$NU 1 (USR) ; ; GT$NM 0 (RMON) Place to gen GT$NM ; GT$NM 1 (USR) ; ; LK4$DV 0 (RMON) Place to generate part of LK4DEV ; 1 (USR) ; (MMG$T) Default value ; ; XFX$XX 0 (RMON) Place to generate part of xFxxx code ; 1 (USR) ; (MMG$T) Default value ; ; USR$CM 0 (RMON) Place to generate part of USRCOM code ; 1 (USR) ; (MMG$T) Default value ; ; GET$FD 0 (RMON) Place to generate GETFD code ; 1 (USR) ; (MMG$T) Default value ; ; OWN$ER 0 No device ownership tables to check ; OWN$ER 1 Device ownership tables to check ; ; UNI$64 0 No extended device-unit support in monitor ; UNI$64 1 Extended device-unit support in monitor ; ; SB = 0 FB/XM ; ; MMG$T 0 FB ; ; GT$NM 0 ; GT$NM 1 ; ; MTT$Y 1* ; ; MMG$T 1 XM ; ; CVT$NU 0 ; CVT$NU 1 ; ; GT$NM 0 ; GT$NM 1 ; ; SUP$Y 0 XM/XB ; SUP$Y 1 ZM/ZB ; ; XM$FET 1+ XM fetch support ; ; + means additive only ; * affects contents of USRBUF only ;- .SBTTL Macro Calls .LIBRARY "SRC:EDTL.MLB" .LIBRARY "SRC:SYSTEM.MLB" ; .LIBRARY "SRC:HARDWA.MLB" ;+ ; Programmed Request and Miscellaneous Utility Macros ;- .MCALL .ADDR .ASSUME .BR .CKXX ;SYSMAC .MCALL .EXIT .PRINT .TTINR ;SYSMAC .MCALL BSS CSIERR EMTER0 EMTER1 EMTER2 ;EDTL .MCALL EMTER3 EMTER4 GET PUT ;EDTL ;+ ; Structure Definition Macros ;- .MCALL .LB ;SYSTEM .MCALL ..SFST ;SYSTEM .MCALL ..PURG ..READ ..SPFU ..WRIT ;SYSTEM .MCALL .CF1DF .CF2DF .CHNDF .CSIDF .CSWDF ;SYSTEM .MCALL .DBKDF .DIEDF .DIHDF .DSCDF .DSTDF ;SYSTEM .MCALL .EMTDF .ERRDF .HANDF .HBFDF .HBGDF ;SYSTEM .MCALL .HNPDF .HSRDF .IMPDF .ISTDF .JSWDF ;SYSTEM .MCALL .QELDF .SGNDF .STWDF .SYCDF .OWNDF ;SYSTEM .SBTTL Invoke Structure Definition Macros ..PURG ;.PURGE EMT Data Layout and Symbolic Constants DOC$UN=1 ;define undocumented offsets ..READ ;.READ EMT Data Layout and Symbolic Constants DOC$UN=0 ..SFST ..SPFU ;.SPFUN EMT Data Layout and Symbolic Constants ..WRIT ;.WRITE EMT Data Layout and Symbolic Constants .CF1DF ;CONFIG First System Configuration Word Format .CF2DF ;CONFG2 Second System Configuration Word Format .CHNDF ;I/O Channel Format .CSIDF ;CSI Return Area Layout .CSWDF ;Channel Status Word (CSW) Bit Definitions .LB DBLK$M,DBLOK$ ;Assign lowest bit in DBLK$M to DBLOK$ .DBKDF ;Dblock (RAD50 filename) Format .DIEDF ;Directory Entry Format .DIHDF ;Directory Header Format .DSCDF ;Device Characteristics Bits for .DSTAT Code .DSTDF ;.DSTATus Return Area Format .EMTDF ;EMT Code and Subcode Values .ERRDF ;EMT Error Code Definitions .HANDF ;Handler Prefix Area (Block 0) Format .HBFDF ;Handler Block 1 Flags Word .HBGDF ;Handler .DRBEG Table Layout .HNPDF ;Handler "NOP" Flag Bit Definitions .HSRDF ;Handler Service Routine Code Definitions FIX$ED=0 ;define floating symbols .IMPDF ;Impure Area Layout FIX$ED=1 .ISTDF ;I.STAT Job State Word Bit Definitions .JSWDF ;$JSW Job Status Word Bit Definitions .OWNDF ;Ownership table offsets and values .QELDF ;Queue Element Format .SGNDF ;SYSGEN Option Bit Definitions .STWDF ;STATWD DCL/@File Status Bit Definitions .SYCDF ;$SYCOM Definitions ;+ ; Define register increment/decrement checking macros ;- .CKXX .SBTTL Delete Structure Definition Macros (Free Up Workfile Space) .MDELET .CKXX ..PURG ..READ ..SPFU ..WRIT .CF1DF .MDELET .CF2DF .CHNDF .CSIDF .CSWDF .DBKDF .DIEDF .MDELET .DIHDF .DSCDF .DSTDF .EMTDF .ERRDF .HANDF .MDELET .HBFDF .HBGDF .HNPDF .HSRDF .IMPDF .ISTDF .MDELET .JSWDF .QELDF .SGNDF .STWDF .SYCDF .SBTTL Force The Correct Ordering Of Psects ;+ ; Force the correct ordering of PSECTs and provide labels at ; the beginning of PSECTs. ;- .PSECT RT11 ;KMON is in here RT11:: .PSECT RMNUSR ;USR is in here RMNUSR:: .PSECT RTDATA ;RMON's data base is in here RTDATA:: .PSECT RMNUSR ;This is the USR .SBTTL LOCATx - USR Entry, EMT 376 Processor ** USR Buffer ** ;+ ; LOCATE,LOCAT1 - Relocate pointers to RMON, USR ; This must be done when the USR is brought into memory ; and anytime the KMON slides it. ; ; LOCATE - Called from KMON whenever it is entered at MEXIT: to ; relocate pointers residing in KMON. ; ; LOCAT1 - Called from RMON via USRBUF when the USR has been freshly read. ; It relocates pointers residing in the USR. ; ; R0 -> dev:filnam.typ ; R1 -> user arguments ; R2 = index into EMT list ; R3 -> CSW for channel, where applicable ; R4 = channel*2 ;- .ENABL LSB USRBUF:: CALL LOCAT1 ;Relocate some pointers CALLR @R5 ;Jump to internal EMT dispatcher ... ............ ; ... (immediately follows USR Buffer) LOCATE:: MOV R1,-(SP) ;Save ... MOV R2,-(SP) ; ... registers .ADDR #,R1 ;Relocate KMON and USR pointers BR 10$ ;Go to common stuff ............ LOCAT1:: MOV R1,-(SP) ;Save MOV R2,-(SP) ; registers .ADDR #,R1 ;Point to start of USR list 10$: MOV @#$SYPTR,R5 ;Address of this RMON CALL RELSUB ;Relocate all RMON pointers .ADDR #,R5 ;Point to directory bottom .BFLOC == .+2 ;**LOAD** Relocate pointer to RMON MOV R5,@#BUFLOC-$RMON ;Initialize BUFLOC CALL RELSUB ;Relocate USR pointers MOV .USRTO,R5 ;Point to permanent USR code .USRLO ==: < . + 2 > ;**LOAD** Relocate address of pointer to USR MOV R5,@#USRLOC-$RMON ;Force RMON to call USR there from now on CLR @.BLKEY ;Clear directory block in memory MOV (SP)+,R2 MOV (SP)+,R1 ;R5 -> to real USR code 20$: RETURN ............ RELSUB: MOV (R1)+,R2 ;Get offset to relocate BEQ 20$ ;Done with RMON pointers ADD PC,R2 ;Form pointer to word to relocate RELLP2: ADD R5,@R2 ;Relocate a pointer into RMON BR RELSUB ;Loop thru RMON pointers ............ .DSABL LSB .SBTTL RELSTx - List Of Pointers Needing Relocation ** USR Buffer ** ;+ ; The relocation list is a list of words within the KMON and USR that ; point into the RMON and must be relocated whenever the KMON/USR or ; just the USR is read in from the system volume. ;- ;+ ; Start of KMON relocation list ; ; This is a list of pointers within the KMON that must be relocated. ; It is used by LOCATE when the KMON and USR have both been read in. ;- RELSTK: .WORD < .$SWPB - RELLP2 > ;-> $SWPBL .WORD < .$MONB - RELLP2 > ;-> $MONBL .WORD < .CORPT - RELLP2 > ;-> CORPTR .WORD < .CURLE - RELLP2 > ;-> CURLEV .WORD < .EXTFL - RELLP2 > ;-> EXTFLG .WORD < .IFSVS - RELLP2 > ;-> IFSVST .WORD < .IFMXN - RELLP2 > ;-> IFMXNST .WORD < .$USRL - RELLP2 > ;-> $USRLC .WORD < .BUFLO - RELLP2 > ;-> BUFLOC .WORD < .KMLOC - RELLP2 > ;-> KMLOC .WORD < .$KMLO - RELLP2 > ;-> $KMLOC .WORD < ..USRL - RELLP2 > ;-> USRLOC .WORD < ..SYSL - RELLP2 > ;-> SYSLOW .WORD < .EXTIN - RELLP2 > ;-> EXTIND .WORD < .ERRLE - RELLP2 > ;-> ERRLEV .WORD < .INDST - RELLP2 > ;-> INDSTA .WORD < .CLIFL - RELLP2 > ;-> CLIFLG .WORD < .CLITY - RELLP2 > ;-> CLITYP .WORD < .CCB - RELLP2 > ;-> CCB .WORD < .$INDD - RELLP2 > ;-> $INDDV .WORD < .LOWMA - RELLP2 > ;-> LOWMAP .IF EQ MMG$T .IF NE > ;If multi-terminal OR no timer support .WORD < .$MTPS - RELLP2 > ;-> $MTPS .ENDC ;NE > .IFF ;EQ MMG$T .WORD < ..I.CN - RELLP2 > ;-> BKGND+I.CNUM .ENDC ;EQ MMG$T ;+ ; End of KMON relocation list ;- ;+ ; Start of USR relocation list ; ; This is a list of pointers within the USR that must be relocated. ; Only this list is used if only the USR is read in. ; Each pointer is of the form: (address in RMON)-$RMON ;- RELST2: .WORD < .USRLO - RELLP2 > ;-> USRLOC .WORD < .BFLOC - RELLP2 > ;-> BUFLOC .WORD < .MONOU - RELLP2 > ;-> MONOUT .IF NE LK4$DV .WORD < .$UNAM - RELLP2 > ;-> $UNAM2 .WORD < .$PNAM - RELLP2 > ;-> $PNAME .WORD < .SYIND - RELLP2 > ;-> SYINDX .WORD < .$ENTR - RELLP2 > ;-> SYINDX .IFF ;NE LK4$DV .WORD < .$UNAM - RELLP2 > ;-> $UNAM2 (for KMOVLY - **TEMP**) .WORD < .$PNAM - RELLP2 > ;-> $PNAME (for KMOVLY - **TEMP**) .WORD < .LK4DV - RELLP2 > ;-> LK4DEV in RMON .ENDC ;NE LK4$DV .IF EQ USR$CM .WORD < .USRC1 - RELLP2 > ;-> USRCOM in RMON .ENDC ;NE USR$CM .WORD < .BLKEY - RELLP2 > ;-> BLKEY .WORD < .CHKEY - RELLP2 > ;-> CHKEY .IF NE TIME$R .WORD < .$UPDA - RELLP2 > ;-> Date update routine in RMON .ENDC ;NE TIME$R .WORD < .$DATE - RELLP2 > ;-> DATE .WORD < .DFLG - RELLP2 > ;-> Abort Holdoff Flag .WORD < .SPUSR - RELLP2 > ;-> SPUSR .WORD < .MAXBL - RELLP2 > ;-> Maximum Size For ENTER .WORD < .STATWD - RELLP2 > ;-> DCL/@File State Word .WORD < .CNFG2 - RELLP2 > ;-> CONFG2 .WORD < .INBFPT - RELLP2 > ;-> DCL/@File Buffer Pointer .WORD < .SPSIZ - RELLP2 > ;-> .SPFUN File Size Pointer .IF EQ MMG$T .WORD < ..$MTP - RELLP2 > ;-> $MTPS .ENDC ;EQ MMG$T .WORD < .SYSLO - RELLP2 > ;-> SYSLOW .WORD < .$SYS - RELLP2 > ;-> Monitor I/O Entry Point .WORD < .DRCAL - RELLP2 > ;-> DRCALL routine .IF EQ GT$NM .WORD < .EMTMO - RELLP2 > ;-> EMTMO1 in RMON .WORD < .GETNM - RELLP2 > ;-> GETNM in RMON .WORD < .GTNM1 - RELLP2 > ;-> GTNM1 in RMON .ENDC ;EQ GT$NM .IF EQ CVT$NU .WORD < .$OCTN - RELLP2 > ;-> $OCTNU in RMON .WORD < .$DECN - RELLP2 > ;-> $DECNU in RMON .WORD < .$CVTN - RELLP2 > ;-> $CVTNU in RMON .ENDC ;EQ CVT$NU .IF EQ XFX$XX .WORD < BRRUGH - RELLP2 > ;-> FSINFO in RMON .ENDC ;EQ XFX$XX .IF EQ GET$FD .WORD < .GTFD1 - RELLP2 > ;-> GETFD1 routine in RMON .ENDC ;EQ GET$FD .IF NE OWN$ER .IF NE USR$CM .WORD < .$OWNE - RELLP2 > ;-> Ownership table for devices .IFF ;NE USR$CM .WORD < .$OWNE - RELLP2 > ;-> $OWNER (for KMOVLY - **TEMP**) .ENDC ;NE USR$CM .ENDC ;NE OWN$ER .WORD < .CNTXT - RELLP2 > ;-> Current context .IF EQ SB .WORD < .$IMPUR - RELLP2 > ;-> Table of impure pointers .WORD < .JOBNUM - RELLP2 > ;-> Current job number .WORD < .CSIER - RELLP2 > ;-> Monitor entry pt for CSI errors .IFF ;EQ SB .IF NE BATC$H .WORD < .BA.NUM - RELLP2 > ;-> BA.SYS slot in $ENTRY table .ENDC ;NE BATC$H .WORD < .I.TERM - RELLP2 > ;-> I.TERM word in BKGND impure area .WORD < .I.STAT - RELLP2 > ;-> I.STAT word in BKGND impure area .IF NE MMG$T .WORD < .PRINTR - RELLP2 > ;-> PRINTR: .PRINT subr. equiv. for SL .ENDC ;NE MMG$T .ENDC ;EQ SB .WORD < .DRVTB - RELLP2 > ;-> Driver relocation table .IF NE MMG$T .WORD < .$RELM - RELLP2 > ;-> Map to user area .WORD < .$KADR - RELLP2 > ;-> Convert User to compatible Kernel ;+ ;*** DBGEXE *** Following modified for DBGEXE ;- .WORD < .$V2P1 - RELLP2 > ;-> Convert Virt->Phys. (chk if PAR1) .WORD < .P1SD - RELLP2 > ;-> Set PAR 1 to default routine .WORD < .PL10W - RELLP2 > ;-> Alloc pool memory (10-wd chunks) .WORD < .UBDTB - RELLP2 > ;-> No UB driver relocation table .IF NE .WORD < .KPSAVE - RELLP2 > ;-> KPSAVE routine (save PAR1/PAR2) .WORD < .KPREST - RELLP2 > ;-> KPREST routine (restore PAR1/PAR2) .ENDC ;NE < UNI$64 & USR$CM & OWN$ER > .IF NE XM$FET .WORD < .PLBYT - RELLP2 > ;-> Alloc pool memory routine (bytes) .WORD < .INTSET - RELLP2 > ;-> Interrupt forwarding setup routine .WORD < .INTRLS - RELLP2 > ;-> Int. forwarding release routine .ENDC ;NE XM$FET .ENDC ;NE MMG$T .WORD < .KMONIN - RELLP2 > ;-> KMON IN flag .WORD 0 ;End of RMON list ............ ;+ ; USR internal relocation list (follows USR relocation list) ; ; This is a list of pointers in the USR to other locations in the ; USR or the USR Buffer. These are relocated by the load address ; of the USR Buffer, and must be changed if the USR slides. Hence: ; ; **** IF YOU CHANGE THIS LIST, CHANGE K M O N ' S ALSO **** ; Each pointer is of the form: (location within USR)-USRBUF ;- .ENABL LSB 10$: .WORD < .USRBU - RELLP2 > ;-> USR Buffer .WORD < .USRTO - RELLP2 > ;-> Top of USR Buffer .WORD < .USRBO - RELLP2 > ;-> First directory entry in segment .WORD < .FNAME - RELLP2 > ;-> Temp area for RENAME and DSTATS .WORD < .FNAM6 - RELLP2 > ;-> End of temp for FETCH .WORD < .D.USR - RELLP2 > ;-> Block number for files in segment .WORD < .M.USR - RELLP2 > ;-> Approx. middle of dir seg. in bfr. .WORD < .USRIO - RELLP2 > ;-> $SYS block for USR Buffer .WORD < .FILDE - RELLP2 > ;-> Area for file desc for CSI .WORD < .HANSP - RELLP2 > ;-> User arguments for CSI .WORD < .DVSTS - RELLP2 > ;-> Device Status Block .IF EQ MMG$T .WORD < .STKSV - RELLP2 > ;-> Stack save area for CSI .WORD < .SVSTK - RELLP2 > ;-> End of stack save area .ENDC ;EQ MMG$T .IF NE LK4$DV .WORD < .LK4DV - RELLP2 > ;-> LK4DEV in USR .ENDC ;NE LK4$DV KURELT ==: < . - 10$ > ;Length of table for crosscheck with USR .WORD 0 ;End of USR relocation list ............ .DSABL LSB .IF EQ MMG$T .SBTTL QSET - Queue Extend EMT ** USR Buffer ** .IFF ;EQ MMG$T .SBTTL QSET - Queue Extend EMT . = < USRBUF + L.UBUF > ;Don't put QSET in buffer if XM BR USRST ;Branch around QSET code ............ .ENDC ;EQ MMG$T ;+ ; QSET - Increase size of job's queue ; ; R0 = number of elements to add to queue ; ARGM1 = address of first new element ; (rest contiguous with first) ; ;- .ENABL LSB QSET: INC ARGPOP ;Set one argument to pop at exit MOV R0,R5 ;Number of additional entries BLE QSOUT ;Just fooling around! .IF EQ MMG$T MOV ARGM1,R1 ;Address of first new entry .IFF ;EQ MMG$T MOV ARGM1,R0 ;R0 = area to use ;+ ;*** DBGEXE *** Following section modified for DBGEXE. ;- .$V2P1 ==: < . + 2 > ;**LOAD** Relocate address of $V2P1 routine CALL @#$V2P1-$RMON ;Phys addr > 28KW boundary or in phys PAR1? BCC 20$ ;If not, use user address ;+ ; If user memory is in extended memory or in PAR1 ; try allocating requested memory from pool. ;- 10$: MOV R5,R0 ;Get number of queue elements to add .PL10W ==: < . + 2 > ;**LOAD** Relocate address of PL10WD routine CALL @#PL10WD-$RMON ;Allocate requested memory from pool BCS QERR ;Branch if allocation failed 20$: MOV R2,R1 ;Move physical address to R1 .P1SD ==: < . + 2 > ;**LOAD** Relocate address of set PAR1 default routine CALL @#P1SD-$RMON ;Restore Kernel PAR1 mapping MOV R5,R0 ;Restore Q count to R0 .ENDC ;EQ MMG$T MOV R1,R4 ;We'll link AVAIL to this soon MOV @.CNTXT,R2 ;R2 -> current context TST (R2)+ ;R2 -> AVAIL queue head .BR 30$ ............ ;+ ; Where AVAIL points now, we'll point new list to same place ;- 30$: MOV R1,R3 ADD #,R1 ;Add Q size to get to next elem. MOV R1,@R3 SOB R0,30$ CLR @R3 ;Clear last link .IF EQ MMG$T MOV #,-(SP) ..$MTP ==: < . + 2 > ;**LOAD** Relocate address of MTPS routine CALL @#$MTPS-$RMON ;Can't abide any interrupts here .IFF ;EQ MMG$T BISB #,@#PS ;Raise priority to 7 .ENDC ;EQ MMG$T MOV @R2,@R3 ;Point our list to where AVAIL goes MOV R4,@R2 ; and link AVAIL to our list .IF EQ MMG$T CLR -(SP) CALL @..$MTP ;Back to level 0 .IFF ;EQ MMG$T BICB #,@#PS ;Drop to Priority 0 .ENDC ;EQ MMG$T MOV R1,@SP ;R0 points to next free memory QSOUT: CALLR COMXIT ............ QERR: JSR R5,COMERR ;Address error, doesn't return .WORD ADDR.E ............ $BSIZ$ ==: < . - USRBUF > / 2 ;Actual size of USR buffer code in words .DSABL LSB .SBTTL USRST - USR Programmed Request Entry, Command Dispatching .IF EQ MMG$T . = < USRBUF + L.UBUF > .ENDC ;EQ MMG$T ;+ ; Command Entry and Dispatching ; ; All requests come here for dispatching either directly from RMON ; or from LOCAT1 after some pointers have been fixed ; ; On entry to USR: ; R1 -> argument list (past 1st argument) ; R2 = request index, sign bit set if arguments came on stack ; R3 -> Channel Status Word ; R4 = channel number * 2 ; @SP = first argument ;- USRST:: MOV @SP,R0 ;Reset pointer to dev:file.ext CLR (PC)+ ;Clear arguments to pop at exit ARGPOP: .WORD 0 ;Number of arguments to pop at exit CLR @.SPUSR ;Clear software error flag MOV (R1)+,(PC)+ ;Save first argument ARGM1: .WORD 0 MOV (R1)+,(PC)+ ;Save second argument ARGM2: .WORD 0 MOV (R1)+,(PC)+ ;Save word 4 of area argument ARGM3: .WORD 0 MOV R2,(PC)+ ;New/old flag USREMT: .WORD 0 MOV SP,(PC)+ ;Current (Kernel) SP in case error USRSP: .WORD 0 CLR R5 ;Some EMT's want R5=0 ROL R2 ;Clear top bit, make index into list TST (R2)+ ;Index into our list ... ADD PC,R2 ; ... pic-ly, of course ADD @R2,PC ;Jump to command .BR ULS ............ ;+ ; A table with the same information as the following, but with reversed order, ; is found at EMTUSR in RMON. Be sure to make any changes to both places!!! ;- ULS: QSET.$ ==: <.-ULS>/2 .WORD < QSET - ULS > ;Setup I/O Queue EMT CLOS.. ==: <.-ULS>/2 .WORD < SPSHSC - ULS > ;Close EMT (special directory only) DELE.. ==: <.-ULS>/2 .WORD < DELETU - ULS > ;Delete EMT LOOK.. ==: <.-ULS>/2 .WORD < LOOKUP - ULS > ;Lookup EMT ENTR.. ==: <.-ULS>/2 .WORD < ENTER - ULS > ;Enter EMT RENM.. ==: <.-ULS>/2 .WORD < RENAMU - ULS > ;Rename EMT PURG.. ==: <.-ULS>/2 .WORD < SPSHSC - ULS > ;Purge EMT (special directory only) INFO.. ==: <.-ULS>/2 .WORD < INFOFS - ULS > ;(G|S)F(DATE|INFO|STAT) EMTs CLOZ.. ==: <.-ULS>/2 .WORD < SPSHCZ - ULS > ;Closz EMT (special directory only) CLOS.$ ==: <.-ULS>/2 .WORD < KLOSE - ULS > ;Close Channel EMT FETC.$ ==: <.-ULS>/2 .WORD < PHETCH - ULS > ;Fetch Device Handler EMT DSTA.$ ==: <.-ULS>/2 .WORD < GESTAT - ULS > ;Get Device Status EMT CSI.$ ==: <.-ULS>/2 .WORD < CSI - ULS > ;Command String Interpreter .SBTTL RENAMU/LOOKUP - LOOKUP and RENAME Requests ;+ ; LOOKUP - Find a specific permanent file, open it for input and/or output ; RENAMU - .LOOKUP a file, change its name, then .CLOSE it ; ; R0 -> dev:file.ext in RAD50. ; R3 -> Channel Status Word ; R4 = channel number * 2 ; ; The handler for the requested device must be in memory ; ; "What we see depends mainly on what we look for." ; - Sir John Lubbock ;- .ENABL LSB RENAMU: MOV #,R5 ;Will be RENAME bit in CSW LOOKUP: JSR R5,USRCOM ;(r5 is clear for LOOKUP) BR LNFILE ;Non file oriented device BR SPLOOK ;Special device LOOKUP JSR R5,SEARCH ;Get a permanent entry of a file name BR LKER1 ;File doesn't exist MOV #,R2 ;Save value because used often TST R5 ;A RENAME done? (R5=0 if LOOKUP) BEQ 10$ ;No, proceed with LOOKUP ADD R2,R0 ;Point to new name CALLR CLOCOM ;Do common close operations ............ 10$: MOV @R1,-(SP) ;Copy E.STAT from entry BIC #^c,@SP ;Clear all except read-only bit BIS (SP)+,(R3)+ ;Or it into the CSW ADD R2,R1 ;Point to length words MOV SBLK,(R3)+ ;Put starting block into CSW area MOV @R1,@SP ;Length to R0 on return MOV (R1)+,(R3)+ ; and also to CSW area MOV (R1)+,(R3)+ ;Data length .IF NE MMG$T CALL @.P1SD ;Restore PAR1 mapping .ENDC ;NE MMG$T CALL @ARGM3 ;Call user for extra word handling BR COMXIT ;Exit this request ............ .DSABL LSB ;+ ; Call special device handler common routine with appropriate function code ;- SPLOOK: BIS #,@R3 ;Rewrite directory bit SPDEL: CALLR SPSHL1 ;Process special directory request ............ .SBTTL COMXIT - Common Exit For All USR Requests LNFILE: CMP (R3)+,(PC)+ ;Leave CSW alone, go clear start block ;>>>BR DELOUT ; (implicit BR DELOUT here, due to (PC)+ ) PROERR: EMTER3 ;ERROR 3 is protection failure BR DELOUT ............ LKER1: EMTER1 ;ERROR 1 (LOOPUP error) DELOUT: CLR @SP ;R0=0 if error or non-file device KILCHN: CLR (R3)+ ;Deactivate channel .BR COMXIT ;Flow into COMXIT ............ ;+ ; COMXIT - Common Exit For All USR Requests ;- COMXIT: MOV ARGPOP,R2 ;Number of arguments to R2 .MONOU ==: < . + 2 > ;**LOAD** Relocate address of monitor exit routine CALLR @#MONOUT-$RMON ;Exit USR ............ .SBTTL COMERR - Common Error Exit For Fatal USR Errors ;+ ; COMERR is the common error exit for all fatal USR errors ;- COMERR: MOVB @R5,CODE ;R5 points to code MOV USRSP,SP ;Reset (Kernel) stack CLR @.DFLG ;Turn off protection CLR @.BLKEY ;No directory in memory EMT ...ERR ;Fatal error (returns only if .SERR) .BYTE 0 ;Level CODE: .BYTE 0 ;Code ...... BR COMXIT ;Go exit (only if .SERR issued) ............ .SBTTL DELETU - Delete A File ;+ ; DELETU - Delete a file ; ; R0 -> dev:filnam.typ ; R3 -> Channel Status Word ; R4 = channel number * 2 ; ; Uses USRCOM to set up a channel for directory operations, and then calls ; search to actually find the file to be deleted. ; The entry is changed to an empty file, the directory consolidator ; is called at CLSQSH, and the channel is closed ;- DELETU: JSR R5,USRCOM ;Setup the channel for directory io BR DELOUT ;Non file structured device ...... BR SPDEL ;Do special delete ...... JSR R5,SEARCH ;Find the file. R0 points to it BR LKER1 ;No such file to delete ...... BMI PROERR ;Give error if protected MOV #,@R1 ;Make entry an empty CALLR CLSQSH ;Consolidate segment and exit ............ .SBTTL ENTER - Open A File On A Device ;+ ; ENTER - Open a file on a device ; ; R0 -> dev:filnam.typ[size] ; R3 -> channel status word ; R4 = channel number * 2 ; ; The file is added into the directory in front of an already existing empty ; directory entry. If the entry before the empty is a tentative file, an ; empty of length 0 is inserted before the second tentative entry. ;- .ENABL LSB ENTER: CLR @.BLKEY ;Force re-read of directory! INC ARGPOP ;Set one argument to pop MOV #,R5 ;Set directory rewrite needed JSR R5,USRCOM ;Do common startup BR LNFILE ;Enter on non-file struct. is same as LOOKUP ...... BR SPENTR ;Special ENTER is special ...... MOV USRBUF+D.HIGH,LSTBLK ;Remember highest directory block CLR ARGM2 ;Clear pass number, indicate pass 1 10$: CLR FNAME ;Use FNAME block to remember entries CLR FNAME+2 ; BR 40$ ;Enter loop (block 1 already in memory) ............ ;+ ; Call special device request common routine with appropriate function code ;- SPENTR: CALLR SPESHL ;Special device ENTER ............ ;+ ; Find a hole for the file ;- 20$: MOV .USRBO,R1 ;R1 -> 1st dir entry in block JSR R5,FILSCN ;Find it if its there BR 30$ ;Not there, on to next segment ...... BMI PROERR ;Protected file, give an error 30$: JSR R5,NXBLK ;Read next block into memory BR 100$ ;No more directory blocks ...... 40$: CALL CONSOL ;Consolidate this block 50$: MOV (PC)+,R5 ;Point to 2nd largest so far .FNAME:: .WORD ;Pointer to FNAME JSR R5,ENTRY ;Get an empty entry .WORD E.MPTY BR 20$ ;No more empties, now find file ...... MOV E.LENG(R1),R4 ;Get length of empty MOV ARGM1,R2 ;Get requested size BEQ 60$ ;0 => get largest two CMP #<-1>,R2 ;-1 => largest BNE 140$ ;No, a specific request .BR 60$ ............ 60$: CMP (R5)+,R4 ;2nd largest : this hole BHIS 90$ ;No good, ignore it CMP @R5,R4 ;Largest : this hole BHIS 70$ ; greater => this is new 2nd largest MOV @R5,-(R5) ;Move former largest to 2nd spot ADD #<8.>,R5 ;Advance pointer MOV -(R5),-(R5) ;Copy block index 70$: MOV R4,-(R5) ;Save hole size 80$: MOV @R3,4(R5) ;Save block pointer 90$: ADD R4,SBLK ;Maintain start block CALL INCR1 ;Bump R1 pointer BR 50$ ;Keep looking ............ ;+ ; Found the holes - convert request to specific, find that hole again ;- 100$: TST (R5)+ ;End of pass 1. Point R5 to largest TST R2 ;Test request size BNE 120$ ;Might have been specific or max ROR @R5 ;Take half the largest hole CMP @R5,-(R5) ;Compare it to the 2nd largest hole BLO 110$ ;2nd largest is bigger TST (R5)+ ;That half is bigger .MAXBL ==: < . + 2 > ;**LOAD** Relocate address of maximum size to ENTER 110$: CMP @#MAXBLK-$RMON,@R5 ;Asking for too much? BHIS 130$ ;No. Leave it alone MOV @.MAXBL,@R5 ;Give only the maximum BIC #,4(R5) ;Must start next pass at INCB 5(R5) ; first directory block .ASSUME DBLOK$ EQ 400 ;.ASSUME so that above "INCB" will work BR 130$ ;Do pass 1 with specific request ............ 120$: COM ARGM2 ;Set pass = 2 INC R2 ;Max request? BNE 130$ ;No. We have min. hole size allowable MOV @R5,-2(R5) ;Minimum hole size allowable is largest 130$: MOV @R5,ARGM1 ;Convert request to specific BEQ LKER1 ;Golly, there's no room at all MOV 4(R5),@R3 ;Start rescan at a good place RENTR: JSR R5,BLKCHK ;Get dblock into memory TST ARGM2 ;Are we on pass 1 BEQ 10$ ;Yes. Must clear FNAME BR 40$ ;Pass 2. Minimum allowable hole size ............ ; is in FNAME ;+ ; Specific requests go here ;- 140$: CMP R4,R2 ;Specific request satisfied? BLO 90$ ;No. Get next TST @R5 ;Is this first satisfaction? BEQ 150$ ;Yes. Use this hole CMP R4,@R5 ;Is this hole smallest so far? BHI 90$ ;No. Get next BEQ 160$ ;Exact match. See if we're done. 150$: MOV R4,(R5)+ ;Save size of smallest hole MOV R2,@R5 ;Save size of request for code at 120$ BR 80$ ; and keep scanning ............ 160$: TST ARGM2 ;Are we done? (pass 2?) BEQ 90$ ;Branch if not .BR 170$ ............ 170$: MOV R1,-(SP) ;Save position of empty, and MOV DREND,R1 ;See if room for 3 more entries CALL INCR2 CALL INCR1 CMP R1,(PC)+ ;Past end of buffer? .USRTO:: .WORD ;-> end of directory segment BHI EXTEND ;Yes, have to open new block ;+ ; We now have a hole for the file, and room in the dir segment in memory ;- MOV (SP)+,R1 MOV SBLK,R4 ;Save starting block MOV R1,R5 SUB R2,E.LENG(R1) ;Decrease length of empty SUB #,R5 ;Status of previous entry SUB USRBUF+D.EXTR,R5 ;Waste words CMP R5,(PC)+ ;Outside directory buffer? .USRBO:: .WORD ;Pointer to directory entries BLO 180$ ;Yes. Previous not tentative BIT #,@R5 ;Previous tentative? BEQ 180$ ;Guess not CALL PUSH ;Put in empty of length 0 MOV #,@R1 ;Status entry CLR E.LENG(R1) ;Clear out the length CALL INCR1 ;Point to next entry 180$: CALL PUSH ;Make room for real entry MOV #,(R1)+ ; and make it tentative MOV (R0)+,(R1)+ ;Fill in file name MOV (R0)+,(R1)+ MOV (R0)+,(R1)+ MOV R2,(R1)+ ;Length of hole .IF NE SB MOV CHNLRG,(R1)+ ;Put in channel number .IFF ;NE SB MOVB CHNLRG,(R1)+ ;Put in channel of request .JOBNU ==: < . + 2 > ;**LOAD** Relocate address of current job number MOVB @#JOBNUM-$RMON,(R1)+ ; and job of requestor .ENDC ;NE SB .IF NE TIME$R .$UPDA ==: < . + 2> ;** LOAD ** Relocate address to date update routine CALL @#UPDDAT-$RMON ;Update date before use .ENDC ;NE TIME$R .$DATE ==: < . + 2 > ;**LOAD** Relocate address of current date MOV @#DATES-$RMON,@R1 ;Date word .IF NE MMG$T CALL @.P1SD ;Restore PAR1 mapping .ENDC ;NE MMG$T CALL @ARGM3 ;Call user for extra word handling TST (R3)+ ;Fill in channel stuff CLR @R3 JSR R5,SEGWR ;Write the segment MOV R4,(R3)+ ;Insert start block MOV R2,(R3)+ ;Hole length CLR @R3 ;Data length MOV -(R3),@SP ;Give back the hole length CALLR COMXIT ............ .IF NE TIME$R .SBTTL UPDDAT - Update DATES before use by ENTER or D$ATE ;+ ; ; UPDDAT ; Ensures the date in the fixed offset are of RMON is as ; up-to-date as possible by performing a time update, which ; causes day (and possibly month and year) rollover. ; ; Note: ; o Code is defined here, but resides in RMON ; o R0 and R1 are saved, GTIHOK routine will ; be using them ; ; "Macbeth: What is the night? ; Lady Macbeth: Almost at odds with morning, which is which?" ; - William Shakespeare, Macbeth, Act III, ; Scene 4, Line 126 ; ;- .SAVE ;the current PSECT status .PSECT USRRMN ;PSECT the following into RMON UPDDAT:: MOV R0,-(SP) ;Save some registers MOV R1,-(SP) ; ... SUB #4,SP ;Reserve space for returned time MOV SP,R0 ;R0 -> 2 words for GTIHOK CALL GTIHOK ;Get the time, update the date ADD #4,SP ;Discard the returned info MOV (SP)+,R1 ;Restore previously saved registers MOV (SP)+,R0 ; ... RETURN ;to caller .RESTORE ;the previous PSECT status .ENDC ;NE TIME$R .SBTTL EXTEND - Enlarge The Size Of A Directory ;+ ; EXTEND - Enlarge the size of a directory ; ; ENTER EXTEND is performed when an entry will not fit into ; an existing directory block. if the directory contains another ; directory block, EXTEND does the following things: ; ; Starting at the approximate middle of a directory segment, search for a ; permanent or tentative or empty entry. When an entry is found, the current ; segment is terminated with an end block mark and written out. The remaining ; entries are the first entries in a new segment. The segments are linked and ; the newly created segment is written out. Block 1 of the directory is ; updated to reflect the highest block used in the directory, and ENTER is ; restarted at the directory block which was split. ;- .ENABL LSB EXTEND: MOV R0,@SP ;Save R0, wipe out junk word on stack MOV (PC)+,R2 ;Highest block now in use LSTBLK: .WORD 0 .DFLG ==: < . + 2 > ;**LOAD** Relocate address of CTRL/C Hold flag INC @#DFLG-$RMON ;Hold off on CTRL/C CMP R2,USRBUF ;Is there another block? BGE 40$ ;No, issue directory overflow error MOV (PC)+,R4 ;R4 -> approx. middle of segment .M.USR:: .WORD USRBUF+<</2+5>*2>-USRBUF ;Tweak to improve perf! MOV (PC)+,R1 ;R1 -> starting block word in header .D.USR:: .WORD MOV (R1)+,R5 ;R5 = starting block for these files 10$: CALL INCR1A ;Bump R1 to next entry, update R5 CMP R1,R4 ;Does R1 -> past middle? BLO 10$ ;No, keep going BIT #,@R1 ;Is it permanent or tentative? BEQ 10$ ;No, bump to next entry MOV @R1,-(SP) ;Save entry type MOV #,@R1 ;Terminate segment INC R2 ;Compute new highest segment in use MOV USRBUF+D.NEXT,-(SP) ;Save link to next segment MOV R2,USRBUF+D.NEXT ;Link this segment to the new segment JSR R5,SEGWR ;Write out shortened segment .BR 20$ ............ 20$: MOV .USRBU,R0 ;Create new segment's header TST (R0)+ ;Leave number of segments open alone MOV (SP)+,(R0)+ ;Link new segment to next segment MOV (SP)+,@R1 ;Restore original status of file at breakpoint CMP (R0)+,(R0)+ ;Ignore high segment and number of extra bytes MOV R5,(R0)+ ;Start block of files in this segment 30$: MOV (R1)+,(R0)+ ;Slide directory entries up to header CMP R1,.USRTO ;Done? BLOS 30$ ;No ;CLC ;*C*=0 Since BLOS=>BLO=BCS above MOV R2,R0 ;*C*=0 Copy new segment's number JSR R5,SEGRW ;*C*=0 Write the new segment JSR R5,SEGRD1 ;Read in segment 1, set BLKEY INC USRBUF+D.HIGH ;Update highest segment used in seg 1 JSR R5,SEGWR ; and rewrite 1 (BLKEY) the segment 1 DEC @.DFLG ;Enable CTRL/C again MOV (SP)+,R0 ;Restore R0 CALLR RENTR ;Restart ENTER ............ 40$: JSR R5,COMERR ;COMERR doesn't return .WORD DOVR.E ;DIR OVERFLOW, no more segments available ............ .DSABL LSB .SBTTL PUSH - Make Room In Current Directory Segment For New Entry ;+ ; PUSH - Make room in directory segment for new entry by sliding entries down ; ; R1 -> place in directory segment to create hole for new entry ; ; CALL PUSH ; ; R5 = incoming R1 ;- .ENABL LSB PUSH: MOV R3,-(SP) ;Save vital R3 pointer MOV R1,R5 ;Mark position of empty JSR R5,ENTRY ;Find end of directory .WORD 0 ;Search for no mask gets to end of block! MOV R1,R3 ;R3 points to end of data CALL INCR1 ;New end is one entry past current segment end CMP (R3)+,(R1)+ ;Move all entries 10$: MOV -(R3),-(R1) CMP R3,R5 BNE 10$ MOV R5,R1 ;Point back to where file goes MOV (SP)+,R3 ;Restore R3 RETURN ............ .DSABL LSB .SBTTL KLOSE - CLOSE A File, Delete Unprotected Duplicates ;+ ; KLOSE - CLOSE a file (tent -> perm), delete unprotected duplicates ; ; R3 -> channel status word ; R4 = 2 * channel number ; ; To Eliminate Duplicates, find 1st file in the directory with the same name ; If NONE, then: ; If .CLOSE, convert the tentative entry associated with the channel ; to a permanent entry, consolidate and rewrite the directory ; If .RENAME, insert the new name in the entry, consolidate and ; rewrite the directory ; ; If a Duplicate File Exists, then: ; If .CLOSE: ; If that file IS protected, issue an error but proceed with the CLOSE. ; TWO FILES WITH THE SAME NAME NOW EXIST ON THE DEVICE. ; If that file ISN'T protected, delete it and proceed with the CLOSE. ; If .RENAME: ; If that file IS protected, and it isn't the same physical file, ; issue an error and abort the RENAME. ; If that file ISN'T protected, and it isn't the same physical file, ; delete it and perform the RENAME. ;- .ENABL LSB KLOSE: ASR R4 ;Make into a real channel number MOV R4,CHNLRG ;Save channel number in CHNLRG CLR C.SBLK-C.CSW(R3) ;Clear starting block # for read/write JSR R5,BLKCHK ;Get a directory block in memory ... BR 20$ ; ... and enter loop ............ 10$: JSR R5,NXBLK ;Get next dir block BR CLSOUT ;Cannot find that tentative ...... 20$: JSR R5,ENTRY ;Find an entry 'tentative' .WORD E.TENT BR 10$ ;Not in this block ...... .IF EQ SB CMPB E.JNUM(R1),@.JOBNUM ;Does tentative belong to us? BNE 30$ ;No .ENDC ;EQ SB CMPB E.CHAN(R1),CHNLRG ;Tentative on this channel? BEQ 40$ ;Yes, process it 30$: CALL INCR1 ;R1 to next entry BR 20$ ............ 40$: MOV R1,R2 ;R2 -> status word of dir entry TST (R2)+ ;R2 -> filnam.ext MOV .FNAME,R0 ;Put file name in permanent place MOV (R2)+,(R0)+ ;Copy filename from dir entry into USR MOV (R2)+,(R0)+ MOV @R2,@R0 ;Move extension CMP -(R0),-(R0) ;Point R0 to name CLOCOM: MOV R1,R4 ;Save pointer to entry for later MOV @R3,@SP ;Save for re-read of this file BIC #,@R3 ;Clear out segment bits ADD #,@R3 ;Start search at block 1 JSR R5,SEARCH ;Find old (permanent) copy BR 80$ ;None to delete ...... ;+ ; Found one. Now check for special case: RENAME of a file to itself ;- CMP @R3,@SP ;Segment numbers match? BNE 50$ ;No CMP R1,R4 ;Is it same file? BEQ 90$ ;Yes, this is special case 50$: TST @R1 ;Is it protected? BPL 70$ ;No, go delete it 60$: EMTER3 ;Protected, give ERROR 3 BIT #,@R3 ;Is this a RENAME? BEQ 80$ ;No, proceed BR CLSOUT ;Leave ............ 70$: MOV #,@R1 ;Delete this one (make it an empty) CMP @R3,@SP ;See if we're in same segment BEQ 80$ ;Yes. Don't rewrite segment INC @.DFLG ;No. Hold off ^C CALL CLOSUP ;Consolidate and rewrite segment 80$: MOV @SP,@R3 ;Restore CSW JSR R5,BLKCHK ;Get correct block into memory MOV R4,R1 ;Point to entry BIT #,@R3 ;RENAME? BNE 90$ ;Yes. Leave lengths alone MOV #,@R1 ;Make it permanent ;Note: To create a protected file, ; do a MOV #,@R1 here ADD #,R1 ;Offset R1 to length word MOV @R1,R2 ;No, get allocated length MOV C.USED(R3),@R1 ;Change file entry to amount used SUB @R1,R2 ;R2 now has unused portion CALL INCR1 ;Point to trailing empty ADD R2,@R1 ;Reclaim unused space CLSQSH: CALL CLOSUP ;Consolidate and rewrite CLR @.DFLG ;Allow ^C CLSOUT: CALLR DELOUT ............ 90$: TST (R1)+ ;Bump to file name MOV (R0)+,(R1)+ ;Re-insert renamed filename MOV (R0)+,(R1)+ ; and MOV (R0)+,(R1)+ ; filetype CMP (R1)+,(R1)+ ;Point to date word for user .IF NE MMG$T CALL @.P1SD ;Restore PAR1 mapping .ENDC ;NE MMG$T CALL @ARGM3 ;Call user for extra word handling BR CLSQSH ;Clean up and get out ............ .DSABL LSB .SBTTL CLOSUP - Consolidate And Rewrite A Directory Segment ;+ ; This routine consolidates a directory segment and rewrites it ; ; BLKEY = directory segment number to write this segment to ; ; CALL CONSOL ; ; R1 -> beginning of segment buffer ; R2,R5 destroyed ;- CLOSUP: MOV R0,-(SP) ;Save FNAME pointr MOV .USRBO,R1 ;Bottom of segment buffer CALL CONSOL ;Consolidate the segment JSR R5,SEGWR ;Rewrite the segment MOV (SP)+,R0 RETURN ............ .IF NE MMG$T .SBTTL MAPFIL - Map To User File Block ;+ ; MAPFIL - Maps to user block in User Space, assuming USR is running in ; Kernel mode. ; ; R0 = user virtual address ; ; CALL MAPFIL ; ; R0 -> user file block, mapped in Kernel space ; R1,R2 modified ;- .ENABL LSB MAPFIL: BIT #,@#PS ;Was caller in User mode? BNE 10$ ;Yes, go relocate PAR1 CALL @.P1SD ;Restore Kernel PAR1 in case RETURN ; and just exit ............ .$RELM ==: < . + 2 > ;**LOAD** Relocate address of address mapping routine 10$: CALLR @#$RELOM-$RMON ;Relocate R0. Return from there ............ .DSABL LSB .ENDC ;NE MMG$T .SBTTL SPESHL/SPSHL1/SPSHCZ/SPSHSC - PROCESS USR REQUESTS FOR SPECIAL DEVICES ;+ ; SPESHL - Used by ENTER ; SPSHL1 - Used by DELETE, LOOKUP, AND RENAME ; SPSHCZ - Used by CLOSZ ; SPSHSC - Used by CLOSE & PURGE ; ; R0, ARGM1, ARGM2, & ARGM3 POINT TO THE EMT ARGUMENT BLOCK OF ; .ENTER, .DELETE, .LOOKUP, .RENAME, AND .CLOSZ: ; R0 -> DEV:FILNAM.TYP ; ARGM1 -> WORD AT OFFSET 4 ; ARGM2 -> WORD AT OFFSET 6 ; ARGM3 -> WORD AT OFFSET 10 ; NOTE THAT ONLY .ENTER REQUIRES ALL THREE ARGUMENT BLOCK POINTERS. ; ; ; ; ; USREMT = code in low byte, old/new indicator in high byte sign ; ; JMP SPSHCZ Copy R0 to Q$WCNT ; JMP SPSHL1 Copy R0 to Q$BUF; ARGM1 to Q$BLKN ; JMP SPESHL Copy R0 to Q$BUF; ARGM1 to Q$WCNT; ARGM2/0 to Q$BLKN ;- SPSHCZ: MOV R0,ARGM1 ;Move Length to ARGM2 (slowly) SPSHSC: ASR R4 ;Make R4 into channel number MOV R4,CHNLRG ;Save channel selector SPSHL1: MOV ARGM1,ARGM2 ; ?? M Y S T E R I O U S ?? ;NOT REALLY -- ;.DELETE: SET SEQNUM INTO ARGM2 ;.LOOKUP: SET SEQNUM INTO ARGM2 ;.RENAME: ARGM1 & ARGM2 UNDEFINED ;.CLOSZ: SET SIZE INTO ARGM2 ;.CLOSE: ARGM1 & ARGM2 UNDEFINED ;.PURGE: ARGM1 & ARGM2 UNDEFINED SPESHL: BIC #,@R3 ;Clear end file, hard err ;+ ; Build argument block for special directory request on stack ;- CLR @.SPSIZ ;Clear Special directory size word .Assume ..WTIO EQ 0 CLR -(SP) ;Make it synchronous (i.e., SPFUNW) MOV USREMT,R2 ;Load function code MOV R2,-(SP) ;Put it on the stack SWAB @SP ;Move function code to high byte MOVB #<..SPFV>,@SP ;Force low byte to 377 (SPFUN) MOV ARGM1,-(SP) ;Pass file size for ENTER in wcnt spot MOV R0,-(SP) ;Pointer to file name in buffer spot CLR -(SP) ;0 block for now TST R2 ;New format EMT? BPL 10$ ;Branch if not MOV ARGM2,@SP ;Fill in file count 10$: MOV CHNLRG,-(SP) ;Now form function word ADD (PC)+,@SP ;Make it a read-wait .BYTE 0,<.READ> ;read request, leave channel as is MOV SP,R0 ;Point R0 to our argument list EMT ...REA ;READW BCC 20$ ;No I/O error CALLR IOER ;Directory I/O error ............ 20$: ADD #,SP ;Clean 'READ' data off stack CLR @.BLKEY ;No directory in memory .SPUSR ==: < . + 2 > ;**LOAD** Relocate address of SPUSR flag MOV @#SPUSR-$RMON,R0 ;Software error? BNE 30$ ;Yes, do an EMTER0 CMPB R2,# ;LOOKUP? BEQ 50$ ;Yes, don't deactivate channel CMPB R2,# ;ENTER? BEQ 50$ ;Yes, don't deactivate channel BR 40$ ;Go deactivate channel then leave ............ 30$: BIS (PC)+,R0 ;Generate appropriate EMT error EMTER0 ;*** Literal For Prev. Instr *** MOV R0,@PC ;Store generated EMTERR EMTER0 ;***This Instr Created Dynamically*** 40$: CLR (R3)+ ;Deactivate channel .SPSIZ ==: < . + 2 > ;**LOAD** Relocate address of SPFUN file size 50$: MOV @#SPSIZE-$RMON,@SP ;Return file size in R0 on LOOKUP ; and ENTER. Meaningless for other fns COMXT2: CALLR COMXIT ;Bye ............ .DSABL LSB .SBTTL GESTAT - Get Device Status EMT (.DSTATUS) ;+ ; GESTAT - (DSTATUS EMT) Returns status of a particular device in the system ; ; R0 -> the device name in RAD50 ; ARGM1 -> user output area ; ; User R0 -> word one of the block on return ; The information returned is: ; 1- $STAT table entry ; 2- Size of device handler in words ; 3- Entry point of handler. 0 if nonresident ; 4- Size of dev direct in 256 word blocks ;- GESTAT: CALL LK4DV1 ;Search table(s) for device .IF NE MMG$T MOV R2,-(SP) ;Save status pointer for later CALL MAPFIL ;Map to user area MOV (SP)+,R2 ;Restore pointer to status word .ENDC ;NE MMG$T MOV @R2,(R0)+ ;Move status into place MOV $HSIZE-$STAT(R2),(R0)+ ;Move handler size to user MOV @R5,(R0)+ ;Move entry point to user MOV $DVSIZ-$STAT(R2),@R0 ;Move device block size to user COMXT3: BR COMXT2 ;Exit. One argument on stack ............ LK4DV1: .IF NE MMG$T CALL MAPFIL ;Map to users file block .ENDC ;NE MMG$T INC ARGPOP ;Set one argument to pop at exit ;ARGM1 odd -> skip logical name search ASR ARGM1 ;Get low bit of ARGM1 to C ;C=1 -> no logical device translation .LK4DV ==: < . + 2 > ;**LOAD** Relocate address of LK4DEV routine .IF EQ LK4$DV JSR R4,@#LK4DEV-$RMON ;Search table(s) for device .IFF ;EQ LK4$DV JSR R4,@#LK4DEV-USRBUF ;Search table(s) for device .ENDC ;EQ LK4$DV BR FCE0X ;No such device name ...... MOV ARGM1,R0 ;Pointer to users area divided by 2 ASL R0 ;Clear low bit, restore address MOV R0,2(SP) ;Return it in R0 RETURN ............ .SBTTL RLEAS - Get Rid Of A .FETCHed Device Handler ;+ ; RLEAS - Release a device handler. If handler was not 'LOAD'ed and if ; it isn't permanently resident, remove handler from system. ; ; R0 == JOBNUM if FB/XM ; (NOTE: condition code Z should be 0/1 based on this value) ; R3 == SYSLOW ; R5 -> $ENTRY word for this device (from beginning of PHETCH:) ;- .ENABL LSB RLEAS: .IF EQ SB BNE COMXT4 ;If RELEASE issued from F/G, ignore it .ENDC ;EQ SB TST @.KMONIN ;Is KMON trying the .RELEASE? BNE 10$ ;Yes, KMON can do what it likes CMP @R5,R3 ;Handler LOADed or permanently resident? BHIS COMXT4 ;Yes, don't RELEASE it 10$: .CNFG2 ==: < . + 4 > ;**LOAD** Relocate address of 2nd configuration word BIS #,@#CONFG2-$RMON ;Tell LD handler about the RELEASE MOV #,R1 ;Indicate doing a RELEASE ; R0 ??? ; R1 == 2 (RELEASE flag) ; R2 ??? MOV R5,R3 ; R3 == $ENTRY for this handler ; R4 ??? ; R5 == $ENTRY for this handler (preserve) CALL @.DRCAL ;Call handler, if requested to do so .IF NE .INTRLS ==: < . + 2 > ;**LOAD** Relocate address of INTRLS routine CALL @#INTRLS-$RMON ;Remove any interrupt forwarding entries .IFF ;NE CLR @R5 ;Zero its entry point in $ENTRY table .ENDC ;NE BR COMXT4 ;Exit USR ............ .DSABL LSB .SBTTL PHETCH - Fetch A Device Driver ;+ ; PHETCH - Read a device driver into memory at a user specified address ; ; Vectors are set up and pointers in driver to RMON are loaded. ; Checks for valid address, won't clobber RMON or USR. ; NOP if device already in memory. ; ; R0 -> Device/file descriptor block ; ARGM1 = User specified load address ; ; Register usage: ; R0 = Block number of handler on SY:, then misc. ; R1 -> USR Buffer (later on), then misc. ; R2 -> USR Buffer, then misc. ; R3 = Device index initially, then -> $ENTRY ; R4 -> RMON ; R5 -> $ENTRY initially, then used for miscellaneous ;- .ENABL LSB PHETCH: CALL LK4DV1 ;Search table(s) for device .SYSLO ==: < . + 2 > ;**LOAD** Relocate address of SYSLOW MOV @#SYSLOW-$RMON,R3 ;Load SYSLOW value CMP @SP,# ;Is this a .FETCH or a .RELEASE? .IF EQ SB MOV @.JOBNUM,R0 ;Load JOBNUM value .ENDC ;EQ SB BLO RLEAS ;FETCH into vectors (usually to 0) is RELEASE .IF EQ SB BEQ 10$ ;We are BG, it's legal to make changes CMP @R5,R3 ;Not BG, is handler now loaded or system? BHIS COMXT4 ;Yes, in memory but not BG, so we're done UNLDRV: JSR R5,COMERR ;Issue unloaded driver error (no return) .WORD UDRV.E ;Unloaded Driver Error ............ 10$: .ENDC ;EQ SB TST @R5 ;Is handler in memory somewhere? BNE COMXT4 ;Yes, we're done .IF NE MMG$T .IF EQ XM$FET TST @.KMONIN ;Is this KMON's request? .IF EQ SB BEQ UNLDRV ;No, then invalid without FETCH support .IFF ;EQ SB BNE 20$ ;Yes, ok UNLDRV: JSR R5,COMERR ;Issue unloaded driver error (no return) .WORD UDRV.E ;Unloaded Driver Error ............ 20$: .ENDC ;EQ SB .ENDC ;EQ XM$FET CALL @.P1SD ;Restore PAR1 mapping MOV @SP,R0 ;R0 = user virtual load address MOV @SP,ARGM1 ;Save for updating R0 when we exit .ENDC ;NE MMG$T MOV R5,R3 ;R3 -> $ENTRY table for this device MOV $HSIZE-$ENTRY(R3),R4 ;R4 = handler size MOV (PC)+,R5 ;R5 -> scratch area .FNAM6:: .WORD ;Pointer to end of scratch area CLR -(R5) ;Wait for completion MOV R4,-(R5) ;Size of handler in bytes ASR @R5 ;Make it words .BR 30$ ............ 30$: .IF NE MMG$T .$KADR ==: < . + 2 > ;**LOAD** Relocate address of $KADR routine CALL @#$KADR-$RMON ;Convert to compatible Kernel address ;+ ;*** DBGEXE *** Following section modified for DBGEXE ;- BCC 40$ ;Branch if in low memory MOV R4,R0 ;R0 = handler size CLR R4 ;Don't update R0 at end of .FETCH .PLBYT ==: < . + 2 > ;**LOAD** Relocate address of PLBYTE routine CALL @#PLBYTE-$RMON ;Allocate requested memory from pool ;>>> consider backing off the allocation for non-fetchable handlers BCS BADFT ;Error if pool not allocated 40$: MOV R2,@SP ;Use fact that Physical <=> Kernel addressing .IFF ;NE MMG$T MOV @SP,R2 ;R2 = address in which to read handler .ENDC ;NE MMG$T MOV R2,-(R5) ;Load address is place to read handler ;+ ; Does handler file exist on SY:? ;- MOV $DVREC-$ENTRY(R3),R0 ;Get block number of handler on SY: BNE 50$ ;Good, the handler exists on SY: BR FCE0 ;Stack is correct as is ............ FCE0X: TST (SP)+ ;Adjust stack FCE0: EMTER0 ;ERROR 0, no handler for device COMXT4: BR COMXT3 ;Exit USR ............ 50$: MOV @(PC)+,R1 ;R1 -> USR Buffer .USRIO:: .WORD <.USRBU-USRBUF> ;Pointer to $SYS 3 word block ADD $HSIZE-$ENTRY(R3),R2 ;R2 -> word beyond top of handler BCS BADFT ;Branch if handler overlays RMON CMP R2,@#$SYPTR ;Will it load entirely below the RMON? BHI BADFT ;No, error CMP R2,R1 ;Is handler top below start of USR? BLOS 60$ ;Yes, ok ADD #,R1 ;Get address above top of USR CMP @SP,R1 ;Is handler start above top of USR? BLO BADFT ;Error if not ;+ ; For non-XM, USR may not necessarily be immediately below SYSLOW ; since the background job can have the USR swap wherever it likes ; below SYSLOW. So, .FETCHes can be done above the USR as long as ; they are below SYSLOW! ;- .IF EQ MMG$T CMP R2,@.SYSLO ;Is top of handler below SYSLOW? BLOS 60$ ;Branch if it is .ENDC ;EQ MMG$T .KMONIN ==: < . + 2 > ;**LOAD** Relocate address of KMON IN flag TST @#KMONIN-$RMON ;Is this KMON's request? BNE 60$ ;KMON can do what it wants BADFT: JSR R5,COMERR ;COMERR doesn't return .WORD FETC.E ;INVALID ADDRESS Error ............ ;+ ; Read handler into memory ;- 60$: .IF EQ MMG$T .$SYS ==: < . + 2 > ;**LOAD** Relocate address of system I/O handler CALL @#$SYS-$RMON ;Call $SYS to read handler in .IFF ;EQ MMG$T CALL $SYS.KM ;Call $SYS with Kernel mode forced .ENDC ;EQ MMG$T BCS BADFT ;Oops, error reading handler .BR 70$ ............ ;+ ; Set up interrupt vector(s) ;- 70$: MOV @SP,R1 ;Point to start of handler CMP #<0>,@.KMONIN ;Is the B/G job KMON? (KMONIN = 0/-1) ;C=0 no, user job; C=1 yes, KMON BIT #,(R1) ;*C* check no fetch/no load ;Z=1 fetchable and loadable ;N=1 not fetchable ;Z=0 not loadable ;Not loadable AND not fetchable is invalid BEQ 90$ ;No restrictions, do it .Assume DV2.NF EQ 100000 BMI 80$ ;Fetching not allowed .Assume DV2.NL NE 100000 BCS BADFT ;Loading not allowed, error if KMON ... BR 90$ ; ... else fetching for user, do it 80$: BCC UNLDRV ;User job, but not fetchable ;>>>can this be shortened? 90$: CLR R0 ;Assume a fixed vector list MOV (R1)+,R5 ;Get handler's vector address(es) BPL 120$ ;0 => no vectors; >0 => one vector ASL R5 ;Vector table, compute offset and dump flag ADD R5,R1 ;Point to handler's table of vectors MOV (R1)+,R5 ;Get a vector BPL 110$ ;Branch if fixed vector list MOV (R1)+,-(SP) ;Get hardware id # of PRO option slot device MOV @#$SYPTR,R5 ;R5 -> $RMON CALL @GETVEC-$RMON(R5) ;@SP = vector A of device MOV (SP)+,R0 ;*C* R0 = vector A of device BCS BADFT ;If cannot find device then error 100$: MOV (R1)+,R5 ;Get a vector 110$: ADD R0,R5 ;Add in vector base (0 if non-option slot) 120$: BLE 130$ ;We're done MOV R1,@R5 ;Put relocation constant into place ADD (R1)+,(R5)+ ;Add offset to interrupt routine MOV (R1)+,@R5 ;Move in PSW value BIS #,@R5 ;Make sure it's Priority 7 .IF NE MMG$T .IF NE XM$FET .INTSET ==: < . + 2 > ;**LOAD** Relocate addr. of vector forwarding routine CALL @#INTSET-$RMON ;Forward the vectoring if necessary. .IF EQ SB BCS UNLDRV ;No table space, must be loaded. BR 100$ ;See if more vectors ............ .IFF ;EQ SB BCC 100$ ;See if more vectors UNLDRV: JSR R5,COMERR ;Issue unloaded driver error (no return) .WORD UDRV.E ;Unloaded Driver Error ............ .ENDC ;EQ SB .IFF ;NE XM$FET BR 100$ ;See if more vectors ............ .ENDC ;NE XM$FET .IFF ;NE MMG$T BR 100$ ;See if more vectors ............ .ENDC ;NE MMG$T .IF NE > ;SB ONLY UNLDRV: JSR R5,COMERR ;Issue unloaded driver error (no return) .WORD UDRV.E ;Unloaded Driver Error ............ .ENDC ;NE > ;+ ; Fix pointers to RMON routines ;- 130$: MOV @SP,R0 ;Point to first word of handler ADD #,R0 ;Point to LQE of handler .IF NE MMG$T ADD R4,ARGM1 ;Point user's returned R0 above handler .IFF ;NE MMG$T ADD R4,@SP ;@SP -> above handler (update user R0) .ENDC ;NE MMG$T MOV (PC)+,R1 ;Point to tbl. of offsets at end of driver tbl .DRVTB:: .WORD ;**LOAD** Reloc. -> to end of drvr tbl .IF NE CMP $PNAME-$ENTRY(R3),$PNAM2-$ENTRY(R3) ;Is it a 64-unit handler? BEQ 140$ ;Branch if not a 64-unit handler SUB #<32.>,R2 ;Skip back over extended unit table .ENDC ;NE 140$: .IF EQ MMG$T MOV @R1,-(R2) ;Load an offset ;>>>Relocate the table contents and remove this instruction ADD @#$SYPTR,@R2 ;Relocate the offset TST -(R1) ;Any more to load? BNE 140$ ;Yes, do them .IFF ;EQ MMG$T CALL LDPTRS ;Load RMON pointers BIT #,H1.FLG-H1.LQE(R0) ;Do flags indicate DMA handler? BNE 92$ ;Yes, skip load of pre-V55 routines .UBDTB == < . + 2 > ;**LOAD** Relocate pointer to end of driver table MOV (PC)+,R1 ;Point to table of offsets .WORD UBDTBL+UBDTSZ-2-$RMON ;-> End of driver table ADD #<12>,R2 ;Point to $PUTWRD pointer ... CALL LDPTRS ; ... and load "No UB" pointers 92$: .ENDC ;EQ MMG$T CLR H1.CQE-H1.LQE(R0) ;Clear CQE and continue .BR 150$ ............ ;+ ; Make handler known to system (plug it's address into $ENTRY table) ; and call it's FETCH entry point, if it has one. ; ;>>>should we hold the handler here?? ;- 150$: MOV R0,@R3 ;Plug address of XXLQE: into $ENTRY table .ASSUME HSR.FE EQ 0 CLR R1 ;Indicate doing a FETCH ;R0 == XXLQE (preserve) ;R1 == 0 (FETCH flag) ;R2 ??? ;R3 == $ENTRY for this handler ;R4 ??? ;R5 ??? .DRCAL ==: < . + 2 > ;**LOAD** Relocate address of handler call routine CALL @#DRCALL-$RMON ;Call handler, if requested to do so BCC 160$ ;Branch if FETCH call successful CLR @R3 ;Else, remove failed handler from $ENTRY ... BR BADFT ; ... and give error ............ 160$: .IF NE MMG$T MOV ARGM1,@SP ;Correct value to return in R0 .ENDC ;NE MMG$T PHOUT: BR COMXT4 ;Exit USR ............ .DSABL LSB .IF NE MMG$T ;+ ; Subroutine to call system read routine with KERNEL mode forced ; ; This is required because a job which fetches a device handler is ; in user mode (from the EMT) but we must work in KERNEL mapping ; since we JSR to RMON instead of doing another EMT which would have ; set the mode properly to KERNEL. ; ; WARNING: R1 is destroyed! ;- $SYS.KM:: CLC ; Clear carry so it won't be set later. MOV @#PS,R1 ; Save the current PSW. BIC #,@#PS ; Force previous mode to KERNEL. .$SYS ==: < . + 2 > ;**LOAD** Relocate address of system I/O handler. CALL @#$SYS-$RMON ; Call $SYS to read handler into memory. BIS R1,@#PS ; Restore the old mode (preserve carry). RETURN ; Return to the fetch code. ............ .ENDC ;NE MMG$T .SBTTL DRVTBL - Copy of Table of RMON Offsets Which is in Each Driver .PSECT USRRMN .IF NE MMG$T UBDTBL: .WORD 0 ;Table terminator .WORD < $OSGTB - $RMON > .WORD < $OSPTB - $RMON > .WORD < $OSPTW - $RMON > UBDTSZ = < . - UBDTBL > .ENDC ;NE MMG$T DRVTBL: .WORD 0 ;Table terminator .IF NE MMG$T .WORD < $RELOC - $RMON > .WORD < $MPPHY - $RMON > .WORD < $GETBY - $RMON > .WORD < $PUTBY - $RMON > .WORD < $PUTWR - $RMON > .ENDC ;NE MMG$T .IF NE ERL$G .WORD < $ERLOG - $RMON > .ENDC ;NE ERL$G .IF NE TIM$IT .WORD < $TIMIO - $RMON > .ENDC ;NE TIM$IT ;+ ; The RTEM-11 bootstrap hooks locations DRINTN and DRINTN+2 to allow ; RTEM-11 to correctly get control from calls by drivers. Both ; routines are located in the RTEM-11 linkage routines. ;- DRINTN::.WORD < $INTEN - $RMON > ;**RTEM** Hooked as ".WORD $INTN". .WORD < $FORK - $RMON > ;**RTEM** Hooked as ".WORD $FORQ". DRVTSZ = < . - DRVTBL > .PSECT RMNUSR .SBTTL USRCOM - Set Up USR For LOOKUP, ENTER, RENAME, DELETE ;+ ; USRCOM - Used by LOOKUP/RENAME, DELETE, and ENTER to prepare a channel ; for I/O operations ; ; R0 -> dev:filnam.typ ; R3 -> channel status word ; R4 = channel number * 2 ; @SP = old R5 = bits to set in CSW: ; LOOKUP - 0 ; RENAME - 100 (RENAM$) ; ENTER - 200 (DWRIT$) ; DELETE - 0 ; ; JSR R5,USRCOM ; ; R0 -> filnam.typ ; R1 -> 1st dir entry in segment in USR Buffer (if file structured op) ; R2 -> $STAT table entry for dev: ; R3 -> channel status word ; R4 = channel number ; CHNLRG = channel number ; SBLK = start block number for ; segment in buffer (if file structured op only) ; ARGM3 -> user extra word handling routine ; ; USRCOM prepares a channel for I/O operations by doing the following: ; ; Test to see if channel is active (it's not supposed to be) ; Test if device is legal, has a handler in memory, and is owned by us ; Sets up CSW with channel active, DBLOCK = 1, the appropriate ; device index, and sets the bits passed @SP ; If a file structured operation is in progress, the first ; directory block is read into the USR Buffer ;- .ENABL LSB USRCOM: ASR R4 ;Make R4 into channel number MOV R4,CHNLRG ;Save channel selector MOV (SP)+,R2 ;Take off saved R5 .ASSUME ACTIV$ EQ 100000 TST @R3 ;Channel active? BMI FCE0 ;Yes, give error ROR R0 ;Set C based on DBLK odd or even JSR R2,10$ ;Set up pic pointer to RETURN RETURN ;Default user routine for info words ............ 10$: BCS 20$ ;Branch if user does want to be called MOV R2,ARGM3 ;Put RETURN address in for no call .BR 20$ ............ 20$: ASL R0 ;Now make R0 good even pointer ... MOV R0,2(SP) ; ... and fix the duplicate copy CLR C.SBLK(R3) ;Clear starting block .IF NE MMG$T CALL MAPFIL ;Map to users file block .ENDC ;NE MMG$T MOV R5,-(SP) ;Need to save R3 ... MOV R3,-(SP) ; ... and R5 ASR ARGM3 ;Get low bit of routine addr to C bit JSR R4,@.LK4DV ;Is device in memory? C=1 -> no logical BR COMNDV ;No such device name ...... BEQ COMNDV ;No device is there! ASL ARGM3 ;Restore good even routine address .IF EQ USR$CM .USRC1 ==: < . + 2 > ;**LOAD** Relocate address of code PSECTed to RMON CALLR @#USRCM1-$RMON ;Transfer control to RMON portion ............ .PSECT USRRMN ;PSECT the following into RMON USRCM1: .ENDC ;EQ USR$CM .IF NE OWN$ER .IF NE UNI$64 MOV R3,R5 ;Copy device index ASL R5 ;R5 = 2 * Device index .IF EQ USR$CM .ADDR #<$OWNER>,R5,ADD ;R5 -> First word of $OWNER pair .IFF ;EQ USR$CM .$OWNER ==: < . + 2 > ;**LOAD** Relocate address of device ownership table ADD #<$OWNER-$RMON>,R5 ;R5 -> First word of $OWNER pair .ENDC ;EQ USR$CM CMP @R5,# ;Is OWN.EX flag set? (extended unit handler) BNE 30$ ;Branch if not, do normal owner check ;+ ; Obtain the address of the extended ownership table from the second word of ; the $OWNER entry. If the pointer is zero, then the handlers load/fetch code ; did not fill it in when the handler was loaded. Since this is a bug, don't ; let the user use the handler until it's fixed. ;- MOV 2(R5),R5 ;R5 = Extended ownership table pointer BEQ 60$ ;Branch if no table, give an error 30$: MOV R1,-(SP) ;Copy unit number ASR @SP ;Compute unit#/2 ADD (SP)+,R5 ;R5 -> ownership byte .IF NE MMG$T .IF EQ USR$CM CALL KPSAVE ;Make sure (extended) owner table is mapped! .IFF ;EQ USR$CM .KPSAVE ==: < . + 2 > ;**LOAD** Relocate pointer to save PAR1/PAR2 routine CALL @#KPSAVE-$RMON ;Make sure (extended) owner table is mapped! .ENDC ;EQ USR$CM .ENDC ;NE MMG$T MOVB @R5,R5 ;Get ownership byte .IF NE MMG$T .IF EQ USR$CM CALL KPREST ;Restore PAR1 to file block .IFF ;EQ USR$CM .KPREST ==: < . + 2 > ;**LOAD** Relocate ptr to restore PAR1/PAR2 routine CALL @#KPREST-$RMON ;Restore PAR1 to file block .ENDC ;EQ USR$CM .ENDC ;NE MMG$T .IFF ;NE UNI$64 MOV R1,R5 ;Copy unit number ASR R5 ;Compute unit#/2 ... ADD R3,R5 ; ... + (2 * device index) ADD R3,R5 .IF EQ USR$CM .ADDR #<$OWNER>,R5,ADD ;R5 -> correct ownership byte MOVB @R5,R5 ;Get ownership byte .IFF ;EQ USR$CM .$OWNER ==: < . + 2 > ;**LOAD** Relocate address of device ownership table MOVB $OWNER-$RMON(R5),R5 ;Get ownership byte .ENDC ;EQ USR$CM .ENDC ;NE UNI$64 BIT #<1>,R1 ;Is unit odd? BEQ 40$ ;No, use low bits ASR R5 ;Yes, use ... ASR R5 ; ... high ... ASR R5 ; ... four ... ASR R5 ; ... bits 40$: BIC #^c<17>,R5 ;Isolate 4 bit ownership field BEQ 50$ ;0 => Public device (i.e., unowned) DEC R5 ;Clear guard (low) bit .IF EQ USR$CM CMP JOBNUM,R5 ;Do we own it? .IFF ;EQ USR$CM CMP @.JOBNUM,R5 ;Do we own it? .ENDC ;EQ USR$CM BNE 60$ ;No, give an error 50$: .ENDC ;NE OWN$ER MOV R3,R5 ;Copy device index number MOV (SP)+,R3 ;Restore CSW pointer BIS R5,@R3 ;Insert device index number in CSW BIS #,@R3 ;Set channel active, DBLOCK=1 MOV (SP)+,R5 ;Restore return address to R5 for RTS R5 SWAB R1 ;Put unit number in high byte so we can ... MOV R1,C.DEVQ(R3) ; ... put it into CSW block (clears low byte) .IF EQ USR$CM MOV #<80$-USRST>,-(SP) ;Transfer control to RMON portion BR 70$ ............ 60$: MOV #,-(SP) ;Transfer control to RMON portion 70$: ADD USRLOC,@SP ;Calculate real location CALLR @(SP)+ ;Return ............ .PSECT RMNUSR ;PSECT following code into USR .IF NE OWN$ER .$OWNER ==: < . > ;**LOAD** Relocate pointer to $OWNER table .WORD < $OWNER - $RMON > ;For KMOVLY (TEMP) .ENDC ;NE OWN$ER 80$: .ENDC ;EQ USR$CM BIT #,@R2 ;Is it a special device? BEQ 90$ ;No, but is it file-structured? BIS @SP,@R3 ;Set rewrite bit for special device BR ENXT ;Special device exit ............ 90$: TST @R2 ;Is it file structured? .Assume FILST$ LT 0 BPL USR3 ;No, don't alter channel word TST @R0 ;Is the name null? BEQ USR3 ;Yes, it's non file operation BIS @SP,@R3 ;Set RENAME or directory rewrite bit JSR R5,BLKCHK ;Get a directory block in memory USR2: TST (R5)+ ;Return for file type operation ENXT: TST (R5)+ USR3: RTS R5 ............ .IF NE MMG$T LDPTRS: MOV @R1,-(R2) ;Load an offset ;>>>Relocate the table contents and remove this instruction ADD @#$SYPTR,@R2 ;Relocate the offset TST -(R1) ;Any more to load? BNE LDPTRS ;Yes, do them RETURN ............ .ENDC ;NE MMG$T .IF NE USR$CM 60$: .ENDC ;NE USR$CM COMNDV: JSR R5,COMERR ;No handler there .WORD NODV.E ............ .DSABL LSB .SBTTL INFOFS - .SFDATE, .GFDATE, .SFSTAT, .GFSTAT, .GFINFO, .SFINFO, .FPROT .ENABLE LSB ;+ ; Operation byte values ;- MAX.F ==: ..MOVF ;Maximum valid value E.COL =: ;Color bits (add to EDTGBL) ;+ ; INFOFS - Set/Get file protection/information/status/date ;- INFOFS: JSR R5,USRCOM ;Do common setup BR 70$ ;Non file oriented device ...... BR SPINFO ;Special directory handler ...... CLR R1 ;Find length of entry CALL INCR1 ;Put length in R1 MOVB ARGM2+1,R4 ;Load offset CMP R4,R1 ;Is offset within range? BHIS 80$ ;No, error JSR R5,SEARCH ;Find entry BR 70$ ;File not found ...... ADD R4,R1 ;Point to word in entry MOV @R1,@SP ;Return current value .ASSUME ..GETF EQ 0 MOVB ARGM2,R5 ;Load operation value, GET operation? BEQ 100$ ;Yes, finished MOV ARGM1,R2 ;Load value CMP #,R4 ;Is this LEN word? BEQ 80$ ;Yes, can't modify it .IF EQ XFX$XX BRRUGH ==: < . + 2 > ;**LOAD** Relocate address of SFINFO routine CALLR @#SFINFO-$RMON ............ .PSECT USRRMN SFINFO: MOV R4,-(SP) ;Save R4 value for test MOV USRLOC,R4 ;Base address of USR .ASSUME E.STAT EQ 0 TST (SP)+ ;E.STAT word? .IFF ;EQ XFX$XX .ASSUME E.STAT EQ 0 TST R4 ;E.STAT word? .ENDC ;EQ XFX$XX BNE 20$ ;No CMPB #<..MOVF>,R5 ;Which operation is it? BNE 10$ ;Not a move BIC #,@R1 ;Clear not to worry bits BIC #^c,R2 ;Clear worry bits BR 40$ ;Using shared bits ............ 10$: BIT #,R2 ;Any sensitive bits set? BNE 90$ ;Yes 20$: .Assume ..BICF-1 EQ 0 DEC R5 ;Is it a BIC operation? BEQ 30$ ;Yes .Assume ..BISF-2 EQ 0 DEC R5 ;Is it a BIS operation? BEQ 40$ ;Yes .Assume ..MOVF-3 EQ 0 DEC R5 ;Is it a MOV operation? BEQ 50$ ;Yes EMTER2 ;Error 2 - Operation is invalid BR 101$ ;Done ............ 30$: BIC R2,@R1 ;Clear selected bits BR 60$ ;And write it back ............ 40$: BIS R2,@R1 ;Set selected bits BR 60$ ;And write it back ............ 50$: MOV R2,@R1 ;Replace it 60$: .IF NE XFX$XX JSR R5,SEGWR ;Write back modified segment .IFF ;NE XFX$XX JSR R5,SEGWR-USRST(R4) ;Write back modified segment .ENDC ;NE XFX$XX ;+ ; Directory I/O err possible (Handled by SEGWR) ;- BR 101$ ;Done ............ 90$: EMTER4 ;Error 4 - Value is invalid .IF NE XFX$XX BR 100$ ;Done ............ .IFF ;NE XFX$XX 101$: CALLR KILCHN-USRST(R4) ;Exit through channel kill code ............ .PSECT RMNUSR .ENDC ;NE XFX$XX 70$: EMTER1 ;Error 1 - File not found BR 100$ ;Done ............ 80$: EMTER3 ;Error 3 - Offset is invalid .BR 100$ ;Done ............ .IF NE XFX$XX 101$: .ENDC ;NE XFX$XX 100$: CALLR KILCHN ;Done, close channel (R3->CSW) ............ SPINFO: MOV USREMT,R2 ;Reload special operation code CALLR SPESHL ;Go do special directory operation ............ .DSABL LSB .SBTTL ENTRY - Scan For Entry Of Specified Type In Current Segment ;+ ; ENTRY - Find an entry of a specified type in a directory segment ; ; R1 -> next directory entry to check ; ; JSR R5,ENTRY ; .WORD entrytype (tent, empty, perm, or endblk) ; Error return - no entry found ; Normal return ; ; R1 -> entry of specified type, or end-of-block marker ; if no entry is found ;- ENTRY: BIT @R5,@R1 ;A match? BNE USR2 ;Yes, get out BIT @R1,# ;End of block? BNE ENXT ;Yes, return ADD E.LENG(R1),(PC)+ ;Update length SBLK: .WORD 0 CALL INCR1 ;Next entry in segment BR ENTRY ; and loop ............ .SBTTL INCR1/2 - Move R1 Past One Or Two Directory Entries ;+ ; These routines move R1 past one or two directory entries ;- INCR1A: ADD E.LENG(R1),R5 ;Update start block BR INCR1 ............ INCR2: MOV PC,-(SP) ;Twice around the loop INCR1: ADD USRBUF+D.EXTR,R1 ;Add extra words ADD #,R1 ;Add entry size RETURN ............ .SBTTL SEARCH - Find A Specified Permanent File ;+ ; SEARCH - Find a specified permanent file ; ; R0 -> filnam.ext ; R3 -> CSW of current channel ; ; JSR R5,SEARCH ; Error return - no such file ; Normal return ; ; R1 -> status word of dir entry for file ; SBLK = starting block number of file ; N bit set IFF file is protected ;- .ENABL LSB SEARCH: JSR R5,BLKCHK ;Get correct dir segment in memory 10$: JSR R5,FILSCN ;Look for file in that segment BR 40$ ;Not there ...... 20$: TST (R5)+ ;Bump to good return TST @R1 ;Set N bit if protected 30$: RTS R5 ............ 40$: JSR R5,NXBLK ;Get next dir segment in memory BR 30$ ;No more ...... BR 10$ ;Keep scanning ............ .SBTTL FILSCN - Scan A Dir Segment In USR Buffer For A Specific Perm File ;+ ; FILSCN - Scan a directory segment in USR Buffer for a specific perm file ; ; R0 -> filnam.ext ; R1 -> first dir entry in segment ; SBLK = starting block number of files in segment ; ; JSR R5,FILSCN ; Error return - no such file ; Good return ; ; R1 -> dir entry of specified file ; SBLK = starting block number of file ; N bit set IFF file is protected ;- FILSCN: JSR R5,ENTRY ;Get next perm entry in this block .WORD E.PERM BR 30$ ;No more ...... CMP @R0,E.NAME(R1) ;First half of name match? BNE 50$ ;No CMP 2(R0),E.NAME+2(R1) ;Second half of name match? BNE 50$ ;Nope CMP 4(R0),E.NAME+4(R1) ;Extensions match? BEQ 20$ ;Yes, return, set N bit if protected 50$: ADD E.LENG(R1),SBLK ;Update starting block number CALL INCR1 ;Point R1 to next entry BR FILSCN ;Keep looking ............ .DSABL LSB .SBTTL NXBLK - Read Next Logical Directory Block Into USR Buffer ;+ ; NXBLK - Gets the next in the sequence of directory blocks if one exists ; ; R3 -> channel status word ; USRBUF+2 = link to next directory block in directory ; ; JSR R5,NXBLK ; Error return - no next block ; Normal return ; ; If there is another segment, it is read in, and: ; ; R1 -> 1st dir entry in segment (in USR Buffer) ; CSW updated with number of dir segment in memory ; BLKEY updated w/ " " " " " " ; CHKEY updated with correct device index and unit number ; SBLK = starting block number for files in new segment ; ; If there is not another segment, nothing is touched ;- NXBLK: MOV R0,-(SP) ;Save pointer to filnam.ext MOV USRBUF+2,R0 ;Is there a next block? BEQ ENRTS ;No SWAB R0 ;Put block number in place BIC #,@R3 ;Clear out block number in CSW BIS R0,@R3 CMP (R5)+,(PC)+ ;Bump to good return, skip MOV R0,-(SP) .ASSUME BLKCHK+2 EQ NO0CHK ;;; BR NO0CHK ;Done by (PC)+ above .BR BLKCHK ;Fall into BLKCHK ............ .SBTTL BLKCHK - Read A Directory Block Into USR Buffer ;+ ; BLKCHK - Reads the specified directory block into the USR Buffer ; If the block is already in the buffer, it is not re-read ; ; R3 -> channel status word (contains dir block number to read) ; ; JSR R5,BLKCHK ; ; R1 -> 1st dir entry in segment in memory (in USR Buffer) ; BLKEY updated w/ " " " " " " ; CHKEY updated with correct device index and unit number ; SBLK = starting block number for files in new segment ;- .ENABL LSB BLKCHK: MOV R0,-(SP) ;Save name pointer NO0CHK: MOV @R3,R0 ;Get channel status word SWAB R0 ;Put block number byte in low byte BIC #^c,R0 ;Isolate desired block MOV C.DEVQ(R3),-(SP) ;See if directory of correct device ... MOVB @R3,@SP ; ... is in memory. Check device pointer, ... BIC #<301>,@SP ; ... and device index CMP R0,@.BLKEY ;Correct segment number in memory? BNE 10$ ;No, we must read CMP @SP,@.CHKEY ;Correct device & unit? BEQ 20$ ;Yes, no need to read 10$: MOV R0,@.BLKEY ;Save the block in memory JSR R5,SEGRD ;Read it in .CHKEY ==: < . + 2 > ;**LOAD** Relocate address of Channel Key 20$: MOV (SP)+,@#CHKEY-$RMON ;Purge stack, set CHKEY MOV .USRBU,R1 ;R1 -> directory segment ; Ck.R1=D.Total ; Ck.R1 D.Total MOV @R1,R0 ;Get total number of directory segments BEQ ILLDIR ;If zero, then invalid directory ; Ck.R1 D.Total CMP #,R0 ;Is total number of dir. segments in range? BLO ILLDIR ;No, invalid ; Ck.R1 D.Total,+2 ; Ck.R1 D.Next,+2 CMP (R1)+,(R1)+ ;Compare D.Total::D.Next BLO ILLDIR ;Next higher than total! ; Ck.R1 D.High,+2 TST (R1)+ ;Skip D.High ; Ck.R1 D.Extra BIT #<1>,@R1 ;Is extra byte count even? BNE ILLDIR ;No, invalid ; Ck.R1 D.Extra,+2 CMP #<--2>/3,(R1)+ ;Are entries short enough? BLO ILLDIR ;No, invalid ASL R0 ;D.Total*2 ADD #<6>,R0 ; " +6 = directory size in disk blocks ; Ck.R1 D.Strt CMP R0,@R1 ;Does data overlap directory? BHI ILLDIR ;Yes, invalid ; Ck.R1 D.Strt,+2 MOV (R1)+,SBLK ;Save file start block ; Ck.R1 D.Leng ENRTS: MOV (SP)+,R0 ;R0 points to file.ext RTS5: RTS R5 ............ .DSABL LSB ILLDIR: JSR R5,COMERR ;COMERR does not return .WORD ILLD.E ;Invalid directory ............ .SBTTL SEGRD/W - Read/Write Directory Segments ;+ ; SEGRD1 - Read dir segment 1 into USR Buffer ; SEGRD - Read dir segment in BLKEY into USR Buffer ; SEGWR - Write dir segment in buffer to device segment number in BLKEY ; SEGRW - Common read/write routine: ; ; BLKEY = segment number to read or write ; C set if operation is read ; ; JSR R5,SEGRD ; ; R0 = undefined ;- SEGRD1: MOV #<1>,@.BLKEY ;Set directory segment to 1 SEGRD: CMP (PC)+,PC ;Set C=1 and skip next instruction SEGWR: CLC ;Set C=0 to flag write (PC>241 here!) .BLKEY ==: < . + 2 > ;**LOAD** Relocate address of Block Key MOV @#BLKEY-$RMON,R0 ;*C* Get segment number into R0 SEGRW: JSR R0,SKIPBL ;*C* Get pic address of read/write area .WORD 0 ;Channel and EMT code .WORD 0 ;Block number on device .USRBU:: .WORD ;Current address of USR Buffer .WORD ;2 block word count .WORD 0 ;Wait mode request SKIPBL: MOVB (PC)+,(R0)+ ;*C* Set channel number CHNLRG: .WORD 0 MOVB #<.WRIT>,@R0 ;*C* Assume default of WRITE EMT .ASSUME .READ EQ < .WRIT - 1 > SBCB (R0)+ ;Adjust EMT code for read if C=1 ASL @SP ;Convert segment number to block ADD #,@SP ;Adjust by physical location on device MOV (SP)+,@R0 ;Put it in EMT area TST -(R0) ;Point back to start of area ... .ASSUME ...REA EQ ...WRI EMT ...REA ; ... and do the EMT BCC RTS5 ;No I/O error, return IOER: JSR R5,COMERR ;COMERR does not return .WORD DIRI.E ;Directory I/O Error ............ .SBTTL CONSOL - Remove Unnecessary Entries From A Directory ;+ ; CONSOL - Removes any unnecessary entries from a given directory ; ; R1 -> 1st entry in directory ; ; CALL CONSOL ; ; DREND -> end of directory ; R2 = undefined ; R5 = undefined ; ; CONSOL is called before an ENTER and after a CLOSE. ; Unnecessary entries come in several flavors: ; a) Unassociated tentative entries ; b) Multiple consecutive empties ; c) Empties of length 0 following a permanent entry ; ; CONSOL makes two passes over the directory segment. ; In pass 1, unassociated tentatives are made into empties. ; In pass 2, consecutive empties are consolidated and ; empty entries preceeded by a permanent entry are deleted. ;- .ENABL LSB CONSOL: MOV SBLK,-(SP) ;Save SBLK, since ENTRY: destroys it MOV R4,-(SP) ;Save active registers MOV R3,-(SP) MOV R1,-(SP) ;R1 points to top of directory MOV #,R4 ;Put entry size into R4 ADD USRBUF+D.EXTR,R4 .BR 10$ ............ ;+ ; Pass 1 - Find unassociated tentatives, convert to empties ;- 10$: JSR R5,ENTRY ;Get a tentative entry .WORD E.TENT BR 50$ ;No more. Do Pass 2 ...... .IF EQ SB MOVB E.JNUM(R1),R2 ;Get job number of tentative BIT #^c,R2 ;Is this a valid job number? BNE 30$ ;No, this tentative is unused .$IMPUR ==: < . + 2 > ;**LOAD** Relocate address of impure area ptr. table MOV $IMPUR-$RMON(R2),R2 ;Get impure area pointer of creator BEQ 30$ ;No job, so tentative is unused .IFF ;EQ SB .CNTXT ==: < . + 2 > ;**LOAD** Relocate address of current context pointer MOV @#CNTXT-$RMON,R2 ;Get pointer to impure area .ENDC ;EQ SB CLR R5 ;Get channel number BISB E.CHAN(R1),R5 ; in R5 CMPB I.CNUM(R2),R5 ;Legal channel for job? BLOS 30$ ;No .IF EQ SB .CNTXT ==: < . + 2 > ;**LOAD** Relocate address of current context pointer CMP @#CNTXT-$RMON,R2 ;Is this our tentative? BNE 20$ ;No .ENDC ;EQ SB CMPB CHNLRG,R5 ;Yes. Is tentative on this request's channel? BEQ 30$ ;Yes, we can clobber it 20$: ASL R5 ;Compute MOV R5,-(SP) ; channel ASL R5 ; number ASL R5 ; times ADD (SP)+,R5 ; 10. ADD I.CSW(R2),R5 ;R5 -> channel of tentative TST @R5 ;Is associated channel open? BPL 30$ ;No, tentative is invalid MOV C.DEVQ(R5),R2 ;Get unit number in high order CLRB R2 ;Clear low byte BISB @R5,R2 ; and assemble device index BPL 30$ ;Channel is LOOKED UP, so tentative invalid BIC #<301>,R2 ;R2 = CHKEY for tentative's channel CMP @.CHKEY,R2 ;Same device and unit? BEQ 40$ ;Yes, this tentative's channel is still open 30$: MOV #,@R1 ;Convert tentative to empty 40$: ADD R4,R1 ;Next entry BR 10$ ;Loop for next entry ............ ;+ ; Pass 2 - merge consecutive empties, delete 0 length empties after perms ;- 50$: MOV @SP,R1 ;Point to first entry in segment again 60$: JSR R5,ENTRY ;Get an empty entry .WORD E.MPTY BR CNSLOV ;No more empties, so done ...... MOV R1,R2 ;Copy empty entry pointer ADD R4,R2 ;Point R2 to next entry BIT #,@R2 ;Is it empty? BEQ 90$ ;No. Check for empty of length 0 ADD E.LENG(R2),E.LENG(R1) ;Merge the empty entries ;+ ; Squeeze an entry out of the directory ;- 70$: MOV R2,R5 ;The entry at R2 will be crunched ADD R4,R5 ;One entry beyond MOV R1,-(SP) ;Save R1 JSR R5,ENTRY ;Get end of directory mark .WORD 0 ;Search for 0 finds end of block MOV R1,R3 ;Copy pointer to end of directory 80$: MOV (R5)+,(R2)+ ;Squeeze the entry CMP R5,R3 ;End of directory yet? BLOS 80$ ;No, loop MOV (SP)+,R1 ;Restore R1 BR 60$ ;Try to merge some more ............ 90$: TST E.LENG(R1) ;Is it length 0? BNE 100$ ;No. Get next entry MOV R1,R2 ;See if previous is permanent MOV R1,R3 SUB R4,R3 CMP R3,@SP ;Doing first entry in direct? BLO 100$ ;Yes. Get next entry BIT #,@R3 ;Permanent entry? BNE 70$ ;Yes, squeeze it out 100$: ADD R4,R1 ;Advance to next entry BR 60$ ............ ;+ ; Done ;- CNSLOV: MOV R1,(PC)+ ;Save position of end of direct DREND: .WORD 0 MOV (SP)+,R1 MOV (SP)+,R3 MOV (SP)+,R4 MOV (SP)+,SBLK ;Restore SBLK RETURN ............ .DSABL LSB .SBTTL LK4DEV - Scan Monitor Device Tables For Specified Device ;+ ; LK4DEV - Scan monitor device tables for specified device ; ; C = 0 means do logical device translation ; C = 1 means do not do logical device translation ; R0 -> dev:filnam.typ (dev: can be a logical device name) ; ; JSR R4,LK4DEV ; Error return ; Normal return ; ; R0 -> filename in block ; R1 = unit number ; R2 -> $STAT word ; R3 = device index number ; R5 -> $ENTRY word ; ; Condition Codes set from $ENTRY word ; ; NOTE ;*C* means that instructions must not alter Carry ;- .ENABL LSB .IF EQ LK4$DV .PSECT USRRMN ;PSECT the following into RMON .ENDC ;EQ LK4$DV LK4DEV::MOV (R0)+,R5 ;*C* Get name in R5, advance R0 BEQ 70$ ;*C* Null name gives error return .IF EQ UNI$64 BCS 20$ ;Skip logical names .IFF ;EQ UNI$64 MOV R0,-(SP) ;*C* Save R0 for scratch use ROR -(SP) ;*C* Save translation flag (C-BIT) on stack BMI 20$ ;C-SET => skip logical name translation .ENDC ;EQ UNI$64 ;+ ; Search for possible logical assignment ;- .IF EQ LK4$DV .ADDR #<$UNAM2>,R1 ;Point to list of user names .IFF ;EQ LK4$DV .$UNAM ==: < . + 2 > ;**LOAD** Relocate address of $UNAM2 table MOV #<$UNAM2-$RMON>,R1 ;Point to list of user names .ENDC ;EQ LK4$DV MOV #<$SLOT+3>,R3 ;Counter in R3 10$: DEC R3 ;Done user name table? BEQ 20$ ;Yes CMP R5,(R1)+ ;Match this entry? BNE 10$ ;No, keep trying MOV $UNAM1-$UNAM2-2(R1),R5 ;Get associated perm name 20$: .IF EQ LK4$DV .ADDR #<$PNAME>,R2 ;Point to perm name table .IFF ;EQ LK4$DV .$PNAM ==: < . + 2 > ;**LOAD** Relocate address of Permanent Name table MOV #<$PNAME-$RMON>,R2 ;Point to perm name table .ENDC ;EQ LK4$DV .IF EQ UNI$64 CMP -(R2),-(R2) ;2 words before table MOV #<-2>,R3 ;Clear slot counter 30$: MOV R5,R1 ;Get search object SUB (R2)+,R1 ;Try this entry BLO 40$ ;No, entry too high BEQ 50$ ;Exact match SUB #<^r 0>,R1 ;Try range of 0-7 unit BLO 40$ ;Not in range CMP R1,# BLOS 50$ ;Got it 40$: INC R3 ;Increment slot number CMP R3,#<$SLOT> ;Too many? BLT 30$ ;Not yet RTS R4 ;Not found. Take error return ............ .IFF ;EQ UNI$64 ;+ ; LK4DE2 is resident in RMON due to USR size restrictions. ; If device is found, return is to word following JSR. ; If device is not found, return is to two words following JSR. ;- JSR R4,LK4DE2-$PNAME(R2) ;Go do last part of LK4DEV in RMON .ENDC ;EQ UNI$64 50$: TST (R4)+ ;Take the success return ASL R3 ;Double device index BPL 60$ ;Positive means not DK or SY .IF EQ LK4$DV MOV SYINDX,R3 ;Get index of system device 60$: .ADDR #<$ENTRY>,R5 ;R5 -> $ENTRY (handler entry point table) .IFF ;EQ LK4$DV .SYIND ==: < . + 2 > ;**LOAD** Relocate address of system device index MOV @#SYINDX-$RMON,R3 ;Get index of system device .$ENTR ==: < . + 2 > ;**LOAD** Relocate address of $ENTRY table 60$: MOV #<$ENTRY-$RMON>,R5 ;Point to entry point table .ENDC ;EQ LK4$DV ADD R3,R5 ;Index to proper entry MOV R5,R2 ;Copy that pointer ADD #<$STAT-$ENTRY>,R2 ; and point R2 to status entry .IF NE UNI$64 TST (SP)+ ;Clean stack of phase flag MOV (SP)+,R0 ;Restore R0 .ENDC ;NE UNI$64 TST @R5 ;Set Cond Code on whether handler is in 70$: RTS R4 ;Return ............ .DSABL LSB .IF NE UNI$64 .PSECT USRRMN ;Due to size, rest of LK4DEV lives in RMON ;+ ; Do physical device name search in $PNAME and $PNAM2 tables ; ; The following section is a modified LK4DEV $PNAME search ; routine which accounts for the fact that extended unit ; handlers have names from d00: through d77: ;- .ENABL LSB LK4DE2:: CRAP ==: < . + 2 > ;**BOOT** Exorcise this abomination when $Rel done MOV #<$PNAME-4>,R2 ;R2 -> $PNAME (Physical name table) ; to special SY and DK entries. ;>>>$Rel .-2 $PNAME-4 RMON ;**BOOT** MOV #<-2>,R3 ;Set initial device index (SY/DK entries) 10$: MOV R5,R1 ;Get device name MOV (R2)+,R0 ;Get $PNAME entry into R0 SUB R0,R1 ;Subtract possible match BLO 20$ ;Branch if entry too high, no match BEQ 50$ ;Branch if exact match, done. (dd:) SUB #<^r 0>,R1 ;Subtract off end RAD50 digit BLO 20$ ;No match possible CMP R1,#<7> ;Set cond codes, 0-7? (dd0-dd7) BLOS 50$ ;Branch if so, match. 20$: TST R3 ;Is device index negative? BMI 70$ ;If so, bypass $PNAM2 check (DK or SY) ;+ ; Now try to match device name in $PNAM2 table ;- MOV R5,R1 ;Get device name SUB $PNAM2-$PNAME-2(R2),R1 ;Subtract possible match BLO 70$ ;Branch if entry too high, no match BEQ 50$ ;Branch if exact match, done. (d:) ;+ ; Because we search $PNAME table entry first, we will always find a two letter ; physical device spec there, before we search the $PNAM2 table. Therefore, ; we only need to search for single letter type device specs here. ;- SUB $PNAM2-$PNAME-2(R2),R0 ;Compare $PNAM2 and $PNAME entries BEQ 70$ ;If EQ, then not an extended unit handler ;+ ; Check for device name d_0-d_7 ;- SUB #<^r 0>,R1 ;Subtract off end RAD50 digit BLO 70$ ;No match possible CMP R1,#<7> ;Set cond codes, 0-7 (d_0-d_7)? BLOS 50$ ;Branch if so, match. SUB #<^r 0 >-<^r 0>,R1 ;Is device name of the form d0: BEQ 50$ ;Branch if so, match. ;+ ; Check for device name d1-d7 and d00-d77 ;- SUB #<^r 0>,R1 ;Subtract off end RAD50 digit BLO 70$ ;No match possible CMP R1,#<^r 77>-<^r 00> ;Dealing with d1-d7 or d00->d77? BHI 70$ ;Branch if not, no match then. CLR R0 ;Quotient=0 30$: INC R0 ;Inc Quotient SUB #<^r A >,R1 ;Subtract RAD50 equivalent of 10 (octal) BPL 30$ ;Loop if no underflow yet ADD #<32.>,R1 ;One too far? BPL 60$ ;Branch if not ASL R0 ;Else unit# = unit# + (8 * quotient) ASL R0 ; ASL R0 ; 40$: ADD R0,R1 ;R1 = unit#, matched. ;+ ; Device name has matched ;- 50$: RTS R4 ;Take success return ............ 60$: SUB #<2>,R1 ;Remainder = 2? (d1: -> d7:) BEQ 40$ ;If so, go set R1 = unit# ;+ ; No match was found, do next entry. ;- 70$: INC R3 ;Increment device index CMP R3,#<$SLOT> ;Done complete table? BLT 10$ ;Branch if not, continue. MOV $PNAM2+<$SLOT*2>,R5 ;R5 = "*" device BEQ 80$ ;Branch if "*" not assigned COM 2(SP) ;Change PHASE -- was old PHASE = LOGICAL? BMI LK4DE2 ;Yes, start again with new "*" device name 80$: TST (R4)+ ;Take the failure (no match) return RTS R4 ............ .DSABL LSB .ENDC ;NE UNI$64 .PSECT RMNUSR ;Back to USR psect .IF EQ LK4$DV .$UNAM ==: < . > ;**LOAD** Relocate address of $UNAM2 table .WORD < $UNAM2 - $RMON > ;For KMOVLY (TEMP?) .$PNAM ==: < . > ;**LOAD** Relocate address of $PNAME table .WORD < $PNAME - $RMON > ;For KMOVLY (TEMP?) .ENDC ;EQ LK4$DV .SBTTL CSI - Command String Interpreter ;+ ; The CSI does the following: ; ; 1 - Tracking of indirect files ; 2 - Tracking of DCL generated command strings ; 3 - Optionally returning the user a copy of the original command ; string for .CSIGEN and .CSISPC ; 4 - "Get Line" EMT to get a data line from console terminal or ; from an indirect file ; 5 - "Get Line ,,term" EMT to get a data line from console terminal ; unconditionally (never from indirect command file) ; ; Some of these are implemented by encoding flags in the normal .CSIGEN ; and .CSISPC arguments to indicate these extra functions and to note ; the presence of an extra argument on the stack. ; ; The EMT arguments look like: ; ; CSIGEN CSISPC .GTLIN ; (SP) .cstring or 0 .cstring or 0 0 ; 2(SP) .defext .defext 0 or prompt str address ; 4(SP) dvspc(+1 if 6(SP)) .outspc(+1 if 6(SP)) 1(3 if .GtLin *,*,TERM) ; 6(SP) buff addr(optional) buff addr(optional) user's buffer address ; ; The low order bit set in 4(SP) indicates a buffer address exists for the ; user to get a copy of the original command string. Get Line is a special ; case of CSISPC where .outspc (MINUS THE FLAG BITs) is zero. ; ; The standard arguments are popped off the stack right away. The new ; optional buffer address is popped off the stack and saved in ORGSPT. ;- ;+ ; WARNING*******WARNING*******WARNING ; ; This code is essentially duplicated in RMON.MAC for the FB/XM ; versions. If you change it here, change it there too. ;- .ENABL LSB CSI: .IF EQ MMG$T MOV (PC)+,R2 ;Setup pointer to stack save area .STKSV:: .WORD ;Pointer to save area 10$: MOV (SP)+,-(R2) ;Save the stack stuff (backwards) CMP R2,.HANSP ;Any more? BHI 10$ ;Yes. Note that R2 -> CSI buffer now! ASR @R2 ;Did he ask for copy of original string? BCS 20$ ;Yes, buffer address is on stack CLR -(SP) ;No, fix stack depth and flag no pointer 20$: MOV (SP)+,(PC)+ ;Save pointer to user's buffer or a 0 ORGSPT: .WORD 0 ;Pointer to user buffer for returned string ASL @R2 ;Restore the argument without flag bit .ENDC ;EQ MMG$T MOV SP,STKLVL ;Save user SP for restart .BR 30$ ............ 30$: .IF NE MMG$T MOV @SP,REG0 ;Copy R0 contents GET SP,R0 ;Get user Stack Pointer to R0 .ADDR #,R2 ;R2 -> argument save area GET (R0)+,-(R2) ;Get GET (R0)+,-(R2) ; three GET (R0)+,-(R2) ; arguments CLR ORGSPTR ;Clear pointer to user's line buffer ASR @R2 ;Did he want copy of command string? BCC 40$ ;No GET (R0)+,(PC)+ ;Yes, addr. for copy is on stack. Save it. ORGSPT: .WORD 0 ;Pointer to user buffer for returned string 40$: ASL @R2 ;Shift back argument without flag bit PUT R0,SP ;Restore updated stack pointer to user SP .IF EQ SB MOV R0,UMODSP ;Save for possible restart .IFF ;EQ SB MOV R0,(PC)+ ;Save for possible restart UMODSP: .WORD 0 ; User stack pointer .ENDC ;EQ SB MOV R0,JOBSTK ; and for pushing switches .ENDC ;NE MMG$T .BR RESTRT ............ .DSABL LSB .ENABL LSB RESTRT: MOV R4,EMTMOD ;Save mode flag. Special mode? BNE 20$ ;Yes, don't close channels in special mode MOV (PC)+,R5 ;Purge channels 10-0 .BYTE <10>,<.PURGE> 10$: MOV R5,R0 ;Issue PURGE EMT ...PUR DECB R5 ;Channel 0? BPL 10$ ;Do 'em all 20$: .IF NE SB .STATWD ==: < . + 2 > ;**LOAD** Relocate address of DCL/@File state word MOV #,R5 ;R5 -> DCL/@File state word .ENDC ;NE SB BIT #,@#$JSW ;Non-terminating request? BNE 30$ ;Yes .IF EQ SB .STATWD ==: < . + 2 > ;**LOAD** Relocate address of DCL/@File state word TSTB @#STATWD-$RMON ;No, did we get a CTRL/C earlier? .IFF ;EQ SB TSTB @R5 ;No, did we get a CTRL/C earlier? .ENDC ;EQ SB BPL 30$ CALLR ABORT2 ;Yes, abort user now ............ 30$: .IF EQ SB MOV R2,R5 ;No, copy buffer pointer for later .ENDC ;EQ SB CLR INFLAG ;Clear input flag for string input MOV STRING,R3 ;Get string address .IF EQ MMG$T BNE 170$ ;Don't print * if from memory .IFF ;EQ MMG$T MOV R3,R0 ;Get 'cstring' virtual address .IF NE SB BEQ 40$ ;0 -> go check DCL/@file or terminal input MOV R2,R5 ;Copy buffer pointer for later .IFF ;NE SB BEQ 60$ ;0 -> go check DCL/@file or terminal input .ENDC ;NE SB CALL MAPFIL ;Map to user string MOV R5,R2 ;Restore R2 (MAPFIL destroys R2) MOV R0,R3 ;Set up pointer to user in-core string BR 170$ ;Proceed ............ .ENDC ;EQ MMG$T .IF NE SB 40$: MOV PC,R0 ;Terminal input. Point R0 at CMP (R0)+,(PC)+ ; default prompt string (asterisk) .ASCII "*"<200> ;Prompt, one word ("*") CLR R1 ;No $JSW TTLC$ bit for CSI EMTs (used later) .IF NE MMG$T CLR (PC)+ ;Default prompt is from Kernel space UKFLG: .WORD 0 ; Flag 0=Kernel, not 0=User mode prompt print .ENDC ;NE MMG$T CMP @R2,#<2> ;Is this a .GTLIN? BHI 60$ ;No, a CSI* MOV DEFEXT,R1 ;Yes, get user's prompt string BNE 50$ ;If present, use user's prompt CMPB (R0)+,(PC)+ ;No user prompt, use null prompt ;*** SKIP NEXT INSTRUCTION *** 50$: MOV R1,R0 ;Set to use user's prompt string .IF NE MMG$T MOV R1,UKFLG ;Flag User/Kernel mode prompt print .ENDC ;NE MMG$T MOV @#$JSW,R1 ;Get contents of current $JSW BIC #^c,R1 ;Isolate lower case bit (for later) TST @R2 ;Is this a .GTLIN *,*,TERM? (Note, R3=0!!) BNE 130$ ;Yes, then get input using .TTYIN .ENDC ;NE SB 60$: .IF EQ SB CMP @R2,#<2> ;Is this a .GTLIN *,*,TERM? ; (Note, R3=0!!) BEQ 130$ ;Yes, then get input using .TTYIN TST @.JOBNUM ;Are we the background job? BNE 80$ ;No, don't do @File/DCL input BIT #,@.STATWD ;Are we to revert to TTY? (Note, R3=0!!) .IFF ;EQ SB BIT #,@R5 ;Are we to revert to TTY? (Note, R3=0!!) .ENDC ;EQ SB BNE 130$ ;Yes, so do it .BR 70$ ............ 70$: .INBFPT ==: < . + 2 > ;**LOAD** Relocate address of DCL/@File buffer pointer MOV @#INBFPT-$RMON,R3 ;Is input from DCL or indirect file? BEQ 80$ ;No, buffer pointer=0 => TTY input MOV .INBFPT,-(SP) ;Save address of pointer for later CMPB @R3,# ;Are we at end of data indicator? (-1) BNE 80$ ;No, leave pointer on stack for later ;+ ;**** If DCL/@File input & pointing to EOD flag, revert to TTY input! **** ;- BIC @(SP)+,R3 ;Yes, pop stack, clear R3. TTY input, ; so we don't need pointer .IF EQ SB BIC #,@.STATWD ;Set not DCL/@File input .IFF ;EQ SB BIC #,@R5 ;Set not DCL/@File input .ENDC ;EQ SB 80$: CLR CSIBUF-2 ;Reset start of buffer MOV R3,INFLAG ;0 => TTY input, <>0 => DCL/@File input .IF NE SB BEQ 130$ ;For TTY input, go prompt user ;+ ; DCL/@File input ;- BIT #,@#$JSW ;Does user want special GTLIN/CSI? BEQ 110$ ;No MOVB @R3,-(SP) ;Yes, get next DCL/@File character BIC #,@SP ;Clear out high bit CMPB (SP)+,# ;Is it a CTRL/C? BNE 110$ ;No TSTB (R3)+ ;Yes, is it from DCL or @File? BPL 90$ ;It's from DCL BIS #,@R5 ;@File, set flag to revert to TTY input 90$: BIS #,@R5 ;Flag we saw ^C during special GTLIN/CSI 100$: TSTB (R3)+ ;Scan to end of line in buffer BNE 100$ ;We ignore this ^C to get to next line MOV R3,@(SP)+ ;Update DCL/@File buffer pointer BR RESTRT ;Retry w/STATWD flags set. This causes ... ............ ; ... us to get next line either from ... ; ... DCL/@File buffer or from console 110$: CMPB #,@R3 ;End of DCL command from IND? BEQ 120$ ;Branch if yes TSTB @R3 ;DCL/@File input. Are we to echo line? BPL 170$ ;No, don't print prompt 120$: BIT #,@R5 ;Maybe, is suppress echo bit set? BNE 170$ ;Yes, don't print it BR 140$ ;Skip terminal mods ............ .ENDC ;NE SB 130$: .IF NE SB .I.TERM ==: < . + 4 > ;**LOAD** Relocate address of BKGND I.TERM word BIC #,@#I.TERM+BKGND-$RMON ;Don't get string in specl mode BIS R1,@.I.TERM ;If GTLIN: $JSW TTLC$ bit to terminal stat. wd 140$: .IF NE BATC$H .BA.NUM ==: < . + 2 > ;**LOAD** Relocate address of BA slot in $ENTRY table MOV @#BA.NUM+$ENTRY-$RMON,R1 ;R1 -> BA.SYS entry in $ENTRY table BEQ 150$ ;BATCH is not in memory TST BATSW$(R1) ;Is BATCH running? BNE 170$ ;Yes, skip prompt .ENDC ;NE BATC$H ;+ ; NOTE: the .PRINT must be followed by MOV R5,R5 to indicate to the SL.SYS to ; that the .PRINT is printing a prompt. To cause SL.SYS to not print the ; prompt for CSISPC/GEN/ GTLIN change the MOV R5,R5 to MOV R4,R4. ;- 150$: .IF NE MMG$T TST UKFLG ;Prompt from Kernel or User space? BEQ 160$ ;If EQ, Kernel space, just do the .PRINT MOV R2,-(SP) ;User, save regs. .IF NE MTT$Y MOV R3,-(SP) ;(MTT$Y PRINTR zaps R3) .ENDC ;NE MTT$Y MOV @.CNTXT,R5 ;R5 -> current context (as w/EMT16 dispatch) .PRINTR ==: < . + 2 > ;**LOAD** Relocate address: subr. equivalent of .PRINT CALL @#PRINTR-$RMON ;Print prompt from User space .IF NE MTT$Y MOV (SP)+,R3 ;Restore reg. .ENDC ;NE MTT$Y MOV (SP)+,R2 ;Restore reg. BR 170$ ;Proceed ............ 160$: .ENDC ;NE MMG$T .PRINT ;Prompt user ..ECSI::MOV R5,R5 ;Indicate this is CSI for SL .ENDC ;NE SB 170$: .IF NE SB MOV R2,R5 ;Copy buffer pointer .ENDC ;NE SB MOV #,R1 ;Setup counter CLR R4 ;Clear output files switch .BR 180$ ............ 180$: .IF EQ MMG$T TST R3 ;Where does input come from? .IFF ;EQ MMG$T TST STRING ;Where does input come from? BNE 190$ ;From in-memory string TST INFLAG ;Not string, is it from DCL/@File? .ENDC ;EQ MMG$T BEQ 240$ ;Input is from the teletype 190$: MOVB (R3)+,R0 ;Get character from string or DCL/@File BIC #,R0 ;Only use seven bits BEQ 250$ ;Terminate on zero character 200$: CMP @R5,#<2> ;Is it a .GTLINE EMT? BLOS 220$ ;Yes, don't syntax check it CMP #<'=>,R0 ;Check for equals BEQ 210$ ;Yes CMP #<'<>,R0 ;< same as = BNE 220$ ;No INC R0 ;Replace < with = 210$: COM R4 ;Was there a previous "=" sign? BNE 220$ ;First time is ok CLR R1 ;Set to give error later 220$: DEC R1 ;Count down characters BLE 230$ ;Ignore it if no room MOVB R0,-(R2) ;Put character into buffer (backwards) 230$: CMP #,R0 ;Is it a CTRL/C? BEQ 250$ ;Yes, terminate the line BR 180$ ;Go get next character ............ 240$: .TTINR ;Get character from sys TTY handler MOV R5,R5 ;*C* Indicate this is from .CSI* BCS 240$ ;Make it back into a .TTYIN CMP #,R0 ;Is it a CARRIAGE RETURN? BEQ 240$ ;Yes, ignore it CMP #,R0 ;Is it LF? BNE 200$ ;No, proceed 250$: MOV INFLAG,R0 ;Input from DCL/@File? (R0<>0 for exit) BEQ 270$ ;No, go on MOV R3,@(SP)+ ;Update the line buffer pointer MOVB @R0,R3 ;Are we to print this line? BPL 260$ ;No, sign bit off, it's a DCL line BIT #,@.STATWD ;Yes, is TT SET QUIET? BNE 260$ ;Yes, don't print BICB #,@R0 ;No, clear high bit for .PRINT .PRINT ;Do it 260$: CMPB CSIBUF-1,# ;Was line a CTRL/C? BNE 270$ ;No ABORT2: BIS SP,R0 ;Yes, (Abort point) R0=non zero for soft exit BIS #,@.STATWD ;Yes, set ^C detected for F/B .EXIT ;Terminate running program ............ PRERR: CSIERR ,ER.PRE ;Output file was protected (error 2) ............ 270$: TST R1 ;Was the line too long? BLE SYNBLE ;Yes, give a syntax error .BR CSI2 ............ .DSABL LSB .SBTTL CSI - Get File Descriptors And Open Files .ENABL LSB CSI2: CLRB -(R2) ;Replace CR w/ 0 byte (R5 -> CSIBUF = HANSPC) MOV ORGSPT,R0 ;Does he want copy of string? BEQ 20$ ;No MOV R5,R3 ;Yes, point to CSIBUF .IF NE MMG$T CALL MAPFIL ;Map to user's line buffer .ENDC ;NE MMG$T 10$: MOVB -(R3),(R0)+ ;Copy string to user buffer BNE 10$ ;Loop 20$: MOV @R5,R2 ;If special mode, get address of output area CMP R2,#<2> ;Is output area present BHI 40$ ;Branch if output area is present JRETRN: CALLR RETURN ;No output area => .GTLINE, so leave now ............ SPECAL: CALL GETFD ;Get file descriptor TST R4 ;Input or output? BEQ SWITLK ;Input, get switches TST @R0 ;Null output file? BEQ 30$ ;Yes CALL OUSTF1 ;Handle some output file checks 30$: TST (R2)+ ;Bump pointer .IF EQ MMG$T SWITLK: BR SWITCH ;Go look for switches ............ .IFF ;EQ MMG$T SWITLK: JMP SWITCH ;Go look for switches ............ .ENDC ;EQ MMG$T 40$: MOV R2,REG0 ;If general, get handler space address .IF NE MMG$T MOV R2,(PC)+ ;Save handler space addr. value for XM monitor VHNSPC: .WORD 0 ;(HANSPC or 39 word block address in XM) .ENDC ;NE MMG$T .BR 50$ ............ 50$: TST EMTMOD ;Is it special mode? BEQ 70$ ;No, don't clear output area .IF NE MMG$T MOV R2,R0 ;Copy virtual address of user output area CALL MAPFIL ;Map to user output area MOV R0,R2 ;Get physical pointer to mapped output area MOV R0,VHNSPC ;Fix VHNSPC for input processing .ENDC ;NE MMG$T MOV #,R1 ;Count of words to clear MOV R2,R3 ;Copy pointer 60$: CLR (R3)+ ;Clear a word SOB R1,60$ ;Loop until done 70$: CLR R3 ;Initialize file counter CLR SWTCNT ;Initialize switch counter .IF NE MMG$T .ADDR #>,R0 ;R0 -> default extension block MOV DEFEXT,R1 ;Get address of default extensions ADD #<4*2>,R1 ;R1 -> past end of user defaults MOV #<4>,-(SP) ;4 default extensions to move 80$: GET -(R1),-(R0) ;Copy an extension to USR DEC @SP ;More to move? BNE 80$ ;Yes, loop TST (SP)+ ;Purge count MOV R0,(PC)+ ;Save for input pass VDFEXT: .WORD 0 ;(Address of temp. DEFEXT blk for xm) .ENDC ;NE MMG$T TST R4 ;Input list only? BNE GETDE ;No, start with output files STRTIN: MOV #<3>,R3 ;Begin input list by setting file number to 3 .IF EQ MMG$T MOV HANSPC,R2 ;Get user output area address .IFF ;EQ MMG$T MOV VHNSPC,R2 ;Get user output area address .ENDC ;EQ MMG$T ADD #,R2 ;Point to start of input space (special mode) CLR R4 ;Set switch to input GETDE: .IF EQ MMG$T MOV DEFEXT,R1 ;Get address of default extensions .IFF ;EQ MMG$T MOV VDFEXT,R1 ;Get address of default extensions .ENDC ;EQ MMG$T MOV #<^rDK >,(PC)+ ;Start by using default device "DK" DEV1:: .RAD50 \DK \ ;"Sticky" device name NXTFIL: CMP #<9.>,R3 ;File number still valid? SYNBLE: BLE SYNERR ;Too many files NXT1: TST R4 ;Output or input files? BEQ 90$ ;Input TST (R1)+ ;Output files, go to next extension 90$: TST (PC)+ ;General or special mode? EMTMOD:: .WORD 0 BNE SPECAL ;Special, no FETCH, ENTER, or LOOKUP MOV (PC)+,R2 ;Setup pointer to file descriptor .FILDE:: .WORD ;Pointer to area for file desc CALL GETFD ;Get the file descriptor TST @R0 ;Was it a null file? BEQ SWITCH ;Yes MOV R0,-(SP) ;Save R0 MOV REG0,-(SP) ;Handler space address EMT ...FET ;FETCH the handler BCS HANERR ;Error on fetch MOV R0,REG0 ;New handler space address MOV R0,HANSPC ;Can't go lower now! MOV (SP)+,R0 ;Pointer to f.d. for LOOKUP or ENTER TST R4 ;Input or output BEQ INFILE ;Input, no output checks CALL OUSTUF ;Go handle some output file checks MOV @R2,-(SP) ;Push size onto stack MOV #,-(SP) ;Build the V1 style ENTER EMT ADD R3,@SP ;Bad technique MOV (SP)+,@PC ; BADDDDD HALT ;Execute EMT here to ENTER the file BCC SWITCH ;Go look for switches CMPB #,@#$ERRBY ;Was it a 1 (=> Device Full)? BNE PRERR ;No, protection violation CSIERR ,ER.FUC ;Error 3 ............ INFILE: MOV #,-(SP) ;Build the V1 style LOOKUP EMT ADD R3,@SP ;Put in the file number MOV (SP)+,@PC ;Bad technique HALT ;LOOKUP the file BCC SWITCH ;Found it. Go do switches CSIERR ,ER.FNC ;Error 4 ............ .DSABL LSB .SBTTL CSI - Get Switches ;+ ; This is here so everybody can reach SYNERR ;- NOSWIT: INC R3 ;Increment file number CMPB @R5,#<',> ;Look for a comma BEQ NXTFIL ;Yes, get next file CMPB @R5,#<'=> ;Look for equal sign BEQ STRTIN ;Start input list MOV (PC)+,-(SP) ;Assuming we're done, push the switch count SWTCNT: .WORD 0 .IF NE MMG$T CALL PUSHSP ;Put it on user stack .ENDC ;NE MMG$T TSTB @R5 ;Null byte here to indicate end of line? BEQ RETURN ;Yes, go home SYNERR: CSIERR ,ER.CMD ;Error 0 ............ .ENABL LSB .IF EQ MMG$T SWITCH: CMPB #<'/>,@R5 ;Check for / start of switch BNE NOSWIT ;No switch if no / ;+ ;>>>consider using RMON(FB) UCASE routine ; MOV R3,R0 ; SWAB R0 ; BISB -(R5),R0 ; BEQ SYNERR ; INC SWTCNT ; CALL @#UCASE ;$REL .-2 @#UCASE USR2RMON ; MOV R0,-(SP) ; CMPB #,-(R5) ;IS THERE A VALUE (:XXXXX)? ;save 5 ;- MOV R3,-(SP) ;Set up file number SWAB @SP ;File number in high byte MOVB -(R5),@SP ;Switch character to low byte BEQ SYNERR ;Error if premature end of line INC SWTCNT ;Keep track of number of switches CMPB #<'a>,@SP ;Less than lowercase a? BHI 10$ ;Branch if yes - no conversion CMPB #<'z>,@SP ;Greater than lowercase z? BLO 10$ ;Branch if yes - no conversion BICB #,@SP ;Convert lowercase alpha to uppercase 10$: CMPB #<':>,-(R5) ;Is there a value (:xxxxx)? BNE SWITCH ;No MOV @SP,-(SP) ;Set up to put value in BPL 20$ ;This is the first value in list INC SWTCNT ;Account for :valu1:valu2 as 2 switches MOV @SP,-(SP) ; and duplicate the switch word 20$: BIS #<100000>,@SP ;Flag switch has value MOV R2,-(SP) ;Preserve R2 across GETNM1 call MOV R5,R0 ;Save scan pointer in case wrong guess CALL DECNUM ;Try converting as decimal first CMPB #<'.>,@R5 ;Is terminator a period? BEQ 50$ ;Yes, treat value as decimal CMPB -(R0),(R5)+ ;Any characters converted as a number? BNE 30$ ;Yes, get number as octal MOV SP,R2 ;Set up to convert RAD50 over decnums 0 .IF EQ GT$NM .GTNM1 ==: < . + 2 > ;**LOAD** Relocate address of GTNM1 routine CALL @#GTNM1-$RMON ;Get extension (1 word of RAD50) .IFF ;EQ GT$NM CALL GETNM1 ;Get extension (1 word of RAD50) .ENDC ;EQ GT$NM BR 40$ ;Go adjust scan pointer for colon check ............ 30$: MOV R0,R5 ;Reset the scan pointer CMPB (SP)+,(R5)+ ;Throw away decimal attempt and fix R5 CALL OCTNUM ;Get the value as octal 40$: INC R5 ;Adjust R5 so ':' check at top works 50$: MOV (SP)+,4(SP) ;Put value where value should go MOV (SP)+,R2 ;Restore R2 BR 10$ ;Look for another switch ............ .IFF ;EQ MMG$T 10$: TST R0 ;No colon. Is there no value at all? BMI SWITCH ;An earlier value MOV R0,-(SP) ;No value. Just stuff it CALL PUSHSP ;Push onto user stack INC SWTCNT ;Increment count of switches SWITCH: CMPB @R5,#<'/> ;Check for / start of switch BNE NOSWIT ;No switch if no / MOVB -(R5),R0 ;Get switch character and save it BEQ SYNERR ;Error if CR ;>>> To be removed **CASE** **TEMP** ;>>>consider using UCASE in RMON ; CALL @#UCASE ;$REL .-2 UCASE USR2RMON ;save 6 CMPB #<'a>,R0 ;Less than lowercase a? BHI 20$ ;Branch if yes - no conversion CMPB #<'z>,R0 ;Greater than lowercase z? BLO 20$ ;Branch if yes - no conversion BICB #,R0 ;Convert lowercase alpha to uppercase 20$: SWAB R0 ;Swap switch character to odd byte ADD R3,R0 ;Add in file number SWAB R0 ;Swap it back DEC R5 ;Move to value delimiter 30$: CMPB @R5,#<':> ;Is there a value (:xxxxx) BNE 10$ ;No, there ain't CMPB #<<'A>-1>,-1(R5) ;Check for octal/decimal or RAD50 BLO 60$ ;Alpha => RAD50 MOV R5,-(SP) ;Decimal or octal, save pointer CALL DECNUM ;Try converting as decimal first DEC R5 ;Advance pointer in case of dec. point CMPB 1(R5),#<'.> ;Was terminator a decimal point? BEQ 50$ ;Yes, number is ok TST (SP)+ ;No, throw away value MOV @SP,R5 ;Restore pointer to beginning of number 40$: CALL OCTNUM ;It's octal, convert it that way 50$: MOV (SP)+,@SP ;Throw away saved pointer on stack CALL PUSHSP ;Put it on user stack BR 70$ ............ .ENDC ;EQ MMG$T HANERR: CSIERR ,ER.DNC ;Error 1 ............ .IF NE MMG$T 60$: MOV R2,-(SP) ;Save R2 MOV SP,R2 ;RAD50 pack returns in @R2 MOV @SP,-(SP) ;Save R2 for real, now ... MOV R0,-(SP) ; ... and R0 .IF EQ GT$NM .GTNM1 ==: < . + 2 > ;**LOAD** Relocate address of GTNM1 routine CALL @#GTNM1-$RMON ;Pack it up .IFF ;EQ GT$NM CALL GETNM1 ;Pack it up .ENDC ;EQ GT$NM MOV (SP)+,R0 ;Restore R0 MOV (SP)+,R2 CALL PUSHSP ;Put it on user stack 70$: BIS #<100000>,R0 ;Set value flag MOV R0,-(SP) ;Put stuff onto stack CALL PUSHSP ;Put it on user stack INC SWTCNT ;Increment count of switches BR 30$ ;Look for another switch ............ .ENDC ;NE MMG$T .DSABL LSB SYNELK: BR SYNERR ;LINK TO SYNERR ............ .SBTTL CSI - Return And Error Processing .ENABL LSB MSG: MOV (PC)+,SP ;Restore stack (eliminate junk) STKLVL: .WORD 0 .IF NE MMG$T MOV UMODSP,JOBSTK ;Restore user stack .ENDC ;NE MMG$T TSTB @#$ERRBY ;Do we already have a serious error? BMI CSIER1 ;Branch if yes MOVB (R0)+,@#$ERRBY TST STRING ;Where did input come from? BNE CSIER1 ;From memory string, don't restart JSR R0,10$ ;Save text message R0 and point to .ASCII "?CSI-F-"<200> ; CSI prefix text .EVEN ............ 10$: .PRINT ;Output it MOV (SP)+,R0 ;Point to the error text .PRINT ; and print the error message TST (PC)+ ;Was input from DCL/@File? INFLAG: .WORD 0 BEQ CSRTRY ;No, real TTY input BIS #,@.STATWD ;Yes, set abort bit for KMON .EXIT ;Exit ............ ;+ ;****************************** NOTE ***************************************** ; To make CSI errors non aborting when from DCL or @files, the code above from ; BEQ CSRTRY to BIS #,@.STATWD ; can be patched to: ; ; BISB #,@#$USRRB ;Set fatal error ; BR CSRTRY ;Retry like TTY ;- CSIER1: .IF EQ MMG$T BIS #,SAVSTK ;Set Carry in PS .IFF ;EQ MMG$T BIS #,OLDPS(SP) ;Set Carry in PS .ENDC ;EQ MMG$T RETURN: .IF EQ MMG$T MOV #<8.>,R2 ;Count for stack restoration MOV (PC)+,R1 ;Setup pointer .SVSTK:: .WORD ;Pointer to end of save area 20$: MOV (R1)+,-(SP) ;Restore stack element SOB R2,20$ ;More? ;CLR R2 ;No arguments to pop .IFF ;EQ MMG$T CLR R2 ;No arguments to pop MOV REG0,@SP ;Update R0 PUT JOBSTK,SP ;Update user SP .ENDC ;EQ MMG$T .IF EQ SB MOV @.CNTXT,-(SP) ;Turn off bit that suppresses address check BIC #,@(SP)+ ; in the job's JSTAT .IFF ;EQ SB .I.STAT ==: < . + 4 > ;**LOAD** Relocate address of BKGND I.STAT word. BIC #,@#I.STAT+BKGND-$RMON ;Turn off bit that suppresses ; address check in the job's JSTAT .ENDC ;EQ SB CALLR @.MONOU ;Return to resident ............ CSRTRY: MOV (PC)+,R2 ;Point R2 to user arguments .HANSP:: .WORD ;Pointer to user arguments .IF NE SB MOV EMTMOD,R4 ;Set Cond. Code for mode CALLR RESTRT ;Try again (get new line from TTY) ............ .IFF ;NE SB .IF EQ MMG$T MOV ORGSPT,-(SP) ;Did user want copy of string? BEQ 40$ ;No, get buffer address off stack INC @R2 ;Yes, set flag bit in next argument ; and leave buffer address on stack 30$: TST -(SP) ;Make room for element on stack 40$: MOV (R2)+,@SP ;Put an argument back on stack CMP R2,.STKSV ;Done all? BLO 30$ ;No, make room for next .IFF ;EQ MMG$T MOV (PC)+,R0 ;R0 -> user stack UMODSP: .WORD 0 ; TST ORGSPT ;Did user want copy of string? BEQ 40$ ;No, proceed PUT ORGSPT,-(R0) ;Yes, move buffer address to user stack INC @R2 ;Set flag bit in next argument 40$: PUT (R2)+,-(R0) ;Move arguments ... PUT (R2)+,-(R0) ; ... back to ... PUT (R2)+,-(R0) ; ... user's stack PUT R0,SP ;Then restore user SP .ENDC ;EQ MMG$T MOV EMTMOD,R4 ;Restore EMT mode ;SEZ/CLZ ;Set Condition Codes on EMT mode for CSIERR .CSIER ==: < . + 2 > ;**LOAD** Relocate address of monitor CSI error subr. CALLR @#CSIERR-$RMON ;Get rid of USR, get line, try again ............ .ENDC ;NE SB .DSABL LSB .SBTTL OUSTUF - Check File-Structured Device Not Opened for Non-File Output ;+ ; OUSTUF - Verify that a file structured device is not being opened for ; output as non-structured (syntax error), then scan the [decimal num] ; that specifies the size of the output file in blocks. ; ; R0 -> file descriptor in RAD50 ; R2 -> word to contain output file size ; R5 -> input string ; ; CALL OUSTUF ; ; R5 -> character after ] if given, else after filename ; @R2 = file size, 0 if not given ; ; OUSTF1 is an entry for XM that moves data to fix mapping problems ;- .ENABL LSB OUSTF1: .IF NE MMG$T MOV R0,-(SP) ;Save original file descriptor pointer MOV (R0)+,FILDES ;Move device name to temp area for XM MOV @R0,FILDES+F.NAME ;Save first word of filename too .ADDR #,R0 ;Point R0 to the device name ... BR 10$ ; ... and proceed ............ .ENDC ;NE MMG$T OUSTUF: MOV R0,-(SP) ;Save file descriptor pointer 10$: TST F.NAME(R0) ;Is file name given? BNE 20$ ;Yes MOV (PC)+,-(SP) ;Pointer to area for DSTATUS .DVSTS:: .WORD ;Pointer to DEVICE STATUS block EMT ...DST ;Get Device information (Vers. 2 .DSTAT) BCS HANERR ;Invalid device error TST @R0 ;Is it a directory device? BMI SYNELK ;Yes, this will destroy its directory 20$: CLR @R2 ;Assume file size is zero CMPB @R5,#<'[> ;Is it a [? BNE 30$ ;No, no size specified, all done CALL DECNUM ;Get the size in blocks CMPB @R5,#<']> ;Check for ] BNE SYNELK ;Syntax error if not present DEC R5 ;Move string past the right bracket MOV (SP)+,@R2 ;Put size where it belongs 30$: MOV (SP)+,R0 ;Restore f.d. pointer RETURN ............ .IF NE MMG$T PUSHSP: SUB #<2>,JOBSTK ;Make room on stack PUT JOBSTK,SP ;Update user's SP PUT 2(SP),@JOBSTK ;Put a value on user stack MOV (SP)+,@SP ;Purge value from our stack RETURN ............ .ENDC ;NE MMG$T .SBTTL GETFD - Get File Descriptor Subroutine ;+ ; GETFD - Get a file descriptor from the input string and ; Store 4 words of radix 50 information of the form: ; .RAD50 "DEV" ; .RAD50 "FILNAM" ; .RAD50 "EXT" ; ; R1 -> default extension ; R2 -> output area (4 words) ; R5 -> input string ; ; CALL GETFD ; ; R0 -> original output area (R2 input) ; R2 -> word after the extension word ; R5 -> character that delimited the name ;- GETFD:: .IF EQ GET$FD .GTFD1 ==: < . + 2 > ;**LOAD** Relocate address of GETFD1 routine CALLR @#GETFD1-$RMON ............ .PSECT USRRMN GETFD1: MOV R4,-(SP) ;Save R4 (Used as USRBUF address) MOV USRLOC,R4 ;-> USRST .ENDC ;EQ GET$FD MOV R2,-(SP) ;Save R2 (later restored into R0) CLR (R2)+ ;Clear device name field .IF EQ GET$FD CALL GETNAM-USRST(R4) ;Look for name .IFF ;EQ GET$FD CALL GETNAM ;Look for name .ENDC ;EQ GET$FD BEQ 50$ ;Null file spec CMPB @R5,#<':> ;Device name followed by colon BNE 40$ ;Not colon, so not a device name TST 2(R2) ;Test for only 3 characters in name BNE 40$ ;Too big for device name .IF EQ GET$FD MOV @R2,DEV1-USRST(R4) ;Save device name as new default CALL GETNAM-USRST(R4) ;Now look for file name 40$: MOV DEV1-USRST(R4),-(R2) ;Put device name into block .IFF ;EQ GET$FD MOV @R2,DEV1 ;Save device name as new default CALL GETNAM ;Now look for file name 40$: MOV DEV1,-(R2) ;Put device name into block .ENDC ;EQ GET$FD ADD #,R2 ;Point to extension field MOV @R1,@R2 ;Assume default CMPB @R5,#<'.> ;If period, extension follows BNE 60$ ;No extension .IF EQ GET$FD .IF EQ GT$NM CALL GTNM1 ;Get Extension .IFF ;EQ GT$NM CALL GETNM1-USRST(R4) ;Get extension .ENDC ;EQ GT$NM .IFF ;EQ GET$FD .IF EQ GT$NM CALL @.GTNM1 ;Get Extension .IFF ;EQ GT$NM CALL GETNM1 ;Get extension .ENDC ;EQ GT$NM .ENDC ;EQ GET$FD TST -(R2) ;Exit adjusting R2 by 4 50$: CMP (R2)+,(R2)+ ;Exit point for adjusting R2 by 6 60$: TST (R2)+ ;Exit for adjusting R2 by 2 .IF EQ GET$FD MOV (SP)+,R0 ;Restore into R0 ... MOV (SP)+,R4 ; ... and restore R4 RETURN ............ .PSECT RMNUSR .IFF ;EQ GET$FD BR 30$ ;Go restore R0 and exit ............ .ENDC ;EQ GET$FD .DSABL LSB .SBTTL GETNAM - Get Name Subroutine ;+ ; GETNAM - Convert a sequence of 0 to 6 alphanumerics to RAD50. ; A 2-word result is stored at the place pointed to by R2. ; The result is padded with 0's (RAD50 blank) if < 6 characters. ; ; R2 -> 2-word result area ; R5 -> source string (backwards) ; ; CALL GETNAM ; ; R0 = undefined ; R5 -> character that delimited the name ; Condition Code 'Zero' if name is all zeros ;- .ENABL LSB .IF EQ GT$NM GETNAM::MOV EMTMOD,@.EMTMO ;Store EMTMOD flag in RMON .GETNM ==: < . + 2 > ;**LOAD** Relocate address of GETNM routine in RMON CALLR @#GETNM-$RMON ;Jump to real GETNAM routine ............ .EMTMO ==: < . > ;**LOAD** Relocate address of EMTMO1 .WORD ;Pointer to EMTMO1 in RMON .PSECT USRRMN GETNM:: CALL GTNM1 ;Get the first 3 assembled .IFF ;EQ GT$NM GETNAM::CALL GETNM1 ;Get the first 3 assembled .ENDC ;EQ GT$NM CMP (R2)+,(R2)+ ;GETNM1 returns R2-2 INC R5 ;Adjust R5 to not skip a character ;Get next 3 by falling into ;GETNM1 which will return with ;R2 correct and Z-bit flag .IF EQ GT$NM GTNM1:: .IFF ;EQ GT$NM GETNM1:: .ENDC ;EQ GT$NM DEC R5 ;First character is -(R5) MOV #<3>,R0 ;Set character count CLR @R2 ;Init output area 10$: DEC R0 ;Adjust counter for later JSR R0,40$ ;Save R0 and for pic address of table 20$: .ASCII "%%" ;Range for % .ASCII "**" ;Range for * .ASCII "09" ;Range for 0-9 .ASCII "AZ" ;Range for A-Z .ASCII "az" ;Range for a-z, lower case 30$: .WORD -11 ;RAD50 adjust amount for % .WORD -15 ;RAD50 adjust amount for * .WORD -22 ;RAD50 adjust amount for 0-9 .WORD -100 ;RAD50 adjust amount for A-Z .WORD -140 ;RAD50 adjust amount for a-z, l.c. ............ 40$: CLR -(SP) ;Init location for next RAD50 character 50$: CMPB (R0)+,@R5 ;Is character in range? BHI 70$ ;No, or hit end of table, fill in with 0's CMPB (R0)+,@R5 ;Check other end of range BLT 50$ ;Try next set CMPB -(R0),-(R0) ;Character identified, see if special BNE 60$ ;No, it's valid .IF EQ GT$NM TST (PC)+ ;Make sure we are in special mode! EMTMO1:: .WORD <.-.> ;**????** .IFF ;EQ GT$NM TST EMTMOD ;Make sure we are in special mode! .ENDC ;EQ GT$NM BEQ 70$ ;No, character acts like delimeter 60$: MOVB @R5,@SP ;Get the character ADD 30$-20$(R0),@SP ;Adjust the character to RAD50 DEC R5 ;Point to next one for later 70$: ASL @R2 ;Multiply ASL @R2 ; total to now ASL @R2 ; by 50 ADD @R2,@SP ;To make room ASL @R2 ; for the ASL @R2 ; new character ADD (SP)+,@R2 ;Add new character to total as low order MOV (SP)+,R0 ;Get loop count word BNE 10$ ;Do 3 characters TST -(R2) ;For GETNAM to adjust R2 and set Z RETURN ;Return ............ .DSABL LSB .IF EQ GT$NM .PSECT RMNUSR .ENDC ;EQ GT$NM .SBTTL xxxNUM - Octal/Decimal Conversion Routine ;+ ; NUM - Get octal/decimal number from input string, returns it on the stack ; ; R5 -> input string (backwards) ; ; CALL OCTNUM/DECNUM/CVTNUM ; (if called at CVTNUM, Carry 0 => octal, 1 => decimal ; ; R5 -> delimiter ; @SP is converted number ;- .IF EQ CVT$NU .$OCTN ==: < . + 2 > ;**LOAD** Relocate address of $OCTNUN routine in RMON OCTNUM::CALLR @#$OCTNUN-$RMON ;Go to actual code in RMON ............ .$DECN ==: < . + 2 > ;**LOAD** Relocate address of $DECNUN routine in RMON DECNUM::CALLR @#$DECNUN-$RMON ;Go to actual code in RMON ............ .$CVTN ==: < . + 2 > ;**LOAD** Relocate address of $CVTNUN routine in RMON CVTNUM::CALLR @#$CVTNUN-$RMON ;Go to actual code in RMON ............ .PSECT USRRMN .ENDC ;EQ CVT$NU .ENABL LSB .IF EQ CVT$NU $OCTNUM::TST (PC)+ ;Clear Carry, skip the SEC $DECNUM::SEC ;Indicate decimal $CVTNUM::MOV @SP,-(SP) ;Save return & leave room for value .IFF ;EQ CVT$NU OCTNUM::TST (PC)+ ;Clear Carry, skip the SEC DECNUM::SEC ;Indicate decimal CVTNUM::MOV @SP,-(SP) ;Save return & leave room for value .ENDC ;EQ CVT$NU MOV R3,-(SP) ;Save registers MOV R4,-(SP) MOV #<100004>,-(SP) ;Set the radix and set ASL to give Carry ADC @SP CMPB -(R5),#<'-> ;Is it a negative number? BNE 10$ ;No, go bump R5 ADD #<140000>,@SP ;Yes, don't bump R5 but leave @SP<0 10$: ASL @SP ;Double radix ADC R5 ;Fix R5 if no '-' sign CLR R4 ;Clear accumulating register 20$: MOVB -(R5),R3 ;Get next character SUB #<'0>,R3 ;Check for a digit CMPB R3,@SP BHIS 40$ ;No,end of number ASL R4 ;Shift accumulator left CMPB @SP,#<10.> ;Is it octal or decimal? BNE 30$ ;Octal, multiply by 8 ADD R4,R3 ;Decimal, multiply by 10 30$: ASL R4 ASL R4 ADD R3,R4 ;Put in new digit BR 20$ ;Get next digit ............ 40$: TST (SP)+ ;Remove radix, check for minus sign BPL 50$ ;All done if plus NEG R4 ;Minus found, so negate result 50$: MOV R4,6(SP) ;Save the result MOV (SP)+,R4 ;Restore regs MOV (SP)+,R3 RETURN ............ .DSABL LSB .IF EQ CVT$NU .PSECT RMNUSR .ENDC ;EQ CVT$NU .SBTTL DRCALL -- Call Handler Entry Points ;+ ; DRCALL ; ; This is called by the .FETCH, .RELEASE, $LOAD and $UNLOAD ; code to check for and possibly process these actions thru ; handler routines. It is also called by the BSTRAP and by ; job abort code. The BSTRAP calls it to "load" SY:, in ; this case it must use the special bootstrap read routine, ; the address of which is passed in R0. It is also called ; by the job abort code when it is "releasing" handlers. ; ; On entry: ; ; R0 Undefined (except BSTRAP -> read routine) ; R1 Type code: ; 0 -- .FETCH ; 2 -- .RELEASE ; 4 -- $LOAD ; 6 -- $UNLOAD ; 10-- Job Abort ; 12-- BSTRAP ; 14-- Booter service routine ; 16-- Bootee service routine ; R2 Undefined ; R3 -> $ENTRY word for this handler ; R4 Undefined ; R5 Undefined (except BSTRAP -> GVEC routine) ; ; Upon call to handler: ; ; R0 -> Handler routine being called ; R1 -> GETVEC routine ; R2 $SLOT*2 ; R3 Type code as above ; R4 -> Read routine ; R5 -> $ENTRY word as above ; ; Registers need not be saved by the handler code ; ; On exit from DRCALL: ; ; R0--R5 preserved - ; Unless an error was detected by $SYS or the handler code ; If an I/O error occurred, R0 will be cleared and Carry set. ; If the handler returns with carry set, R0 will be passed ; as it was returned by the handler. ; ; NOTE: This code is PSECTed into the resident monitor (RMON). ; This is in USR.MAC so that we don't have to have a copy in ; both RMONSJ.MAC and RMONFB.MAC. ;;;>>>??? NOTE: When Common Monitor Done, This Should Go Into RMON!!!! ;- .PSECT USRRMN .ENABL LSB S.BEG=1000 DRCALL:: CK.SP=S.BEG MOV R5,-(SP) ; and 5 CK.SP ,-2,S.R5 .IF NE MMG$T CALL KPSAVE ;Map PAR1/PAR2 to low memory .ENDC ;NE MMG$T MOV R4,-(SP) ; and 4 CK.SP ,-2,S.R4 MOV R3,-(SP) CK.SP ,-2,S.R3 MOV R2,-(SP) CK.SP ,-2,S.R2 MOV R1,-(SP) CK.SP ,-2,S.R1 MOV R0,-(SP) CK.SP ,-2,S.R0 .ADDR #,R4 ;Assume not BSTRAP, point to read routine MOV GETVEC,DRGVEC ; and to RMON GETVEC CMP R1,# ;Called from BSTRAP? BNE 10$ ;No MOV R0,R4 ;Substitute bootstrap read routine MOV R5,DRGVEC ; and GVEC value 10$: MOV R3,R5 ;Save -> $ENTRY word TST R1 ;Is it from .FETCH? BNE 20$ ;Branch if not from .FETCH TST KMONIN ;Is it from KMON? BEQ 20$ ;Branch if not from KMON MOV #,R1 ;Yes, then it is a $LOAD 20$: MOV R1,R3 ;Save type code MOV @R5,R0 ;Get address of handler MOV H1.NOP-H1.LQE(R0),R0 ;Get first instruction in handler CMP #,R0 ;Might it be a "NOP" BHI 50$ ;No, nothing to do CMP #,R0 ;Is it a "NOP" BLO 50$ ;No, nothing to do ASR R1 ;Change from word index to byte index .ADDR #,R1,ADD ;Point to table entry corresponding BITB @R1,R0 ;Is the bit set for this service? BEQ 50$ ;No, nothing to do ;>>> do we need to serialize access to USR here (SET doesn't?) CLR BLKEY ;Indicate no directory in buffer MOV $DVREC-$ENTRY(R5),R0 ;Get block number DEC R0 ;Read block 0, not block 1 MOV #,R1 ;Just 1 block ;+ ; This is what's in RMONFB, which comes out to be the following ;- ;.IF EQ BF ; TST USRLOC ;is the USR in memory? ; BEQ 60$ ;no, whats to do? ;.IFF ;EQ BF ;.IF EQ MMG$T ; TST USRLOC ;is the USR in memory? ; BEQ 60$ ;no, whats to do? ;.ENDC ;EQ MMG$T ;.ENDC ;EQ BF .IF EQ MMG$T TST USRLOC ;Is the USR in memory? BEQ 60$ ;No, what's to do? .ENDC ;EQ MMG$T MOV BUFLOC,R2 ;Point to buffer CALL @R4 ;Read it BCS 60$ ;Branch if error MOV R2,R1 ;Copy buffer pointer CMP (R1)+,#<^rHAN> ;Is it a handler block 0 with extended status? BNE 50$ ;No, done ADD R3,R1 ;Point to offset CMP R3,# ;Is it JOBABORT or BSTRAP? BLO 30$ ;Branch if no .ASSUME EQ SUB #,R1 ;Yes, chg JOBABORT->RELEASE; BSTRAP->LOAD 30$: MOV @R1,R0 ;Load offset value BEQ 50$ ;Branch if no offset, done CMP R0,# ;In block 0? BLO 40$ ;Yes, just go to it ;NOTE: BLO is BCS, so carry is clear here MOV R0,-(SP) ;Save the value CK.SP ,-2 ROR R0 ;/2, high byte is now block SWAB R0 ;Block number to low byte BIC #^c<377>,R0 ;Clear junk in high byte ADD $DVREC-$ENTRY(R5),R0 ;Get block number DEC R0 ;Adjust MOV #<2*BK.WD>,R1 ;Read 2 blocks CALL @R4 ;Now MOV (SP)+,R0 ;*C* Get value back CK.SP ,+2 BCS 60$ ;Branch if error BIC #^c,R0 ;Clear block part 40$: ADD R2,R0 ;Point to entry point MOV #<$SLOT*2>,R2 ;Pass in number of slots in $PNAME .IF NE MMG$T MOV @#PS,R1 ;Save PS BIC #,@#PS ;Force KERNEL MOV R1,-(SP) ;Save old PS (now, not before CK.SP ,-2,S.PS ; ... because we may switch stack ; ... when we change modes) CK.SP S.PS BIC #,@SP ;Clear carry in saved PS .ENDC ;NE MMG$T MOV (PC)+,R1 ;Pass in GVEC or GETVEC address ... DRGVEC: .WORD <.-.> CALL @R0 ; ... and go to it .IF NE MMG$T CK.SP S.PS ADC @SP ;If carry set, also set in saved PS CK.SP S.PS,+2 MOV (SP)+,@#PS ;Restore PS .ENDC ;NE MMG$T BCC 50$ ;No error indicated CK.SP S.R0 MOV R0,@SP ;*C* Return R0 value rather than saved value BR 70$ ;*C* Restore regs ............ 50$: TST (PC)+ ;Normal return, clear carry & ; ... skip clearing saved R0 CK.SP S.R0 ;+ ; I/O error return ;- 60$: BIC @SP,@SP ;*C* Clear saved R0, preserve carry CK.SP S.R0,+2 70$: MOV (SP)+,R0 ;*C* Restore registers CK.SP S.R1,+2 MOV (SP)+,R1 ;*C* ... CK.SP S.R2,+2 MOV (SP)+,R2 ;*C* ... CK.SP S.R3,+2 MOV (SP)+,R3 ;*C* ... CK.SP S.R4,+2 MOV (SP)+,R4 ;*C* ... .IF NE MMG$T CALL KPREST ;Map PAR1/PAR2 back to what it was on entry .ENDC ;NE MMG$T BR 80$ ;*C* Go restore R5 ............ DRREAD: MOV R5,-(SP) ;Save R5 .ADDR #,R5 ;Point to IOB CK.R5=DRCNT+2 MOV R1,-(R5) ;Put in count CK.R5 DRCNT,-2 MOV R2,-(R5) ;Put in buffer address CK.R5 DRBUF,-2 CK.R5 DRIOB .IF EQ MMG$T CALL $SYS ;Read it .IFF ;EQ MMG$T MOV $USRLC,-(SP) ;Point to USR ADD #<$SYS.KM-RMNUSR>,@SP ;Now to $SYS.KM CALL @(SP)+ ;Read it using USR special read .ENDC ;EQ MMG$T CK.SP S.R5,+2 80$: MOV (SP)+,R5 ;*C* Restore R5 CK.SP S.BEG RETURN ;Done ............ .DSABL LSB DRTABL: .BYTE HNP.FE ;.FETCH entry point .BYTE HNP.RE ;.RELEASE entry point .BYTE HNP.LO ;$LOAD entry point .BYTE HNP.UN ;$UNLOAD entry point .BYTE HNP.RE ;JOBABORT (.RELEASE) entry point .BYTE HNP.LO ;BSTRAP ($LOAD) entry point .EVEN DRIOB: DRBUF: .BLKW 1 ;USR buffer location DRCNT: .BLKW 1 ;Count .WORD ..WTIO ;Wait I/O .PSECT RMNUSR .SBTTL Line Buffer And Stack Save Area FNAME: BSS 4 ;Scratch area - used by many routines .IF NE MMG$T JOBSTK: .WORD 0 ;Job stack pointer .ENDC ;NE MMG$T DEVSTS::.BLKW ;Device status information block .IIF NDF CSIBFL, CSIBFL =: 81. .BLKB CSIBFL ;CSI Line Buffer (chars go backwards) .EVEN ;+ ;*****Following Three Words Must Be Kept In Order *************** CSIBUF: ;Line Buffer HANSPC: .WORD 0 ;Handler Space Address DEFEXT: .WORD 0 ;Default Extension Block Address STRING: .WORD 0 ;Input String (0 means input from TTY) ;**************************************************************** ;- .IF NE MMG$T DEFBLK: .WORD 0, 0, 0, 0 ;Default Extension Save Area .ENDC ;NE MMG$T ;+ ;******* Following Save Area Must Not Be Moved Or Reordered ***** .IF EQ MMG$T SAVSTK: .BLKW 7 ;Stack save (PS,PC,R1,R2,R3,R4,R5,R0) .ENDC ;EQ MMG$T REG0: .WORD 0 ;Top of handler space returned here STKSAV: FILDES: .BLKW 5 ;File descriptor (General Mode ONLY) ;*************************************************************** ;- ;+ ; This routine is moved to top of the USR by KMON (KUMOVE routine) ; It is used to help move the KMON/USR downward in memory. ; It is moved over the last 13 (10) words of the USR. ; It should not overlay anything the KMON might be using at the time of move. ; It can be moved over SAVSTK, REG0, and FILDES which are not used by the KMON ; ;. = < . - 26. > ;CAUTION ON THIS SIZE !!!!!!!! ; ; .ENABL LSB ; ;MOVEDN: MOV SP,R3 ;Save SP to find it in loop ; CLR -(SP) ;Make us stop at stack top ;10$: MOV (R1)+,(R4)+ ;Copy a word ; BNE 10$ ;Loop when non-0 ; CMP R1,PC ;Are we done (past ourselves)? ; BHI 20$ ;Yes ; CMP R1,R3 ;Did we get the stack topper? ; BNE 10$ ;Keep moving ; MOV R4,SP ;Switch to new stack (& pop!) ; BR 10$ ; and continue ;20$: ADD R0,@SP ;Relocate return address ; RETURN ;Bye ; .WORD 0 ;This stops the move! ; ; .DSABL LSB ; ;.ASSUME < . - MOVEDN > LE 26. MESSAGE=<<.-MOVEDN>;SIZE OF MOVEDN CHANGED!!!> ;- .SBTTL Final Size Checks And Adjustments USRSZ ==: < . - USRBUF + BD.BLK > / BK.BYT ;Size of USR in Blocks USRSIZE ==: < USRSZ * BK.BYT > ;Size of USR in Bytes USRLEN ==: < USRSZ * BK.WD > ;Size of USR in Words $USIZ$ ==: < . - USRBUF > / 2 ;Actual Size Of USR In Words .IF EQ MMG$T .ASSUME USRSZ LE 10,MESSAGE=<$USIZ$-<10*BK.WD>>;USR too big by this many words> .ENDC ;EQ MMG$T . = < USRBUF + USRSIZE > ;+ ; . = < . + KMSIZE + USRSIZ + BK.BYT > ; ; The extra block is because we SWAP too much if the KMON ; is not on a block boundary. ;- SWAPSZ ==: 28. .END