home *** CD-ROM | disk | FTP | other *** search
- {
- Demonstrates formatting a floppy disk from Turbo Pascal.
- This version only formats DSDD 9 sector floppies (360KB).
- Works with DOS 2.0 or 3.0 in either 360K or 1.2M drives.
- Does not support a /S option.
- Supports a /N or -N option that turns off the verify after format.
- Turn off verify step and obtain a 2x speedup vs. DOS format.
-
- Requires Turbo version 3.0 to compile. Compile with Minheap=Maxheap=$200.
- Requires a cloning procedure after being compiled to a .COM file.
- The cloning procedure copies the boot sector of an already-formatted
- floppy into the program, where it can be used thereafter. To clone,
- call the program as follows:
-
- FMAT @ <enter>
-
- Written 10/26/85. Kim Kokkonen, TurboPower Software.
- Compuserve 72457,2131. (408)-378-3672.
- }
-
- PROGRAM fmat;
- {-format a disk, DSDD 9 sectors per track only}
- TYPE
- {holds sector data during sector setup after formatting}
- SectorBuffer = ARRAY[1..512] OF Char;
- {same size as sector buffer but easily initialized in code segment}
- FakeSectorBuffer = RECORD
- l, h : STRING[255];
- END;
- FormatRecord = RECORD
- cyl, hed, rec, num : Byte;
- END;
- FormatArray = ARRAY[1..18] OF FormatRecord;
- DiskBaseRec = RECORD
- unk1, unk2, mtr, bps, eot, gpl,
- dtl, glf, fbf, hst, mst : Byte;
- END;
- DiskBasePtr = ^DiskBaseRec;
- registers = RECORD
- CASE Integer OF
- 1 : (ax, bx, cx, dx, bp, si, di, ds, es, flags : Integer);
- 2 : (al, ah, bl, bh, cl, ch, dl, dh : Byte);
- END;
- FATtable = ARRAY[0..1023] OF Byte;
-
- CONST
- {bootrecord is customized after the .COM file is created.
- call FMAT with a single command line parameter '@' as follows:
- FMAT @ <Enter>. This will fill in bootrecord with a real boot record}
- BootRecord : FakeSectorBuffer = {fill in with bootrecord}
- (l : ''; h : '');
-
- VAR
- reg : registers;
- SB : SectorBuffer; {will fill in with dir sectors}
- BR : SectorBuffer ABSOLUTE BootRecord;
- VB : ARRAY[1..9] OF SectorBuffer; {will use for fast verify}
- FMT : FormatArray;
- FAT : FATtable;
- drName : STRING[2];
- param : STRING[10];
- drive, dType : Byte;
- ch : Char;
- doVerify : Boolean;
- BiosDiskBase : DiskBasePtr ABSOLUTE 0 : $78;
- OldDiskBase : DiskBasePtr;
- i, error : Integer;
- tavail : Integer;
- bavail : Real;
-
- PROCEDURE BIOSreadSectors(funct, drive : Byte;
- sector, track, head : Integer;
- sects : Integer;
- VAR buffer;
- VAR error : Integer);
- {-execute int 13 to read disk or verify via BIOS at low level}
- BEGIN
- reg.ax := (funct SHL 8) OR sects;
- reg.dl := drive;
- reg.dh := head;
- reg.ch := track AND 255;
- reg.cl := (sector AND 63) OR ((track SHR 8) SHL 6);
- reg.es := Seg(buffer);
- reg.bx := Ofs(buffer);
- Intr($13, reg);
- IF Odd(reg.flags AND 1) THEN
- error := reg.ax SHR 8
- ELSE
- error := 0;
- END {biosreadsectors} ;
-
- PROCEDURE BIOSwriteSectors(drive : Byte;
- sector, track, head : Integer;
- sects : Integer;
- VAR buffer : SectorBuffer;
- VAR error : Integer);
- {-execute int 13 to write disk via BIOS at low level}
- BEGIN
- reg.ax := $300 OR sects;
- reg.dl := drive;
- reg.dh := head;
- reg.ch := track AND 255;
- reg.cl := (sector AND 63) OR ((track SHR 8) SHL 6);
- reg.es := Seg(buffer);
- reg.bx := Ofs(buffer);
- Intr($13, reg);
- IF Odd(reg.flags AND 1) THEN BEGIN
- error := reg.ax SHR 8;
- WriteLn('error during format...');
- Halt;
- END ELSE
- error := 0;
- END {bioswritesectors} ;
-
- PROCEDURE InitBoot;
- {-self-customize this program to hold the boot record}
- VAR
- ch : Char;
- error : Integer;
- f : FILE;
- tries : Byte;
-
- FUNCTION CodeSize : Integer;
- {thanks to Bob Tolz and Randy Forgaard for this function}
- VAR
- i : Byte;
- BEGIN
- i := 11;
- WHILE NOT((Mem[DSeg-2 : i+3] <> $00E9) AND (MemW[DSeg-2 : i+4] = $0000)) AND
- NOT((MemW[DSeg-2 : i+0] = $00E9) AND (MemW[DSeg-2 : i+2] = $E800)) DO
- i := i+1;
- CodeSize := ((((DSeg-2)-CSeg) SHL 4)+i+6)-$100
- END {CodeSize} ;
-
- BEGIN
- WriteLn('You will now clone a copy of the boot record into this program...');
- WriteLn('The completed version will be written to FMAT.COM');
- Write('Place a DOS formatted disk in drive A: and press any key when ready ');
- Read(Kbd, ch);
- WriteLn;
- {read the boot record}
- tries := 0;
- REPEAT
- tries := Succ(tries);
- BIOSreadSectors(2, 0, 1, 0, 0, 1, BR, error);
- UNTIL (error = 0) OR (tries = 3);
- IF error <> 0 THEN BEGIN
- WriteLn('could not read boot record');
- Halt;
- END;
- {clone this program}
- Assign(f, 'FMAT.COM');
- Rewrite(f, 1);
- BlockWrite(f, Mem[CSeg : $100], CodeSize);
- Close(f);
- Halt;
- END {initboot} ;
-
- FUNCTION DOSversion : Byte;
- {-return the major version number of DOS}
- BEGIN
- reg.ah := $30;
- MsDos(reg);
- DOSversion := reg.al;
- END {dosversion} ;
-
- FUNCTION ATmachine : Boolean;
- {-return true if machine is AT class}
- VAR
- machtype : Byte ABSOLUTE $FFFF : $000E;
- BEGIN
- ATmachine := (machtype = $FC);
- END {ATmachine} ;
-
- PROCEDURE readDASD(drive : Byte; VAR dType : Byte);
- {-read dasd for DOS 3}
- {-whatever dasd is!}
- BEGIN
- reg.ah := $15;
- reg.dl := drive;
- Intr($13, reg);
- IF Odd(reg.flags AND 1) THEN BEGIN
- WriteLn('error reading DASD for format...');
- Halt;
- END;
- dType := reg.ah;
- END {readdasd} ;
-
- PROCEDURE setDASD(drive, dType : Byte);
- {-execute int 13 to "set DASD" for format of 360K disks on 1.2MB floppies}
- VAR
- tries : Byte;
- BEGIN
- tries := 0;
- REPEAT
- tries := Succ(tries);
- reg.ah := $17;
- reg.al := dType;
- reg.dl := drive;
- Intr($13, reg);
- UNTIL (tries = 3) OR NOT(Odd(reg.flags AND 1));
-
- IF Odd(reg.flags AND 1) THEN BEGIN
- WriteLn('error setting DASD for format...');
- Halt;
- END;
- END {setdasd} ;
-
- PROCEDURE InitFAT;
- {-initialize a FAT sector}
- BEGIN
- {fill fat with all zeros}
- FillChar(FAT, 1024, 0);
- {fill in the ID Bytes}
- FAT[0] := $FD; {9 sector DSDD drive}
- FAT[1] := $FF; {boilerplate}
- FAT[2] := $FF;
- tavail := 80;
- END {initfat} ;
-
- PROCEDURE InitDiskBase;
- {-modify the disk base data per DOS 3 instructions}
- BEGIN
- {save old pointer}
- OldDiskBase := BiosDiskBase;
- {make a new disk base data area}
- New(BiosDiskBase);
- {put the data from the old area in the new one}
- BiosDiskBase^ := OldDiskBase^;
- {modify per dos 3 instructions, doesn't hurt on DOS 2}
- BiosDiskBase^.glf := $50;
- BiosDiskBase^.eot := 9;
- END {initdiskbase} ;
-
- PROCEDURE Format(drive : Byte; VAR FMT : FormatArray; VAR error : Integer);
- {-lay down format tracks}
- VAR
- i : Integer;
- BEGIN
- {initialize format table}
- FOR i := 1 TO 9 DO
- WITH FMT[i] DO BEGIN
- cyl := 0; {cylinder number, will fill in during format}
- hed := 0; {head number}
- rec := i; {sector number}
- num := 2; {indicates 512 bytes per sector}
- END;
- FOR i := 1 TO 9 DO
- WITH FMT[i+9] DO BEGIN
- cyl := 0; {cylinder number, will fill in during format}
- hed := 1; {head number}
- rec := i; {sector number}
- num := 2; {indicates 512 bytes per sector}
- END;
- {write the format information}
- INLINE(
- $8A/$56/$0C/ {MOV DL,[BP+0C] - get drive number}
- $C4/$5E/$08/ {LES BX,[BP+08] - get pointer to format array}
- $B9/$01/$00/ {MOV CX,0001 - track 0 sector 1}
-
- {nexttrack: - loop over 40 disk tracks}
- $8B/$FB/ {MOV DI,BX - index into format array}
- $B0/$12/ {MOV AL,12 - number of sectors per track = 18}
-
- {inittrack: - loop over 18 sectors per track}
- $26/$88/$2D/ {MOV ES:[DI],CH - track track number in format array}
- $81/$C7/$04/$00/ {ADD DI,0004}
- $FE/$C8/ {DEC AL}
- $75/$F5/ {JNZ inittrack}
-
- $B6/$00/ {MOV DH,00 - format 9 sectors on side 0}
- $B8/$01/$05/ {MOV AX,0501}
- $CD/$13/ {INT 13}
- $72/$18/ {JB error - check for errors}
-
- $B6/$01/ {MOV DH,01 - format 9 sectors on side 1}
- $B8/$01/$05/ {MOV AX,0501}
- $53/ {PUSH BX}
- $81/$C3/$24/$00/ {ADD BX,0024}
- $CD/$13/ {INT 13}
- $72/$0A/ {JB error - check for errors}
-
- $5B/ {POP BX}
- $FE/$C5/ {INC CH - next track}
- $80/$FD/$28/ {CMP CH,28}
- $75/$D2/ {JNZ nexttrack}
-
- $31/$C0/ {XOR AX,AX - no errors, return 0}
-
- {error:}
- $C4/$7E/$04/ {LES DI,[BP+04]}
- $26/$89/$05 {MOV ES:[DI],AX - return error code}
- );
- END {format} ;
-
- PROCEDURE Verify(drive : Byte; VAR FAT : FATtable; VAR error : Integer);
- {-verify that sectors were formatted}
- VAR
- t, h : Integer;
- cluster, fatofs, topcluster, content : Integer;
- BEGIN
- {initialize the verify buffer - 9 sectors * 512 bytes}
- FillChar(VB, 4608, $F6);
- {verify all sectors}
- FOR t := 0 TO 39 DO
- FOR h := 0 TO 1 DO BEGIN
- BIOSreadSectors(4, drive, 1, t, h, 9, VB, error);
-
- IF error <> 0 THEN BEGIN
- {mark the clusters on this track as unavailable}
- cluster := ((9*(h+2*t)) DIV 2)-4;
- topcluster := cluster+5;
- WHILE cluster < topcluster DO BEGIN
- fatofs := (3*cluster) DIV 2;
- {get a word from the FAT}
- Move(FAT[fatofs], content, 2);
- {replace 12 bits of the word}
- IF Odd(cluster) THEN
- content := content OR $FF70
- ELSE
- content := content OR $0FF7;
- {store it back}
- Move(content, FAT[fatofs], 2);
- cluster := Succ(cluster);
- END;
-
- {reduce the number of tracks available}
- tavail := Pred(tavail);
- END;
- END;
- END {verify} ;
-
- PROCEDURE InitDIR;
- {-initialize a sector for the root directory}
- VAR
- i : Integer;
- BEGIN
- {fill with format bytes}
- FillChar(SB, 512, $F6);
- {mark each directory entry as available}
- FOR i := 1 TO 481 DO
- IF ((i-1) MOD 32) = 0 THEN SB[i] := #0;
- END {initdir} ;
-
- BEGIN
-
- doVerify := True;
-
- {get the drive and doverify option}
- IF ParamCount = 0 THEN BEGIN
- Write('Enter drive to format: ');
- ReadLn(drName);
- END ELSE BEGIN
- {read the command line parameters}
- i := 1;
- drName := '';
- WHILE i <= ParamCount DO BEGIN
- param := ParamStr(i);
- CASE param[1] OF
- '@' : InitBoot; {clone the boot record into this program}
- '-', '/' : {check for options}
- IF (Length(param) = 2) AND (UpCase(param[2]) = 'N') THEN
- doVerify := False
- ELSE
- WriteLn('WARNING: unrecognized command line option ', param);
- ELSE
- drName := param;
- END;
- i := Succ(i);
- END;
- END;
-
- {make sure the bootrecord has been cloned into program}
- IF BR[1] = #0 THEN BEGIN
- WriteLn('You must first clone a copy of the boot record');
- WriteLn('into this program. Call as FMAT @ <Enter> to clone...');
- Halt;
- END;
-
- {check for errors, should use DOS facilities to check non-removables}
- IF (drName = '') OR NOT(UpCase(drName[1]) IN ['A', 'B']) THEN BEGIN
- WriteLn('Drive not Specified or cannot be formatted');
- Halt;
- END;
-
- REPEAT
-
- {get BIOS drive number}
- drive := Ord(UpCase(drName[1]))-65;
-
- Write('Insert new disk in drive ', Chr(65+drive));
- Write(' and press <Enter> to begin formatting ');
- REPEAT
- Read(Kbd, ch)
- UNTIL (ch = ^M);
- WriteLn;
-
- IF ATmachine AND (DOSversion = 3) THEN BEGIN
-
- {get the drive type, necessary when dealing with 1.2MB drives}
- readDASD(drive, dType);
- IF (dType = 0) OR (dType = 3) THEN BEGIN
- WriteLn('Drive is not present or non-removable');
- Halt;
- END;
- IF dType = 2 THEN
- WriteLn('Formatting 360K floppy in 1.2MB drive');
-
- {set the DASD type accordingly}
- setDASD(drive, dType);
-
- END;
-
- Write('Formatting... ');
-
- {set up the disk_base table}
- InitDiskBase;
-
- {lay down format tracks}
- Format(drive, FMT, error);
-
- {restore the disk_base table}
- BiosDiskBase := OldDiskBase;
-
- IF error <> 0 THEN BEGIN
- WriteLn('Error during format...');
- Halt;
- END;
-
- {initialize the FATtable}
- InitFAT;
-
- IF doVerify THEN BEGIN
- {verify sectors}
- Write('Verifying... ');
- Verify(drive, FAT, error);
- END;
-
- IF error <> 0 THEN
- WriteLn('Bad disk, format not verified...')
-
- ELSE BEGIN
-
- Write('Writing BOOT/FAT/DIR... ');
-
- {write the boot record}
- BIOSwriteSectors(drive, 1, 0, 0, 1, BR, error);
-
- {write the FAT sectors}
- Move(FAT[0], SB, 512);
- BIOSwriteSectors(drive, 2, 0, 0, 1, SB, error);
- Move(FAT[512], SB, 512);
- BIOSwriteSectors(drive, 3, 0, 0, 1, SB, error);
- Move(FAT[0], SB, 512);
- BIOSwriteSectors(drive, 4, 0, 0, 1, SB, error);
- Move(FAT[512], SB, 512);
- BIOSwriteSectors(drive, 5, 0, 0, 1, SB, error);
-
- {write the root directory}
- InitDIR;
- BIOSwriteSectors(drive, 6, 0, 0, 1, SB, error);
- BIOSwriteSectors(drive, 7, 0, 0, 1, SB, error);
- BIOSwriteSectors(drive, 8, 0, 0, 1, SB, error);
- BIOSwriteSectors(drive, 9, 0, 0, 1, SB, error);
- BIOSwriteSectors(drive, 1, 0, 1, 1, SB, error);
- BIOSwriteSectors(drive, 2, 0, 1, 1, SB, error);
- BIOSwriteSectors(drive, 3, 0, 1, 1, SB, error);
-
- {calculate bytes available on disk}
- {12 sectors are used by BOOT/FAT/DIR}
- bavail := 512.0*(9.0*tavail-12.0);
- WriteLn('Format complete'#7);
- WriteLn('Bytes Available: ', bavail : 0 : 0);
-
- END;
-
- WriteLn;
- Write('Format another? (Y/N) ');
- REPEAT
- Read(Kbd, ch);
- ch := UpCase(ch);
- UNTIL (ch IN ['Y', 'N']);
- WriteLn(ch);
-
- UNTIL ch = 'N';
-
- END.
- ad(K