.TITLE MAG TAPE DLU FILE READER DRIVER (RT-11 V03) .IDENT /V01/ .ENABL LC ; ; ; This is a modified version of the ROLLIN file handler. ; It was fairly easy to modify cause DLU and ROLLIN both ; work on the same principle of writing out large buffers ; of data to mag tape for disk backup. ROLLIN uses a fixed ; 4096 word buffer while DLU uses a one track buffer depending ; upon the disk being backed up. RK05's use a (12 * 256) 3072 ; word buffer and RL01's use (20 * 256) 5120 word buffers. ; DLU uses the first record of the file to store disk type information ; and a title of the disk being backed up. ROLLIN, I believe, ; is not as convienent to use as DLU because it is stand-alone ; and must use the system console. DLU, on the other hand, ; runs under RT-11 and uses its drivers. More devices can be ; added by adding the track size to the table in DLU. ; ; I am sorry to say that the program is written to require EIS ; hardware. If you write a DIV macro, you can use this on ; EAE or no-EIS hardware machines. I plan to fix the EIS ; dependence when I first need it. ; ; And finally, I have added the ability to use this handler on ; any of the attached tape drives. Just specify RO0: through ; RO7: and it will pick up the unit number. You will still have ; to tell it the file number ; ; ; Modified by Ned W. Rhodes May-80 ; ; ; SET MACROS ; ; .MCALL ..V2..,.PRINT,.TTYIN,.FORK,.DRBEG,.DRAST,.DRFIN,.DREND .MCALL .SYNCH ..V2.. ; ; ; SET ADDRESSES ; ; ROS=172520 ROC=172522 ROBRC=172524 ROCMA=172526 ROVEC=224 ; ; ; BITS 800 BPI 9-TRACK/DUMP MODE 7-TRACK,INTERUPT ENABLE,GO ; ; M=60101 ; ; ; DEFINE CONDITIONAL ASSEMBLY PARAMETERS ; ; .IIF NDF,MMG$T,MMG$T=0 ; IF NOT XM MONITOR .IIF NDF,ERL$G,ERL$G=0 ; IF NO ERROR LOGGER .IIF NDF,TIM$IT,TIM$IT=0 ; IF NO TIME OUT ; ; ; BEGINING OF INITALIZATION CODE ; ; .DRBEG RO,ROVEC,11300,100034 ; SET UP HEADER INFO RO: NOP ; ; ; THIS AREA IS A SPECIAL PART OF THE INITIALIZATION ; PROCEEDURE-THE FIRST TIME THROUGH-THE MAGTAPE HAS TO BE ; POSITIONED,SO THE INSTRUCTION AT RO: ALLOWS THE FOLLOWING ; INSTRUCTION TO BE EXECUTED ; ; JMP FSTIM ; ; ; THE ROUTINE 'FSTIM' THEN REPLACES THE 'NOP' AT RO: BY A ; 'BR .+6' ; SO THAT ALL SUBSEQUENT CALLS TO THE DRIVER DO NOT GO THROUGH ; THE ONE TIME ONLY CODE 'FSTIM' ; ; THE FOLLOWING CODE IS THE REGULAR I/O INIT CODE ; ; OTRTIM: MOV ROCQE,R4 ; GET POINTER TO QUE ELEMENT TST 6(R4) ; IS IT READ OR WRITE BLT ROERR ; IF LT 0 THEN ERROR-THIS IS A READ ONLY DEVICE MOV #8.,CTR ; SET READ TRY COUNTER TO 8 TRYS MOV (R4),R3 ; GET THE BLOCK NO (256. WORDS/BLOCK ) CLR R2 ; CLEAR UPPER BITS DIV NUMB,R2 ; FIND TAPE RECORD NUMBER MOV R2,R1 ; WORK ON COPY ONLY SUB PTR,R1 ; GET OFFSET FROM BLOCK NOW IN MEMORY BEQ INMEM ; IF BLOCK NOW IN MEMORY, NO TAPE HANDLEING NEEDED BLT BACKUP ; NOT IN MEMORY-GOT TO BACK UP TO GET IT DEC R1 ; SINCE THE MAG TAPE IS POSITIONED AFTER ; THE BLOCK IN MEMORY-WE ONLY NEED TO SKIP N-1 ; BLOCKS TO BE ABLE TO READ THE ONE WANTED BEQ NXTBLK ; BLOCK WANTED IS NEXT BLOCK-SO NO SKIP NEEDED SKPFWD: NEG R1 ; RECORD CONTER NEEDS 2'S COMPLIMENT MOV R1,@#ROBRC MOVB #0,ROIBR ; WHEN SKIP COMPLETED-ON INTERUPT ; GO TO ROUTINE RDBLK MOV R2,PTR ; SET POINTER TO NOEW BLOCK TO BE IN MEMORY MOV SKF,@#ROC ; GO DO IT RTS PC BACKUP: DEC R1 ; HAVE TO SKIP BACK ONE MORE BLOCK THAN DIFFERECE ; CALCULATED DUE TO POSITION OF TAPE MOV R1,@#ROBRC ; SET UP RCORD COUNTER MOV R2,PTR ; NEW BLOCK IN MEM VALUE MOVB #0,ROIBR ; WHEN SKIP DONE-DO A RDBLK MOV SKB,@#ROC ; EXECUTE RTS PC INMEM: MOVB #4,ROIBR ; JUST COPY CONTENTS OF MEMORY BR SIMINT ROERR: MOVB #2,ROIBR ; ON INTERUPT-DO ERROR EXIT BR SIMINT ; FORCE AN INTERUPT NXTBLK: MOVB #0,ROIBR ; ON INTERUPT-READ A BLOCK INC PTR ; NEXT BLOCK NO-UPDATE PTR SIMINT: MOV #100,@#ROC ; FORCE AN IMEDIATE INTERUPT ; BY SETTING THE I.E BIT ONLY RTS PC ; ; ; INTERUPT SERVICE ROUTINES ; ; .DRAST RO,5,RODONE ; ; ; TIME IS NOT CRITICAL-WAIT UNTILL ALL INTERUPTS THAT ; NEED THE TIME ARE DONE ; ; .FORK ROFBLK ; ; ; THE FOLLOWING IS A TABLE THAT ALLOWS DIFFERENT ; INTERUPT SERVICE ROUTINES TO BE CALLED AS NEEDED ; THE "BR .+N" INSTRUCTION IS MODIFIED BY MOVB ; INSTRUCTIONS TO BRANCE TO THE JUMP INSTRUCTION ; TO THE ROUTINE WANTED. ; THE COMMENTED NUMBER AFTER THE JUMP IS THE VALUE IN THE ; LOW ORDER BYTE TO GET TO THAT JUMP ; ; ROIBR: BR 1$ JMP RDBLK ; 0 1$: JMP ERROR ; 2 JMP CPYMEM ; 4 ; ; ; THE FOLLOWING ARE USED AS PART OF THE FIRST TIME THROUGH ; CODE ONLY AND AS SUCH THOSE ROUTINES RESIDE IN THE BUFFER AREA ; ; JMP SKPHDR ; 6 JMP NXTF1 ; 10 JMP BUFSZZ ; 12 JMP SKP2 ; 14 ; ; ; THE FOLLOWING ROUTINE IS USED TO INPUT A NEW BLOCK INTO THE ; DRIVERS INTERNAL BUFFER.THIS WILL BE BLOCK NO. N WHOSE VALUE IS ; FOUND IN PTR ; ; RDBLK: MOV #-10240.,@#ROBRC ; 5120 WORD BUFFER MOV #,R4 ; GET THE ADDRESS OF THE BUFER ADD @#ROVEC,R4 ; IN A DRIVER POSITION INDEPENDENT MANNER MOV R4,@#ROCMA ; AND LOAD IT MOVB #4,ROIBR ; WHEN IN COPY PART WANTED TO USERS BUFFER MOV READ,@#ROC ; HAVE AT IT RTS PC ; ; ; ERROR REPORTING ROUTINE ; ; ERROR: MOV ROCQE,R4 ; GET POINTER TO QUE ELEMENT BIS #1,@-2(R4) ; SET HARD ERROR BIT BR DONE ; GO TO COMPLETION ROUTINE EXIT ; ; ; COPY THE PORTION OF BUFFER STORED IN DRIVE ; TO USER ; ; CPYMEM: MOV ROCQE,R4 ; GET THE YOU KNOW WHAT TST @#ROC ; WAS THEIR AN ERROR BGE 1$ ; IF NO JST PROCEED WITH THE COPY OPERAQTION DEC CTR ; DEC RETRY COUNTER BLE 2$ ; IF USED UP ALL TRYS-REPORT THE ERROR, AND ; USE THE BUFFER AS IS MOV #-1,@#ROBRC ; OTHERWISE BACK UP FOR ANOTHER TRY MOVB #0,ROIBR MOV SKB,@#ROC ; ONCE MORE IN TO THE BREACH DEAR FRIENDS RTS PC 2$: BIS #1,@-2(R4) ; REPORT THE ERROR ; ; ; AND CONTINUE AS IF NOTHING HAD HAPPENED ; ; 1$: TST 6(R4) ; WAS IT A SEEK COMMAND BEQ DONE ; IF IT WAS WE ARE DONE 5$: MOV #256.,R5 ; ALL MOVES ARE DONE IN BLOCKS OF ; 256 WORDS OR LESS CMP R5,6(R4) ; IS IT LESS?? BLE 3$ ; IF NO-USE 256. MOV 6(R4),R5 ; IF YES-USE THE LESS 3$: MOV (R4),R3 ; GET THE BLOCK NO (256. WORDS/BLOCK ) CLR R2 ; CLEAR UPPER BITS DIV NUMB,R2 ; FIND TAPE RECORD NUMBER SWAB R3 ; MULTIPLY BY 512 ASL R3 ADD #,R3 ; CALCULATE THE BUFFER LOCATION ADD @#ROVEC,R3 ; IN A POSITION INDEPENDENT WAY 4$: .IF EQ,MMG$T ; IF NOT XM MONITOR MOV (R3)+,@4(R4) ; MOVE WORD TO USER BUFFER ADD #2,4(R4) ; BUMP POINTER .IFF ; IF IT IS XM MONITOR MOV (R3)+,-(SP) ; STORE WORD TO BE STORED ON STACK JSR PC,@$PTWRD ; LET MONITOR STORE IT AND BUMP COUNTER .ENDC DEC 6(R4) ; DEC WC DEC R5 ; DEC BLOCK COUNTER BGT 4$ ; ; ; 256 OR LESS WORD BLOCK MOVED ; ; INC (R4) ; INC BLOCK NUMBER TO NEXT BLOCK TST 6(R4) ; WC=0(DONE) BEQ DONE ; IF SO-NO NEED TO HANG AROUND MOV (R4),R3 ; GET BLOCK NUMBER CLR R2 ; CLEAR HIGH BITS DIV NUMB,R2 ; ONLY REALLY WANT REMAINDER TST R3 ; IS REMAINDER NOT 0?? BNE 5$ ; IN SAME BUFFER INC PTR ; OTHERWISE GET ANOTHER BUFFER FULL MOV #8.,CTR JMP RDBLK RODONE: DONE: CLR @#ROC .DRFIN RO ; GO TO COMPLETION ROUTINE NUMB: .WORD 0 ; NUMBER OF BLOCKS PER RECORD PTR: .WORD 0 ; NUMBER OF 4096 WORD BOCK IN BUFFER CTR: .WORD 0 ; READ RETRY COUNTER RW: .WORD M+16 ; REWIND SKF: .WORD M+10 ; SKIP FORWARD SKB: .WORD M+12 ; SKIP BACKWARD READ: .WORD M+2 ; READ ROFBLK: .WORD 0,0,0,0 ; FORK BLOCK ROSYN: .WORD 0,0,0,0,0,-1,0 ; SYNCH BLOCK ROADR: .WORD 0 ; SYNCH ADDRESS ; ; ; THE FOLLOING IS FIRST TIME THORUGH ONLY CODE,SO ; IT RESIDES IN THE SAME AREA AS THE DRIVERS BUFFER ; ; BUFFER: BUFEND =.+10240. ; ; ; END OF BUFFER VALUE ; ; FSTIM: MOV #402,RO ; RESET NOP TO PERMINATELY BRANCH AROUND ; THE JUMP TO THIS CODE-ONCE IS ENOUGH MOV ROCQE,R0 ; GET QUEUE ADDRESS MOV 2(R0),R0 ; GET UNIT NUMBER BIC #174377,R0 ; ISOLATE BITS BIS R0,RW ; OR IN UNIT BIS R0,SKF ; OR IN UNIT BIS R0,SKB ; OR IN UNIT BIS R0,READ ; OR IN UNIT MOV #,R0 ; GET MESSAGE ADDRESS ADD @#ROVEC,R0 ; USEING A NOW FAMILIAR DRILL .PRINT ; TO PRINT OUT THE REQUEST MESSAGE CLR R1 ; ; ; GET THE DLU FILE NUMBER ; ; 1$: .TTYIN CMPB #15,R0 ; WAS IT BEQ 1$ ; IGNORE THEM CMPB #12,R0 ; WAS IT BEQ 2$ ; KEY ON THOSE AS END OF LINES SUB #60,R0 ; CONVERT IT TO BINARY BLT 1$ ; IF NOT A DIGIT-IGNORE IT CMPB #8.,R0 ; WAS IT A NON OCTAL CHR BLE 1$ ; IF SO IGNORE THEM TO ASL R1 ; TIMES TWO MOV R1,-(SP) ; STACK IT ASL R1 ; TIMES FOUR ASL R1 ; TIMES EIGHT ADD (SP)+,R1 ; MULT R1 BY 10 ADD R0,R1 ; AND PUT IN NEW DIGIT BR 1$ ; GET NEXT CHR 2$: MOV R1,FILNO ; STORE FILE NUMBER MOVB #14,ROIBR ; AFTER REWIND-SKIP THE HEADER BIT #40,@#ROS ; ARE WE AT LOAD POINT?? BNE SKPHDR ; YES MOV RW,@#ROC ; REWIND TO BOT RTS PC ROMSG: .ASCII /?RO-I-Enter DLU file number: / .BYTE 200 .EVEN FILNO: .WORD 0 ; ; ; READ THE FIRST RECORD OF THE FILE ; ; SKPHDR: BIT #2000,@#ROS ; END OF TAPE?? BNE EOV ; YES BIT #40,@#ROS ; ARE WE AT LOAD POINT?? BNE SKP2 ; YES BIT #40000,@#ROS ; END OF FILE?? BEQ NXT1A ; NO, SKIP AGAIN SKP2: MOV #-2.,@#ROBRC ; 1 WORD MOV #,R4 ; GET THE ADDRESS OF THE BUFFER ADD @#ROVEC,R4 ; IN A DRIVER POSITION INDEPENDENT MOV R4,@#ROCMA ; MANNER AND LOAD IT MOVB #12,ROIBR ; DETERMINE BUFFER SIZE ROUTINE MOV READ,@#ROC ; READ IT RETURN ; ; ; END OF VOLUME CODE ; ; EOV: MOV ROCQE,R4 ; POINTER TO QUEUE ELEMENT MOV 2(R4),R0 ; GET JOB NUMBER BIC #103777,R0 ; ISOLATE BITS SWAB R0 ; MOVE BITS AROUND ASR R0 ; TO THE RIGHT ASR R0 ; TO THE RIGHT ASR R0 ; TO THE RIGHT MOV R0,ROSYN+2 ; FILL IN JOB NUMBER AGAIN: .SYNCH ROSYN,PIC ; SYNCH IT BR AGAIN ; TRY UNTIL DONE MOV R0,-(SP) ; SAVE R0 MOV #,R0 ; GET MESSAGE ADDRESS ADD @#ROVEC,R0 ; USING A NOW FAMILIAR DRILL .PRINT ; ALERT USER MOV (SP)+,R0 ; RESTORE R0 MOV #-1,@#ROBRC ; SKIP BACK ONE RECORD MOVB #2,ROIBR ; WHEN SKIP DONE-DO ERROR MOV SKB,@#ROC ; EXECUTE RETURN EOVM: .ASCIZ /?RO-F-End of volume/ .EVEN ; ; ; DETERMINE NUMBER OF BLOCKS PER RECORD ; ; BUFSZZ: BIT #2000,@#ROS ; END OF TAPE?? BNE EOV ; YES BIT #40000,@#ROS ; END OF FILE?? BNE EOV ; YES CMP #"RL,FSTIM ; IS IT AN RL?? BEQ RLBUF ; YES ; ; ; ASSUME AN RK ; ; BUZ: MOV #12.,NUMB ; NUMBER OF BLOCK PER RECORD BR NXTF1 ; CONTINUE RLBUF: MOV #20.,NUMB ; NUMBER OF BLOCKS PER RECORD ; ; ; THE NEXT TWO ROUTINE ARE USED TO SKIP TO THE DLU FILE ; WANTED ; ; NXTF1: TST FILNO ; WAS FILE 0 SECIFIED BEQ 1$ ; IF YES NO NEED TO DEC AS FILE 0 AND 1 ARE THE ; SAME DEC FILNO ; HOW MANY FILES NEED TO BE SKIPED 1$: TST FILNO ; IF NONE THEN BLE JST2 ; JUST SKIP THE NEXT BLOCK OF DATA NXT1A: CLR @#ROBRC ; 65K SKIP MOVB #6,ROIBR ; WHEN SKIP COMPLETED GO TO SKPHDR MOV SKF,@#ROC ; HAVE AT IT RTS PC ; ; ; NOW IN RIGHT FILE ; ; JST2: MOV ROCQE,R4 ; GET POINTER TO QUE ELEMENT TST 6(R4) ; IS IT READ OR WRITE BGE 1$ ; IF LT 0 THEN ERROR-THIS IS A READ ONLY DEVICE BIS #1,@-2(R4) ; SET HARD ERROR BIT CLR 6(R4) ; TURN INTO A SEEK 1$: MOV #8.,CTR ; SET READ TRY COUNTER TO 8 TRYS MOV (R4),R3 ; GET THE BLOCK NO (256. WORDS/BLOCK ) CLR R2 ; CLEAR DIVISOR DIV NUMB,R2 ; RECORD NUMBER ON TAPE MOV R2,R1 ; WORK ON COPY ONLY MOV R1,PTR ; UPDATE POINTER BEQ JST2D ; IF ZERO NO SKIP NEG R1 ; USE 2'S COMP ONLY MOV R1,@#ROBRC ; JST 2 MORE BLOCKS TO GO MOVB #0,ROIBR ; WHEN DONE HERE READ BLOCK MOV SKF,@#ROC ; JST AN EASY BUMP RTS PC JST2D: JMP RDBLK ; READ A BUFFER ; ALLOW SPACE FOR THE 5120 WORD BUFFER A =. . =.-+10240. .DREND RO .END