From e78a69be207d584e24b8dca621e97d5fa2bdfd31 Mon Sep 17 00:00:00 2001 From: Lars Brinkhoff Date: Fri, 21 Oct 2022 17:59:19 +0200 Subject: [PATCH] SALV - Salvager for the SITS file system. --- build/misc.tcl | 4 + build/timestamps.txt | 3 + doc/rjl/salvd.3 | 128 ++ src/rjl/flopdf.10 | 63 + src/sits/salv.175 | 3552 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 3750 insertions(+) create mode 100755 doc/rjl/salvd.3 create mode 100755 src/rjl/flopdf.10 create mode 100755 src/sits/salv.175 diff --git a/build/misc.tcl b/build/misc.tcl index b46fcdfe..46e1b51f 100644 --- a/build/misc.tcl +++ b/build/misc.tcl @@ -1634,6 +1634,10 @@ respond "*" ":cwd sits\r" respond "*" ":palx sits\r" expect ":KILL" +# Salvager for the SITS file system. +respond "*" ":palx salv\r" +expect ":KILL" + # TORTIS respond "*" ":midas;324 radia;_tortis\r" expect ":KILL" diff --git a/build/timestamps.txt b/build/timestamps.txt index 73d7b834..73778b56 100644 --- a/build/timestamps.txt +++ b/build/timestamps.txt @@ -1811,10 +1811,12 @@ reh/mmacro.51 198210111328.44 rg/chess2.614 197705140751.33 rjl/edit.memo 197509301913.38 rjl/files.31 197201301710.18 +rjl/flopdf.10 197705111553.50 rjl/logo.49 197303061208.18 rjl/logops.70 197303061151.09 rjl/lstops.11 197109150931.27 rjl/musops.21 197302212116.23 +rjl/salvd.3 197512150856.09 rjl/turops.67 197303061139.25 rjl/vecops.1 197107261022.12 rlb/fasdmp.124 197901090635.35 @@ -1904,6 +1906,7 @@ shrdlu/ts.twdemo 197110311544.38 sits/-read-.-this- 197503032229.00 sits/conven.3 197503051957.44 sits/docum.66 197607010317.17 +sits/salv.175 197711241704.25 sits/sitmac.6 197609212250.40 sits/sits.119 197712281629.08 sits/styi.207 197702231829.55 diff --git a/doc/rjl/salvd.3 b/doc/rjl/salvd.3 new file mode 100755 index 00000000..0ebd6513 --- /dev/null +++ b/doc/rjl/salvd.3 @@ -0,0 +1,128 @@ +SALV, the SITS/LOGO File System Checker + +Introduction + + The program called SALV is a utility program for the maintence of +disks for the SITS/LOGO systems. Its main function is to provide a consitency +check of the directory structure on the disks, but it also includes functions +for initializing format and file structure, and copying disks in various ways. +The purpose of this document is to aquaint the reader with both the theory +and the operation of SALV, and in particular give him enough information +to enable him to deal with both day-to-day file system maintence and the +many special problems that can arise. + +The SITS File System + + The SITS file system provides users of the SITS system with very flexible +ways of maintaining disk files. It makes no attempt to impose any restrictions +on the type and format of the data stored in the files, provided that that data +can be represented as an ordered vector of 16 bit words. It does, however, +impose a structure of 1directories0 in which files may be kept. That structure +is a strictly inverted tree, that is, pointers from directories must always +point downward in the structure. Also, no directory may be pointed at by +more or less than one other directory, except in the special case of the +1root0 directory, which no other directory points to. Now, we shall try to +clarify this. + +The Notion of Directory + + In the SITS file system, a directory is a vector of files and +inferior directories. The inferior directories may in turn contain +directories. Each entry in the vector has a name and a type and possibly +a version number. The entries are kept in alphabetical order by name, and +when names are the same, in numerical order by version number. Each entry +also contains a block descriptor which provides the disk addresses of zero +or more blocks that are associated with the file or directory described +by the entry. There are also two special entries at the beggining of each +directory which we will discuss later. + At the very top of the directory structure of each disk is the special +directory called the root. The main thing that is special about +the root directory is that its disk address is predefined. +The first block of the root directory of each logical disk resides on block 46 of that +disk. All other information about what is where on any given disk +can and must be determined by reading the root directory and +following the tree structure downwards to the file or directory of +interest. + +Files + + A file is a vector of 8 bit bytes stored in blocks of 1024 bytes +on the disk. Each byte has a number assigned to it called its 1address in the +file0. Thus, the first byte of a file is byte 0, the last byte in the +first block of a file is byte 1023, etc. A file has a length, which is the +byte address of the last byte of the file; this length is not restricted +to be a multiple of 1024, nor of 2. +Files may in theory be up to +2**25 (about 33.5 million) bytes long, but other restrictions reduce this. +It is possible for there to be 1holes0 in the file +these holes must start and end on file address which are a multiple of 1024, +that is, on block boundaries. These holes are not particularly useful +and we will attempt to avoid any futher discussion of them. + The directory entry for a file contains two pieces of information +that describe the file: the file address of the first byte which is +1not0 in the file, and an encoded list of the disk block addresses +where the bytes of the file reside. + In addition to the name and version number the file entry also +contains the date and time that the file was created. The file +entry also potentially contains an 1access list0 which would +restrict access to files to specified users, but neither LOGO nor +SITS support this feature. + +Operation of the SALV Program + + Now that the reader (hopefully) has a general idea of what the +file system looks like, we will switch topics drascially and discuss +the operation of the SALV program, particularlly it's user interaction. + The SALV program currently can only be run standalone, that is, +it cannot be run under the SITS timesharing system since it does +direct hardware disk operations, and also because the operation of +SITS could cause the file structure to become inconsistent. +SALV can either be loaded with RUG or directly from paper tape. +Its starting address is 1000, and it can be safely restarted at +(almost) any time. Restarting SALV is a perfectly valid way to +abort an operation. Generally, SALV is either waiting for command +input from the teletype or running performing some function +commanded from the teletype. It ignores typing while it is +performing a function. All functions are initated with one character +commands. Most functions also accept preceeding arguments or +require inputs. Some of the more drastic functions require +confirmation after they have described themselves. At +any time SALV is waiting for an input character the character +Z may be typed which will cause SALV to execute +a BPT instruction which should in turn cause RUG to be called, +if SALV was loaded by RUG. If SALV is then proceeded (type P +to RUG) you will reenter the typein wait you just left. +SALV can also be restarted (type G to RUG) to go +back to the beginning. The following commands take a 1 digit +number preceeding the command as input. The number specifies +which disk the command is to effect: + + C Check a disk. The main function of SALV. + + I Initialize a disk. + + F Format a disk. + +The following commands take no preceeding input: + + U Copy logigical disks 0 and 1 to logical disks + 2 and 3, i.e. copy the fixed platter up to the + removable platter on double density drives. + + D As U, but copy 2 and 3 to 0 and 1, i.e. + copy removable down to fixed. + + C Asks for two disk numbers and copies one logical + disk to another logical disk. + +(A note about the meaning of "logical disk": currently the only type +of disk supported by LOGO/SITS/SALV/RUG is the RK11 compatible units +made by DEC and others. The disk DEC makes has one disk per drive, +and each disk has 203. tracks; this corresponds to the standard +"logical disk". The drives made by Caleus and Wangco and supported by +IMS disk controllers have 2 disks in each drive, one fixed and one +removeable. Most of these have 203. tracks on each pyhsical disk +and thus coorespond to 2 logical disks, but there are drives that +have 406. tracks on each disk, and in this case, currently, each +pyhsical disk cooresponds to 2 logical disks, and therefore there +are 4 logical disks per drive. Clear?) \ No newline at end of file diff --git a/src/rjl/flopdf.10 b/src/rjl/flopdf.10 new file mode 100755 index 00000000..f468bce5 --- /dev/null +++ b/src/rjl/flopdf.10 @@ -0,0 +1,63 @@ +SMSCSR==177200 ;THE CSR FOR THE SMS TO PDP11 INTERFACE +SMSDBF==SMSCSR+2 ;THE DATA BUFFER BYTE +SMSCMD==SMSDBF+2 ;THE COMMAND BUFFER BYTE +SMSLGT==SMSCMD+2 ;LIGHT REGISTER +SMSBRV==270 ;TRAP VECTOR ADDRESS +SMSTV==SMSBRV +CLKBRV==100 ;CLOCK TRAP ADDRESS +SMSPRM==173000 ;PROM ADDRESS +SMSPRE==173376 ;LAST PROM ADDRESS (CONFIGURATION WORD) + SMS60H==1 ;IF THIS BIT IS ONE, MACHINE IS 60HZ, ELSE 50HZ +SMSRST==0 ;RESET COMMAND, SECOND BYTE IGNORED +SMSSEK==1 ;SEEK, OR WITH DISK DRIVE_3, SECOND BYTE TRACK ADDRESS +SMSRED==2 ;READ, OR WITH DISK DRIVE_3 AND: + SMSDTB==100 ;DISK TO BUFFER BIT + SMSBTH==200 ;BUFFER TO HOST BIT + ;SECOND BYTE ON READ IS SECTOR +SMSRID==3 ;READ NEXT SECTOR ID, OR WITH DISK DRIVE_3, SECOND BYTE IGNORED +SMSWRT==4 ;WRITE, OR WITH DISK DRIVE_3 AND: + SMSBTD==100 ;BUFFER TO DISK + SMSHTB==200 ;HOST TO BUFFER + ;SECOND BYTE ON WRITE IS SECTOR +SMSWRD==5 ;WRITE WITH DELETED DATA MARK, OTHERWISE SAME AS WRITE +SMSFMT==6 ;FORMAT THE TRACK THE HEADS ARE OVER + ;OR WITH DISK DRIVE_3, SECOND BYTE IS TRACK ADDRESS TO WRITE ON DISK +SMSSTS==7 ;READ STATUS, OR WITH DISK DRIVE_3, SECOND BYTE IGNORED + +;STATUS BITS IN CSR +SMSERR==100000 ;ERROR IN OPERATION +SMSRSB==40000 ;RESET BIT +SMSPWR==4000 ;POWER ON DISK DRIVES +SMSCLE==2000 ;CLOCK INTERUPT ENABLE +SMSST1==1000 ;STAT ID BIT 1 +SMSST0==400 ;STAT ID BIT 0 +SMSDNE==200 ;DONE +SMSINT==100 ;INT ENABLE +SMSBSY==40 ;BUSY +SMSCMW==20 ;WAITING FOR A COMMAND BYTE +SMSDDR==10 ;DATA DIRECTION +SMSFDO==4 ;FDC ON +SMSXFW==1 ;WAITING FOR XFR + +;STATUS BITS IN STATUS BYTE +;COMMAND STATUS +SMSITA==2 ;INVALID TRACK ADDRESS +SMSISA==4 ;INVALID SECTOR ADDRESS +SMSIBS==10 ;INVALID BUFFER SPEC +;DISK DRIVE STATUS +SMSDNR==1 ;DRIVE NOT READY +SMSDUS==2 ;DRIVE UNSAFE +SMSDWP==4 ;DRIVE WRITE PROTECTED +SMSNAM==10 ;NO ADDRESS MARKS FOUND +SMSSIP==40 ;SEEK IN PROGRESS +;OPERATION STATUS +SMSRWA==1 ;READ/WRITE ABORTED +SMSHPE==2 ;HEAD POSITIONING ERROR +SMSDAM==4 ;DATA ADDRESS MARK MISSING +SMSDOV==10 ;DATA OVERRUN +SMSSUR==20 ;SECTOR UNRECOVERABLE +SMSCRC==40 ;CRC ERROR +SMSRWC==100 ;READ/WRITE COMPLETE +SMSDDR==200 ;DELETED DATA READ + + \ No newline at end of file diff --git a/src/sits/salv.175 b/src/sits/salv.175 new file mode 100755 index 00000000..976a5bb8 --- /dev/null +++ b/src/sits/salv.175 @@ -0,0 +1,3552 @@ + .TITLE "SALVAGER" FOR THE SITS FILE SYSTEM +%COMPAT==0 +VERN==%FNAM2 + .STITL PARAMETERS + .ABS + +;WHEN INITING THE MOVING HEAD DISK +;RUG WANTS BLOCKS 0,4-23, AND 54-217 ON DISK 0 +;LOGO WANTS 100-1100 FOR SWAPPING ON DISK 1 + +;WHEN INITING THE FIXED HEAD DISK +;RUG WANTS BLOCKS 0,4-23, AND 54-217 +;LOGO WANTS 500-1777 FOR SWAPPING + +;FOR FLOPPY DISK BLOCKS 0-3 (2K WORDS) +;SHOULD BE RESERVED FOR THE BOOT PROGRAM +.INSRT SITS;SITMAC > +.IIF NDF FLOP,FLOP==0 +.IIF NZ FLOP,.INSRT RJL;FLOPDF > +.IIF NDF LSI,LSI==0 +.IIF NDF OFLOP,OFLOP==0 + + + + A=%0 + B=%1 + C=%2 + D=%3 + E=%4 + F=%5 + P=%6 + PC=%7 + .XCREF A,B,C,D,E,F,P,PC + + DISKWR==3 + DISKRD==5 + DISKWC==7 + WCERR==1 + + TBUFLN==100 + +.IIF Z LSI, SWB=177570 ;DATA SWITCHES +.IFZ FLOP + RKER=177402 ;MOVING HEAD DISK REGS + RKCS=177404 + RKWC=177406 + RKBA=177410 + RKDA=177412 + + ONEDSK==20000 + PLATR1==20000 + PLATR2==40000 + PLATR3==60000 +.IFF + ONEDSK==10 +.ENDC +.IFZ 105 + DSKS=177460 ;FIXED HEAD DISK REGS + DSKWC=177462 + DSKCA=177464 + DSKA=177466 + DSKAE=177470 + DSKDBR=177472 +.ENDC + NRETRY==30 + + + +;STACK FRAME OFFSETS + FFBCKP==0 ;BY DEFINITION; POINTS TO PREV. STACK FRAME + FENTRP==FFBCKP+2 ;ORIG. ADDR OF THIS ENTRY; FOR ALFORD + FNXNTRY==FENTRP+2 ;NEXT ENTRY OF PUSHED DIRECTORY + FDDESC==FNXNTRY+2 ;DESCRIPTOR OFFSET IN THIS ENTRY + FDBYTES==FDDESC+2 ;DESCRIPTOR LENGTH + FENTRY==FDBYTES+2 ;START OF ACTUAL ENTRY + +;ENTRY TYPES (TIMES 2 FOR DISPATCHING) +;A TYPE AS SEEN HERE, * 1000, = A TYPE AS IN TYPE FIELD + PARENT==0 + DIREC==2 + FILE==4 +; LAST==6 + SELF==10 + LINK==12 + ALFORQ==14 + BITS==16 + +;BITS IN FLAG BYTE + MFISTB==1 ;BLOCK EXISTS BIT (EOF POINTS TO EXISTING BLOCK) + TYPEM==177761 ;TYPE FIELD MASK + SHRB==20 ;SHARED BLOCK FLAGS (DON'T CLEAR IN BIT TABLE) + ACCB==100 ;ACCESS CODES EXIST + EOFB==200 ;EOF, DATE-TIME EXISTS + +;DESCRIPTOR BYTE TYPES + DTYPEF==300 ;TYPE-OF-DESCRIPTOR-BYTE FIELD + DTSKP==0 ;SKIP N AND GRAB 1 BLOCK + DTCNT==100 ;GRAB N+1 BLOCKS + DTHOL==140 ;HOLE OF N+1 BLOCKS + DTSADR==200 ;GRAB N+1 BLOCKS STARTING AT X (SET ADDR) + DTSKCT==300 ;SKIP N1 AND GRAB N2+1 BLOCKS + DTCNTF==77 ;FOR FIRST THREE TYPES, THE N FIELD + DTSCSK==70 ;FOR SKIP/COUNT, THE SKIP FIELD N1 + DTSCCT==7 ; " " , THE COUNT FIELD N2 + +;CACHE CODING CONSTANTS + SSR0=177572 + SSR1=177574 + SSR2=177576 + SSR3=172516 + KIAR=172340 + KIDR=172300 + KDAR=172360 + KDDR=172320 + +.IIF NDF SGMNTR, SGMNTR==1 ;1 MEANS SEGMENTER ON; 0 MEANS OFF + BEBRV=4 ;BUS ERROR BPT VECTOR + + MYPAG==5 ;I-SPACE PAGE CHOSEN FOR ALTERATION + MYPAR==KIAR+ ;ADDR OF PAGE ADDR REG (PAR) CORRES TO MYPAG + MYADDR==MYPAG*20000 ;BEG. LOC OF MYPAG + MYOPAD==MYPAG*200 ;BASE ADDR (IN PAR) OF MYPAG + + + + .STITL MACROS +.MACRO FPUSH X + .XLIST + MOV X,(F)+ + .LIST +.ENDM + +.MACRO PUSH X + .XLIST + MOV X,-(P) + .LIST +.ENDM + +.MACRO POP X + .XLIST + MOV (P)+,X + .LIST +.ENDM + +.MACRO TEXT X + .XLIST + .ASCII ØŠ .BYTE 0 + .EVEN + .LIST +.ENDM + +.MACRO TYPEIT X + .XLIST + JSR F,TXTYPE + TEXT ^ØŠ .LIST +.ENDM + +.MACRO ERROR X + .XLIST + JSR PC,ERRORX + TYPEIT ^/Error--'X/ + JSR PC,@(P)+ + .LIST +.ENDM + +.MACRO ENTERR X + .XLIST + JSR PC,ERRORX + TYPEIT ^/Error--entry / + MOV ENTRYP,B + JSR PC,NAMOUT + TYPEIT ^/X/ + JSR PC,@(P)+ + .LIST +.ENDM + +.MACRO BUG X + .XLIST + JSR PC,ERRORX + TYPEIT ^/Bug--'x/ + JSR PC,@(P)+ + .LIST +.ENDM + +.MACRO MSG X + .XLIST + JSR PC,ERRORX + TYPEIT ^/X/ + JSR PC,@(P)+ + .LIST +.ENDM + +.MACRO FLTEXT X + .XLIST + .IRPC XC,^/X/ + .IFNZ .LENGTH ^/X/,-<.IRPCN+1> + .LIST + .BYTE ''XC + .XLIST + .IFF + .LIST + .BYTE 200+''XC + .XLIST + .ENDC + .ENDM + .LIST +.ENDM + .STITL SET TRAP VECTORS TO HALT +.=0 +.REPT 100 +.XLIST +.+2 +HALT +.LIST +.ENDR + .STITL VARIABLES AND THINGS + .=1000 + JMP SALV +.IF NZ FLOP + .=300 + JMP SALV +.ENDC + .=2000 +PDL==. +;PDP10 COMMUNICATION AREA +;NOTE THAT THE 10 ACTS AS A SLAVE TO THE 11 +COMPNT==40 ;POINTER TO 10-11 COM AREA +.=<.!77>+1 ;COM AREA MUST START ON MULTIPLE OF 100 BOUNDARY +ELVRDY: 0,0 ;NON-ZERO IMPLIES 11 HAS DATA TO TRANFER + ;OR IS READY FOR NEXT TRANSFER +TENFUN: 0,0 ;DIRECTION OF TRANSFER + ;0=> NO TRANSFER + ;1=> WRITE TO PDP10 + ;-1=> READ FROM PDP10 +TENRDY: 0,0 ;NON-ZERO IMPLIES TEN HAS DATA TO TRANSFER + ;OR IS READY FOR NEXT DATA +TENBUF: 0,&1777 ;BUFFER ADDRESS + +.IFNZ SGMNTR +LCSLOT: -1 ;NEXT SLOT TO THROW SOMEONE OUT OF +NCBLKS: 0 ;NUMBER OF BLOCKS TO USE FOR CACHE +MEMHGH: 0 ;HIGHEST MEMORY ADDRESS +CBLKTB: .BLKW 200. ;GREATEST NO. CACHE BLKS POSSIBLE ON ANY PDP-11 +.ENDC +DSKEM: 0 ;EXTENDED MEMORY BITS FOR DISK ROUTINES +ERRCNT: 0 ;COUNT OF ERRORS ON THIS CHECK +.IF Z FLOP +BACKCN: 203.*12. +BACKIN: 1 +BACKTL: -1000 +.IFF +BACKCN: 19. +BACKIN: 13. +BACKTL: -13.*1000 +.ENDC +RUGDSK: 0 ;SET WHEN INITING A RUG DISK +OLDDSK: 0 ;OLD DISK FUNCTION TO REPEAT ON WRITE CHECK ERROR +NDISK: 0 ;NEW DISK POSITION +NBLOKS: 0 ;COUNT OF BLOCKS IN FILE +DSCEOF: 0 ;END OF DISK DESCRIPTOR FILE +TOFIND: 0 ;ADDR OF ENTRY NAME TO BE FOUND +DIREND: 0 ;END OF DIRECTORY (AS SET BY LOADIR) +FBACKP: 0 ;POINTS TO PARENT ENTRY OF THIS DIRECTORY +NEXTF: 0 ;POINTS TO NEXT AVAILABLE F-STACK FRAME +ENTRYP: 0 ;POINTS TO CURRENT ENTRY IN CURRENT DIRECTORY +NXNTRY: 0 ;TO NEXT ENTRY IN CURR. DIR. +ETYPE: 0 ;TYPE * 2 OF THIS ENTRY +NBYTES: 0 ;LENGTH OF ENTRY +FLAGS: 0 ;RANDOM FLAGS IN ENTRY +DDESCR: 0 ;OFFSET OF DISC BLOCK DESCRIPTOR +DBYTES: 0 ;LENGTH OF DESCRIPTOR +DSCEND: 0 ;POINTS TO END OF DESCRIPTOR + ;(CAN BE FOUND BY FTYPE) + +VN: 0 ;SLOT FOR VERSION NUMBER, IN ALFORD. +OENTRY: 0 ;PTS TO PREV. ENTRY IN CURR. DIR., FOR ALPH. ORD. +OTYPE: 0 ;IS IT A PARENT OR SELF ENTRY +OFLAGS: 0 ;HAS IT A VERSION NUMBER +OVN: 0 ;ITS VERSION NUMBER + +BITFND: 0 ;BIT FOUND SET IN BITTABLE 2 BY CKBIT2 +BITLIM: 0 ;FIRST !BYTE! AFTER END OF BIT TABLE +BITSAT: 0 ;HOW MUCH OF BIT TABLE YOU'VE TRANSFERRED SO FAR +DIRCNG: 0 ;HAS THE DIRECTORY BEEN MODIFIED +DISKIO: 0 ;DIRECTION OF TRANSFER (DISKRD OR DISKWR) +BLOKNO: 0 ;BLOCK NUMBER OF CURRENT DISK BLOCK +BLKLIM: 0 ;FIRST BLOCK NO. NOT ON DISK +RNG01F: .BYTE 0 ;FLAGS FOR BCOMP, TO MANAGE GROUPING OF BITS +RNG10F: .BYTE 0 ; THAT DISAGREE IN OLD AND NEW BIT TABLES. + ;0 = NO SEQUENCE, 1 = SINGLETON, + ;2 = SEQ OPEN, BE SURE TO CLOSE IT +RANYBQ: 0 ;STAYS 0 IF NO BAD BITS SEEN. +WCHDSK: 0 ;WHICH PLATTER +PRINTF: 0 ;FLAG FOR DOING PRINT OF DISK INFO +BLOKDO: 0 ;WHAT TO DO WHEN DMARCH SAYS "BLOCK # N" +RETRYS: 0 ;# RETRYS LEFT BEFORE COMPLAINT +DSKERR: 0 ;DISK ERROR WORD +ERNTRYP:0 ;POINTS TO LAST STACKED ENTRY VISITED BY BACKTRACE +BKFBKP: 0 ;BACKTRACE'S STACK POINTER AS IT TRACES BACK + +NCHR: 0 ;NUMBER OF CHARS IN TYPEIN BUFFER +TBUFPT: 0 ;PTR INTO BUFFER: FILLING AND EMPTYING +RUBING: 0 ;NON-0 MEANS RUBBING OUT CHARS + + +TRNSLE: -1000 ;TRANSFER LENGTH +DOWHAT: 0 ;ADDRESS OF DISPATCH TABLE FOR ENTRY TYPES + +DSKSIZ: +.IF NZ FLOP +.IIF NZ OFLOP,250. +.IIF Z OFLOP,247. +.ENDC +.IIF Z FLOP,4604 + +.IFNZ FLOP +;FLOPPY DISK DATA AREA +FLOPTR: 0 ;CURRENT TRACK ADDRESS +FLOPSC: 0 ;CURRENT SECTOR +FLOPNS: 0 ;REAL SECTOR AFTER MUNGING +FLOPSS: 0 ;SAVED SECTOR NUMBER +FLOPWC: 0 ;UNEXPIRED PART OF WORD COUNT +FLOPHW: 0 ;HALF OF WORD COUNT +FLOPCA: 0 ;CORE ADDRESS +FLPSCA: 0 ;SAVED CORE ADDRESS +ERRDAT: 0 ;DATA FROM LAST ERROR +ERRST: 0 ;TYPE OF LAST ERROR +FLPTYP: OFLOP ;NON-ZERO => OLD FORMAT +.ENDC + + .SBTTL DISPATCH TABLES +DSPTAB: SALVQ ;^@ + SALVQ ;^A + SALVQ ;^B + COPY ;^C + CNTLD ;^D + SALVQ ;^E + FRMT ;^F + SALVQ ;^G + SALVQ ;^H + SALVQ ;^I + SALVQ ;^J + SALVQ ;^K + SALVQ ;^L + SALVQ ;^M + SALVQ ;^N + SALVQ ;^O + SALVQ ;^P + SALVQ ;^Q + SALVQ ;^R + SCAN ;^S + TENCOM ;^T + CNTLU ;^U + SALVQ ;^V + SALVQ ;^W + SALVQ ;^X + SALVQ ;^Y + SALVQ ;^Z + SALVQ ;^[ + SALVQ ;^\ + SALVQ ;^] + SALVQ ;^^ + SALVQ ;^_ + SALVQ ; + SALVQ ;! + SALVQ ;" + SALVQ ;# + SALVQ ;$ + SALVQ ;% + SALVQ ;& + SALVQ ;' + SALVQ ;( + SALVQ ;) + SALVQ ;* + SALVQ ;+ + SALVQ ;, + SALVQ ;- + SALVQ ;. + SALVQ ;/ + SALVN ;0 + SALVN ;1 + SALVN ;2 + SALVN ;3 + SALVN ;4 + SALVN ;5 + SALVN ;6 + SALVN ;7 + SALVQ ;8 + SALVQ ;9 + SALVQ ;: + SALVQ ;; + SALVQ ;< + SALVQ ;= + SALVQ ;> + SALVEX ;? + SALVQ ;@ + SALVQ ;A + BLOCKT ;B + CHECK0 ;C + SALVQ ;D + SALVQ ;E + SALVQ ;F + GOGOGO ;G + SALVQ ;H + INIT0 ;I + SALVQ ;J + SALVQ ;K + SALVQ ;L + SALVQ ;M +.IFNZ FLOP + NEW ;N + OLD ;O +.IFF + SALVQ + SALVQ +.ENDC + PRINTD ;P + SALVQ ;Q +.IIF Z FLOP, SALVQ ;R +.IIF NZ FLOP, REFRMT + SCAN ;S + TRACKT ;T + SALVQ ;U + SALVQ ;V + SALVQ ;W + SALVQ ;X + SALVQ ;Y +.IIF NZ FLOP,SALVQ +.IIF Z FLOP,ZERO ;Z + SALVQ ;[ + SALVQ ;\ + SALVQ ;] + SALVQ ;^ + SALVQ ;_ + SALVQ ;` + SALVQ ;a + BLOCKT ;b + CHECK0 ;c + SALVQ ;d + SALVQ ;e + SALVQ ;f + GOGOGO ;g + SALVQ ;h + INIT0 ;i + SALVQ ;j + SALVQ ;k + SALVQ ;l + SALVQ ;m +.IFNZ FLOP + NEW ;N + OLD ;O +.IFF + SALVQ + SALVQ +.ENDC + PRINTD ;p + SALVQ ;q +.IIF Z FLOP, SALVQ ;R +.IIF NZ FLOP, REFRMT + SCAN ;s + TRACKT ;t + SALVQ ;u + SALVQ ;v + SALVQ ;w + SALVQ ;x + SALVQ ;y +.IIF NZ FLOP,SALVQ +.IIF Z FLOP,ZERO ;z + SALVQ ;{ + SALVQ ;| + SALVQ ;} + SALVQ ;~ + SALVQ ;Š +CKTAB1: CKPAR ;DISPLATCH TABLE FOR PASS 1 (FIND SHARED BLOCKS) + CKDIR + CKFILE + CKLAST + CKSELF + CKLINK + ALFORD ;YES, CHECK ALPHABETICAL ORDER + SETB12 ;SET BIT TABLE 1, "OVERFLOW" TO TABLE 2 + +CKTAB2: C2PAR ;DISPATCH TABLE FOR PASS 2 (MARK FILES SHARING BLOCKS) + C2DIR + C2FILE + C2LAST + C2SELF + C2LINK + SKPPNM ;SKIP PAST THE NAME + CKBIT2 ;SET DON'T DELETE FLAGS IF TABLE 2 SET + + +LOADX: LODSKP + LODCNT + LODSAD + LODSC + +RTSPC: RTS PC + +BITSE: FLTEXT ^/BITS/ ;NAME OF BIT TABLE FILE +DESCRE: FLTEXT ^/DESCR/ ;NAME OF DISK DESCRIPTOR FILE + .EVEN + +TBUF: .=.+TBUFLN + 0 ;JUST IN CASE + .STITL !THE! !SALVAGER!!! +SALV: RESET ;INIT THE BUSS + MOV #PDL,P ;INIT THE STACK POINTER + MOV #-1000,TRNSLE ;INIT TRANSFER LENGTH + +.IFNZ SGMNTR + JSR PC,SEGSET ;TURN ON SEGMENTER + JSR PC,MEMTST ;FIND NO. 512-WORD BLKS IN HIGH MEMORY +.ENDC + JSR PC,ITYI ;INIT THE TYI + TYPEIT ^/_SALV / ;_ MAKES A CRLF + MOV #VERN,B + JSR PC,DECOUT +SALV2: MOV #PDL,P +.IF NZ FLOP + JSR PC,DSKOFF + CLR SMSLGT +.ENDC + TYPEIT ^/_*/ +SALV5: JSR PC,TYI1 + MOV A,B + ASL B +.IIF NZ FLOP, JSR PC,DISKON + JSR PC,@DSPTAB(B) + BR SALV2 + +SALVN: SUB #'0,A + MOV A,WCHDSK ;SET THE VARIABLE + BR SALV5 +SALVQ: MOV #PDL,P + TYPEIT ^/ ?/ + BR SALV2 +.IFZ 105 +FXB0I0: TYPEIT ^/ixed head disk block 0 init_sure? / + JSR PC,TYI1 + CMP #' ,A + BEQ GOFXB0 + CMP #'Y,A + BNE SALVQ +GOFXB0: JSR PC,CRLF + JMP FXINIT +.ENDC +INIT0: TYPEIT ^/nit_sure?/ + JSR PC,TYI1 + CMP #' ,A + BEQ GOINIT + CMP #'Y,A + BNE SALVQ +GOINIT: JSR PC,CRLF + JMP INITD + +CHECK0: TYPEIT ^/heck_/ + JSR PC,CHECK + JMP SALV2 + +GOGOGO: MOV #4,-(P) + CLR WCHDSK +1$: JSR PC,CHECK + INC WCHDSK + DEC (P) + BNE 1$ +.IFZ LSI + JMP 157002 ;EXIT TO SITS +.IFF + JMP 173000 ;FIX LATER +.ENDC + +.IFNZ FLOP +SALVEX: TYPEIT ^/ +B Set for block at a time copies +C Check disk +C Copy disk to disk. Asks for From: and To: +F Format disk +I Initialize disk +N New format +O Old format +P Print info about disk while checking it +R Reformat disk from old format to new +S Scan disk for bad blocks +T Set for track at a time copies (normal state) +0-3 Set disk number to use (except for copy) +/ + JMP SALV2 +.IFF +SALVEX: TYPEIT ^& +B Set for block at a time copies (normal state) +C Check disk +C Copy disk to disk. Asks for From: and To: +D Double density mass copy down +F Format disk +I Initialize disk +P Print info about disk while checking it +S Scan disk for bad blocks +T Set for track at a time copies +T Set up for disk copy to/from PDP10 +U Double density mass copy up +0-3 Set disk number to use (except for copy) +& + JMP SALV2 +.ENDC + + + + .IFZ 105 + .STITL WRITE OUT AN INITIAL BLOCK 0 ON FIXED HEAD DISK. +FXINIT: MOV #FHIDIR,A ;POINT TO THE IMAGE + MOV #DSKBUF,B ;WHERE TO PUT IT + MOV #</2>,C ;THE LENGTH IN WORDS + MOV #2000,D ;THE LENGTH OF A DISK BLOCK + MOV (A)+,(B)+ ;COPY IT + SOB C,.-2 + CLR (B)+ ;CLEAR OUT THE REST + SOB D,.-2 + PUSH WCHDSK ;SAVE THE DISK + CLR BLOKNO ;WRITE BLOCK 0 + MOV #-1,WCHDSK ;SAY THE FIXED DISK + JSR PC,DSKWR1 ;WRITE IT + POP WCHDSK + JMP SALV2 ;ALL DONE, THIS DISK CAN'T WRITE-CHECK. +.ENDC + + .STITL CHECK THE FILE SYSTEM +CHECK2: MOV #FBASE,F + MOV F,NEXTF + MOV F,FBACKP + MOV F,ERNTRYP + MOV #-1,BLKLIM ;ALLOW ANY BLOCK # TILL YOU GET THE BIT TABLE + MOV #46,BLOKNO + JSR PC,DIRBLR ;GET FIRST BLOCK OF HEADER + MOVB DIR+1,FLAGS ;GET ROOT HEADER FLAGS + MOV #DIR,B ;GET THE END OF THE DIRECTORY + ADD 6(B),B ;ADD THE EOF WORD TO THE POINTER + MOV B,DIREND ;SAY IT IS THE END OF THE DIRECTORY + MOV #DIR,ENTRYP ;POINT TO THE SELF ENTRY + JSR PC,TYPEWD ;GET READY TO PUSH IT ONTO THE F STACK + JSR PC,SKIPVN ;MAKE SURE THERE IS A DIRID + ADD #10,E ;SKIP EOF AND DATE TIME + JSR PC,SKPACC ;SKIP THE ACCES CODES + JSR PC,SKPNAM ;SKIP THE NAME + JSR PC,ATDESC ;ALL SET TO STACK + MOV #DIR+14,A + MOV #DIR+4,B ;KLUDGE FIRST DIRECTORY ENTRY + MOV DDESCR,C + ADD #DIR,C ;POINT TO THE FIRST OF DESCR. +CHECK1: MOVB (A)+,(B)+ ;COPY IT + CMP A,C + BLO CHECK1 + MOVB #200,(B)+ + MOVB #46,(B)+ + CLRB (B)+ ;FAKE DESCRIPTOR + CLRB (B)+ + BIC #1,B ;ROUND IT + MOVB B,DIR ;FAKE LENGTH + BIC #EOFB*400,DIR ;ELIMINATED THE EOF WORD + JSR PC,TYPEWD + JSR PC,SKIPVN + JSR PC,SKPACC + JSR PC,SKPNAM + JSR PC,ATDESC + JSR PC,PSHDIR ;SET UP BASE OF F-STACK + MOV #-1,BLKLIM ;ALLOW ANY BLOCK # + JSR PC,LOADIR ;GET WHOLE ROOT DIRECTORY + MOV #BITSE,TOFIND + JSR PC,FINDE ;FIND BITS FILE + BEQ CKSYS1 + ERROR ^/NO BITS FILE/ +CKSYS1: MOV #FSTBLK,BLOKDO + JSR PC,EDMARCH +.IFNZ FLOP + TST FLPTYP ;OLD OR NEW? + BNE 1$ ;OLD STYLE + CMP #247.,DSKBUF ;ALREADY FIXED? + BEQ 1$ + TYPEIT <_Fixing size of disk to 247._> + MOV #247.,DSKBUF + MOV PC,RANYBQ ;CAUSE BIT TABLE TO BE WRITTEN OUT +1$: +.ENDC + MOV DSKBUF,BLKLIM ;FIRST WORD OF FILE IS DISK LENGTH + JSR PC,DESRF ;SET UP DESCRIPTOR FILE +CKSYS2: RTS PC + +DESRF: MOV #DESCRE,TOFIND + JSR PC,FINDE ;FIND DISK DESCRIPTOR FILE + BEQ CKSYS4 + ERROR ^/NO DISK DESCRIPTOR/ +CKSYS4: JSR PC,L1BLKF ;LOAD 1-BLOCK FILE + MOV B,DSCEOF ;L1BLKF RETURNS EOF ADDR IN B + MOV #DSKBUF+2,E ;START AFTER THE BASE YEAR + MOV #2,D ;2 SWAP AREAS + TST PRINTF + BEQ SRES1 + TYPEIT +SRES1: MOV (E)+,BLOKNO ;AREA STARTING AT BLOCK NO. + MOV (E)+,C ;SO MANY BLOCKS + BEQ SRES3 ;NO BLOCKS +SRES2: TST PRINTF + BEQ 1$ + SAVE A + MOV BLOKNO,A + JSR PC,PRONL + TYPEIT <-> + ADD C,A + JSR PC,PRONL + TYPEIT < > + REST A +1$: JSR PC,BTADR ;SET BIT FOR ONE BLOCK + BISB A,DBITS2(B) + INC BLOKNO + SOB C,1$ +SRES3: SOB D,SRES1 +SRES4: TST PRINTF + BEQ 2$ + TYPEIT <_Reserved: > +2$: CMP E,DSCEOF ;RESERVED BLOCKS WORDS TO END OF FILE + BNE CKIT1 ;EOF: BIT TABLE ALL SET! + TST PRINTF + BEQ 1$ + TYPEIT <_> +1$: RTS PC +CKIT1: BLO SRES5 + ERROR ^/DISK DESCRIPTOR EOF OUT OF SYNC?/ +SRES5: MOV (E)+,B ;WORD OFFSET IN BIT TABLE + MOV (E)+,A ;MASK OF RESERVED BLOCKS + BIS A,DBITS2(B) ;SET WHOLE WORD + TST PRINTF + BEQ SRES4 + SAVE A + MOV B,A + JSR PC,PRONL + REST A + TYPEIT < > + JSR PC,PRONL + BR SRES4 + + + +PRINTD: MOV PC,PRINTF + BR CHECKP + + +CHECK: CLR PRINTF ;CLEAR SPECIAL PRINT FLAG +CHECKP: +.IIF NZ SGMNTR, JSR PC,CACHNT ;INITIALIZE CACHE BLK NO. TABLE + CLR ERRCNT ;NO ERRORS SO FAR + CLR RANYBQ ;NO BIT TABLE ERRORS SO FAR + MOV #DBITS1,A ;CLEAR BOTH BIT TABLES + MOV #20000,B ;2*4K WORDS + CLR (A)+ + SOB B,.-2 + JSR PC,CHECK2 + TYPEIT ^\Checking disk \ + MOV #DIR,B + JSR PC,NAMOUT + JSR PC,CRLF +CKIT: MOV #CKTAB1,DOWHAT ;CHECK THE WORLD PASS 1! + JSR PC,DOROOT + MOV #DBITS2,A ;GET ALL THE USED BLOCKS -> TABLE 1 + MOV #DBITS1,B + MOV #10000,C ;EACH TABLE 4K WORDS LONG + BIS (A)+,(B)+ ;.OR. TABLE 2 INTO TABLE 1 + SOB C,.-2 + MOV #CKTAB2,DOWHAT ;CHECK FOR SHARED BLOCKS! + JSR PC,DOROOT + ;FINALLY: + ;1: COMPARE BIT TABLE 1 WITH DISK. + MOV BLKLIM,A ;GET LENGTH OF BIT TABLE IN BYTES + DEC A ;(JUST FOR DMARCHING) + ASH #-3,A + INC A ;FIRST BYTE AFTER BIT TABLE + BIC #160000,A ;CLEAR SIGN EXTEND + MOV A,BITLIM + + MOV #BITSE,TOFIND + JSR PC,FINDE + + MOV #BITSRD,BLOKDO + JSR PC,BITSIO ;READ IN THE BIT TABLE INTO TABLE 2 + + CLR C ;DO THE COMPARE: STOP WHEN BLOCK NO. = BLKLIM + CLR RNG01F ;ASSERT NO 0->1 OR 1->0 (CLRS BOTH FLAGS) + MOV #DBITS1,D + MOV #DBITS2,E + +BCOMP1: MOV (D),A + MOV (E),B + BIC (E)+,A ;GET DBITS1 - 2: MARKING A "FREE" BLOCK + BIC (D)+,B ;GET DBITS2 - 1: MARKED BUT NOT FOUND + + MOV #20,F +BCOMP2: ASHC #-1,A ;RIGHT SHIFT ONE BOTH + BCC 1$ + JSR PC,BAD10 ;FOUND A 2-1 (1 -> 0) + BR BCOMP4 +1$: + TST B + BGE 2$ + JSR PC,BAD01 ;FOUND A 1-2 (0 -> 1) BAD NEWS + BR BCOMP4 +2$: + JSR PC,BCGOOD + +BCOMP4: INC C ;COUNT THE BLOCK + CMP C,BLKLIM ;EXIT IF ALL BLOCKS DONE ON DISK + BHIS BCOMP3 + SOB F,BCOMP2 + BR BCOMP1 + +BCOMP3: JSR PC,BCGOOD + TYPEIT ^/Disk / + MOV #FBASE+FENTRY,B + JSR PC,NAMOUT + TYPEIT ^/ refreshed_/ + TST RANYBQ ;CHANGED ANY BITS? + BEQ NWRITE + TST ERRCNT ;ANY ERRORS? + BEQ WRITEB + TYPEIT ^/Write bit table? / + JSR PC,TYI1 + CMP #'Y,A + BNE NWRITE ;DO IT + TYPEIT ^/_Are you sure you know what you are doing?/ + JSR PC,TYI1 + CMP #'Y,A + BNE NWRITE ;DO IT + +WRITEB: JSR PC,CRLF + + ;2: STORE TABLE 1 AS NEW BIT TABLE + MOV #BITSWR,BLOKDO + JSR PC,BITSIO ;WRITE OUT NEW BIT TABLE + + + TYPEIT ^/written_/ +NWRITE: MOV #DBITS1,C + MOV BLKLIM,B + CLR A + MOV #1,D +3$: BIT D,(C) + BNE 1$ + INC A +1$: ASL D + BCC 2$ + TST (C)+ + MOV #1,D +2$: SOB B,3$ + JSR PC,PRDN + TYPEIT < blocks free out of > + MOV BLKLIM,A + JSR PC,PRDN + TYPEIT <_> + RTS PC + +.IFZ FLOP +SCAN: TYPEIT ^/Scan/ +.IFZ 105 +;SCAN DISK A TRACK AT A TIME FOR BAD BLOCKS + MOV WCHDSK,A ;BLOCK TO START WITH + ASH #13.,A + SAVE A +;THE TOP OF THE STACK IS ALWAYS THE FIRST BLOCK THAT MIGHT HAVE AN ERROR +TRKLOP: MOV #1,RKCS ;RESET THE WORLD + MOV (P),RKDA + MOV #DSKBUF,RKBA + MOV #-24.*256.,RKWC ;A WHOLE TRACK + MOV #4405,RKCS ;READ, BUT DON'T INCREMENT ADDRESS + ;AND STOP ON SOFT ERROR + TSTB RKCS + BPL .-4 ;WAIT FOR THE TRANSFER TO FINISH + TST RKCS ;IS THERE ANY ERROR? + BLT ERRLOP ;YES, CHECK IT OUT + MOV RKDA,(P) + BR TRKLOP +ERRLOP: MOV #256.,C ;NUMBER OF TIMES TO DO THIS + BIT #100,RKER ;IS IT THE END OF THE DISK? + BNE NOSCN1 ;YES, DONE + PUSH (P) ;RECOPY THE DISK ADDRESS +ERLP2: MOV #1,RKCS + MOV #-256.,RKWC + MOV #4405,RKCS ;READ BUT DONT INC + TSTB RKCS + BPL .-4 + TST RKCS ;ERROR + BGE ERLP1 ;NO + BIT #100,RKER ;END OF DISK? + BNE NOSCN1 ;YES + TYPEIT ^/_SCAN ERROR RKDA=/ + MOV RKDA,B + JSR PC,OCTOUT + JSR PC,CRLF + TYPEIT ^/RKER=/ + MOV RKER,B + JSR PC,OCTOUT + JSR PC,CRLF +ERLP1: MOV RKDA,(P) ;GET NEW + SOB C,ERLP2 + TST (P)+ + JMP TRKLOP +NOSCN1: ADD #4,P ;POP ARGS +.ENDC + CLR -(P) +SCANLP: CMP #313*12.,(P) + BEQ SCANL1 + MOV (P),B + JSR PC,DBFRED + INC (P) + BR SCANLP +SCANL1: TST (P)+ + JMP SALV2 +.ENDC + ;GIVEN A LAST-CHAR-FLAGGED STRING IN (A)+, +;FIND A FILE WITH THAT NAME. +FINDE: MOV #DIR,ENTRYP +FINDE1: JSR PC,FIND + BEQ FOUNDE +FIND1: RTS PC + +FIND: JSR PC,TYPEWD + JSR PC,SKIPVN + BIT #EOFB,FLAGS + BEQ 1$ + ADD #10,E +1$: BIT #ACCB,FLAGS + BEQ 2$ + JSR PC,SKPACC +2$: MOV TOFIND,C + JSR PC,CMPNAM + BEQ FIND1 + CMP NXNTRY,DIREND + BEQ NFOUND + BLO FINDE2 + ENTERR ^/ OVERSHOT DIRECTORY END/ + BPT +FINDE2: MOV NXNTRY,ENTRYP + BR FIND + +FOUNDE: JSR PC,ATDESC + SEZ + RTS PC + +NFOUND: CLZ + RTS PC + +FILLEN: MOV #CNTBKN,BLOKDO + CLR A + CLR B + JSR PC,EDMARCH + MOV A,B + RTS PC + +CNTBKN: INC A + RTS PC + + + + +LENFIL: MOV #CNTBLK,BLOKDO + CLR A + CLR NBLOKS + JSR PC,EDMARCH + MOV NBLOKS,B + BEQ LENFL2 + MOV ENTRYP,A ;POINT TO ENTRY + ADD #4,A ;POINT TO EOF WORD + MOV (A)+,C ;GET THE PAGE NO. + MOV (A)+,D ;GET THE BYTE COUNT + ASH #3,D ;GET IT LINED UP + ASHC #-13.,C ;GET THE NUMBER OF BLOCKS + BIT #MFISTB,FLAGS ;BLOCK EXIST? + BEQ 1$ + INC D +1$: CMP D,B ;THE SAME? + BEQ LENFL2 ;YES + ENTERR ^/ BAD LENGTH FILE/ +LENFL2: RTS PC + +CNTBLK: INC NBLOKS ;COUNT A BLOCK + RTS PC + ;DMARCH ROUTINE TO GET THE FIRST BLOCK OF A FILE +FSTBLK: MOV #DSKBUF,B + JSR PC,DSKRED + ADD #6,P ;CROCK!!! + ;POP OUT OF FSTBLK, DOBLOK, @LOADX(B), DMARCH + RTS PC ;BACK TO JSR PC,DMARCH + + +L1BLKF: MOV #L1BLK,BLOKDO ;LOAD A ONE-BLOCK FILE + JSR PC,EDMARCH + MOV ENTRYP,D ;POINT TO THE ENTRY + MOV 6(D),B ;GET THE EOF + ADD #DSKBUF,B + RTS PC ;B POINTS TO END OF FILE + +L1BLK: MOV #ER1BLK,BLOKDO + MOV #DSKBUF,B + JSR PC,DSKRED + RTS PC + +ER1BLK: ERROR ^/DESCR FILE TOO LONG/ + BPT + BR .-2 + BITSIO: JSR PC,EDMARCH ;CALLED BEFORE AND AFTER BCOMP + CMP BITSAT,BITLIM ;TO I/O THE BIT TABLE + BHIS BITSI1 + ERROR ^/BIT TABLE TOO SHORT/ +BITSI1: RTS PC + + +BITSRD: MOV #DSKBUF,B ;READ IN FIRST BLOCK OF BIT TABLE + JSR PC,DSKRED + + PUSH C + MOV #777,C ;BLT 1000-1 WORDS + MOV #DSKBUF+2,A ;SKIPPING BLKLIM WORD + MOV #DBITS2,B + MOV (A)+,(B)+ + SOB C,.-2 + POP C + + MOV #1776,BITSAT ;WE'VE READ IN THIS MANY BYTES + MOV #BITSR2,BLOKDO ;NEXT BLOCK, DO THIS + RTS PC + +BITSR2: CMP BITSAT,BITLIM ;READ IN NEXT BLOCK IF NOT OVERSHOT + BLO BITSR3 + ERROR ^/BIT TABLE TOO LONG/ + +BITSR3: MOV #DSKBUF,B + JSR PC,DSKRED + + PUSH C + MOV #1000,C ;BLT 1000 WORDS + MOV #DSKBUF,A + MOV #DBITS2,B + ADD BITSAT,B ;TO CURRENT PLACE IN BIT TABLE 2 + MOV (A)+,(B)+ + SOB C,.-2 + POP C + + ADD #2000,BITSAT ;WE READ IN THIS MANY MORE BYTES + RTS PC + +BITSWR: MOV BLKLIM,DSKBUF ;WRITE FIRST BLOCK OF BIT TABLE: + ;FIRST WORD IS # BLOCKS ON DISK + PUSH C + MOV #777,C + MOV #DBITS1,A ;BLT TABLE 1 TO DSKBUF+2, 1000-1 WORDS + MOV #DSKBUF+2,B + MOV (A)+,(B)+ + SOB C,.-2 + POP C + + MOV #DSKBUF,B + JSR PC,DSKWRT ;WRITE THE BLOCK + + MOV #1776,BITSAT ;THIS MANY BYTES TRANSFERED + MOV #BITSW2,BLOKDO ;DO THIS TO NEXT BLOCK + RTS PC + +BITSW2: CMP BITSAT,BITLIM ;WRITE NEXT BLOCK UNLESS OVERSHOT + BLO BITSW3 + ERROR ^/BIT TABLE TOO LONG/ + +BITSW3: PUSH C + MOV #1000,C ;NOW BLT 1000 MORE WORDSG OUT + MOV #DBITS1,A + ADD BITSAT,A ;FROM WHERE YOU LEFT OFF + MOV #DSKBUF,B + MOV (A)+,(B)+ + SOB C,.-2 + POP C + + MOV #DSKBUF,B + JSR PC,DSKWRT ;WRITE THE BLOCK + + ADD #2000,BITSAT ;YOU'VE DONE THIS MANY MORE BYTES NOW + RTS PC + ;COMPLAIN ABOUT OLD BIT TABLE +BAD01: JSR PC,CLOS10 + JSR PC,OPEN01 + RTS PC + +BAD10: JSR PC,CLOS01 + JSR PC,OPEN10 + RTS PC + +BCGOOD: JSR PC,CLOS01 + JSR PC,CLOS10 + RTS PC + + +OPEN01: TSTB RNG01F ;IS THIS RANGE ALREADY OPEN? + BNE OPN01B + JSR PC,BBFOUN + JSR PC,RNGEDG ;NO, TYPE ITS OPENING NUMBER + INCB RNG01F ;ASSERT JUST OPENED + RTS PC +OPN01B: CMPB #2,RNG01F + BLE 1$ + INCB RNG01F ;ASSERT LONG RANGE +1$: RTS PC ;(OR ALREADY LONG RANGE) + +OPEN10: TSTB RNG10F ;IS THIS RANGE OPEN? + BNE OPN10B + JSR PC,BBFOUN ;BAD BIT FOUND: SET RANYBQ ("ANY BADBIT?") + JSR PC,TAB ;NO, GO TO 1->0 COLUMNL + JSR PC,RNGEDG ;AND TYPE ITS OPENING NUMBER + INCB RNG10F ;ASSERT NOW JUST OPENED + RTS PC +OPN10B: CMPB #2,RNG10F + BLE 1$ + INCB RNG10F ;NEW LONG RANGE +1$: RTS PC + +BBFOUN: TST RANYBQ ;FIRST BAD BIT? + BNE BBFOU1 + TYPEIT ^/_0 -> 1 1 -> 0_/ + INC RANYBQ ;NO MORE FIRST BAD BITS. +BBFOU1: RTS PC + +CLOS01: DECB RNG01F ;IS THIS RANGE MORE THAN 1 LONG? + BLE CLS01B ;NO, JUST CLEAR IT. + TST RANYBQ + BNE 1$ + BPT ;SHOULDN'T CLOSE IF NOT OPENED!! +1$: TYPEIT ^/ to_/ ;else state it's a long range + DEC C + JSR PC,RNGEDG ;AND IT ENDS 1 BEFORE HERE + INC C +CLS01B: CLRB RNG01F ;AND CLEAR IT + RTS PC + +CLOS10: DECB RNG10F ;IS THIS RANGE MORE THAN JUST BEGUN? + BLE CLS10B ;NO, JUST CLEAR ITL + TST RANYBQ + BNE 1$ + BPT ;NOT IF NOT OPENED! +1$: JSR PC,TAB ;ELSE (IN 1->0 COLUMN) + TYPEIT ^/ to_/ ;state it's a long range + JSR PC,TAB + DEC C + JSR PC,RNGEDG ;AND IT ENDS 1 BEFORE HERE + INC C +CLS10B: CLRB RNG10F ;AND CLEAR IT + RTS PC + +TAB: TYPEIT ^/ / ;6 SPACES + 2 FOR MARGIN + RTS PC + +RNGEDG: PUSH A + PUSH B + MOV C,B ;TYPE OUT BLOCK NUMBER IN C + JSR PC,OCTOUT ;(MAY BE DIDDLED) + JSR PC,CRLF + POP B + POP A + RTS PC + .STITL CRUNCH A DIRECTORY +DOROOT: JSR PC,DODIRA ;DO THE DIRECTORY AS USUAL + MOV DOWHAT,A ;EXCEPT WHEN IT COROUTINES BACK + ;AFTER DOING THE HEADER, + JSR PC,@BITS(A) ;ALSO SET/CHECK THE HEADER'S BLOCK BITS. + JSR PC,@(P)+ ;NOW RETURN TO DODIRA + RTS PC ;AND WHEN IT RETURNS, YOU'RE ALL DONE. + +DODIR: JSR PC,DODIRA ;DO THE DIRECTORY + JSR PC,@(P)+ ;DOING NOTHING EXTRA AFTER THE HEADER + RTS PC ;AND DONE + +DODIRA: JSR PC,LOADIR ;USES PUSHED ENTRY ON F-STACK, + ;SETS DIREND + MOV #DIR,ENTRYP + JSR PC,TYPEWD ;SETS E,TYPE,NBYTES,NXNTRY,FLAGS,DSCEND + CMP #SELF,ETYPE ;HEADER ENTRY? + BEQ DODIR1 + ENTERR ^/ FIRST BUT NOT SELF ENTRY, GIVING UP ON THIS DIR/ ;UGH, GROSSLY CLOBBERED + JMP DODONE +DODIR1: MOV DOWHAT,A + JSR PC,@SELF(A) ;PROCESS THE HEADER + JSR PC,@(P)+ ;COROUTINE WITH NEXT LEVEL UP-- + ;ASK TO DO AFTER THE HEADER. +DODIR2: MOV NXNTRY,ENTRYP + JSR PC,TYPEWD + CMP #PARENT,ETYPE + BEQ DODIR3 + ENTERR ^/ SECOND BUT NOT PARENT, GIVING UP ON THIS DIR/ + JMP DODONE +DODIR3: MOV DOWHAT,A + JSR PC,@PARENT(A) ;PROCESS PARENT HEATER + +DOENTRY:: CMP NXNTRY,DIREND + BNE 1$ + JMP DODONE ;HIT END OF DIRECTORY +1$: BLO DOENT3 + ENTERR ^/ OVERSHOT DIRECTORY END/ + BPT + BR .-2 + +DOENT3: MOV ENTRYP,OENTRY ;SAVE LAST ENTRY POINTER + JSR PC,TYPEWD ;GET LAST ENTRY'S TYPE AND FLAGS AGAIN! + MOV ETYPE,OTYPE ;SAVE THEM + MOV FLAGS,OFLAGS + + MOV NXNTRY,ENTRYP ;NOW FOR NEXT ENTRY!! + JSR PC,TYPEWD + CMP #SELF,ETYPE + BNE DOENT2 ;CAN'T HAVE TWO HEADERS + ENTERR ^/ IS 2ND SELF ENTRY/ + BR DODONE ;PRETEND END OF DIR +DOENT2: CMP #PARENT,ETYPE + BNE DOENT4 + ENTERR ^/ IS 2ND PARENT ENTRY/ + BR DODONE +DOENT4: MOV DOWHAT,A ;CHECK ALPHABETICAL ORDER (ON PASS 1) + JSR PC,@ALFORQ(A) ;ALWAYS SKIPS VERSION NUMBER,EOF,AND ACCESS CODES + JSR PC,SKPACC + MOV DOWHAT,A + ADD ETYPE,A ;DISPATCH ON TYPE OF ENTRY + JSR PC,@(A) ;PROCESS THIS ENTRY + JMP DOENTRY + +DODONE: JSR PC,PUTDIR ;IF DIRECTORY MODIFIED, REWRITE IT. + RTS PC + .STITL PASS 1 CRUNCH-ENTRY ROUTINES +CKSELF: BIT #EOFB,FLAGS + BNE CKSLF3 + ERROR ^/NO EOF IN SELF ENTRY/ + RTS PC +CKSLF3: MOV FBACKP,D + MOV D,C + ADD #FENTRY+4,C ;POINT TO THE DIRECTORY ENTRY + JSR PC,SKIPVN + ADD #10,E ;SKIP THE EOF AND DATE + JSR PC,CMPNAM ;NAMES THE SAME? + BEQ CKSLF1 ;YES +CKSLF2: ERROR ^/SELF ENTRY DOESN'T DESCRIBE SELF/ + RTS PC +CKSLF1: JSR PC,ATDESC +CKSLF4: JSR PC,CMPDSR + BNE CKSLF2 + RTS PC + +CKPAR: BIT #EOFB,FLAGS ;IS THERE A EOF + BEQ CKPAR4 ;NO,GOOD + ERROR ^/PARENT HAS EOF BIT/ + RTS PC +CKPAR4: BIT #ACCB,FLAGS ;ARE THERE ACCESS CODES + BEQ CKPAR5 + ERROR ^/PARENT HAS ACCESS CODE/ + RTS PC +CKPAR5: MOV FBACKP,D ;GET OWN DIRECTORY ENTRY (ON STACK) + MOV (D),C ;GET THE + MOV C,D ;COPY IT + ADD #FENTRY+4,C ;GET NAME FROM ENTRY + JSR PC,SKIPVN ;SKIP THE VERSION NUMBER +CKPAR3: JSR PC,CMPNAM ;(COMPARE NAMES IN (C)++ AND (E)++) + BNE CKPAR2 ;NOT THE SAME + JSR PC,ATDESC ;SET DDESCR (=OFFSET), DBYTES FOR HEADER DESCR + ;(DESCRIBES PARENT) + BVS CKPWIN +CKPAR6: MOV D,C + ADD #FENTRY,C ;GO TO START OF ENTRY + ADD FDDESC(D),C ;AND TO START OF DESCRIPTOR + JSR PC,CMPDSR ;ARE THE DESCRIPTORS THE SAME + BEQ CKPWIN ;SAME, WE ARE WINNERS +CKPAR2: ERROR ^/PARENT ENTRY DOES NOT DESCRIBE PARENT/ +CKPWIN: RTS PC + +SKPPNM: JSR PC,SKIPVN + BIT #EOFB,FLAGS + BEQ 1$ + ADD #10,E +1$: JSR PC,SKPACC + JSR PC,SKPNAM + RTS PC + +C2PAR: JSR PC,SKIPVN + JSR PC,SKPNAM + JSR PC,ATDESC + RTS PC + +C2SELF: JSR PC,SKIPVN + ADD #10,E + JSR PC,SKPACC + JSR PC,SKPNAM + JSR PC,ATDESC + RTS PC + + C2LINK: +CKLINK: ENTERR ^/ IS A LINK; FEATURE NOT IMPLEMENTED/ + RTS PC + +C2LAST: +CKLAST: ENTERR ^/ IS A LAST, FEATURE FLUSHED/ + RTS PC + + +C2FILE: +CKFILE: BIT #EOFB,FLAGS + BNE CKFIL1 + ERROR ^/NO EOF IN FILE ENTRY/ +CKFIL1: JSR PC,ATDESC ;SET DDESCR AND DBYTES FOR DESCRIPTOR + BVS CKFIL2 + JSR PC,LENFIL ;CHECK FOR REASONABLE LENGTH OF FILE + MOV DOWHAT,A + JSR PC,@BITS(A) ;SET BITS IN TABLE 1; IF SET, SET TABLE 2 +CKFIL2: RTS PC ;ALL DONE!! + +C2DIR: +CKDIR: BIT #EOFB,FLAGS + BEQ CKDIR1 + ERROR ^/EOF IN DIRECTORY ENTRY/ + RTS PC +CKDIR1: BIT #ACCB,FLAGS + BEQ CKDIR2 + ERROR ^/ACCESS CODES IN DIRECTORY ENTRY/ + RTS PC +CKDIR2: JSR PC,ATDESC ;DDESCR AND DBYTES + BVS CKDIR3 + MOV DOWHAT,A + JSR PC,@BITS(A) ;SET BITS + JSR PC,PUTDIR ;REWRITE DIRECTORY IF MODIFIED + JSR PC,PSHDIR ;PUSH THIS ENTRY ONTO THE F-STACK + JSR PC,DODIR ;CRUNCH THE DIRECTORY + JSR PC,POPDIR ;POP ENTRY + JSR PC,LOADIR ;RELOAD CURRENT DIRECTORY +CKDIR3: RTS PC + + .STITL WALK-THROUGH-AN-ENTRY ROUTINES +TYPEWD: ;GIVEN AN ENTRYP, GETS TYPE, NBYTES, NXNTRY, FLAGS, AND DSCEND + ;AND SETS E POINTING TO THE VERSION NUMBER OR DIRID + MOV ENTRYP,E + MOVB (E)+,C ;SET UP THE NUMBER OF BYTES + MOVB C,NBYTES ;SET IN NUMBER OF BYTES + MOVB (E)+,A ;GET FLAGS BYTE + MOV A,B ;COPY IT + BIC #TYPEM,A ;GET JUST TYPE + MOV A,ETYPE + ADD ENTRYP,C ;POINT TO NEXT ENTRY + CMP C,DIREND + BLOS TYPEW2 + ENTERR ^/ OVERFLOWS DIRECTORY/ + MOV DIREND,C ;MAKE NXNTRY = DIREND +TYPEW2: MOV C,DSCEND ;SET UP DESCRIPTOR END POINTER + INC C + BIC #1,C ;ROUND IT UP + MOV C,NXNTRY + MOV B,FLAGS + RTS PC + +SKPNAM: JSR PC,EBYTE ;GET BYTE OF ENTRY + BVS NAMERR ;COMPLAIN ON ENTRY OVERFLOW + TSTB A ;IS THE CHAR FLAGGED? + BGE SKPNAM ;SKIP TO NEGATIVE BYTE (LAST OF NAME) + RTS PC + + +CMPDSR: JSR PC,EBYTE + BEQ CMPDS1 ;GOT LAST BYTE + BVS CMPDS2 ;NO BYTE + CMPB (C)+,A ;IS IT THE SAME + BNE CMPDS2 ;NO + BR CMPDSR +CMPDS1: CMPB (C)+,A + BNE CMPDS2 + SEZ + RTS PC +CMPDS2: CLZ + RTS PC + +CMPNAM: JSR PC,EBYTE + BVS NAMERR + CMPB (C)+,A + BNE CMPNMF ;MISMATCH + TSTB A + BGE CMPNAM ;200 BIT ENDED BOTH NAMES + SEZ + RTS PC ;RETURN WITH Z-BIT SET +CMPNMF: TSTB A + BLT 1$ + JSR PC,SKPNAM +1$: CLZ + RTS PC +NAMERR: ENTERR ^/: NAME OVERFLOWS ENTRY/ + CLZ + RTS PC + +ALFCMP: JSR PC,EBYTE ;GET BYTE OF FIRST NAME + TSTB (C) ;HAS THE SECOND ENDED + BLT ALFCM1 ;YES + CMPB (C)+,A ;ARE THE BYTES THE SAME + BEQ ALFCMP ;NO + PUSH A + BLT 1$ + JSR PC,SKPNAM +1$: POP A ;HAS FIRST ENDED + BMI ALFCM2 ;YES + CMPB -(C),A ;COMPARE THEM + RTS PC +ALFCM2: BIC #177600,A ;GET THE CHARACTER + CMPB -(C),A ;CMP THEM + RTS PC +ALFCM1: PUSH A ;SAVE IT + BLT 1$ ;YES + JSR PC,SKPNAM ;SKIP THE REST OF THE NAME +1$: CMPB (C),(P)+ ;ARE THEY THE SAME + RTS PC + + +SKIPVN: JSR PC,EBYTE + BVS SKPVNE + JSR PC,EBYTE + BVC SKPVN1 +SKPVNE: ENTERR ^/: VN OVERFLOWS ENTRY/ +SKPVN1: RTS PC + +SKPACC: BIT #ACCB,FLAGS ;ACCESS SHOULD NOT APPEAR AT FIRST + BEQ SKPVN1 +SKPAC2: JSR PC,EBYTE ;GOOD ACCESS CODES COME IN THREES + BVS SKPACE + JSR PC,EBYTE + BVS SKPACE + JSR PC,EBYTE + BVS SKPACE + TSTB A ;NEG. THIRD BYTE IS LAST TRIPLET + BGE SKPAC2 + RTS PC +SKPACE: ENTERR ^/: ACCESS OVERFLOWS ENTRY/ + RTS PC + +ATDESC: MOV E,DDESCR + SUB ENTRYP,DDESCR ;GET OFFSET OF DESCRIPTOR IN ENTRY + MOV DSCEND,DBYTES + SUB E,DBYTES ;AND LENGTH OF DESCRIPTOR + BGE ATDES1 + ENTERR ^/: NO ROOM FOR DESCRIPTOR/ + SEV +ATDES1: RTS PC + +EBYTE: MOVB (E)+,A ;GET A BYTE OF ENTRY + CMP DSCEND,E ;COMPLAIN ON OVERFLOW + BHIS 1$ + SEV +1$: RTS PC + ;THIS ENTRY MUST FOLLOW THE LAST IN ALPHABETICAL ORDER + + +ALFSR1: POP C + MOV NXNTRY,ENTRYP +ALFSRT: CMP ENTRYP,DIREND + BEQ ALFSR2 + JSR PC,TYPEWD + MOV ENTRYP,OENTRYP + PUSH C + JSR PC,ALFCMP + BGT ALFSR1 + POP C +ALFSR2: RTS PC + + + +ALFORD: JSR PC,SKIPVN + BIT #EOFB,FLAGS + BEQ 1$ + ADD #10,E ;POINT AFTER EOF WORD +1$: JSR PC,SKPACC ;SKIP ACCESS CODES + CMP #SELF,OTYPE ;DON'T COMPARE IF LAST ENTRY WAS HEADER + BNE ALFOR5 ;OTHERWISE DO COMPARE +ALFRET: JSR PC,SKPNAM ;SKIP THE NAME + RTS PC +ALFOR5: CMP #PARENT,OTYPE ;DONT COMPARE IF LAST WAS PARENT + BEQ ALFRET +ALFOR1: MOV OENTRY,C ;LAST NAME TO THE STARTING LINE + TST (C)+ ;(SKIP TYPE AND FLAGS) + MOV (C)+,OVN ;GET OLD VERSION NUMBER + CMP OTYPE,#DIREC ;IS IT A DIRECTORY? + BNE 1$ ;NO , THEN GOOD VERSION NUMBER + MOV #-1,OVN ;NO REAL VERSION NUMBER, JUST DIRID +1$: BIT #EOFB,OFLAGS ;EOF? + BEQ 2$ + ADD #10,C ;SKIP THEM +2$: BIT #ACCB,OFLAGS ;ARE THERE ACCESS CODES + BEQ ALFOR2 ;NO +ALFOR3: ADD #2,C ;SKIP FIRST WORD + TSTB (C)+ ;IS THIS THE LAST + BMI ALFOR3 ;NO +ALFOR2: JSR PC,ALFCMP ;WHICH IS BIGGER + BEQ ALFOR4 ;THE SAME, CHECK THE VERSION NUMBERS + BLE ALFOR9 ;THE OLD ENTRY WAS BIGGER!!!!!! +ALFOR6: ERROR ^/ENTRY OUT OF ORDER/ + RTS PC +ALFOR4: MOV ENTRYP,A ;POINT TO THE START OF THIS ENTRY + TST (A)+ ;SKIP HEADER + MOV (A)+,VN ;GET THE VERSION NUMBER + CMP OVN,VN + BGE ALFOR6 ;OLD >= NEW NO GOOD +ALFOR9: RTS PC + + .STITL PUSH AND POP DIRECTORY STACK +PSHDIR: MOV NEXTF,F ;GET NEXT SLOT + MOV FBACKP,(F) ;SAVE BACK POINTER FROM HERE + MOV F,FBACKP ;AND BACK POINTER TO HERE + TST (F)+ + FPUSH ENTRYP ;FOR ALPHABETIZING + FPUSH NXNTRY ;WHEN DONE WITH THIS DIRECTORY ENTRY + FPUSH DDESCR ;OFFSET OF DESCRIPTOR IN SAVED ENTRY + FPUSH DBYTES ;LENGTH OF DESCRIPTOR + MOV ENTRYP,E + MOV NBYTES,A + INC A + ROR A ;PUSH ENTRY BY WORDS +PSHDR2: FPUSH (E)+ ;NEXT WORD OF ENTRY + SOB A,PSHDR2 + CMP F,#FEND-100 + BHIS 1$ + MOV F,NEXTF ;NEXT SLOT IS AFTER THE ENTRY + RTS PC +1$: ERROR ^/OVERPUSH/ + BPT + RTS PC + +POPDIR: CMP #FBASE,FBACKP + BLO POPDR2 + BUG ^/OVERPOP?/ +POPDR2: MOV FBACKP,F ;ENTRY IS POPPED + MOV F,NEXTF ;FREE POPPED SLOT + MOV (F),FBACKP ;STEAL BACK POINTER OUT OF POPPED ENTRY + CMP F,ERNTRYP ;POPPED BACK TO ERRORSTUMP? + BHI POPDR4 ;ERRORSTUMP STILL BELOW YOU + BEQ POPDR3 ;SAW OFF ERRORLIMB AS YOU CLIMB BACK. + BUG ^/ERRORLIMB LEFT HANGING??/ +POPDR3: MOV FBACKP,ERNTRYP ;MOVE IT DOWN THE STACK +POPDR4: MOV FENTRP(F),ENTRYP ;GET OLD ENTRYP FOR ALPHABETICALS + MOV FNXNTRY(F),NXNTRY ;AND NEXT ENTRYP + RTS PC ;I THINK ALL THE REST PUSHED HAS BEEN USED. + .STITL DISK-BLOCK FUNNIES (LOAD/REWRITE, SET/CHECK BIT TABLE) +;ALWAYS DO LOADIR, PUTDIR IN MATCHED PAIRS: +;LOADIR (DODIR) +;PUTDIR (CKDIR.1) +; LOADIR (DODIR) +; PUTDIR (DODONE) +;LOADIR (CKDIR.2) +;PUTDIR (DODONE) +;ETC. +;NOT NESTED PAIRS. PUT THE DIR WHENEVER YOU'RE ABOUT TO LOAD ANOTHER +;AS AT CKDIR AND DODONE. +;THIS MAKES DIRCNG ACT PROPERLY AT PUTDIR. + +PUTDIR: TST DIRCNG ;REWRITE DIRECTORY IF MODIFIED + BEQ PUTDI1 + + TYPEIT ^/Rewriting dir / + PUSH A + JSR PC,BACKTR + JSR PC,CRLF + POP A + + MOV #DIRBLW,BLOKDO ;REWRITE DIRECTORY + JSR PC,IODIR + CLR DIREND +PUTDI1: RTS PC + +LOADIR: CLR DIRCNG ;USED IN NEXT PUTDIR + MOV #DIRBLR,BLOKDO ;LOAD A DIRECTORY + JSR PC,IODIR + MOV DIR+6,B + ADD #DIR,B + MOV B,DIREND + RTS PC + +IODIR: ;FOR EACH BLOCK, LOAD OR PUT IT. + MOV FBACKP,E ;GET DESCRIPTOR FROM PUSHED ENTRY + MOV E,D ;SETUP DESCRIPTOR + ADD #FENTRY,D + ADD FDDESC(E),D + MOV FDBYTES(E),E + JSR PC,DMARCH ;CRUNCH DESCRIPTOR!! + MOV FBACKP,E + RTS PC + + +SETB12: ;SET BITS IN BIT TABLE 1; + ;IF ONE ALREADY SET, SET IT IN BIT TABLE 2. + MOV #BTS12,BLOKDO ;DO THIS FOR EACH BLOCK + JSR PC,EDMARCH + RTS PC + +CKBIT2: ;CHECK BIT TABLE 2; IF ONE SET, RETURN NOT-EQUAL + MOV #BTT2,BLOKDO ;FOR EACH BLOCK + CLR BITFND ;IF ZERO ON RETURN, FILE OK. + JSR PC,EDMARCH + MOV ENTRYP,A + INC A ;SET UP TO MUNG REAL FLAG BYTE + TST BITFND + BNE CKBIT3 + BITB #SHRB,(A) ;NO SHARED BLOCKS: CAREFUL-CLEAR NODELF + BEQ CKBIT9 + BICB #SHRB,(A) ;ELSE CLEAR IT AND SAY DIR. MODIFIED + INC DIRCNG + TYPEIT ^/Entry / + MOV ENTRYP,B + JSR PC,NAMOUT + TYPEIT ^/ no longer shares blocks, is deletable_/ +CKBIT9: RTS PC +CKBIT3: BITB #SHRB,(A) ;SHARED BLOCKS: SET DON'T DELETE THEM FLAG + BNE CKBIT9 + BISB #SHRB,(A) + INC DIRCNG ;DIRECTORY CHANGED + RTS PC + EDMARCH: MOV ENTRYP,D + ADD DDESCR,D + MOV DBYTES,E + JSR PC,DMARCH ;DMARCH THIS ENTRY + RTS PC + +;DMARCH NEEDS (WHAT TO DO WITH EACH BLOCK) IN BLOKDO, +; (ADDR OF DISK BLOCKS DESCRIPTOR) IN D, +; AND (# BYTES OF DESCR) IN E. +DMARCH: CLR BLOKNO + TST E ;ANY DESCRIPTOR? + BNE DNEXT ;YES + RTS PC +DNEXT: MOVB (D)+,C ;BYTE OF DESCRIPTOR + MOV C,B + BIC #-DTYPEF-1,B + ASH #-5,B + JSR PC,@LOADX(B) ;CRUNCH DESCR BYTE + SOB E,DNEXT + RTS PC + +;LOADX DISPATCHES TO THESE 4 ROUTINES +LODSKP: BIC #-DTCNTF-1,C ;GET COUNT FIELD FOR SKIP + BEQ LODSK1 ;"SKIP 0" = .BYTE 0; NO-OP, SPECIAL CASE. + ADD C,BLOKNO ;SKIP N BLOCKS + JSR PC,DOBLOK ;CRUNCH ONE BLOCK +LODSK1: RTS PC + +LODCNT: BIC #-DTCNTF-1,C ;GET COUNT FIELD + INC C ;GET N+1 BLOCKS + CMP C,#40 ;IS IT MORE THAN 32 BLOCKS? + BLE LODCT2 ;NO, IS JUST GRAB DESCR. + SUB #40,C ;IS A HOLE TYPE, GET THE NUMBER OF BLOCKS IN HOLE + ADD C,NBLOKS ;INCREMENT COUNT OF BLOCKS + RTS PC ;RETURN, NOTHING TO DO +LODCT2: JSR PC,DOBLOK ;CRUNCH ONE BLOCK AFTER ANOTHER + SOB C,LODCT2 ;UNTIL N+1 + RTS PC + +LODSAD: CMP #3,E ;THREE BYTES LEFT? + BGT LSADER ;NO, COMPLAIN + MOVB (D)+,BLOKNO ;FROM NEXT TWO BYTES, + MOVB (D)+,BLOKNO+1 ;SET UP BLOCK NUMBER + SUB #2,E + BIC #-DTCNTF-1,C ;GET THE NUMBERS + INC C + BR LODCT2 ;AND CRUNCH N+1 BLOCKS (N IN FIRST BYTE) +LSADER: ENTERR ^/(?): NO ROOM FOR DESC. SET-ADDR/ + RTS PC + +LODSC: MOV C,B + BIC #-DTSCSK-1,B + ASH #-3,B ;SKIP N1 BLOCKS + ADD B,BLOKNO + BIC #-DTSCCT-1,C ;AND CRUNCH ONLY N2+1 BLOCKS + BR LODCNT + +DOBLOK: CMP BLOKNO,BLKLIM ;IS IT ON THE DISK? + BHIS DOBLER + JSR PC,@BLOKDO + INC BLOKNO + RTS PC + +DOBLER: JSR PC,ERRORX + TYPEIT ^/Error--block / + MOV BLOKNO,B + JSR PC,OCTOUT + TYPEIT ^/ not on disk; / + JSR PC,ENTOUT + JSR PC,@(P)+ + RTS PC + +ENTOUT: TYPEIT ^/Entry = / + MOV ENTRYP,B + JSR PC,NAMOUT + RTS PC + .IFZ 105 +RFBLK: CMP #DISKWC,DISKIO + BEQ RFBLK1 + MOV TRNSLE,DSKWC ;THE TRANSFER LENGTH + MOV B,DSKCA ;THE BUSS ADRESS + CLR A + MOV BLOKNO,B + ASHC #9.,A ;GET THE EXTENSION BITS + MOV B,DSKA ;THE DISK ADRESS + MOV A,DSKAE ;THE EXTENSION BITS + MOV DISKIO,DSKS ;THE FUNCTION + TSTB DSKS + BGE .-4 +RFBLK1: POP B + POP A + TST DSKS + BLT DBERR + RTS PC +.ENDC + +DBLERR: ERROR ^/DIRECTORY TOO LONG/ + RTS PC +DIRBLR: MOV #DBLERR,BLOKDO ;DIR'S ARE ONE BLOCK + MOV #DIR,B +.IIF NZ SGMNTR, JMP CACHE ;USE CACHE TO HOLD DIR. BLKS +DSKRED: CLR DSKEM ;NO EXTENDED MEMORY +DSKRD1: MOV #NRETRY,RETRYS + MOV #DISKRD,DISKIO + MOV DISKIO,OLDDSK ;SET UP THE OLD FUNCTION + JSR PC,DSKBLK + MOV #DISKWC,DISKIO ;NOW A WRITE CHECK TO VERIFY THAT WE READ IT RIGHT. + JMP DSKBLK + + +.IFZ FLOP +DSKBLK: MOV #NRETRY,RETRYS ;READ IN A BLOCK FROM DISK +DSKBL1: MOV BLOKNO,SWB + PUSH A + PUSH B + MOV TRNSLE,RKWC ;TRANSFER LENGTH + MOV B,RKBA ;CORE ADDR + MOV BLOKNO,B ;GET DISK ADDR + ASL B ;DOUBLE IT: 2 SECTORS/BLOCK + CLR A + DIV #12.,A ;12 SECTORS/TRACK-SURFACE + ASH #4,A + ADD A,B ;ALL DONE FOR FIXED PLATTER + MOV B,RKDA ;DISK ADDR + MOV WCHDSK,B + ASH #13.,B + BIS B,RKDA + MOV DSKEM,RKCS ;INSERT EM BITS INTO RKCS + BIS DISKIO,RKCS ;START TRANSFER + TSTB RKCS ;TEST READY BIT + BGE .-4 ;WAIT + POP B + POP A + TST RKCS ;TEST ERROR BIT + BLT DBERR + RTS PC + +DBERR: DEC RETRYS + BGT DSKBL1 +DBERR2: SUB #2,P ;CREATE A CELL + PUSH A + PUSH B + TYPEIT ^/Disk / + MOV WCHDSK,B + JSR PC,OCTOUT + TYPEIT ^/ error accessing block / + MOV BLOKNO,B + JSR PC,OCTOUT + TYPEIT ^/_RKER = / + MOV RKER,B +DBERR4: MOV #1,RKCS ;POWER CLEAR THE DISK + JSR PC,OCTOUT + JSR PC,CRLF + TYPEIT ^/(I)gnore, (T)ry again_?/ + JSR PC,TYI1 ;GET A CHAR + MOV A,4(P) ;THE CELL CREATED ABOVE + POP B + POP A + CMP #'I,(P) + BNE .+6 + MOV #RTSPC,(P) + CMP #'T,(P) + BNE .+6 + MOV #DBERR5,(P) + BITB #177,1(P) + BEQ .+4 + JMP @(P)+ + BPT + BR .-4 ;TRY TO RETURN + + +DBERR5: CMP #DISKWC,DISKIO + BEQ .+6 + JMP DSKBLK + MOV OLDDSK,DISKIO ;THE OLD FUNCTION + JSR PC,DSKBLK + MOV #DISKWC,DISKIO + JMP DSKBLK +.ENDC + +.IFZ 105 +DBERR3: SUB #2,P ;CREATE A WORK CELL + PUSH A + PUSH B + TYPEIT ^/_DAE=/ + MOV DSKAE,B + JSR PC,OCTOUT + JSR PC,CRLF + TYPEIT ^/DCS=/ + MOV DSKS,B + BR DBERR4 +.ENDC + +.IFNZ FLOP +;SPECIAL DSKBLK FOR COPIES +DSKSBL: SAVE + BR DSKBLS ;CALLER MUST SET UP FLOPSC AND FLOPTR + + +;DISK ROUTINES FOR THE FLOPPY DISK +DSKBLK: SAVE + MOV BLOKNO,F ;THE BLOCK NUMBER + CLR E + ASHC #3,E ;8 SECTORS/BLOCK + DIV #26.,E ;26 SECTORS/TRACK + TST FLPTYP ;OLD OR NEW? + BNE 1$ ;OLD + INC E ;NEW OFFSETS TRACKS BY 1 +1$: MOV E,FLOPTR ;TRACK + INC F ;SECTORS ARE NUMBERED FUNNY + MOV F,FLOPSC ;SECTOR +DSKBLS: MOV FLOPSC,FLOPSS ;SAVED SECTOR + MOV B,FLOPCA ;SAVE STARTING CORE ADDRESS + MOV B,FLPSCA + MOV TRNSLE,FLOPWC ;STARTING WORD COUNT + SUB TRNSLE,B + SUB TRNSLE,B ;GET END OF BUFFER ADDRESS + MOV B,FLOPHW ;FOR "HALF WAY" MARK + MOV #SMSCSR,F ;THE CONTROL REGISTER + MOV #SMSDBF,E ;THE DATA BUFFER + +DSKBL1: TST FLOPWC ;ANY WORDS LEFT TO XFER? + BNE 1$ ;YUP + REST + RTS PC +1$: + + + MOV #NRETRY,RETRYS ;SET RETRYS FOR THIS SECTOR +DSKBL2: MOV #SMSSEK,A ;REENTER HERE ON ERROR + JSR PC,DCMD + MOV FLOPTR,A + JSR PC,CMD2 ;SEEK TO TRACK + JSR PC,GETST ;GET STATUS OF THE SEEK + BEQ FLPERR + JSR PC,SECMUN ;GO MUNG WITH SECTOR NUMBER + CMP #DISKWR,DISKIO ;WRITE? + BEQ FLOPWR + CMP #DISKWC,DISKIO ;WRITE CHECK? + BEQ FLOPCM + CMP #DISKRD,DISKIO ;READ? + BEQ FLOPRD +2$: HALT ;?????? + BR 2$ + +FLOPWR: MOV #SMSWRT!SMSHTB,A ;TRANSFER BLOCK TO BUFFER + JSR PC,DCMD + JSR PC,CMD2 ;SECOND BYTE IGNORED +2$: BIT #SMSXFW,(F) ;WAITING YET? + BEQ 2$ + MOV FLOPCA,A ;BUFFER ADDRESS + MOV #128.,B ;# OF BYTES/SECTOR +1$: MOVB (A)+,(E) + SOB B,1$ + JSR PC,GETST ;CHECK FOR ERROR + BEQ FLPERR ;GOT ERROR THIS TIME + MOV #SMSWRT!SMSBTD,A ;TRANFER BUFFER TO THE DISK + JSR PC,DCMD + MOV FLOPNS,A ;THIS SECTOR + JSR PC,CMD2 + JSR PC,GETST ;GET STATUS OF THE TRANSFER + BEQ FLPERR + BR FLPSEC ;DONE WITH THIS SECTOR + +FLPERR: JMP FLPERX + +FLOPRD: MOV #SMSRED!SMSDTB,A ;TRANFER DISK TO BUFFER + JSR PC,DCMD + MOV FLOPNS,A ;THIS SECTOR + JSR PC,CMD2 + JSR PC,GETST ;GET STATUS OF THE TRANSFER + BEQ FLPERR + MOV #SMSRED!SMSBTH,A ;TRANSFER BUFFER TO HOST + JSR PC,DCMD + JSR PC,CMD2 ;SECOND BYTE IGNORED + MOV FLOPCA,A ;BUFFER ADDRESS + MOV #128.,B ;# OF BYTES/SECTOR +1$: MOVB (E),(A)+ + SOB B,1$ + JSR PC,GETST ;CHECK FOR ERROR + BEQ FLPERR ;GOT ERROR THIS TIME + BR FLPSEC ;DONE WITH THIS SECTOR + +FLOPCM: MOV #SMSRED!SMSDTB,A ;TRANFER DISK TO BUFFER + JSR PC,DCMD + MOV FLOPNS,A ;THIS SECTOR + JSR PC,CMD2 + JSR PC,GETST ;GET STATUS OF THE TRANSFER + BEQ FLPERR + MOV #SMSRED!SMSBTH,A ;TRANSFER BUFFER TO HOST + JSR PC,DCMD + JSR PC,CMD2 ;SECOND BYTE IGNORED + MOV FLOPCA,A ;BUFFER ADDRESS + MOV #128.,B ;# OF BYTES/SECTOR +1$: CMPB (E),(A)+ + BNE FLPERC + SOB B,1$ + JSR PC,GETST ;CHECK FOR ERROR + BEQ FLPERR ;GOT ERROR THIS TIME + BR FLPSEC + +FLPERC: DEC B ;ONE LESS BYTE + BEQ 2$ ;ERROR ON LAST BYTE +1$: MOV (E),A ;TO EMPRY BUFFER + SOB B,1$ +2$: JSR PC,GETST + BR FLPERR ;NOW DO THE ERROR + +FLPSEC: ADD #64.,FLOPWC ;TRANSFERED 64. WORDS + BEQ 1$ ;DONE TRANSFER + ADD #256.,FLOPCA ;OR 128. BYTES + TST FLPTYP ;OLD OR NEW? + BEQ FLPNSC ;NEW + ADD #2,FLOPSC ;OR ONE SECTOR + CMP FLOPHW,FLOPCA ;ARE WE PAST THE BUFFER END? + BLOS 2$ ;YUP, TIME TO DOUBLE BACK + CMP #27.,FLOPSC ;OVER TRACK BOUNDARY? + BGT 1$ + BIT #1,FLOPSC ;ON FIRST HALF OF THIS PARTIAL TRACK TRANSFER? + BNE 2$ ;YUP, GO DO SECOND + MOV #1,FLOPSC ;TO START ON NEXT TRACK + INC FLOPTR + SUB #128.,FLOPCA ;BACK OFF THE CA + MOV FLOPCA,FLPSCA + MOV FLOPSC,FLOPSS + BR 1$ +2$: MOV FLOPSS,FLOPSC ;GET SAVED SECTOR NUMBER + INC FLOPSC + MOV FLPSCA,FLOPCA ;GET SAVED CA + ADD #128.,FLOPCA +1$: JMP DSKBL1 ;GO CONTINUE THE TRANSFER + +FLPNSC: INC FLOPSC ;NEXT SECTOR + SUB #128.,FLOPCA ;CORRECT FOR OLD ROUTINES MISTAKES + CMP #27.,FLOPSC + BNE 1$ + INC FLOPTR + MOV #1,FLOPSC +1$: JMP DSKBL1 + +SECMUN: TST FLPTYP ;OLD OR NEW? + BEQ 1$ ;NEW + MOV FLOPSC,FLOPNS ;OLD + RTS PC ;IS SIMPLE +1$: SAVE + MOV FLOPTR,B ;NEW IS HARDER + DEC B + MUL #3,B ;SECTORS ARE OFFSET BY 6 FOR EACH TRACK + CLR A + ADD FLOPSC,B + DEC B + DIV #13.,A + ASL B + INC B + CMP #13.,FLOPSC + ADC B + MOV B,FLOPNS + REST + RTS PC + +FLPERX: DEC RETRYS ;TIME TO GIVE UP? + BGE 1$ +2$: TYPEIT + JSR PC,TYI1 + CMP #'I,A + BNE 3$ + JMP FLPSEC +3$: CMP #'R,A + BNE 2$ + BR RECAL ;SEEK TO ZERO AND RETRY +1$: MOV ERRST,A + ASL A + JMP @.+4(A) + DSKBL2 ;STRANGE, ERROR DISAPPEARED??? + BADER ;COMMAND ERROR IS BAD + DRERR ;DRIVE ERROR + OPRERR ;OPERATION ERROR + +BADER: TYPEIT +1$: HALT + BR 1$ + +DRERR: TYPEIT + JSR PC,TYI1 + JMP RECAL + +OPRERR: BIT #SMSHPE!SMSDAM!SMSSUR,ERRDAT ;SEEK ERROR? + BEQ OPRER1 ;NOPE +RECAL: MOV #SMSSEK,A + JSR PC,DCMD + CLR A ;SEEK TO TRACK ZERO + JSR PC,CMD2 + JSR PC,GETST +OPRER1: JMP DSKBL2 ;TRY AGAIN + + + + +FORMAT: TYPEIT + JSR PC,TYI1 + CMP #'Y,A + BEQ 1$ + JMP CRLF +1$: MOV #76.,E ;TRACK COUNTER + MOV #SMSCSR,F +FORMA1: MOV E,FLOPTR ;FOR ERROR PRINTOUT + MOV #SMSSEK,A ;FIRST SEEK TO TRACK + JSR PC,DCMD ;ON SELECTED DISK + MOV E,A ;TRACK ADDRESS + JSR PC,CMD2 ;ISSUE SECOND BYTE OF COMMAND + JSR PC,GETST ;GET STATUS OF COMMAND +FORMA2: JSR PC,REQST ;GET DISK STATUS + BIT #SMSSIP,A ;SEEK STILL GOING? + BNE FORMA2 ;YUP, WAIT FOR IT TO END + + MOV #SMSFMT,A ;FORMAT THIS TRACK + JSR PC,DCMD + MOV E,A ;LABEL THE TRACK CORRECTLY + JSR PC,CMD2 +1$: TSTB SMSCSR ;DONE? + BPL 1$ ;NOT YET + JSR PC,GETST ;GET STATUS OF OPERATION + DEC E + BGE FORMA1 ;DO NEXT TRACK + RTS PC ;DONE FORMATTING + + + + + + ;ROUTINES TO INTRACT WITH THE DISK ON A LOW LEVEL + +;GET THE STATUS OF THE SELECTED DISK +REQST: MOV #SMSSTS,A ;GET STATUS + JSR PC,DCMD ;ISSUE REQUEST FOR STATUS + JSR PC,CMD2 ;SECOND BYTE IGNORED + JSR PC,GETST ;GET THE STATUS + ;IF WE GET BACK WITHOUT ERROR IT WILL BE DISK STATUS + RTS PC + +;ISSUE THE FIRST COMMAND BYTE (IN A), ORING IN THE DISK NUMBER +DCMD: SAVE A ;SAVE THE COMMAND BYTE + MOV (F),A ;GET THE CSR + BIC #--1,A ;CLEAR USELESS BITS + CMP #SMSCMW!SMSDNE,A ;IS IT IN A GOOD STATE? + BEQ 1$ + TYPEIT + JSR PC,FLOPER + HALT +1$: MOV WCHDSK,A + ASH #3,A + BIS (P)+,A + MOV A,SMSCMD ;GIVE COMMAND + RTS PC + +;ISSUE THE SECOND BYTE OF A COMMAND +CMD2: SAVE ;SAVE THE COMAND BYTE + MOV #20,B +2$: MOV (F),A ;GET THE CSR + BIC #--1,A ;CLEAR USELESS BITS + CMP #SMSCMW,A ;IS IT IN A GOOD STATE? + BEQ 1$ + SOB B,2$ + TYPEIT + JSR PC,FLOPER + HALT +1$: REST ;GIVE IT THE BYTE + RTS PC + +GETST: CLR A ;TO TIME OUT +1$: BIT #SMSST1!SMSST0,(F) ;STATUS AVAILABLE? + BNE 2$ + SOB A,1$ + TYPEIT + JSR PC,FLOPER + HALT +2$: BIT #SMSERR,(F) ;ERROR? + BNE 3$ ;YUP + BIT #SMSXFW,(F) ;WAITING TO TRANSFER? + BNE 4$ + TYPEIT + JSR PC,FLOPER + HALT +4$: MOV SMSDBF,A ;GOBBLE STATUS + CLZ + RTS PC + +3$: JSR PC,ERRGBL ;GOBBLE ERROR STATUS + JSR PC,FLOPER + SEZ + RTS PC + +ERRGBL: BIT #SMSST1!SMSST0,(F) ;ANYTHING THERE? + BEQ ERRGB1 ;NOPE, KEEP OLD ERROR + MOVB 1(F),A ;GET NEW ERROR TYPE + BIC #177774,A ;FLUSH EXTRA STUFF + MOV A,ERRST + BIT #SMSXFW,(F) ;WAITING FOR XFR? + BNE 1$ + TYPEIT + JSR PC,FLOPER + HALT ;TO AVOID RECURSIVE LOOP +1$: MOV SMSDBF,ERRDAT +ERRGB1: RTS PC + +;GENERAL ERROR PRINTOUT ROUTINE +FLOPER: SAVE + TYPEIT <_Error csr: > + MOV SMSCSR,A + JSR PC,PRONL + TYPEIT < disk: > + MOV WCHDSK,A + JSR PC,PRDN +.IFZ 105 + TYPEIT < block: > + MOV BLOKNO,A + JSR PC,PRONL +.ENDC + TYPEIT < trk: > + MOV FLOPTR,A + JSR PC,PRONB + TYPEIT < rsec: > + MOV FLOPNS,A + JSR PC,PRONB + TYPEIT < vsec: > + MOV FLOPSC,A + JSR PC,PRONB + JSR PC,ERRGBL ;GOBBLE UP THE ERROR STATUS IS THERE IS ONE + ;OTHERWISE LEAVE BEHIND THE OLD STATUS + TYPEIT <_Etyp: > + MOV ERRST,A ;THE BITS THAT GIVE THE TYPE OF ERROR + JSR PC,PRONB + TYPEIT < edat: > + MOV ERRDAT,A + JSR PC,PRONB + TYPEIT <_> + MOV ERRST,A + ASL A + JMP @.+4(A) + NOERR + CMDERR + DRVERR + OPERR + +NOERR: TYPEIT < No error available +> + JMP FLOPE1 + +CMDERR: TYPEIT < Cmd err: > + BIT #SMSITA,ERRDAT + BEQ 1$ + TYPEIT +1$: BIT #SMSISA,ERRDAT + BEQ 2$ + TYPEIT +2$: BIT #SMSIBS,ERRDAT + BEQ 3$ + TYPEIT +3$: TYPEIT <_> + JMP FLOPE1 + +DRVERR: TYPEIT < Drive error: > + BIT #SMSDNR,ERRDAT + BEQ 1$ + TYPEIT +1$: BIT #SMSDUS,ERRDAT + BEQ 2$ + TYPEIT +2$: BIT #SMSDWP,ERRDAT + BEQ 3$ + TYPEIT +3$: BIT #SMSNAM,ERRDAT + BEQ 4$ + TYPEIT +4$: BIT #SMSSIP,ERRDAT + BEQ 5$ + TYPEIT +5$: TYPEIT <_> + JMP FLOPE1 + +OPERR: TYPEIT + BIT #SMSRWA,ERRDAT + BEQ 1$ + TYPEIT +1$: BIT #SMSHPE,ERRDAT + BEQ 2$ + TYPEIT +2$: BIT #SMSDAM,ERRDAT + BEQ 3$ + TYPEIT +3$: BIT #SMSDOV,ERRDAT + BEQ 4$ + TYPEIT +4$: BIT #SMSSUR,ERRDAT + BEQ 5$ + TYPEIT +5$: BIT #SMSCRC,ERRDAT + BEQ 6$ + TYPEIT +6$: BIT #SMSRWC,ERRDAT + BEQ 7$ + TYPEIT +7$: BIT #SMSDDR,ERRDAT + BEQ 8$ + TYPEIT +8$: TYPEIT <_> + +FLOPE1: REST + RTS PC + + +DISKON: SAVE + BIS #SMSRSB!SMSPWR,SMSCSR ;RESET CONTROLLER AND POWER DRIVES ON + CLR A ;FOR TIMER + MOV #30.,B ;ALSO +1$: BIT #SMSFDO,SMSCSR ;IS IT RESET YET? + BEQ 2$ + SOB A,1$ ;WAIT + SOB B,1$ ;A LONG TIME +5$: TYPEIT + HALT + BR DISKON +2$: MOV #10000.,B + MOV #SMSCSR,F +3$: MOV #SMSSTS,A + JSR PC,DCMD + JSR PC,CMD2 + JSR PC,GETST + BIT #SMSDNR,A ;DISK READY? + BEQ 4$ ;YUP + SOB B,3$ + BR 5$ ;NOPE +4$: REST + RTS PC + +DSKOFF: BIS #SMSRSB,SMSCSR + BIC #SMSPWR,SMSCSR +1$: RTS PC + + +.ENDC + ;GENERAL PRINT NUMBER ROUTINE +;CALL WITH A CLEAR, NUMBER TO BE PRINTED IN B +;MINIMUM NUMBER OF DIGITS TO PRINT IN C +;AND RADIX TO PRINT IN (=< 10.) IN D +PRN: DIV D,A + SAVE + MOV A,B + CLR A + DEC C + BGT PRN + TST B + BNE PRN + RTS PC ;RETURN TO PRNDIG + +PRNDIG: REST D ;DIGIT TO PRINT + ADD #60,D + SAVE A + MOV D,A + JSR PC,TYPE + REST A + RTS PC + +;PRINT A DECIMIAL NUMBER IN B +PRDN: SAVE + MOV #10.,D + MOV A,B + CLR A + CLR C + JSR PC,PRN + REST + RTS PC + +PRONL: SAVE + MOV #8.,D + MOV A,B + CLR A + MOV #6,C + JSR PC,PRN + REST + RTS PC + +PRONB: SAVE + MOV #8.,D + MOV A,B + CLR A + MOV #3,C + JSR PC,PRN + REST + RTS PC + + + +DIRBLW: MOV #DBLERR,BLOKDO + MOV #DIR,B +.IFNZ SGMNTR ;REMOVE BLOKNO FROM CACHE BLK TABLE + PUSH C + PUSH D + MOV NCBLKS,D ;NO. CACHE BLKS + MOV #CBLKTB,C ;BEG. OF CACHE BLK TABLE +1$: CMP BLOKNO,(C)+ ;SEE IF THIS BLOKNO IN TABLE + BEQ 2$ + SOB D,1$ + TYPEIT ^/Blokno not in cache/ + BR 3$ +2$: MOV #-1,-(C) ;INDICATE SLOT EMPTY +3$: POP D + POP C +.ENDC +DSKWRT: CLR DSKEM + PUSH A + PUSH B + TYPEIT ^/Writing block / + MOV BLOKNO,B + JSR PC,OCTOUT + JSR PC,CRLF + POP B + POP A +DSKWR1: MOV #DISKWR,DISKIO + MOV DISKIO,OLDDSK + JSR PC,DSKBLK + MOV #DISKWC,DISKIO + JSR PC,DSKBLK + RTS PC + + +DBFRED: PUSH BLOKNO + MOV B,BLOKNO + MOV #DSKBUF,B + JSR PC,DSKRED + POP BLOKNO + RTS PC + +DBFWRT: PUSH BLOKNO + MOV B,BLOKNO + MOV #DSKBUF,B + JSR PC,DSKWRT + POP BLOKNO + RTS PC + + .STITL COPY DISK IN FILE FORMAT + +NDSKWR: MOV #DSKBUF,B ;BLOCK TO WRITE IS IN DSKBUF +NDKWR1: PUSH BLOKNO ;SAVE OLD BLOKNO + PUSH WCHDSK ;SAVE OLD DISK + MOV NDISK,WCHDSK ;MOV DISK TO WRITE ON TO WCHDSK + MOV A,BLOKNO ;MOVE BLOCK TO WRITE ON INTO BLOKNO + JSR PC,DSKWR1 ;DO THE WRITE + POP WCHDSK ;RESTORE OLD DISK + POP BLOKNO ;RESOTORE ALD BLOCK NO + RTS PC + +NDSKRD: MOV #DSKBUF,B ;BLOCK IS READ INTO DSKBUF +NDKRD1: PUSH BLOKNO ;SAVE OLD BLOCK NO. + PUSH WCHDSK ;SAVE OLD DISK + MOV NDISK,WCHDSK ;NDISK IS THE DISK TO READ FROM + MOV A,BLOKNO ;A CONTAINS BLOCK NO. TO BE READ + JSR PC,DSKRED ;READ THE BLOCK + POP WCHDSK ;RESTORE THE WORLD + POP BLOKNO + RTS PC + +BREAD: +.IIF NZ FLOP, JSR PC,DISKON + PUSH B + JSR PC,DBFRED ;THIS IS WHERE TO $G IN RUG; + POP B + BPT ;SET B TO BLOKNO FIRST. + +BWRITE: +.IIF NZ FLOP, JSR PC,DISKON + PUSH B + JSR PC,DBFWRT ;(SIM) + POP B + BPT + BTADR: MOV BLOKNO,B ;BLOKNO -> BIT TABLE BYTE OFFSET, BIT IN BYTE +BTADR1: PUSH B + BIC #177770,B + MOV #1,A + ASH B,A ;BIT IN BYTE + POP B + ASH #-3,B + BIC #160000,B ;BYTE OFFSET + RTS PC + +BTSET1: JSR PC,BTADR + BISB A,DBITS1(B) + RTS PC + + +BTSTST: PUSH B + JSR PC,BTADR1 + BITB A,DBITS1(B) + BEQ BTST1 + POP B + CLZ + RTS PC +BTST1: POP B + SEZ + RTS PC + + +BTSET: PUSH B + JSR PC,BTADR1 + BISB A,DBITS1(B) + POP B + RTS PC + + +BTS12: ;BIT TABLE SET + JSR PC,BTADR + BITB A,DBITS1(B) ;1 CLEAR? + BEQ BTS0. + BISB A,DBITS2(B) ;NO,SET 2 + RTS PC ;DONE +BTS0.: BITB A,DBITS2(B) ;1 CLEAR: 2 SET? + BNE BTS01 + BISB A,DBITS1(B) ;NO, JUST SET 1 + RTS PC +BTS01: JSR PC,ERRORX ;1 CLEAR, 2 SET: RESERVED BLOCK + TYPEIT ^/Error--block / + MOV BLOKNO,B + JSR PC,OCTOUT + TYPEIT ^/ reserved; / + JSR PC,ENTOUT + JSR PC,@(P)+ + RTS PC + +BTT2: ;BIT TABLE 2 TEST + JSR PC,BTADR + BITB A,DBITS2(B) ;2 SET? + BEQ BTT9 + JSR PC,ERRORX ;FILE HAS SHARED BLOCK. + TYPEIT ^/Error--block / + MOV BLOKNO,B + JSR PC,OCTOUT + TYPEIT ^/ shared; / + JSR PC,ENTOUT + JSR PC,@(P)+ + INC BITFND +BTT9: RTS PC + + .STITL CACHE ROUTINES +.IFNZ SGMNTR +;MAIN CACHE ROUTINE:TRANSFERS A BLK FROM CACHE INTO LOWER CORE +;B CONTAINS LOWER CORE ADDR +CACHE: PUSH A + PUSH C + PUSH D + PUSH E + PUSH F +CACH1: MOV NCBLKS,D ;NO BLKS IN CACHE + MOV #CBLKTB,C ;POINT TO BEG. OF CACHE BLK TABLE +1$: CMP BLOKNO,(C)+ ;IS DESIRED BLOKNO IN CACHE? + BEQ 2$ ;YES + SOB D,1$ ;NO, TEST NEXT SLOT + JMP RICACH ;BLK NOT IN CACHE, SO READ IT IN +2$: SUB #CBLKTB+2,C ;GET SLOT NO. IN TABLE + ASR C +;GET NEW PAF POINTING INTO CACHE AREA + ASH #4,C ;MULT. BY 20(00) I.E., NO. BYTES/PAGE + ADD #1600,C ;ADD BASE ADDR + MOV C,MYPAR ;RESET CHOSEN PAR +;TRANSFER DATA TO ADDR IN B + MOV #MYADDR,D ;VIRT. ADDR OF 0'TH BYTE OF CHOSEN PAGE + MOV #512.,E ;INDEX +3$: MOV (D)+,(B)+ ;TRANSFER 1 WORD + SOB E,3$ ;REPEAT + MOV #MYOPAD,MYPAR ;REPLACE OLD PAF + POP F + POP E + POP D + POP C + POP A + RTS PC + +;ROUTINE TO READ A BLOCK FROM DISK INTO CACHE AREA +RICACH: INC LCSLOT ;INCREMENT LAST SLOT NO. IN CBLKTB + CMP LCSLOT,NCBLKS ;HAVE GONE BEYOND END OF TABLE? + BLO 1$ ;BRANCH IF NOT + CLR LCSLOT ;START OVER +1$: MOV LCSLOT,F ;GET PAF FOR THIS SLOT: + ASH #4,F ;BASE ADDR + 20 * SLOT NO. + ADD #1600,F + + CLR E ;GET PHYSICAL ADDR + ASHC #6,E ;SHIFT OFF MEM. EXTEN. BITS + ASH #4,E ;SHIFT THEM TO POSITIONS 4 & 5 + MOV E,DSKEM ;AND SAVE THEM + PUSH B + MOV F,B ;REST OF PHYS. ADDR IN F; SET UP FOR SUBROUT. + JSR PC,DSKRD1 ;READ BLOCK + POP B + MOV LCSLOT,E ;GET DISPLACEMENT INTO CBLKTB + ASL E + MOV BLOKNO,CBLKTB(E) ;PUT BLOKNO INTO CACHE BLK TABLE + JMP CACH1 + + +;DETERMINE HOW MUCH MEMORY, IN 512-WORD CHUNKS, CAN BE USED AS CACHE + ;IT IS DIFF. BETWEEN 28K WORDS AND THE END OF MEMORY +MEMTST: MOV #CORCHK,BEBRV ;SET UP FOR INTERRUPT CODING + MOV #1600,MYPAR ;PUT BASE ADDR CORRES. TO 28K IN CHOSEN PAR +1$: INC MYPAR ;INC ADDR BY 32 WORDS + MOV A,MYADDR ;TRY TO REFEFENCE NEW LOC + BR 1$ ;LOOP TERMINATED BY INTERRUPT + MOV MYPAR,MEMHGH ;SAVE HIGHEST 32-WORD ADDR + MOV #MYOPAD,MYPAR ;REPLACE OLD BASE ADDR FOR PAGE + + MOV MEMHGH,B + CMP #6000,B ;HAVE I GOT ALL MY MARBLES? + BLE 2$ ;YUP + TYPEIT <_MEMORY POWERED DOWN!!!!_> +2$: SUB #1600,B ;MEMHGH - 28K + ASH #-4,B ;GET NO. 512-WORD BLKS + DEC B ;CAN'T USE LAST MEM LOC, SO 1 BLK LESS + MOV B,NCBLKS ;SAVE NO. OF BLOCKS + MOV #BEBRV+2,BEBRV ;REPLACE EXIT LOC IN TRAP VECTOR + RTS PC + +CORCHK: ADD #2,(P) ;INCREMENT PROG. COUNTER + RTI ;SKIP NEXT INSTRUCTION + +;SEGMENT LOWER MEMORY UP TO 28K WORDS +;IGNORE D-SPACE +SEGSET: CLR SSR0 ;TURN OFF SEGMENTATION INITIALLY + MOV #10,C ;DO FOR 8 KERNAL I-SPACE PAGES + CLR D ;D=0 + MOV #KIDR,A ;POINT TO PDR'S +SEGST1: MOV D,KIAR-KIDR(A) ;PUT BASE ADDR'S IN PAR'S + ADD #200,D + MOV #77406,(A)+ ;SET PDR'S: PAGE LEN=128 32-WORD BLKS + ;WITH READ/WRITE ACCESS + SOB C,SEGST1 + MOV #7600,KIAR+16 ;LAST PAR POINTS TO I/O PAGE + MOV #1,SSR0 ;ENABLE MEMORY MANAGEMENT + RTS PC + +CACHNT: MOV NCBLKS,D ;INITIALIZING ROUTINE + MOV #CBLKTB,C ;POINT TO BEG. OF CACHE BLK TABLE +1$: MOV #-1,(C)+ ;FILL EA. SLOT WITH -1 + SOB D,1$ ;REPEAT TILL END + RTS PC +.ENDC + + + .STITL ERROR ROUTINES +ERRORX: INC ERRCNT ;ONE MORE ERROR ON THIS DISK + PUSH A + JSR PC,ERFROM ;TYPE ADDRESS OF ERROR CALL + POP A + JSR PC,@(P)+ ;CALL BACK TO TYPE ERROR MESSAGE + PUSH A + JSR PC,CRLF + JSR PC,BACKTR ;PRINT BACK TRACE OF DIRECTORY TREE + .IFZ 1 + TYPEIT ^/_GO ON? / + JSR PC,TYI1 + CMP #15,A + BEQ ERRX1 + CMP #'Y,A + BNE ERRX2 + .ENDC + JSR PC,CRLF +ERRX1: POP A + RTS PC +ERRX2: BPT + JMP SALV + +TXTYPE: PUSH A +TXTYP2: MOVB (F)+,A ;TYPE MESSAGE + BEQ TXTYP3 + CMP #'_,A + BNE 1$ + MOV #15,A ;PRINT CRLF FOR _ +1$: JSR PC,TYPE + BR TXTYP2 +TXTYP3: INC F ;RETURN-ADDR IS TO AFTER STRING + BIC #1,F + POP A + RTS F + + +BACKTR: TYPEIT ^/in dir / + CMP #FBASE,NEXTF + BNE BKTR0 + TYPEIT ^/(NIL)/ + RTS PC ;NO BACKTRACE +BKTR0: PUSH B + MOV #FBACKP,BKFBKP +BKTR1: MOV @BKFBKP,B ;CLIMB DOWN TREE TO A BRANCH YOU'VE SEEN BEFORE + MOV B,BKFBKP + ADD #FENTRY,B + JSR PC,NAMOUT ;TYPE DIRECTORY NAME + CMP BKFBKP,ERNTRYP ;FOUND OLD ERRORSTUMP? + BEQ BKTR2 + MOV #'<,A ;NO, KEEP GOING + JSR PC,TYPE + BR BKTR1 +BKTR2: MOV FBACKP,ERNTRYP ;YES, DONE; MAKE THIS THE ERRORTWIG. + POP B ;;;WHEN POPDIR POPS THE ERRORLIMB IT SAWS IT OFF. + RTS PC + + +ERFROM: PUSH B + MOV 6(P),B ;GET ERROR RETURN ADDRESS: A PUSH A, + ;ANOTHER JSR AND A PUSH B ARE ON TOP OF IT NOW + SUB #4,B ;GET REAL JSR PC,ERRORX ADDR. + JSR PC,OCTOUT + MOV #' ,A + JSR PC,TYPE + POP B + RTS PC + + OCTOUT: PUSH C + MOV #6,C + CLR A + ASHC #1,A ;FIRST DIGIT IS TOP BIT +OCOLUP: ADD #'0,A + JSR PC,TYPE + CLR A + ASHC #3,A + SOB C,OCOLUP ;PRINT 6 DIGITS + POP C + RTS PC + + +DECOUT: PUSH C + CLR C ;0 DIGITS SO FAR + TST B + BEQ DECOT0 ;TYPE 0 +DECOT1: INC C ;NEXT DIGIT: + CLR A + DIV #10.,A + PUSH B ;PUSH REMAINDER + MOV A,B ;# 10'S TO B + BNE DECOT1 ;UNTIL NO 10'S +DECOT2: POP A ;POP A REMAINDER + ADD #'0,A ;ENCODE IT + JSR PC,TYPE + SOB C,DECOT2 ;TYPE ALL THE REMAINDERS + POP C + RTS PC + +DECOT0: MOV #'0,A ;TYPE '0 + JSR PC,TYPE + POP C + RTS PC + + +NAMOUT: PUSH C + PUSH (B)+ ;SAVE FLAGS WORD + MOV #16.,C ;CURTAIL AFTER 16 LETTERS + PUSH (B)+ + BITB #EOFB,3(P) + BEQ 1$ + ADD #10,B +1$: BITB #ACCB,3(P) + BEQ NAMOU2 +NAMOU6: ADD #2,B + TSTB (B)+ + BMI NAMOU6 +NAMOU2: MOVB (B)+,A + JSR PC,TYPE + TSTB A + BLT NAMOU3 + SOB C,NAMOU2 + TYPEIT ^/.../ ;NAME CURTAILED + BR NAMOU4 ;DON'T LOOK FOR VN + +NAMOU3: BIT #4*400,2(P) ;HAVE WE A VERSION NO. TO PRINT? + BEQ NAMOU4 + TST (P) ;IS IT A VALID ONE? + BLE NAMOU4 ;NO + TYPEIT ^/ #/ ;YES + POP B + JSR PC,DECOUT ;(TYPE NUMBER) + BR NAMOU5 + +NAMOU4: POP C +NAMOU5: POP C + POP C + RTS PC + .STITL INITIALIZE THE DISK +ROTMID: .BYTE ENDP-ROTMID,DIREC+1 ;RUG'S POINT DIRECTORY + -1 + FLTEXT ^/./ + .BYTE 200,45,0 +ENDP==. + .EVEN +BITBEG==. + .BYTE BITEND-BITBEG,FILE+200 ;BITS FILE IS IN WHOLE BLOCKS + .WORD -1,0,2000,-1,-1 + FLTEXT ^/BITS/ + .BYTE DTSKP+47 +BITEND==. + .EVEN + +DESBEG==. + .BYTE DESEND-DESBEG,FILE+201 ;DISK DESCRIPTOR FILE + .WORD -1,0 +DESLEN: 0 ;LENGTH OF DESCRIPTOR PUT HERE + .WORD -1,-1 + FLTEXT ^/DESCR/ + .BYTE DTSKP+50 +DESEND==. + .EVEN +ROTEND: +.IFZ FLOP +SYMBEG==. ;THE SYMBOL FILE FOR RUG + .BYTE SYMEND-SYMBEG,FILE+200 + .WORD -1,3,12000,-1,-1 ;FILE IS <201-144>*2000 BYTES LONG + FLTEXT ^/SYMS/ + .BYTE DTSADR+34 ;SET THE ADDRESS TO 144 + ;AND GRAB 35 BLOCKS + .BYTE 144,0 +SYMEND==. + .EVEN +ROTEN1: +.ENDC + +RUGBEG: + .BYTE RUGND-RUGBEG,SELF+201 + .WORD -1,0,0,-1,-1 + FLTEXT ^/./ + .BYTE 200,45,0 +RUGND==. + .EVEN +RUGEND:: + COPY: TYPEIT ^/_Mass copy from: / + JSR PC,DECIN + BNE .+6 +COPY1: JMP SALVQ + CMP B,#3 + BHI COPY1 + MOV B,WCHDSK + TYPEIT ^/to: / + JSR PC,DECIN + BEQ COPY1 + CMP B,#3 + BHI COPY1 + MOV B,NDISK + JSR PC,BACKUP +SLV2: JMP SALV2 + +CNTLU: TYPEIT + CLR WCHDSK + MOV #2,NDISK +DDMCPY: JSR PC,TYI1 + CMP #'Y,A + BNE SLV2 + JSR PC,BACKUP + INC WCHDSK + INC NDISK + JSR PC,BACKUP + JMP SALV2 + +CNTLD: TYPEIT + CLR NDISK + MOV #2,WCHDSK + BR DDMCPY + +BLOCKT: TYPEIT + MOV #-1000,BACKTL +.IIF NZ FLOP, MOV #247.,BACKCN +.IIF Z FLOP, MOV #203.*12.,BACKCN + MOV #1,BACKIN + JMP SALV2 + +TRACKT: TYPEIT + JSR PC,TRKSET + JMP SALV2 + +TRKSET: +.IIF NZ FLOP, MOV #-13.*1000,BACKTL +.IIF Z FLOP, MOV #-14000,BACKTL +.IF Z FLOP + MOV #203.,BACKCN + MOV #12.,BACKIN +.IFF + MOV #19.,BACKCN + MOV #13.,BACKIN ;SPECIAL FLOPPY MODE +.ENDC + RTS PC + +.IFNZ FLOP +SCAN: TYPEIT + JSR PC,TRKSET + MOV #-1,NDISK + JSR PC,BACKUP + JMP SALV2 +.ENDC + +BACKUP: MOV BACKTL,TRNSLE ;LENGTH OF A CYLINDER + MOV BACKCN,E ;NUMBER OF CYLINDERS ON A DISK + CLR BLOKNO ;START AT BLOCK 0 + +BCKUP1: MOV #DSKBUF,B ;WHERE TO PUT DATA + JSR PC,DSKRED ;READ A CYLINDER + CMP #-1,NDISK + BEQ 1$ ;FOR SCAN + MOV BLOKNO,A ;WHERE TO PUT IT + JSR PC,NDSKWR ;WRITE IT ON THE OTHER DISK +1$: ADD BACKIN,BLOKNO ;GET THE NEXT CYLINDER + SOB E,BCKUP1 ;DO IT FOR ALL THE CYLINDERS + MOV #-1000,TRNSLE ;RESTORE THE BLOCK LENGTH + RTS PC + +.IFNZ FLOP + +OLD: TYPEIT +OLD1: MOV #250.,DSKSIZ + MOV PC,FLPTYP + RTS PC + +NEW: TYPEIT +NEW1: MOV #247.,DSKSIZ + CLR FLPTYP + RTS PC + +REFRMT: TYPEIT + JSR PC,TYI1 + CMP #'Y,A + BEQ 1$ + JMP SALVQ +1$: SAVE FLPTYP + JSR PC,OLD1 + MOV #247.,DSKSIZ ;TO CHECK FOR FILES ABOVE THE TOP + JSR PC,CHECK + JSR PC,NEW1 + TST ERRCNT ;ANY ERRORS ON CHECK? + BEQ 2$ ;NO, GO ON + TYPEIT + REST FLPTYP + RTS PC +2$: MOV #75.,BLOKNO + MOV #-26.*64.,TRNSLE ;LENGTH OF A CYLINDER +3$: MOV PC,FLPTYP ;SET TO OLD TYPE + MOV #DSKBUF,B + MOV #DISKRD,DISKIO + MOV BLOKNO,FLOPTR ;WILL USE THIS AS THE TRACK ADDRESS + MOV #1,FLOPSC + JSR PC,DSKSBL ;DO SPECIAL READ + MOV #DISKWR,DISKIO + MOV BLOKNO,FLOPTR + INC FLOPTR + MOV #1,FLOPSC + CLR FLPTYP ;SET TO NEW DISK TYPE + JSR PC,DSKSBL + DEC BLOKNO + CMP #1,BLOKNO ;AVOID MUNGING LOADER + BLT 3$ + JSR PC,NEW1 + JSR PC,CHECK ;CHECK THE NEW DISK, CHANGEING 250.=>247. + REST FLPTYP + MOV #-1000,TRNSLE + RTS PC +.ENDC + + + +.IFZ FLOP +ZERO: TYPEIT + JSR PC,NOABRT ;ABORT IF NO + MOV #DSKBUF,A + MOV #512.,B +1$: CLR (A)+ + SOB B,1$ + MOV #-1000,TRNSLE + CLR DSKEM + CLR BLOKNO + MOV #12.,E ;NUMBER OF BLOCKS ON A TRACK +2$: MOV #DSKBUF,B + JSR PC,DSKWR1 + INC BLOKNO + SOB E,2$ + CLR BLOKNO + MOV #-14000,TRNSLE +3$: JSR PC,DSKRED ;READ THE ZERO TRACK + BR 3$ + +FFCMPE: TYPEIT + INC A + CMP #10.,A + BLT .+4 + RTS PC + TYPEIT + JMP SALVQ +.ENDC +FRMT: JSR PC,FORMAT + JMP SALV2 + +NOABRT: JSR PC,TYI1 + CMP #'Y,A + BEQ NOABR1 + CMP #'y,A + BEQ NOABR1 + JMP SALVQ +NOABR1: RTS PC + +.IFZ FLOP +FORMAT: TYPEIT + JSR PC,TYI1 + CMP #'Y,A + BEQ FORMA1 + CMP #'y,A + BNE NOFMT +FORMA1: CLR B + MOV #313*2,D +FFLP1: MOV #12.,C +FFLP2: MOV B,DSKBUF + MOV #77776,DSKBUF+2 + MOV WCHDSK,A + ASH #13.,A + BIS B,A + MOV A,RKDA + MOV #-2,RKWC ;LARGE NEGATIVE NUMBER=>OVERFLOW ENDS XFER + MOV #DSKBUF,RKBA + MOV #2003,RKCS + TSTB RKCS + BPL .-4 + TST RKCS + BMI FMTER + INC B + SOB C,FFLP2 + BIC #17,B + ADD #20,B + SOB D,FFLP1 + CLR A + CLR B + MOV #313*2,D +FFLP3: MOV #12.,C +FFLP4: MOV WCHDSK,F + ASH #13.,F + BIS B,F + MOV F,RKDA + MOV #-2,RKWC ;LARGE NEGATIVE NUMBER=>OVERFLOW ENDS XFER + MOV #DSKBUF,RKBA + MOV #2005,RKCS + TSTB RKCS + BPL .-4 + TST RKCS + BMI FMTER + CMP B,DSKBUF + BEQ FFLP5 + JSR PC,FFCMPE +FFLP5: CMP #77776,DSKBUF+2 + BEQ FFLP6 + JSR PC,FFCMPE +FFLP6: INC B + SOB C,FFLP4 + BIC #17,B + ADD #20,B + SOB D,FFLP3 +NOFMT: JSR PC,CRLF + RTS PC + +FMTER: TYPEIT + JMP SALVQ +.ENDC + +INITD: TYPEIT F + JSR PC,FORMAT + MOV #-1,BLKLIM + MOV #DBITS1,A + MOV #20000,B + CLR (A)+ ;CLEAR 2*4K WORDS (BOTH BIT TABLES) + SOB B,.-2 + CLR RUGDSK ;NOT A RUG DISK UNLESS HE ASKS +.IFZ FLOP + TYPEIT ^/_Rug disk?/ +.IFF + TYPEIT ^/_Bootable disk?/ +.ENDC + JSR PC,TYI1 + CMP #'Y,A + BNE INITD1 ;NO + COM RUGDSK ;SET FLAG +.IFZ FLOP + TYPEIT <_Reserved for syms file: 144-200î> + MOV #DBITS1+14,A ;POINT TO THE BIT TABLE + MOV #-1,B ;TO MARK BLOCKS WITH + MOV #177760,(A)+ ;MARK BLOCKS 144-157 + MOV B,(A)+ ;MARK BLOCKS 160-177 + MOV #1,(A)+ ;MARK BLOCK 200 +.ENDC +INITD1: BIS #740,DBITS1+4 ;MARK BLOCKS 45-50 + MOV DSKSIZ,BLKLIM ;NO. BLOCKS ON DISK + JSR PC,CLRBUF + MOV #DSKBUF,D + +BASEYR: CLR (D)+ ;# IS BASE YEAR, NO LONGER USED + +AREA1: JSR PC,AREAN + TYPEIT ^/1/ ;BACK FOR "SWAP AREA 1: " + JSR PC,@(P)+ ;CONTINUE + BVS AREA1 ;BAD SYNTAX: "?" ALREADY TYPED + BNE AREA2 ;# BLOCKS = 0? + CMP (D)+,(D)+ ;YES, JUST CR TYPED: SKIP AREA 2 + BR RESRVD + +AREA2: JSR PC,AREAN + TYPEIT ^/2/ ;BACK FOR "SWAP AREA 2: " + JSR PC,@(P)+ ;CONTINUE + BVS AREA2 + +RESRVD: TST RUGDSK ;IS IT A RUG DISK? + BEQ RESRV1 ;NO +.IFZ FLOP + CLR C ;BLOCK 0 + MOV #1,B ;ONE BLOCK WORTH + JSR PC,SETMSK ;SET IT IN + TYPEIT ^/_Reserved: 0_/ + MOV #4,C ;NOW THE INVIOLATE PORTION OF RUG + MOV #24-4,B ;THAT MANY BLOCKS + JSR PC,SETMSK + TYPEIT ^/Reserved: 4-23_/ + MOV #54,C ;THE CORE IMAGE OF RUG + MOV #144-54,B ;RIGHT UP TO THE START OF THE SYMS FILE + JSR PC,SETMSK ;SET UP THE MASK + TYPEIT ^/Reserved: 54-143_/ + MOV #201,C ;START RIGHT AFTER THE SYMS FILE + MOV #220-201,B ;RESERVE UP TO 217 + JSR PC,SETMSK ;OKAY ALL DONE WITH THE INITIAL STUFF + TYPEIT ^/Reserved: 201-217_/ +.IFF + CLR C + MOV #4,B ;4 BLOCKS + JSR PC,SETMSK + TYPEIT ^/_Reserved: 0-3_/ +.ENDC +RESRV1: TYPEIT ^/_Reserved: / + JSR PC,ITYI + JSR PC,RANGIN + BVS RSRVX1 ;BAD RANGE SYNTAX + CMP #15,A ;CR AFTER FIRST RANGE? + BEQ RSRVCR + CMP #',,A ;COMMA AFTER FIRST RANGE? + BNE RSRVX1 ;MUST BE ONE OR THE OTHER + TST B + BEQ RSRVX1 ;NO RANGE FOLLOWED BY COMMA NO GOOD + JSR PC,SETMSK ;SET BITS AND MAKE OFFSET/MASK FOR THIS RANGE + BR RESRVC + +RSRVCR: TST B + BEQ DESCWR ;NO RANGE ON LINE -> ALL DONE. + JSR PC,SETMSK ;CRUNCH RANGE + BR RESRVD ;ANOTHER LINE OF "RESERVED: " + +RSRVX1: TYPEIT ^/ ?/ ;LINE SYNTAX NO GOOD + BR RESRVD ;TRY LINE AGAIN + + +RESRVC: ;AFTER A COMMA: + JSR PC,RANGIN + BVS RSRVX2 ;BAD RANGE SYNTAX + TST B + BEQ RSRVX2 ;AFTER A COMMA YOU MUST HAVE A RANGE + CMP #15,A + BEQ RSVCR2 ;ENDED WITH CR + CMP #',,A + BNE RSRVX2 ;MUST HAVE EITHER THAT OR COMMA + JSR PC,SETMSK ;CRUNCH RANGE + BR RESRVC ;ANOTHER RANGE ON THIS LINE + +RSVCR2: JSR PC,SETMSK ;CRUNCH RANGE + BR RESRVD ;ANOTHER LINE + +RSRVX2: TYPEIT ^/ ?_Bad syntax after comma/ + JMP RESRVD ;TRY LINE AGAIN + +DESCWR: SUB #DSKBUF,D + MOV D,DESLEN ;SAVE THE DESRIPTOR LENGTH + MOV #50,B + JSR PC,DBFWRT ;WRITE BLOCK 50: DESCR FILE DONE + XBITS: JSR PC,CLRBUF + MOV BLKLIM,DSKBUF ;NO. BLOCKS ON DISK + MOV #777,C ;BLT 1000-1 WORDS INTO DSKBUF+2 + MOV #DBITS1,A + MOV #DSKBUF+2,B + MOV (A)+,(B)+ + SOB C,.-2 + MOV #47,B ;WRITE THIS FILE + JSR PC,DBFWRT ;STILL ONLY ALLOW 17760 BLOCKS ON DISK + +XROOT: JSR PC,CLRBUF + MOV #DSKBUF+1,B + MOVB #SELF+201,(B)+ ;ROOT HAS WORD LEFT FOR LENGTH + MOV #-1,(B)+ ;SET IN THE DIRID + ADD #10,B ;SKIP EOF, AND DATE AND TIME + JSR PC,GETNAM ;GET NAME OF DISK + MOVB #200,(B)+ + MOVB #46,(B)+ ;SAY BLOCK 46 + TSTB (B)+ ;THE LENGTH OF ROOT + MOV B,A + SUB #DSKBUF,A + MOVB A,DSKBUF ;HEADER LENGTH BYTE + INC B + BIC #1,B ;ROUND IT + MOV #DSKBUF+14,C ;SKIP HEADER AND DIRID + MOVB DSKBUF,F ;COPY THE LENGTH + SUB #10,F ;THE EOF AND DATE/TIME DONT EXIST + MOVB F,(B)+ ;SET IN THE LENGTH INTO PARENT ENTRY + MOVB #PARENT+1,(B)+ ;SET IN THE TYPE + MOV #-1,(B)+ ;AND DIRID + SUB #3,F ;SKIP THE HEADER AND DIRID + ASR F ;TURN INTO WORD COUNT + MOV (C)+,(B)+ ;COPY THE ENTRY + SOB F,.-2 + MOV #ROTMID,A + MOV #/2,C +.IFZ FLOP + TST RUGDSK ;IS IT A RUG DISK? + BEQ XROOT1 ;NO + MOV #/2,C ;ADD IN THE SYMS FILE +.ENDC +;FALLS THROUGH + ;FALLS IN +XROOT1: MOV (A)+,(B)+ ;FILL IN POINT, BITS AND DESCR ENTRIES (FIXED) + SOB C,.-2 + SUB #DSKBUF,B ;NUMBER OF BYTES INROOT + MOV B,DSKBUF+6 + MOV #46,B + JSR PC,DBFWRT + +XPOINT: MOVB DSKBUF,F ;THE LENGTH OF THE SELF ENTRY + SUB #10,F ;NO EOF/DATE/TIME + MOV F,E ;THE NUMBER OF WORDS TO TRANSFER + INC E + ASR E + MOV #DIR,C ;PLACE TO SAVE ENTRY + MOV #DSKBUF+14,B ;POINTER TO NAME OF ROOT + MOV #*400,(C) ;SAVE THE TYPE + ADD F,(C)+ ;SET IN THE LENGTH + MOV #-1,(C)+ ;SET IN THE DIRID + DEC E ;DONT TRANSFER THE HEADER EITHER + DEC E + MOV (B)+,(C)+ ;COPY THE ENTRY + SOB E,.-2 + JSR PC,CLRBUF + MOV #DSKBUF,B ;THE PLACE TO CONSTRUCT POINT + MOV #RUGBEG,A + MOV #/2,C ;THE LENGTH OF STARTING ENTRY + MOV (A)+,(B)+ ;COPY THE SELF ENTRY + SOB C,.-2 + MOVB DIR,C ;THE LENGTH OF NEW ENTRY + INC C + BIC #1,C + MOV C,F + ASR C + MOV #DIR,A ;POINT TO IT + MOV (A)+,(B)+ ;COPY THE PARENT ENTRY + SOB C,.-2 + INC F + BIC #1,F + MOVB DSKBUF,E + ADD E,F + INC F + BIC #1,F + MOV F,DSKBUF+6 + MOV #45,B + JSR PC,DBFWRT +INITDX: JMP SALV2 + CLRBUF: MOV #DSKBUF,A + MOV #1000,B ;512 WORD IN BUFFER + CLR (A)+ + SOB B,.-2 + RTS PC + +GETNAM: TYPEIT ^/_Disk name: / + JSR PC,ITYI +GETNM2: JSR PC,TYI + CMPB #15,A ;CR ENDS NAME + BEQ GETNMR + MOVB A,(B)+ ;NEXT CHAR OF HEADER ENTRY + BR GETNM2 +GETNMR: MOV #12,A ;ECHO CRLF + JSR PC,TYPE + TSTB -(B) ;FLAG PREVIOUS CHAR AS LAST CHAR OF NAME + BISB #200,(B)+ + RTS PC + DECIN: CLR B ;Z IF NO DIGITS TYPED; + JSR PC,DECDIG ;# IN B, END CHAR IN A + BNE DECIN2 + SEZ ;NO NUMBER + RTS PC +DECIN2: JSR PC,DECDIG + BNE DECIN2 + CLZ ;NON-DIGIT SEEN + RTS PC + +DECDIG: JSR PC,TYI ;Z IF NOT DIGIT; + CMP #'0,A ;CHAR IN A, ACCUM'ED # IN B + BGT DECDGX + CMP #'9,A + BLT DECDGX + SUB #'0,A + MUL #10.,B + ADD A,B + CLZ ;THIS WAS A DIGIT + RTS PC +DECDGX: SEZ + RTS PC ;NOT A DIGIT + + +RANGIN: ;GET A RANGE, C = STARTING BLOCK, B = # BLOCKS + ;SET V IF BAD SYNTAX + JSR PC,OCTIN + BEQ RANGE0 ;NO RANGE + MOV B,C ;FIRST BLOCK OF GROUP GOES IN C + CMP #'-,A ;ONE BLOCK OR GROUP? + BEQ RANGI2 + MOV #1,B ;JUST ONE NUMBER- LENGTH OF GROUP IS 1 + RTS PC +RANGE0: CLR B ;NO RANGE: + CLR C + RTS PC ;FIRST NUMBER NOT TYPED--B=0 IS FLAG + +RANGI2: JSR PC,OCTIN ;GET LAST BLOCK NUMBER + BEQ RANGIX ;BAD SYNTAX--NO END # + SUB C,B ;MAKE B NUMBER OF BLOCKS + INC B ;FROM FIRST AND LAST BLOCKS + BLT RANGIX ;FIRST MUST NOT BE > LAST + RTS PC +RANGIX: SEV ;BAD RANGE SYNTAX + RTS PC + + +OCTIN: CLR B ;Z IF NO DIGITS; # IN B, BREAK CHAR IN A + JSR PC,OCTDIG + BNE OCTIN2 + SEZ ;NO NUMBER + RTS PC +OCTIN2: JSR PC,OCTDIG + BNE OCTIN2 + CLZ ;NON-DIGIT SEEN + RTS PC + +OCTDIG: JSR PC,TYI ;Z IF NOT A DIGIT; + CMP #'0,A ;CHAR IN A, ACCUM'ED # IN B + BGT OCTDGX + CMP #'7,A + BLT OCTDGX + SUB #'0,A + ASH #3,B + ADD A,B + CLZ ;WE GOT A DIGIT + RTS PC +OCTDGX: SEZ ;NOT A DIGIT + RTS PC + AREAN: TYPEIT ^/_Swap area / + JSR PC,@(P)+ ;GO BACK TO TYPE SWAP AREA # + TYPEIT ^/: / ;HELLO AGAIN + JSR PC,ITYI + JSR PC,RANGIN + BVS AREANX ;BAD RANGE SYNTAX + CMP #15,A ;MUST BE CR AFTER RANGE + BNE AREANX + JSR PC,SETAREA ;SET RANGE IN BIT TABLE AND DESCR FILE + RTS PC ;IF B = 0 BLOCKS IT WAS JUST CR; + ;Z IS SET AND CALLER WILL GO TO RESRVD. +AREANX: TYPEIT ^/ ?/ ;SYNTAX BAD + SEV + RTS PC + + +SETAREA: MOV C,(D)+ ;GIVEN A GROUP OF BLOCK, FIRST ONE IN C, + MOV B,(D)+ ;# OF BLOCKS IN B, PUT THEM IN DESCR AND + BNE .+4 ;SET THEIR BITS IN DBITS1 + RTS PC ;BUT IF B = 0 DON'T BOTHER + MOV C,BLOKNO + MOV B,C ;GOOD PLACE FOR COUNTER + +SETAR2: CMP BLOKNO,BLKLIM + BHIS NDISKX ;BLOCK FELL OFF DISK: FATAL ERROR + JSR PC,BTADR ;BLOKNO -> BIT IN A, BYTE OFFSET IN B + BITB A,DBITS1(B) + BEQ 1$ + JSR PC,BALRES ;BLOCK ALREADY RESERVED +1$: BISB A,DBITS1(B) ;RESERVE THE BLOCK + INC BLOKNO ;LOOP TO NEXT BLOCK + SOB C,SETAR2 ;COUNT OUT # OF BLOCKS + RTS PC + SETMSK: MOV C,BLOKNO ;GIVEN A GROUP OF BLOCKS, SET UP OFFSET/MASK PAIRS + MOV B,C ;IN DESCR AND RESERVE THE BLOCKS IN DBITS1 + BR SETMS3 ;THERE SHOULD BE NO B=0 CASES + +SETMS2: BIT #17,BLOKNO ;RUNNING INTO NEW MASK WORD? + BNE SETMS4 + TST (D)+ ;YES, BE DONE WITH OLD ONE, +SETMS3: JSR PC,OFFSET ;MAKE NEW OFFSET WORD +SETMS4: CMP BLOKNO,BLKLIM + BHIS NDISKX ;BLOCK FELL OFF DISK--FATAL ERROR + JSR PC,BTADR ;BLOKNO -> BIT IN A, BYTE OFFSET IN B + BITB A,DBITS1(B) ;BLOCK RESERVED? + BEQ .+6 + JSR PC,BALRES ;"BLOCK N ALREADY RESERVED" + BISB A,DBITS1(B) ;RESERVE THE BLOCK + BIT #10,BLOKNO ;ODD BYTE? + BEQ .+4 + SWAB A ;IF ODD TEN THEN PUT IN ODD BYTE + BIS A,(D) ;SET NEW BIT IN MASK + + INC BLOKNO + SOB C,SETMS2 + TST (D)+ ;END LAST MASK WORD + CMP D,#DSKBUF+2000 + BHIS DESCRX ;DESCR OVERFLOW--FATAL + RTS PC + + +OFFSET: CMP D,#DSKBUF+1776 + BHIS DESCRX ;DESCR FILE OVERFLOW--FATAL ERROR + MOV BLOKNO,A + ASH #-3,A ;BLOCK # -> BYTE OFFSET + BIC #1,A ;-> WORD OFFSET IN BIT TABLE + MOV A,(D)+ ;MAKES OFFSET WORD OF DESCR FILE + RTS PC + +DESCRX: TYPEIT ^/_Descr file overflowed_/ + HALT ;INITD NO GOOD + BR .-2 + + + +BALRES: PUSH A ;BLOCK ALREADY RESERVED + PUSH B + TYPEIT ^/_Block / + MOV BLOKNO,B + JSR PC,OCTOUT + TYPEIT ^/ already reserved_/ + POP B + POP A + RTS PC + + +NDISKX: TYPEIT ^/_Block not on disk_/ + HALT ;INITD NO GOOD + +;PDP10 COMMUNICATION +TENCOM: CLR COMPNT ;SET OF COM POINTER + MOV #&1777,COMPNT+2 ;SO TEN POINTS AT THE COM AREA + CLR TENFUN ;NULL FUNCTION + CLR TENRDY ;TEN NOT READY + CLR ELVRDY ;SAY NOT READY + MOV #10.,E ;TRY 10 TIMES +1$: JSR PC,DELAY ;WAIT A SEC + COM ELVRDY ;GIVE THE 10 A FLASH + TST TENRDY ;IS THE TEN READY? + BNE 2$ ;YES, IT GOT THE MESSAGE + SOB E,1$ + TYPEIT + JMP SALVQ + +2$: CLR ELVRDY ;I'M NOT READY + CLR TENRDY ;AND NEITHER IS THE 10 + TYPEIT + JSR PC,TYI1 + CMP #'R,A + BEQ TENRED + CMP #'W,A + BEQ TENWRT + COM ELVRDY ;SAY WE ARE READY FOR ZERO FUNCTION (E.G. DONE) + JMP SALVQ ;AND QUIT + +TENRED: MOV #-1,TENFUN ;SAY WE WANT TO READ + JSR PC,TENWAIT + CLR BLOKNO + MOV #203.*12.,F +TENRE1: JSR PC,TENWAIT ;WAIT FOR A BLOCK FROM THE 10 + MOV #DSKBUF,B + JSR PC,DSKWR1 ;WRITE IT SILENTLY + INC BLOKNO + SOB F,TENRE1 + CLR TENFUN ;DONE + JSR PC,TENWAIT + RTS PC + +TENWRT: MOV #1,TENFUN ;SAY WE WANT TO WRITE + JSR PC,TENWAIT ;GO SAY WE ARE READY AND WAIT FOR TEN + CLR BLOKNO + MOV #203.*12.,F ;NUMBER OF BLOCKS TO TRANSFER +TENWR1: MOV #DSKBUF,B + JSR PC,DSKRED ;READ A BLOCK + JSR PC,TENWAIT ;TELL TEN TO READ IT + INC BLOKNO + SOB F,TENWR1 + CLR TENFUN ;TELL TEN WE ARE DONE + JSR PC,TENWAIT ;LET IT CONFIRM + RTS PC ;RETURN TO COMMAND LOOP + +DELAY: MOV A,-(P) + CLR A + SOB A,. + MOV (P)+,A + RTS PC + +TENWAI: CLR TENRDY + MOV #-1,ELVRDY +1$: TST TENRDY + BEQ 1$ + CLR TENRDY + RTS PC + + .STITL TYI & TYO +CRLF: MOV #15,A + JSR PC,TYPE + RTS PC + +ECHO: TST RUBING ;RUBBING OUT CHARS? + BEQ TYPE + PUSH A ;YES, LEAVE RUBBING MODE + MOV #'\,A + JSR PC,TYPE + CLR RUBING + POP A + +TYPE: TSTB %TPS + BPL TYPE + MOVB A,%TPB + CMP #15,A + BEQ .+4 + RTS PC + PUSH A + MOV #12,A + JSR PC,TYPE +.IF Z LSI + CLR A + JSR PC,TYPE + JSR PC,TYPE + JSR PC,TYPE +.ENDC + POP A + RTS PC + +TYI1: TSTB %TKS + BPL TYI1 + MOVB %TKB,A + BIC #177600,A + CMP #'G-100,A ;BELL? + BEQ TYIRUG + CMP #'Z-100,A ;^Z? + BEQ TYIRUG + CMP #'A+40,A + BGT TYI2 + CMP #'Z+40,A + BLT TYI2 + SUB #40,A +TYI2: CMP #177,A ;RUBOUT? + BNE .+6 + SEV + RTS PC ;IF RUBOUT THEN 1) SET V 2) DON'T ECHO + JSR PC,ECHO ;ECHO + RTS PC +TYIRUG: BPT + BR TYI1 + +ITYI: CLR NCHR + RTS PC + +TYI: DEC NCHR ;ONE LESS CHAR TO READ + BLT TYLINE ;IF IT'S THERE + MOVB @TBUFPT,A ;THEN HERE IT IS + INC TBUFPT + RTS PC + +TYLINE: CLR NCHR ;OUT OF CHARS: GET A NEW LINE + CLR RUBING ;NOT RUBBING OUT + MOV #TBUF,TBUFPT ;READ INTO BUFFER +TYLIN2: CMP #TBUFLN,NCHR ;ROOM IN BUFFER? + BLOS LINERR + JSR PC,TYI1 ;GET A CHAR + BVS TYLRBO ;RUBOUT + MOVB A,@TBUFPT ;STORE CHAR + INC TBUFPT + INC NCHR ;ONE MORE CHAR IN BUFFER + CMP #15,A ;CR? + BNE TYLIN2 ;NO, KEEP LISTENING + MOV #TBUF,TBUFPT ;YES, BUFFER READY: FEED HIM THE FIRST CHAR + BR TYI + +TYLRBO: DEC NCHR ;RUB IT OUT: ONE LESS CHAR + BLT TYLINE ;NO CHARS TO RUB OUT: RESET LINE + DEC TBUFPT + TST RUBING ;ALREADY IN RUBBING MODE? + BNE TYLRB2 ;YES + MOV #'\,A + JSR PC,TYPE + INC RUBING +TYLRB2: MOVB @TBUFPT,A ;TYPE RUBBED OUT CHAR + JSR PC,TYPE + TST NCHR ;FIRST CHAR RUBBED OUT? + BNE TYLIN2 ;NO, DONE WITH RUBOUT + MOV #'\,A ;YES, CLOSE RUBBING MODE + JSR PC,TYPE + BR TYLINE + +LINERR: TYPEIT ^/ ?_TYI BUFFER FULL, TRY IT ALL OVER/ + BPT + JMP SALV2 + + +PATLOC: +PATCH: .=.+400 +.IFZ 105 +;************* +;FIXED HEAD DISK BLOCK 0 BOOTSTRAP FOR LOGO AND RUG +; +FHIDIR: MOV #DSKAE,B + CLR (B) + MOV #4000,-(B) + MOV #120000,-(B) + MOV #160000,-(B) + MOV #DISKRD,-(B) + TSTB (B) + BPL .-2 + CMP #177000,@#SWB + BEQ .+6 + JMP @#120000 ;CLEAR SWITCHES TO GET RUG + JMP @#120002 ;LEAVE SWITCHES UP FOR LOGO +FHIDIZ: +;************* +.ENDC + FBASE=<.!1777>+1 + FEND==FBASE+4000 + DBITS1=FEND + DBITS2=DBITS1+20000 + DIR=DBITS2+20000 + DIRBUF==DIR+20000 + DSKBUF=DIR+20000 + +.END SALV