forked from climatex/8FORMAT
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path8FORMAT.C
632 lines (534 loc) · 17.5 KB
/
8FORMAT.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <dir.h>
#include "8format.h"
#include "8floppy.h"
#include "isadma.h"
/* Obtained from the command line later */
unsigned int nFDCBase = 0x3f0;
unsigned char nUseFM = 0;
unsigned char nFormatWithVerify = 0;
unsigned char nQuickFormat = 0;
unsigned char nNoCreateFilesystem = 1;
unsigned char nDriveNumber = 0;
unsigned char nTracks = 77;
unsigned char nHeads = 2;
unsigned int nPhysicalSectorSize = 0;
unsigned int nLogicalSectorSize = 0;
unsigned char nSectorsPerTrack = 0;
unsigned char nLogicalSectorsPerTrack = 0;
unsigned char nCustomGapLength = 0;
unsigned char nCustomGap3Length = 0;
unsigned char nOnlyReprogramBIOS = 0;
unsigned char nOnlyRecalibrateFDD = 0;
unsigned char nUseIRQ = 6;
unsigned char nUseDMA = 2;
unsigned char nLaunch8TSR = 0;
unsigned char sFormatType[5] = {0};
unsigned char nFormatByte = 0xF6;
/* Terminate with exit code, do cleanup beforehand */
void Quit(int nStatus)
{
RemoveISR();
FDDHeadRetract();
FreeDMABuffer();
/* Important before passing control to DOS */
FDDResetBIOS();
/* EXEC 8TSR if need be */
if (nLaunch8TSR == 1)
{
/* 8TSR.EXE must exist */
char* pSearchPath = searchpath("8tsr.exe");
/* Not in current directory, not in PATH */
if (pSearchPath == NULL)
{
printf("\n8TSR.EXE not found, cannot set the BIOS diskette parameter table.\n");
}
/* Nested too much in 255byte PATH? */
else if (strlen(pSearchPath) > 200)
{
printf("\n8TSR.EXE nested in too many subdirectories. Aborting.\n");
}
/* Overlay process */
else
{
FDDWriteINT1Eh(pSearchPath);
}
printf("\nError launching 8TSR.EXE\n");
}
/* Exit to OS */
exit(nStatus);
}
/* Determine if the machine is an IBM 5150 or XT. */
unsigned char IsPCXT()
{
unsigned char nPcByte = *((unsigned char far*)MK_FP(0xf000, 0xfffe));
return (nPcByte > 0xfc) || (nPcByte == 0xfb);
}
/* Discard crappy systems right off the bat */
void DetectMemory()
{
asm int 0x12
if (_AX < 256)
{
printf("\nNot enough memory\n");
Quit(EXIT_FAILURE);
}
}
/* Redraw line */
void DelLine()
{
printf("\r \r");
}
/* Print splash */
void PrintSplash()
{
printf("8FORMAT - 8\" floppy format utility for DOS, (c) J. Bogin\n");
/* And quit rightaway :) */
DetectMemory();
}
/* Printed on incorrect or no command line arguments */
void PrintUsage()
{
printf("\nUse either 8FORMAT X: TYPE [/1] [/V] [/MFM] [/FAT12] [/Q]\n"
" [/FDC port] [/IRQ num] [/DMA num] [/G len] [/G3 len]\n"
" or 8FORMAT /USE TYPE [/1] [/G len] [/G3 len], where:\n\n"
" X: the drive letter where the 77-track 8\" disk drive is installed; A to D,\n"
" TYPE sets geometry, density (data encoding) and physical sector size:\n"
" DSSD: 500kB double-sided, single-density (FM), 26 128B sectors,\n"
" DSDD: 1.2MB double-sided, double-density (MFM), 8 1024B sectors,\n"
" EXT1: 1.2MB double-sided, double-density (MFM), 16 512B sectors,\n"
" EXT2: 1.0MB double-sided, double-density (MFM), 26 256B sectors,\n"
" EXT3: 693kB double-sided, double-density (MFM), 9 512B sectors.\n"
" /USE for BIOS to use new Diskette Parameter Table for given TYPE geometry.\n"
" Applied for ALL floppy drives until reboot. Disk stays untouched.\n"
" /1 (optional): Single-sided format for the chosen TYPE. Capacity halved.\n"
" /V (optional): Format and verify. MUCH slower.\n"
" /MFM (optional): Use MFM data encoding with type DSSD.\n"
" /FAT12 (optional): Format and try writing the DOS boot sector and filesystem.\n"
" /Q (optional): Do not format, just write the boot sector and filesystem.\n"
" /FDC (optional): Use a different FD controller base hex port; default 0x3f0.\n"
" Use /IRQ (3..15) and /DMA (0..3) to override default IRQ 6 and DMA 2.\n"
" /G,/G3 (optional): Custom GAP (write) or Gap3 (format) sizes in hex. Max 0xff.\n");
Quit(EXIT_SUCCESS);
}
/* Parse the command line */
void ParseCommandLine(int argc, char* argv[])
{
int indexArgs = 0;
unsigned char nForce512Physical = 0;
/* Incorrect number of arguments */
if ((argc < 3) || (argc > 20))
{
PrintUsage();
}
for (indexArgs = 1; indexArgs < argc; indexArgs++)
{
/* Case insensitive comparison */
const char* pArgument = strupr(argv[indexArgs]);
/* Determine drive letter */
if (indexArgs == 1)
{
/* Only update the global BIOS Diskette Parameter Table, /USE TYPE
Optional: /1, /G, /G3, /512PH (UNDOCUMENTED) */
if (strcmp(pArgument, "/USE") == 0)
{
nOnlyReprogramBIOS = 1;
continue;
}
/* Determine drive letter (physical drive number) */
if ((strlen(pArgument) > 2) || ((strlen(pArgument) == 2) && pArgument[1] != ':'))
{
PrintUsage();
}
/* Must be A: to D: */
nDriveNumber = pArgument[0] - 65;
if (nDriveNumber > 3)
{
PrintUsage();
}
}
/* Determine TYPE (density and geometry combo) */
else if (indexArgs == 2)
{
/* ! UNDOCUMENTED: Only try to fix an out-of-alignment drive caused by BIOS POST seek
Requires drive letter as a first argument */
if ((strcmp(pArgument, "/UNFUCK") == 0) && (nOnlyReprogramBIOS == 0))
{
nOnlyRecalibrateFDD = 1;
break;
}
/* Determine TYPE */
if (strlen(pArgument) != 4)
{
PrintUsage();
}
/* Copy TYPE string. */
strncpy(sFormatType, pArgument, 4);
/* 500kB DSSD */
if (strcmp(pArgument, "DSSD") == 0)
{
nUseFM = 1;
nSectorsPerTrack = 26;
nLogicalSectorsPerTrack = 26;
nPhysicalSectorSize = 128;
nLogicalSectorSize = 128;
}
/* 1.2MB DSDD */
else if (strcmp(pArgument, "DSDD") == 0)
{
nSectorsPerTrack = 8;
nLogicalSectorsPerTrack = 8;
nPhysicalSectorSize = 1024;
nLogicalSectorSize = 1024;
}
/* 1.2MB EXT1 */
else if (strcmp(pArgument, "EXT1") == 0)
{
nSectorsPerTrack = 16;
nLogicalSectorsPerTrack = 16;
nPhysicalSectorSize = 512;
nLogicalSectorSize = 512;
}
/* 1.0MB EXT2 */
else if (strcmp(pArgument, "EXT2") == 0)
{
nSectorsPerTrack = 26;
nLogicalSectorsPerTrack = 26;
nPhysicalSectorSize = 256;
nLogicalSectorSize = 256;
}
/* 693kB EXT3 */
else if (strcmp(pArgument, "EXT3") == 0)
{
nSectorsPerTrack = 9;
nLogicalSectorsPerTrack = 9;
nPhysicalSectorSize = 512;
nLogicalSectorSize = 512;
}
/* 1.3MB CRAM UNDOCUMENTED */
else if (strcmp(pArgument, "CRAM") == 0)
{
nTracks = 78;
nSectorsPerTrack = 17;
nLogicalSectorsPerTrack = 17;
nPhysicalSectorSize = 512;
nLogicalSectorSize = 512;
nCustomGapLength = 16;
nCustomGap3Length = 32;
}
/* Unrecognized */
else
{
PrintUsage();
}
}
/* Force MFM encoding */
else if (strcmp(pArgument, "/MFM") == 0)
{
nUseFM = 0;
}
/* Force single-sided operation */
else if (strcmp(pArgument, "/1") == 0)
{
nHeads = 1;
}
/* UNDOCUMENTED: Recalculate geometry with 512-byte physical sectors, treat TYPE as logical */
else if (strcmp(pArgument, "/512PH") == 0)
{
nForce512Physical = 1;
}
/* Format with verify */
else if (strcmp(pArgument, "/V") == 0)
{
nFormatWithVerify = 1;
}
/* Format and create filesystem */
else if (strcmp(pArgument, "/FAT12") == 0)
{
nNoCreateFilesystem = 0;
}
/* Create FAT12 only */
else if (strcmp(pArgument, "/Q") == 0)
{
nQuickFormat = 1;
nNoCreateFilesystem = 0;
}
/* Custom floppy drive controller port has been specified */
else if ((strcmp(pArgument, "/FDC") == 0) && (argc > indexArgs+1))
{
char* pEndPointer;
unsigned long nPort = strtoul(argv[++indexArgs], &pEndPointer, 16);
if ((nPort != 0) && (nPort < 0xffff))
{
nFDCBase = (unsigned int)nPort;
}
else
{
PrintUsage();
}
}
/* Custom write gap length has been specified */
else if ((strcmp(pArgument, "/G") == 0) && (argc > indexArgs+1))
{
char* pEndPointer;
unsigned long nGapLen = strtoul(argv[++indexArgs], &pEndPointer, 16);
if ((nGapLen != 0) && (nGapLen <= 0xff))
{
nCustomGapLength = (unsigned char)nGapLen;
}
else
{
PrintUsage();
}
}
/* Custom format gap3 length has been specified */
else if ((strcmp(pArgument, "/G3") == 0) && (argc > indexArgs+1))
{
char* pEndPointer;
unsigned long nGapLen = strtoul(argv[++indexArgs], &pEndPointer, 16);
if ((nGapLen != 0) && (nGapLen <= 0xff))
{
nCustomGap3Length = (unsigned char)nGapLen;
}
else
{
PrintUsage();
}
}
/* Custom IRQ number (dec.) */
else if ((strcmp(pArgument, "/IRQ") == 0) && (argc > indexArgs+1))
{
int nIrq = atoi(argv[++indexArgs]);
if ((nIrq > 2) && (nIrq < 16))
{
nUseIRQ = (unsigned char)nIrq;
}
else
{
PrintUsage();
}
}
/* Custom 8-bit DMA channel */
else if ((strcmp(pArgument, "/DMA") == 0) && (argc > indexArgs+1))
{
int nDma = atoi(argv[++indexArgs]);
if ((nDma >= 0) && (nDma < 4))
{
nUseDMA = (unsigned char)nDma;
}
else
{
PrintUsage();
}
}
/* Invalid or misspelled command */
else
{
PrintUsage();
}
}
/* Force 512B physical sectors and logical TYPE - change the physical geometry */
if (nForce512Physical == 1)
{
unsigned int nTotalBytesPerTrack = nSectorsPerTrack * nPhysicalSectorSize;
nPhysicalSectorSize = 512;
/* Recalculate new (physical) sectors per track count, keep the logical count as is. */
nSectorsPerTrack = (unsigned char)(nTotalBytesPerTrack / nPhysicalSectorSize);
if ((nTotalBytesPerTrack % nPhysicalSectorSize) > 0)
{
nSectorsPerTrack++;
}
}
/* Only update the DPT or recal the drive - do not show any warnings following */
if ((nOnlyReprogramBIOS == 1) || (nOnlyRecalibrateFDD == 1))
{
return;
}
/* Info or warning messages follow. */
/* Running on IBM PC/XT */
if (IsPCXT() == 1)
{
printf("\nWARNING: IBM 5150 or XT detected. Unless there's a high-density capable FDC,"
"\n8\" floppy access won't work (500kHz clock rate%sis required).\n",
(nUseFM == 1) ? " with FM support " : " ");
}
/* Custom FDC port, IRQ or DMA specified ? */
if ((nFDCBase != 0x3f0) || (nUseIRQ != 6) || (nUseDMA != 2))
{
printf("\nUsing floppy controller base address at 0x%03X, IRQ %d and DMA channel %d.\n", nFDCBase, nUseIRQ, nUseDMA);
}
/* FAT on a non-standard physical sector size */
if ((nNoCreateFilesystem == 0) && (nPhysicalSectorSize != 512))
{
printf("\nWARNING: non-standard physical sector size for a FAT12 floppy (%u bytes).\n"
"The disk might not be DOS-accessible.\n", nPhysicalSectorSize);
}
/* FAT on a non-standard 512B geometry */
if ((nNoCreateFilesystem == 0) && (nForce512Physical == 1))
{
printf("\nWARNING: non-standard 512B sector geometry for a FAT12 floppy.\n"
"Using FAT media ID 0xf0, the disk might not be universally accessible however.\n");
}
}
unsigned char WaitEnterOrEscape()
{
unsigned char nScanCode = 0;
/* While not ENTER (or ESC) */
while ((nScanCode != 0x1C) && (nScanCode != 1))
{
asm xor ax,ax
asm int 16h
asm mov nScanCode,ah
}
return nScanCode;
}
void AskToContinue()
{
printf("Insert a disk into drive %c: and press ENTER to continue; ESC to quit...",
nDriveNumber + 65);
/* ESC */
if (WaitEnterOrEscape() == 1)
{
printf(" ESC\n");
Quit(EXIT_SUCCESS);
}
DelLine();
}
void DoOperations()
{
/* Only reprogram the BIOS floppy geometry ? */
if (nOnlyReprogramBIOS == 1)
{
FDDWriteINT1Eh(NULL);
Quit(EXIT_SUCCESS);
}
/* UNDOCUMENTED: Only try to fix a drive out of alignment ? */
if (nOnlyRecalibrateFDD == 1)
{
FDDReset();
FDDCalibrate();
/* Seek to the last 77th track, and back to track 0 again */
FDDSeek(76, 0);
delay(500);
FDDCalibrate();
Quit(EXIT_SUCCESS);
}
/* Inform about the drive geometry */
printf("\nUsing%s TYPE %s with the following physical geometry and parameters:\n"
"%u tracks, %u %s, %u %uB sectors, R/W gap 0x%02X, Gap3 0x%02X, 500kHz%s %s%s.\n\n",
((nPhysicalSectorSize != nLogicalSectorSize) && (nNoCreateFilesystem == 0)) ? " logical" : "",
sFormatType,
nTracks,
nHeads,
(nHeads > 1) ? "heads" : "head",
nSectorsPerTrack,
nPhysicalSectorSize,
GetGapLength(0),
GetGapLength(1),
(IsPCXT() == 1) ? "(?)" : "",
(nUseFM == 1) ? "FM" : "MFM",
((IsPCXT() == 1) && (nUseFM == 1)) ? "(?)" : "");
/* Ask to put the disk into drive */
AskToContinue();
/* Initialize DMA */
InitializeDMABuffer();
/* Prepare FDC and drive */
printf("Initializing floppy drive controller...");
FDDReset();
FDDCalibrate();
/* Seek to the last 77th track, and back to track 0 again */
FDDSeek(76, 0);
delay(500);
FDDCalibrate();
DelLine();
/* Format 77 tracks */
if (nQuickFormat == 0)
{
unsigned char nTrackIndex = 0;
unsigned char nHeadIndex = 0;
unsigned int nBadsOccurence = 0;
randomize();
printf("Formatting...\n");
for (; nTrackIndex < nTracks; nTrackIndex++)
{
while (nHeadIndex != nHeads)
{
printf("\rHead: %u Track: %u ", nHeadIndex, nTrackIndex);
FDDSeek(nTrackIndex, nHeadIndex);
/* Format without verify? */
if (nFormatWithVerify == 0)
{
printf("\r");
FDDFormat();
}
else
{
/* Format with verify */
unsigned char nVerifyResult;
unsigned char nRandomIndex;
const unsigned char nTestWriteByte = (unsigned char)random(256);
printf(" Format");
FDDFormat(); /* Whole track at once */
/* Write random byte on all sectors on track */
printf(" Write");
memset(pDMABuffer, nTestWriteByte, nPhysicalSectorSize*nSectorsPerTrack);
FDDWrite(0xff); /* whole track */
/* Read the sectors. Compare the last byte of each (sector buffer is filled with nTestWriteByte) */
printf(" Verify");
memset(pDMABuffer, 0, nPhysicalSectorSize*nSectorsPerTrack);
FDDRead(0xff); /* whole track */
nRandomIndex = random(nPhysicalSectorSize*nSectorsPerTrack); /* Random buffer position */
nVerifyResult = pDMABuffer[nRandomIndex] == nTestWriteByte; /* Verify buffer contents */
if (nVerifyResult != 1)
{
printf(" - did not format correctly\n");
nBadsOccurence++;
}
/* Verify success */
else
{
DelLine();
/* Format the track again */
FDDFormat();
}
}
nHeadIndex++;
}
nHeadIndex = 0;
}
/* Skip creation of filesystem if any bad occurences were found during verify */
if (nBadsOccurence > 0)
{
printf("\n\nA total of %d tracks failed to format properly.", nBadsOccurence);
if (nNoCreateFilesystem == 0)
{
printf("\nSkipping filesystem creation. To force it, run 8FORMAT without /V.");
nNoCreateFilesystem = 1;
}
printf("\n");
}
}
DelLine();
/* Write FAT12 */
if (nNoCreateFilesystem == 0)
{
printf("Creating file system...\n");
WriteFAT12();
}
printf("Finished.\n\n");
FDDHeadRetract();
/* Ask to update the BIOS INT 1Eh diskette parameter table */
printf("Apply a new BIOS Diskette Parameter Table (DPT) to reflect the new 8\" geometry?\n"
"The BIOS/DOS will then try to use the new sector size, sector and track counts.\n"
"Be warned that other floppy drives will not work until you reboot.\n"
"Do not proceed if you run 8FORMAT from an another floppy drive.\n"
"ENTER: continue, ESC: skip.\n");
/* Update BIOS floppy parameter table */
if (WaitEnterOrEscape() == 0x1C)
{
FDDWriteINT1Eh(NULL);
}
Quit(EXIT_SUCCESS);
}