.TITLE TPC - DOS11 TAPE/DISK COPY UTILITY .SBTTL INTRODUCTION .IDENT /V01.1/ .MCALL GCMLB$,GCML$,CSI$,CSI$1,CSI$2,CSI$SW,CSI$ND,DIR$,PUT$ .MCALL FDBDF$,FDAT$R,NMBLK$,WTSE$S,GET$,EXIT$S .MCALL QIOW$,OFNB$,CSI$SV,FSRSZ$ .MCALL QIOW$S,ASTX$S,FDOP$R,QIO$S,CLEF$S,SETF$S .NLIST BEX ;+ ; VERSION 01 ; ; REID L BROWN 27-OCT-77 ; ; MODIFIED BY: ; ; G H COHEN, 21-AUG-78 ; INSERT A DEFAULT VALUE FOR FILE ALLOCATION SIZE ; USE .TRNCL IN PLACE OF .CLOSE ; PROVIDE A MEANS FOR FILE EXTENSION ; ATTACH TO MAGTAPE UNIT AND SET DENSITY TO 800BPI ; ; ;++AF1 A E Frisbie, 31-JAN-80 ;++AF1 When moving error codes to MTERR or DSKERR, use MOVB instead of MOV, ;++AF1 followed by a MOVB #-1 if the result is negative. This corrects the ;++AF1 problem of error numbers being printed as a positive value. ; ;++AF2 A E Frisbie, 12-MAR-80 ;++AF2 Enlarge buffer size to handle larrrrrrrge records (4200. bytes). ;++AF2 This allows TPC to copy DSC and BRU tapes. ; ; THIS ROUTINE WILL PRESERVE A DOS-11 MAGTAPE IN IMAGE FORMAT ON DISK, OR ; RESTORE AN IMAGE FORMAT FILE FROM DISK TO MAGTAPE. ITS UTILITY IS ITS ; ABILITY TO DRIVE THE MAGTAPE DRIVE AT FULL SPEED. THIS FEATURE IS USEFUL ; WHEN MAKING LARGE NUMBERS OF COPIES OF DOS-11 MAGTAPE DATA. THE RSX-11 ; FILES-11 FILE IS COMPATIBLE WITH FCS VARIABLE LENGTH, BLOCK SPANNED ; RECORD MODE. ; ;- ; ; LOCAL MACROS ; .MACRO ERRMSG MESSAG,WHERE,?A,?B,?C BR C A: .ASCII ^MESSAG^ B: .EVEN C: MOV #A,QIO+Q.IOPL MOV #B-A,QIO+Q.IOPL+2 DIR$ #QIO .IIF DF,WHERE JMP WHERE .ENDM ERRMSG .MACRO PAUSE CLEF$S #16. WTSE$S #16. .ENDM PAUSE .MACRO RESUME SETF$S #16. .ENDM RESUME ; ; ALLOCATE FSR AREA ; FSRSZ$ 3 ; ALLOCATE 3 BUFFERS .SBTTL CSI & FCS DATA & BUFFERS ; ; FILE DESCRIPTOR BLOCKS & RELATED INFORMATION ; FDBST: ; START OF FDB'S FDBINP::FDBDF$ ; DEFINE INPUT FDB FDBOUT::FDBDF$ ; DEFINE OUTPUT FDB FDBEND: ; END ADDR OF FDB'S GCMBLK: GCMLB$ 3,TPC,,TILUN ; COMMAND LINE CONTROL BLOCK INDFN: NMBLK$ ,DOS ; DEFAULT FILENAME: '.DOS' OUTDFN: NMBLK$ ,DOS ; " " '.DOS' ; ; LUNS ; INLUN= 1 ; INPUT FILE ON 1 OUTLUN= 2 ; OUTPUT FILE ON 2 TILUN= 5 ; GCML & QIO'S TO #5 (DEFAULT FROM TKB) ; ; COMMAND STRING INTERPRETER ; CSIFLG: .WORD 0 ; FLAG WORD FOR COMMAND SWITCHES HLPMSK= 1 ; /HE - PRINT HELP MESSAGE BLKMSK= 2 ; /BL - ALLOCATE BLOCKS SALMSK= 4 ; /SA - SECONDARY ALLOCATION (BLOCKS) CONMSK= 10 ; /CO - CONTIGUOUS FILE HDMSK=20 ; /HD - 1600 BPI TAPE I/O NRMSK=40 ; /NR - NO REWIND BEFORE START ERMSK=100 ; /ER - IGNORE ERRORS (EXCEPT END-TAPE,EOV) CSISW: CSI$SW HE,HLPMSK,CSIFLG CSI$SW BL,BLKMSK,CSIFLG,,,ALCTAB CSI$SW SA,SALMSK,CSIFLG,,,SALTAB CSI$SW CO,CONMSK,CSIFLG CSI$SW HD,HDMSK,CSIFLG CSI$SW NR,NRMSK,CSIFLG CSI$SW ER,ERMSK,CSIFLG CSI$ND ALCTAB: CSI$SV DECIMAL,ALLOC,2 SALTAB: CSI$SV DECIMAL,SALOC,2 CSI$ND ALLOC: .WORD -100. ; ALLOCATION VALUE [+/-] SALOC: .WORD -50. ; SECONDARY ALLOCATION VALUE [+/-] CSI$ CSI: .BLKB C.SIZE ; DEFINE THE CSI WORK AREA .EVEN .SBTTL HELP MESSAGE & TEXT ; ; ERROR MESSAGE PROCESSING & HELP ; QIO:: QIOW$ IO.WVB,TILUN,1,,IOSTAT,,<.-.,.-.,40,.-.,.-.,.-.> IOSTAT::.WORD 0,0 ERRBUF: .BLKB 80. HLPMSG: .ASCIZ 'TPC - DOS11 TAPE / DISK UTILITY PROGRAM' .ASCIZ ' THIS PROGRAM WILL COPY DOS-11 MAGTAPES TO RSX-11 DISK' .ASCIZ ' FILES AND RECORD THEM IN A SPECIAL IMAGE MODE' .ASCIZ ' THIS ALLOWS VERY FAST MULTIPLE COPIES OF TAPES TO BE MADE' .ASCIZ ' FROM THE DISK IMAGE (MUCH FASTER THAN FILEX).' .ASCIZ ' ' .ASCIZ ' THE COMMAND FORMAT IS STANDARD RSX-11:' .ASCIZ ' ' .ASCIZ ' TPC>OUTFILE=INFILE[/BL:NNNN][/SA:MMMM][/CO][/HE]' .ASCIZ ' WHERE:' .ASCIZ ' -ONE "FILE" MUST BE A MAGTAPE DEVICE' .ASCIZ ' /BL:NNNN = AN OPTIONAL ALLOCATION SPECIFICATION' .ASCIZ ' IF DISK IS THE OUTPUT DEVICE' .ASCIZ ' /SA:MMMM = AN OPTIONAL SECONDARY ALLOCATION AMOUNT' .ASCIZ ' IF DISK IS THE OUTPUT DEVICE' .ASCIZ ' /CO = DISK FILE TO BE CONTIGUOUS' .ASCIZ ' /HE = THIS HELP TEXT' .ASCIZ ' /NR = DO NOT REWIND TAPE BEFORE USE' .ASCIZ ' /HD = USE HIGH DENSITY (1600 BPI) ON TAPE' .ASCIZ ' /ER = IGNORE INPUT TAPE ERRORS EXCEPT EOT/EOV/EOF' HLPEND= . .EVEN DSKERM: .ASCIZ 'TPC -- DISK I/O ERROR. CODE=%D' MTERM: .ASCIZ 'TPC -- MAGTAPE I/O ERROR. CODE=%D' .EVEN .SBTTL TAPE / DISK DATA & TABLES ; ; DISK & TAPE OPERATIONS ARE ENTIRELY AST DRIVEN, USING LINKED LISTS TO ; CONTROL THE SEQUENCE OF EVENTS TO BE FOLLOWED. ALL BUFFERS FOR BOTH ; INPUT & OUTPUT OPERATIONS ARE KEPT IN LINKED LISTS BY TYPES (INPUT OR ; OUTPUT) AND ARE SCANNED AT EACH AST TO SEE WHAT WORK NEEDS TO BE DONE. ; ; THE GENERAL FORMAT FOR A LIST NODE IS: ; N.FWD = 0 ; WD: 0 [ LINK TO NEXT NODE ] N.BWD = 2 ; WD: 1 [ LINK TO PRIOR NODE ] N.IOST = 4 ; WD: 2 [ IO STATUS WORD #0 ] ; WD: 3 [ IO STATUS WORD #1 ] N.WRK = 10 ; WD: 4 [ TEMPORARY WORK VAR. ] N.BUF = 12 ; WD: 5 [ BUFFER ADDRESS ] N.LEN = 14 ; WD: 6 [ BUFFER LENGTH ] N.PTR = 16 ; WD: 7 [ CURRENT BUFFER POINTER] N.BKH = 20 ; WD: 10 [ HIGH ORDER BLOCK NO. ] N.BKL = 22 ; WD: 11 [ LOW ORDER BLOCK NO. ] N.SIZE = 24 ; SIZE OF NODE ; DSKBKS= 20. ;++AF2 NO. OF BLOCKS IN DISK BUFFER DSKBFS = DSKBKS*512. ; DISK BUFFER SIZE = 16 BLOCKS DSKBF0: .BLKB DSKBFS ; ALLOCATE 1ST BUFFER DSKBF1: .BLKB DSKBFS ; & 2ND BUFFER TPBFS = 4200.+2 ;++AF2 TAPE BUFFER SIZE = 1 BLOCK + 1 WORD TPBF0: .BLKB TPBFS ; TAPE BUFFER 1 TPBF1: .BLKB TPBFS ; TAPE BUFFER 2 TPBF2: .BLKB TPBFS ; TAPE BUFFER 3 TPBF3: .BLKB TPBFS ; TAPE BUFFER 4 ; ; CONTROL VARIABLES ; DSKFCT: .WORD DSKBKS ; DISK BLOCKING FACTOR INVEC: .WORD 0 ; CURRENT INPUT VECTOR OUTVEC: .WORD 0 ; CURRENT OUTPUT VECTOR OUTDVF: .WORD 0 ; OUTPUT DEVICE FLAG(-1 FOR MAGTAPE, 0 FOR DISK) INDVF: .WORD 0 ; INPUT DEVICE FLAG MAGDEV: .WORD "MM,"MT,0 ; MAGTAPE DEVICE LIST IOST: .WORD 0,0 ; I/O STATUS BLOCK FOR SIMPLE QIO'S FLAGS: .WORD 0 ; DISK & MAGTAPE FLAGS MTERR: .WORD 0 ; MAGTAPE ERROR VALUE DSKERR: .WORD 0 ; DISK ERROR VARIABLE ; ; FLAG VALUES FOR DISK & MAGTAPE FLAGS ; EOV = 1 ; END OF VOLUME SEEN EOF = 2 ; END OF FILE SEEN ERR = 4 ; ERROR ENCOUNTERED DONE = 10 ; TRANSFER DONE ; ; DISK NODE LIST ; DSKLHD: .WORD DSKLHD ; DISK NODE LISTHEAD, FORWARD POINTER .WORD DSKLHD ; & BACKWARD POINTER ; NOTE: LISTHEAD & LISTS MUST REMAIN TOGETHER DSKLST: .WORD 0,0,0,0,0,DSKBF0,DSKBFS,DSKBF0,0,0 ; DISK NODE #0 .WORD 0,0,0,0,0,DSKBF1,DSKBFS,DSKBF0,0,0 ; DISK NODE #1 DSKLND= . ; ; TAPE NODE LIST ; TPLHD: .WORD TPLHD ; TAPE NODE LISTHEAD ADDRESS, FORWARD POINTER .WORD TPLHD ; & BACKWARD POINTER TPLST: .WORD 0,0,0,0,0,TPBF0,TPBFS,0,0,0 ; TAPE BUFFER #0 .WORD 0,0,0,0,0,TPBF1,TPBFS,0,0,0 ; TAPE BUFFER #1 .WORD 0,0,0,0,0,TPBF2,TPBFS,0,0,0 ; TAPE BUFFER #2 .WORD 0,0,0,0,0,TPBF3,TPBFS,0,0,0 ; TAPE BUFFER #3 TPLND= . .SBTTL PARSE INPUT SPECIFICATION & CHOOSE ACTION ; ; GET COMMAND LINE, PARSE IT & START ALL FILES ; START: CALL CLOSE ; INSURE ALL FILES ARE CLOSED (IGNORE ERRORS) MOV #FDBST,R0 ; POINT TO THE FIRST FDB 110$: CLR (R0)+ ; CLEAR OUT THE FILE DESCRIPTOR BLOCKS CMP R0,#FDBEND ; AT END YET? BLO 110$ ; NO - CONTINUE CLR CSIFLG ; RESET THE COMMAND STRING FLAGS CLR INDVF ; RESET INPUT DEVICE TYPE CLR OUTDVF ; RESET OUTPUT DEVICE TYPE MOV #-100.,ALLOC ; RESET THE ALLOCATION AMOUNT MOV #-50.,SALOC ; RESET THE SECONDARY ALLOCATION GCML$ #GCMBLK ; READ A COMMAND LINE BCC 130$ ; CONTINUE IF NO ERRORS CMPB #GE.EOF,G.ERR(R0) ; END OF COMMAND INPUT? BNE 120$ ; NO - COMMAND INPUT ERROR EXIT$S 120$: ERRMSG BR START 130$: CSI$1 #CSI,GCMBLK+G.CMLD+2,GCMBLK+G.CMLD ; PARSE COMMAND LINE BCC 140$ ; CONTINUE IF NO ERRORS 135$: ERRMSG BR START 140$: CSI$2 R0,OUTPUT,#CSISW ; PARSE OUTPUT FILESPEC & SWITCHES BCC 160$ ; NO ERRORS - CONTINUE 150$: ERRMSG JMP START 160$: BITB #,C.STAT(R0) BNE 135$ BIT #HLPMSK,CSIFLG ; DID THE USER WANT HELP? BEQ 161$ ; NO - CONTINUE JMP HELP ; GIVE HIM HELP 161$: BIT #CONMSK,CSIFLG ; IS FILE TO BE CONTIGUOUS BNE 162$ ; IF NE, YES TST ALLOC ; IS ALLOC NEGATIVE BMI 163$ ; IF YES SKIP NEG ALLOC ; NEGATE IT BR 163$ 162$: TST ALLOC ; IS ALLOC POSITIVE BPL 163$ ; IF YES SKIP NEG ALLOC ; NEGATE IT 163$: BNE 263$ ; (ALWAYS ALLOCATE SOMETHING!) MOV #200.,ALLOC ;START AT 200 AT LEAST 263$: TST SALOC ; BUT NEVER LET SALOC REMAIN NEGATIVE BPL 164$ ; IF POSITIVE, SKIP NEG SALOC ; NEGATE IT 164$: BNE 264$ ;ALSO ALWAYS HAVE A SECONDARY ALLOC. MOV #50.,SALOC 264$: FDAT$R #FDBOUT,#R.VAR,#FD.CR,,ALLOC,SALOC ; INIT THE FDB FDOP$R R0,#OUTLUN MOV R0,R1 ; R1 = FILENAME BLOCK ADDRESS ADD #F.FNB,R1 ; ... MOV #CSI+C.DSDS,R2 ; R2 = DATASET DESCRIPTOR MOV #OUTDFN,R3 ; R3 = DEFAULT FILENAME ADDRESS CALL .PARSE ; PARSE THE FILENAME BLOCK INFO BCS 168$ ; ERROR ON PARSE CALL MAGTST ; TEST FOR MAGTAPE DEVICE BCC 167$ ; OUTPUT FILE IS DISK - OPEN IT DEC OUTDVF ; OUTPUT IS MAGTAPE - SO INDICATE BR 170$ ; CONTINUE 167$: OFNB$ R0,#FO.WRT,#OUTLUN,,,#FD.RWM BCC 170$ ; CONTINUE IF NO ERRORS 168$: ERRMSG JMP START 170$: MOV #1002,F.RSIZ(R0) ; INIT THE RECORD SIZE IN FDB CLR F.FFBY(R0) ; INDICATE NEXT BLOCK EMPTY CSI$2 #CSI,INPUT,#CSISW ; PARSE INPUT FILE & SWITCHES BCC 171$ ; NO ERROR IF CARRY CLEAR JMP 150$ ; REPORT SWITCH ERROR 171$: BITB #,C.STAT(R0) ; NO WILDCARDS, ETC ALLOWED BEQ 173$ ; OK - CONTINUE JMP 135$ ; REPORT IT AS ERROR 173$: BIT #HLPMSK,CSIFLG ; DID HE WANT HELP? BEQ 175$ ; NO - CONTINUE JMP HELP ; YES - GIVE HIM HELP 175$: FDOP$R #FDBINP,#INLUN ; DECLARE LUN TO INPUT FDB MOV R0,R1 ; R1 = FNB ADDRESS ADD #F.FNB,R1 ; ... MOV #CSI+C.DSDS,R2 ; R2 = DATASET DESCRIPTOR MOV #INDFN,R3 ; R3 = DEFAULT FILENAME CALL .PARSE ; PARSE THE FILENAME BLOCK DATA BCS 180$ ; ERROR ON PARSE CALL MAGTST ; SEE IF THIS IS MAGTAPE BCC 190$ ; NO - TRY TO OPEN THE FILE DEC INDVF ; INDICATE INPUT DEVICE IS MAGTAPE BR 200$ ; CONTINUE 180$: ERRMSG JMP START 190$: OFNB$ R0,#FO.RD,,#INLUN,,,#FD.RWM BCS 180$ ; ERROR ON OPEN ; ; DETERMINE WHETHER WE HAVE CORRECT COMBINATION OF DISK & MAGTAPE DEVICES: ; I.E. 1 DISK & 1 MAGTAPE ; 200$: MOV OUTDVF,R0 ; R0 = OUTPUT DEVICE FLAG MOV INDVF,R1 ; R1 = INPUT DEVICE FLAG XOR R0,R1 ; IF NOT -1, THEN WE HAVE 2 OF A KIND! BMI 210$ ; GOOD! - CONTINUE ERRMSG ,START 210$: TST R0 ; WHICH WAS IT? BPL 215$ ; OUTPUT IS DISK JMP DSKTTP ; OUTPUT IS MAGTAPE 215$: JMP TPTDSK ; TAPE-TO-DISK ; ; MAGTST - SUBROUTINE TO TEST FOR MAGTAPE AS THE REDIRECTED DEVICE WHICH ; WAS ASSIGNED IN THE FILENAME BLOCK. ; MAGTST: MOV #MAGDEV,R5 ; POINT R5 TO DEVICE LIST 10$: CMP (R5)+,N.DVNM(R1); TEST DEVICE NAME FIELD OF FILENAME BLOCK BEQ 90$ ; GOT IT! - ITS MAGTAPE (SET CARRY) TST (R5) ; ANY MORE ENTRIES? BNE 10$ ; YES - CONTINUE RETURN 90$: SEC ; INDICATE MAGTAPE RETURN ; ; CLOSE - CLOSE FILES AT END OF RUN ; CLOSE: MOV #FDBINP,R0 ; POINT TO INPUT FDB CALL .TRNCL ; TRUNCATE AND CLOSE IT MOV #FDBOUT,R0 ; POINT TO OUTPUT FDB CALL .TRNCL ; TRUNCATE AND CLOSE IT RETURN ; ; HELP - LIST OUT THE HELP TEXT ON TI: ; HELP: MOV #HLPMSG,R0 ; R0 = HELP MESSAGE TEXT ADDRESS MOV #40,QIO+Q.IOPL+4; SET THE CC-TYPE TO CR-LF 10$: MOV R0,QIO+Q.IOPL ; PUT THE ADDRESS IN THE DPB MOV R0,R1 ; SAVE THE BEGINNING ADDRESS IN R1 20$: TSTB (R0)+ ; SCAN TO NULL AT END BNE 20$ ; CONTINUE TILL NULL CHARACTER MOV R0,R2 ; R2 = ENDING LINE ADDRESS + 1 DEC R2 ; BACKUP TO END OF LINE SUB R1,R2 ; R2 = LENGTH OF LINE MOV R2,QIO+Q.IOPL+2 ; PUT LENGTH IN QIO DPB DIR$ #QIO ; OUTPUT THE LINE CMP R0,#HLPEND ; ANY MORE TEXT TO GO? BLO 10$ ; YES - CONTINUE JMP START .SBTTL WAIT CODE & ERROR PROCESSING ; ; WAIT- PROCESSING OF NORMAL CODE SUSPENDS ITSELF HERE AFTER INITIATING ; THE TAPE COPY OPERATION. ALL WORK IS DONE VIA AST ROUTINES, AND ; IS COMPLETELY 'INTERRUPT' DRIVEN. WHEN AN ERROR OCCURS, OR THE ; TRANSFER IS FINISHED, THE MAIN PROGRAM IS 'RESUMED'. IT MUST THEN ; CHECK FOR ANY ERRORS ENCOUNTERED IN THE AST ROUTINES. ; WAIT: PAUSE ; WAIT FOR PROCESSING TO COMPLETE BIT #ERR,FLAGS ; ANY ERRORS ? BNE 20$ ; YES - PROCESS IT JMP START ; NO - RESTART 20$: MOV #DSKERM,R1 ; ASSUME A DISK ERROR MOV DSKERR,-(SP) ; PUT ERROR CODE ON STACK BEQ 30$ ; NO CODE - NOT DISK ERROR JMP ERROR ; GO PROCESS ERROR 30$: MOV #MTERM,R1 ; SETUP MAGTAPE ERROR MESSAGE MOV MTERR,-(SP) ; & ERROR CODE JMP ERROR ; PROCESS THE ERROR ; ; ERROR-PROCESS ERROR MESSAGES. THIS ROUTINE OUTPUTS ERROR MESSAGES TO ; THE USERS TERMINAL USING $EDMSG. THE PATTERN STRING IS ASSUMED ; TO BE POINTED TO BY R1, AND THE ERROR CODE ON THE STACK. THIS ; ROUTINE SHOULD BE PASSED CONTROL VIA 'JMP ERROR'. ; ERROR: MOV #ERRBUF,R0 ; R0 = OUTPUT BUFFER POINTER MOV SP,R2 ; R2 = PARAMETER POINTER CALL $EDMSG ; EDIT THE MESSAGE MOV #ERRBUF,QIO+Q.IOPL ; SETUP THE QIO DPB MOV R1,QIO+Q.IOPL+2 ; ... TST (SP)+ ; POP THE PARAMETER FROM THE STACK DIR$ #QIO ; OUTPUT IT JMP START ; RESTART .SBTTL TAPE TO DISK OPERATIONS ; ; TAPE TO DISK ; ; THIS FUNCTION INITIATES A TRANSFER SEQUENCE FROM THE TAPE DRIVE ; TO THE DISK FILE. THE TAPE IS REWOUND PRIOR TO THE START OF ; THE COPY, AND ALL OPERATIONS ARE MULTI-BUFFERED. ; TPTDSK: CLR FLAGS ; RESET ALL FLAGS CLR DSKERR ; RESET DISK ERROR VALUE CLR MTERR ; & MAGTAPE ERROR VALUE MOV #TAPEIN,INVEC ; SETUP AST VECTORS MOV #DSKOUT,OUTVEC ; ... QIOW$S #IO.ATT,#INLUN,#1 ; ATTACH TO TAPE UNIT BIT #NRMSK,CSIFLG ;DID HE WANT TO SKIP THE REWIND? BNE 200$ ;IF SO, SKIP REWIND QIOW$S #IO.RWD,#INLUN,#1 ; REWIND THE MAGTAPE 200$: CLR R0 ;SET 800 BPI DENSITY INITIALLY BIT #HDMSK,CSIFLG ;DID HE SAY HIGH DENSITY? BEQ 201$ ;IF NOT LEAVE AT 800 BPI MOV #4000,R0 ;IF SO, SET 1600 BPI 201$: QIOW$S #IO.STC,#INLUN,#1,,,, ; SET TO 800BPI OR 1600 BPI ; ; INITIALIZE & PLACE ALL DISK BUFFERS IN THE QUEUE ; MOV #DSKLHD,R0 ; R0 = DISK BUFFER LISTHEAD MOV R0,R4 ; R4 = SAVED LISTHEAD ADDRESS MOV R4,(R0)+ ; SETUP A NULL LISTHEAD MOV R4,(R0)+ ; ... ; NOTE: THE LISTHEAD & LISTS MUST BE TOGETHER! 10$: MOV R0,R5 ; R5 = BUFFER NODE ADDRESS CALL NODADD ; ADD IT TO DISK QUEUE MOV N.BUF(R5),N.PTR(R5) ; UPDATE POINTER TO BUFFER START ADD #N.SIZE,R0 ; R0 = NEXT POINTER CMP R0,#DSKLND ; AT END OF LIST YET? BLO 10$ ; NO - CONTINUE ; ; INITIALIZE TAPE BUFFER LISTHEAD TO NULL, AND INITIATE I/O TO THE TAPE ; DRIVE FOR EVERY AVAILABLE BUFFER NODE IN ORDER TO START THE PROCESS GOING. ; MOV #TPLHD,R0 ; R0 = TAPE LISTHEAD ADDRESS MOV R0,R1 ; R1 = SAVED LISTHEAD ADDRESS MOV R1,(R0)+ ; INITIALIZE THE LISTHEAD TO NULL MOV R1,(R0)+ ; ... 30$: MOV R0,R1 ; R1 = COPY OF NODE ADDRESS CLR N.PTR(R0) ; RESET THE POINTER VALUE ADD #N.IOST,R1 ; R1 = IO STATUS ADDRESS MOV R1,R2 ; R2 = " " " ADD #N.BUF-N.IOST,R1; POINT R1 TO BUFFER ADDRESS CELL MOV (R1)+,R3 ; R3 = BUFFER ADDRESS TST (R3)+ ; ADVANCE BEYOND 1ST WORD MOV (R1),R4 ; & GET BUFFER SIZE SUB #2,R4 ; DECREASE BY TWO TO ACCOUNT FOR R3 OFFSET QIO$S #IO.RLB,#INLUN,,,R2,INVEC, ; READ THE BLOCK ADD #N.SIZE,R0 ; R0 = ADDRESS OF NEXT BUFFER NODE CMP R0,#TPLND ; ANY MORE TAPE BUFFERS? BLO 30$ ; YES - CONTINUE JMP WAIT ; NO - GO WAIT FOR I/O DONE .SBTTL TAPEIN - TAPE INPUT AST ; ; TAPEIN - HANDLE TAPE INPUT AST ; TAPEIN: MOV (SP)+,R5 ; R5 = I/O STATUS ADDRESS BIT #,FLAGS ; ERROR OR END FLAGGED? BNE 100$ ; YES - GET OUT MOV N.BUF-N.IOST(R5),R4 ; R4 = BUFFER ADDRESS BIT #ERMSK,CSIFLG ;IGNORING ERRORS? BEQ 2$ ;IF NOT, LOOK AT ALL. CMPB #IE.EOF,@R5 ;WAS IT ENDFILE??? BEQ 2$ ;YES, LEAVE THAT ERROR CMPB #IE.EOT,@R5 BEQ 2$ ;OR EOT CMPB #IE.EOV,@R5 BEQ 2$ CMPB #IE.PRI,@R5 BEQ 2$ ;OR IF TAPE DISMOUNTED ;MAKE ALL OTHER ERRORS BE IGNORED... MOVB #IS.SUC,@R5 ; YES, SAY ALL WAS OK 2$: TSTB (R5) ; ERROR ON I/O? BPL 50$ ; NO - SETUP & LINK BUFFER TO LISTHEAD CMPB #IE.EOF,(R5) ; EOF? BNE 90$ ; NO - ERROR BIT #EOF,FLAGS ; IS THIS 2ND EOF IN ROW? (EOV?) BNE 20$ ; YES - END-OF-VOLUME BIS #EOF,FLAGS ; NO - SO SET IT TO INDICATE 1ST EOF MOV #2,2(R5) ; YES - SET LENGTH FOR OUTPUT = 2 BYTES CLR (R4) ; DATA VALUE = 0 (COUNT = 0) BR 60$ ; CONTINUE 20$: BIS #EOV,FLAGS ; INDICATE EOV SEEN MOV #4,2(R5) ; YES - DATA LENGTH = 4 BYTES (2 NULLS) CLR (R4)+ ; RESET THE TWO 'NULL' RECORDS CLR (R4) ; ... BR 60$ ; CONTINUE 50$: MOV 2(R5),(R4) ; SETUP 1ST BUFFER WORD WITH DATA LENGTH ADD #2,2(R5) ; TOTAL LENGTH INCLUDES THE LENGTH WORD BIC #EOF,FLAGS ; RESET THE EOF SEEN FLAG 60$: SUB #4,R5 ; ADJUST R5 TO POINT TO START OF NODE MOV N.BUF(R5),N.PTR(R5) ; SETUP THE POINTER TO START OF DATA MOV TPLHD+2,R4 ; R4 = PRIOR NODE ADDRESS FOR ADD OPERATION CALL NODADD ; ADD NODE TO TAPE BUFFER LIST JMP TPDKDQ ; GO TRY TO DEQUEUE SOME WORK. 90$: QIOW$S #IO.KIL,#INLUN,#1,,IOST ; CANCEL ALL TAPE I/O'S IN PROG. BIS #ERR,FLAGS ; FLAG THE ERROR MOVB (R5),MTERR ;++AF1 COPY ERROR CODE FOR MAGTAPE BPL 95$ ;++AF1 SKIP IF POSITIVE (NOT LIKELY) MOVB #-1,MTERR+1 ;++AF1 ELSE MAKE HI BYTE NEGATIVE ALSO 95$: RESUME ; RESUME THE MAIN TASK 100$: ASTX$S ; EXIT THE AST .SBTTL DSKOUT - DISK OUTPUT AST ; ; DSKOUT - PROCESS DISK OUTPUT AST ; DSKOUT: MOV (SP)+,R5 ; R5 = AST ADDRESS BIT #,FLAGS ; ANY ERRORS OR OPERATION COMPLETE? BNE 100$ ; YES - JUST EXIT AST TSTB (R5) ; ANY ERRORS ON OPERATION? BMI 90$ ; YES - ERROR SUB #4,R5 ; R5 = NODE ADDRESS (ADJUSTED) MOV N.BUF(R5),N.PTR(R5) ; RESET THE BUFFER POINTER MOV DSKLHD+2,R4 ; R4 = PRIOR NODE ADDRESS FOR ADD CALL NODADD ; ADD THIS TO DISK BUFFER QUEUE JMP TPDKDQ ; TRY TO DEQUEUE SOME WORK 90$: QIOW$S #IO.KIL,#OUTLUN,#1,,#IOST ; CANCEL ALL OUTPUT I/O BIS #ERR,FLAGS ; FLAG THE ERROR MOVB (R5),DSKERR ;++AF1 SAVE THE ERROR CODE BPL 95$ ;++AF1 SKIP IF POSITIVE (NOT LIKELY) MOVB #-1,DSKERR+1 ;++AF1 ELSE MAKE HI BYTE NEGATIVE ALSO 95$: RESUME ; CONTINUE THE MAIN TASK 100$: ASTX$S .SBTTL TPDKDQ - TAPE TO DISK DEQUEUE ROUTINE ; ; TPDKDQ- ; ; THIS ROUTINE PERFORMS THE MAJORITY OF WORK IN THE TRANSFER OPERATION. ; ENTRIES IN THE TAPE INPUT QUEUE REPRESENT DATA INPUT FROM THE MAG- ; TAPE DRIVE, WHICH NEEDS TO BE OUTPUT TO THE DISK. THE ENTRIES IN THE ; DISK QUEUE ARE EMPTY BUFFERS. THIS ROUTINE COPIES MAGTAPE BUFFER ; INFORMATION STARTING WITH THE 1ST BUFFER IN THE QUEUE TO THE DISK ; BUFFERS, ONLY EXITING THE AST WHEN THERE ARE NO MORE BUFFERS AVAILABLE ; AT ANY TIME TO CONTINUE THE OPERATION. ; TPDKDQ: MOV #DSKLHD,R0 ; R0 = DISK LISTHEAD ADDRESS CMP R0,(R0) ; ANY OUTPUT BUFFERS AVAILABLE? BEQ 10$ ; NO - JUST EXIT AST MOV (R0),R0 ; R0 = BUFFER NODE ADDRESS MOV #TPLHD,R2 ; R2 = TAPE LISTHEAD ADDRESS CMP R2,(R2) ; ANY TAPE BUFFERS READY? BEQ 10$ ; NO - WAIT FOR SOME TO COME MOV (R2),R2 ; R2 = BUFFER ADDRESS BR 20$ ; CONTINUE 10$: ASTX$S ; ; THERE IS AT LEAST ONE INPUT BUFFER READY & ONE OUTPUT BUFFER AVAILABLE. ; SETUP ALL POINTERS, CALCULATE THE NUMBER OF BYTES TO COPY & THE AMOUNT ; OF SPACE LEFT IN THE DISK BUFFER. TRANSFER AS MUCH AS WILL FIT INTO ; THE DISK BUFFER. ; 20$: MOV N.PTR(R0),R1 ; R1 = REMAINING LENGTH IN DISK BUFFER SUB N.BUF(R0),R1 ; ... NEG R1 ; (R1 = -AMOUNT USED) ADD N.LEN(R0),R1 ; ... BLE 70$ ; NONE LEFT! MOV N.IOST+2(R2),R3 ; R3 = LENGTH OF TAPE BUFFER DATA BEQ 80$ ; NO TAPE DATA! CMP R1,R3 ; COMPARE REMAINING DISK TO TAPE BUFFER BHIS 40$ ; DISK BUFFER WILL HOLD IT ALL - CONTINUE SUB R1,R3 ; R3 = AMOUNT WHICH WILL NOT FIT MOV R3,N.IOST+2(R2) ; UPDATE THE AMOUNT WHICH REMAINS FOR TAPE MOV R1,R3 ; R3 = TRANSFER COUNT BR 50$ ; CONTINUE 40$: CLR N.IOST+2(R2) ; XFER WILL FIT - NO DATA WILL BE LEFT 50$: MOV N.PTR(R2),R4 ; R4 = FROM POINTER MOV N.PTR(R0),R5 ; R5 = TO POINTER ASR R3 ; R3 = XFER COUNT IN WORDS 60$: MOV (R4)+,(R5)+ ; COPY THE BUFFER SOB R3,60$ ; ... MOV R5,N.PTR(R0) ; RESTORE NEW BUFFER POINTER VALUES MOV R4,N.PTR(R2) ; ... ; ; WRITE OUT DISK BUFFER IF REQUIRED ; SUB N.BUF(R0),R5 ; R5 = AMOUNT OF BUFFER USED CMP R5,N.LEN(R0) ; COMPARE TO BUFFER SIZE BLO 80$ ; CONTINUE IF MORE ROOM LEFT 70$: MOV R0,R5 ; R5 = NODE ADDRESS CALL NODDEL ; DELETE THE NODE MOV R2,-(SP) ; SAVE R2 MOV #FDBOUT,R4 ; GET FDB ADDRESS 76$: MOV N.LEN(R0),R2 ; COPY BUFFER LENGTH ASH #-9.,R2 ; CHANGE IT TO BLOCKS INC R2 ; AND ROUND UP CLR R3 ; CLEAR HIGH ORDER ADD F.EFBK+2(R4),R2 ; ADD LOW ORDER CURRENT BLOCK ADC R3 ; ADD CARRY INTO HIGH ORDER ADD F.EFBK(R4),R3 ; ADD HIGH ORDER CURRENT BLOCK CMP R3,F.HIBK(R4) ; COMPARE ULTIMATE HIGH ORDER TO ; AMOUT ALLOCATED ALREADY BHI 71$ ; IF HIGH, MUST EXTEND CMP R2,F.HIBK+2(R4) ; COMPARE ULTIMATE LOW ORDER BLO 75$ ; IF LOW, THERE IS ROOM 71$: MOV R0,-(SP) ; PUSH NODE ADDRESS ON STACK MOV R4,R0 ; COPY FDB ADDRESS MOV SALOC,R1 ; GET SECONDARY ALLOCATION VALUE MOV #203,R2 ; SET CONTROL BITS FOR ENABLE, CONTIGUOUS ; (BUT FILE IS NOW NON-CONTIGUOUS) BIT #CONMSK,CSIFLG ; IS /CO SET? BNE 73$ ; YES, HENCE WANTED CONTIGUOUS BIC #7,R2 ; CHANGE CONTROL INDICATORS TO NON-CONTIGUOUS 73$: CALL .EXTND ; DO THE EXTEND BCC 74$ ; IF NO ERROR FROM EXTEND, GO ON MOV #ERR,FLAGS ; FLAG AN ERROR TST (SP)+ ; POP STACK BR 100$ ; GET OUT 74$: MOV (SP)+,R0 ; RESTORE NODE ADDRESS IN R0 BR 76$ ; GO BACK TO CHECK THAT INCREMENT WAS ENOUGH 75$: MOV (SP)+,R2 ; RESTORE R2 MOV R0,R1 ; COPY NODE ADDRESS TO R1 ADD #N.IOST,R1 ; R1 = IO STATUS BLOCK ADDRESS MOV #FDBOUT,R3 ; R3 = OUTPUT FDB POINTER MOV N.BUF(R0),R4 ; R4 = BUFFER ADDRESS MOV N.LEN(R0),R5 ; R5 = BUFFER LENGTH MOV F.BKVB(R3),N.BKH(R0) ; MOVE BLOCK# INTO NODE MOV F.BKVB+2(R3),N.BKL(R0) ; ... QIO$S #IO.WVB,#OUTLUN,,,R1,OUTVEC, ADD DSKFCT,F.BKVB+2(R3) ; UPDATE BLOCK NUMBER TO NEXT WRITE ADC F.BKVB(R3) ; ... MOV F.BKVB(R3),F.EFBK(R3) ; UPDATE EOF BLOCK# MOV F.BKVB+2(R3),F.EFBK+2(R3) ; ... ; ; QUEUE UP MAGTAPE FOR MORE INPUT IF BUFFER IS EMPTY ; 80$: TST N.IOST+2(R2) ; ANY MORE DATA TO XFER FROM THIS BUFFER? BEQ 81$ ; NO JMP TPDKDQ ; TRY TO DEQUEUE MORE WORK 81$: BIT #EOV,FLAGS ; DONE? BEQ 85$ ; NO - CONTINUE BIS #DONE,FLAGS ; YES - FLAG IT MOV #DSKLHD,R0 ; R0 = DISK LISTHEAD ADDRESS CMP R0,(R0) ; ANY ENTRIES IN LIST? BEQ 100$ ; NO - DONE MOV (R0),R0 ; R0 = DISK NODE ADDRESS CMP N.BUF(R0),N.PTR(R0) ; ANY DATA IN BUFFER? BNE 70$ ; YES - GO WRITE IT OUT BEQ 100$ ; GO RESUME MAIN TASK & EXIT 85$: MOV R2,R5 ; COPY NODE ADDR TO R5 CALL NODDEL ; DELETE THE NODE MOV R2,R3 ; COPY NODE ADDRESS TO R3 ADD #N.IOST,R3 ; R3 = IO STATUS ADDR MOV N.BUF(R2),R4 ; R4 = BUFFER ADDRESS TST (R4)+ ; ADVANCE OVER 1ST WORD IN BUFFER MOV N.LEN(R2),R5 ; R5 = LENGTH (MAX) FOR READ SUB #2,R5 ; REDUCE BY AMOUNT BUFFER WAS ADVANCED QIO$S #IO.RLB,#INLUN,,,R3,INVEC, JMP TPDKDQ ; TRY TO DEQUEUE MORE WORK 90$: ASTX$S ; EXIT THE AST 100$: RESUME ; RESUME THE MAIN TASK ASTX$S ; EXIT AST .SBTTL DISK TO TAPE OPERATIONS ; ; DISK TO TAPE ; ; THIS FUNCTION TRANSFERS DATA FROM THE DISK FILE TO MAGTAPE. THE ; MAGTAPE IS REWOUND PRIOR TO PROCESSING. ALL READS FROM DISK ARE ; MULTI-BLOCK QIO'S (ALSO MULTI-BUFFERED) TO TAKE ADVANTAGE OF THE ; HIGHER THROUGHPUT OF THE DISK. MAGTAPE OPERATIONS ARE ALSO MULTI- ; BUFFERED. ; DSKTTP: CLR FLAGS ; RESET ALL FLAGS CLR DSKERR ; RESET DISK ERROR VALUE CLR MTERR ; RESET MAGTAPE ERROR MOV #DSKIN,INVEC ; SETUP INPUT VECTOR MOV #TAPOUT,OUTVEC ; & OUTPUT VECTOR QIOW$S #IO.ATT,#OUTLUN,#1 ; ATTACH TO TAPE UNIT BIT #NRMSK,CSIFLG BNE 200$ ;DID HE SAY NO REWIND? QIOW$S #IO.RWD,#OUTLUN,#1 ; REWIND TAPE 200$: CLR R0 ;800 BPI DEFAULT BIT #HDMSK,CSIFLG ;1600 BPI TAPE? BEQ 201$ ;IF NOT LEAVE 800 MOV #4000,R0 ;IF SO SAY 1600BPI 201$: QIOW$S #IO.STC,#OUTLUN,#1,,,, ; SET TO 800BPI OR 1600BPI ; ; INITIALIZE & PALACE ALL TAPE BUFFERS IN OUTPUT QUEUE ; MOV #TPLHD,R0 ; R0 = TAPE BUFFER LISTHEAD MOV R0,R4 ; R4 = SAVED LISTHEAD ADDR MOV R4,(R0)+ ; SET LISTHEAD TO NULL MOV R4,(R0)+ ; ... 10$: MOV R0,R5 ; R5 = BUFFER NODE ADDRESS CALL NODADD ; ADD TAPE BUFFER TO LIST MOV N.BUF(R5),N.PTR(R5) ; INIT THE POINTER CLR N.WRK(R5) ; RESET 'NUMBER REMAINING BYTES' COUNT ADD #N.SIZE,R0 ; ADVANCE TO NEXT BUFFER CMP R0,#TPLND ; AT END OF TAPE BUFFERS? BLO 10$ ; NO - CONTINUE ; ; INITATE DISK I/O OPERATIONS FOR ALL AVAILABLE DISK BUFFERS ; MOV #DSKLHD,R0 ; R0 = DISK LISTHEAD POINTER MOV R0,R1 ; R1 = SAVE LISTHEAD ADDR MOV R1,(R0)+ ; INITIATE THE LISTHEAD TO NULL MOV R1,(R0)+ ; ... 20$: MOV N.BUF(R0),R2 ; R2 = BUFFER ADDRESS MOV R2,N.PTR(R0) ; INIT THE BUFFER POINTER MOV N.LEN(R0),R3 ; R3 = LENGTH OF READ MOV R0,R1 ; R1 = IO STATUS BLOCK ADDR ADD #N.IOST,R1 ; ... MOV #FDBINP,R5 ; R5 = INPUT FDB ADDRESS QIO$S #IO.RVB,#INLUN,,,R1,INVEC, ADD DSKFCT,F.BKVB+2(R5) ; UPDATE THE NEXT BLOCK NO. ADC F.BKVB(R5) ; ... ADD #N.SIZE,R0 ; ADVANCE TO NEXT BUFFER NODE BLO 20$ ; CONTINUE IF IN RANGE JMP WAIT ; ELSE GO WAIT FOR XFER TO COMPLETE .SBTTL DSKIN - DISK INPUT AST ROUTINE ; ; DSKIN - HANDLE DISK I/O DONE AST ; DSKIN: MOV (SP)+,R5 ; R5 = IO STATUS ADDRESS SUB #4,R5 ; POINT R5 TO NODE BEGINNING BIT #,FLAGS ; ANY ERRORS OR IS I/O COMPLETE? BNE 100$ ; YES - JUST EXIT THE AST TSTB N.IOST(R5) ; WAS THERE AN ERROR ON THIS XFER? BPL 50$ ; NO - CONTINUE CMPB #IE.EOF,N.IOST(R5) ; WAS IT EOF? BNE 90$ ; NO - REAL ERROR BIS #EOF,FLAGS ; FLAG EOF BR 100$ ; & IGNORE AST 50$: MOV N.IOST+2(R5),N.WRK(R5) ; COPY THE # BYTES XFERRED ADD N.BUF(R5),N.WRK(R5) ; POINT TO END BYTE + 1 MOV N.BUF(R5),N.PTR(R5) ; SETUP THE BEGINNING PTR MOV DSKLHD+2,R4 ; R4 = PRIOR (LAST) NODE IN LIST ADDR CALL NODADD ; ADD NODE TO END OF QUEUE JMP DKTPDQ ; GO TO MAIN DE-QUEUING ROUTINE 90$: QIOW$S #IO.KIL,#INLUN,#1,,#IOST ; CANCEL ALL OTHER DISK I/O'S BIS #ERR,FLAGS ; FLAG THE ERROR MOVB N.IOST(R5),DSKERR ;++AF1 SAVE DISK ERROR CODE BPL 95$ ;++AF1 SKIP IF POSITIVE (NOT LIKELY) MOVB #-1,DSKERR+1 ;++AF1 ELSE MAKE HI BYTE NEGATIVE ALSO 95$: RESUME ; CONTINUE THE MAIN TASK 100$: ASTX$S ; EXIT THE AST .SBTTL TAPOUT - TAPE OUTPUT I/O DONE AST ROUTINE ; ; TAPOUT - TAPE OUTPUT I/O DONE ROUTINE ; TAPOUT: MOV (SP)+,R5 ; R5 = I/O STATUS ADDRESS BIT #,FLAGS ; ERRORS OR DONE? BNE 100$ ; YES - JUST EXIT SUB #N.IOST,R5 ; ADJUST R5 TO POINT TO NODE BIT #ERMSK,CSIFLG ;TRYING TO IGNORE TAPE ERRORS? BEQ 200$ ;IF NOT, LOOK AT ALL CMPB N.IOST(R5),#IE.PRI ;TAPE UNMOUNTED? BEQ 90$ ;IF SO THEN DONE. IGNORE OTHER ERRORS CMPB N.IOST(R5),#IE.EOT BEQ 90$ CMPB N.IOST(R5),#IE.EOV BEQ 90$ ;ALLOW PRIV, EOT, OR EOV AS REAL. BR 201$ ;SKIP NORMAL TEST THEN 200$: TSTB N.IOST(R5) ; WAS THERE AN ERROR ON THE XFER? BMI 90$ ; YES - SO INDICATE 201$: MOV N.BUF(R5),N.PTR(R5) ; SETUP THE BUFFER POINTER CLR N.WRK(R5) ; RESET THE NO. BYTES LEFT TO XFER MOV TPLHD+2,R4 ; R4 = PRIOR (LAST) EXISTING NODE ADDR CALL NODADD ; ADD THE NODE TO FREE TAPE BUFFER LIST JMP DKTPDQ ; GO TO THE MAIN DE-QUEUING ROUTINE 90$: QIOW$S #IO.KIL,#OUTLUN,#1,,#IOST ; CANCEL ALL CURRENT I/O'S BIS #ERR,FLAGS ; FLAG THE ERROR MOVB N.IOST(R5),MTERR ;++AF1 SAVE ERROR CODE BPL 95$ ;++AF1 SKIP IF POSITIVE (NOT LIKELY) MOVB #-1,MTERR+1 ;++AF1 ELSE MAKE HI BYTE NEGATIVE ALSO 95$: RESUME ; CONTINUE EXECUTION OF MAIN TASK 100$: ASTX$S .SBTTL DKTPDQ - DISK TO TAPE DEQUEUE ROUTINE ; ; DKTPDQ- ; ; THIS ROUTINE INTERFACES THE DATA COMING IN A CONTINUOUS STREAM ; FROM THE DISK (IN MULTI-BLOCK BUFFERS) TO THE MAGTAPE OUTPUT. AS ; THE TAPE IS BLOCKED 512., IT IS DESIRABLE TO KEEP A CONSTANT NO. ; OF I/O REQUESTS QUEUED UP TO THE TAPE DRIVE, THEREBY ALLOWING ; THIS PROGRAM TO PAY FOR ITSELF. ; DKTPDQ: MOV #DSKLHD,R0 ; R0 = DISK LISTHEAD POINTER CMP (R0),R0 ; NULL LIST? BEQ 10$ ; YES - WAIT FOR WORK MOV (R0),R0 ; R0 = THE 1ST NODE ADDR IN LIST MOV #TPLHD,R2 ; R2 = TAPE OUTPUT LISTHEAD ADDR CMP (R2),R2 ; ANY NODES FREE FOR OUTPUT? BEQ 10$ ; NO - WAIT FOR SOME TO FREE UP MOV (R2),R2 ; R2 = ADDR OF 1ST FREE TAPE NODE BR 20$ ; CONTINUE 10$: ASTX$S ; EXIT AST ; ; TRANSFER DATA FROM THE CURRENT DISK BUFFER TO THE CURRENT TAPE BUFFER ; (NOTE THAT THIS MIGHT BE THE RESUMPTION OF A TRANSFER BEGUN EARLIER). WHEN ; THE TAPE BUFFER IS FILLED (OR THE OPERATION TYPE DETERMINED IF EOF), THE ; THE TAPE NODE IS DEQUEUED & THE OUTPUT INITIATED. WHEN A DISK BUFFER IS ; EMPTY, THE NEXT ONE IN THE QUEUE IS SERVICED. ; 20$: MOV N.WRK(R2),R3 ; R3 = REMAINING BYTES IF PARTIAL XFER BNE 30$ ; WAS A PARTIAL - CONTINUE IT MOV @N.PTR(R0),R3 ; ELSE, START OF NEW RECORD ADD #2,N.PTR(R0) ; ADVANCE OVER CONTROL WORD MOV R3,N.WRK(R2) ; SAVE IT AS SIZE REQ'D BEQ 70$ ; ZERO - GO WRITE EOF 30$: MOV N.WRK(R0),R1 ; R1 = ENDING DISK BUFFER ADDR SUB N.PTR(R0),R1 ; R1 = # BYTES LEFT IN BUFFER BEQ 80$ ; NO BYTES LEFT IN BUFFER! CMP R1,R3 ; WILL THIS BE A PARTIAL COPY? BHIS 40$ ; NO - ALL OF DATA IN DISK BUFFER SUB R1,R3 ; R3 = AMOUNT STILL REQ'D MOV R3,N.WRK(R2) ; UPDATE TAPE BUFFER REMAINING COUNT MOV R1,R3 ; R3 = ACTUAL NUMBER OF BYTES TO XFER BR 50$ ; CONTINUE 40$: CLR N.WRK(R2) ; INDICATE WHOLE XFER GOOD 50$: MOV N.PTR(R0),R4 ; R4 = FROM POINTER MOV N.PTR(R2),R5 ; R5 = TO POINTER ASR R3 ; R3 = WORD XFER COUNT 60$: MOV (R4)+,(R5)+ ; COPY THE DARA SOB R3,60$ ; ... MOV R4,N.PTR(R0) ; UPDATE THE DISK POINTER MOV R5,N.PTR(R2) ; & THE TAPE POINTER TST N.WRK(R2) ; DO WE WRITE THE TAPE BUFFER? BNE 80$ ; NO - SEE ABOUT DISK MOV N.BUF(R2),R4 ; R4 = TAPE BUFFER ADDRESS SUB R4,R5 ; R5 = NO. BYTES DATA IN BUFFER MOV R2,R3 ; R3 = THE IO STATUS ADDR ADD #N.IOST,R3 ; ... QIO$S #IO.WLB,#OUTLUN,,,R3,OUTVEC, BIC #EOV,FLAGS ; RESET THE END-OF-VOLUME TEST BIT BR 75$ ; CONTINUE 70$: MOV R2,R3 ; R3 = IO STATUS ADDR ADD #N.IOST,R3 ; ... QIO$S #IO.EOF,#OUTLUN,,,R3,OUTVEC BIT #EOV,FLAGS ; WAS EOV FLAG SET LAST TIME? BNE 100$ ; YES - TWO EOF'S = EOV BIS #EOV,FLAGS ; NO - SO SET IT FOR THIS EOF 75$: MOV R2,R5 ; R5 = NODE ADDRESS FOR DELETE CALL NODDEL ; DELETE THE NODE FROM THE QUEUE ; ; DETERMINE WHETHER CURRENT DISK BUFFER IS EMPTY & INITIATE A NEW READ IF SO ; 80$: CMP N.WRK(R0),N.PTR(R0) ; BUFFER EMPTY? BHI DKTPDQ ; NO - CONTINUE DEQUEUEING MOV R0,R5 ; R5 = NODE ADDR CALL NODDEL ; DELETE THE NODE FROM DISK QUEUE MOV R0,R1 ; R1 = IO STATUS ADDR ADD #N.IOST,R1 ; ... MOV N.BUF(R0),R4 ; R4 = BUFFER ADDR MOV N.LEN(R0),R5 ; R5 = NO. BYTES TO READ MOV #FDBINP,R3 ; R3 = FDB ADDR QIO$S #IO.RVB,#INLUN,,,R1,INVEC, ADD DSKFCT,F.BKVB+2(R3) ; UPDATE NEXT BLOCK# ADC F.BKVB(R3) ; ... JMP DKTPDQ ; CONTINUE 100$: BIS #DONE,FLAGS ; FLAG I/O DONE RESUME ; CONTINUE THE MAIN TASK ASTX$S ; EXIT AST .SBTTL --SUBROUTINES-- .SBTTL NODADD - ADD NODE TO DEQUE ; ; NODADD- ADD NODE TO DEQUE LIST ; ; INPUTS: R5 = NODE ADDRESS ; R4 = PRIOR NODE ADDRESS ; ; OUTPUTS: SAME ; NODADD: MOV R4,2(R5) ; SETUP BACKWARD POINTER MOV (R4),(R5) ; SETUP FORWARD POINTER MOV R5,(R4) ; SETUP PRIOR FORWARD POINTER MOV (R5),R5 ; POINT R5 TO NEXT NODE MOV (R4),2(R5) ; SETUP NEXT BACKWARD POINTER MOV (R4),R5 ; RESTORE R5 RETURN .SBTTL NODDEL - DELETE NODE FROM DEQUE ; ; NODDEL- DELETE NODE FROM DEQUEUE LIST ; ; INPUTS: R5 = NODE ADDRESS ; ; OUTPUTS: SAME ; NODDEL: MOV (R5),@2(R5) ; POINT PRIOR TO NEXT MOV (R5),-(SP) ; SAVE NEXT ADDRESS ADD #2,(SP) ; POINT TO NEXT BACWARD POINTER MOV 2(R5),@(SP)+ ; POINT NEXT BACKWARD TO PRIOR RETURN .END START