Floppy Format Program for XT
Aubrey McIntosh
aubrey at rpp386.cactus.org
Wed Jan 3 17:03:06 AEST 1990
This program works in MS-DOS under Logitech 3.x. It is hard coded
to format a 3.5" drive in drive A: (/dev/fd0) to 720kb. The user
must provide FAT and empty Directory (mkfs must also be run).
There is no I/O, so there is no concern with different calling conventions
between systems: this talks directly with DMA and the NEC765.
NO SYSTEM CALLS are made. The ROM bios is used, but is intact during
the Minix bootup menu period.
I am looking for someone to correspond with as I translate it into C.
I know Zilch about C, and am still trying to get 1.1 --> 1.2 upgrades
from NoDak. Actually, I'm looking for help there too.
If no one comes forth, I may cheat and post format.a in hand translation.
------------------------format.mod---------------------
(*
* NOTICES
* Aubrey McIntosh
* December 4, 1989
* Austin, Texas
*
* world!cs.utexas.edu![ rpp386.Cactus.ORG | val.COM ]!aubrey
*
* Contract Programming Services available.
*
* Copyright 1989 by Aubrey McIntosh.
* Permission granted to make derivative work, and to distribute
* for any reasons, provided that this comment remains intact,
* derivations are identified by author(s), and original works
* can be identified.
*
* BACKGROUND
* This file contains a study for a floppy disk format program
* running under Minix. Unfortunately I haven't written C. However,
* 'we' can translate a working Modula-2 program into C or .asm
* with some confidence. Actually (12/28/89) this draft just
* talks with the NEC765, with little regard for Minix.
*
* Minimal guidance for identifier names and structure taken from
* the floppy.c driver under Minix 1.1
*
* This program (shall) run(s) under MS-DOS with the Logitech 3.x
* environment.
*
* USAGE
* In MS-DOS, type
* c:> format0
* Drive 0 will be formatted as a 720kB 3.5" floppy. (hard coded const)
* use Norton to write dir stock and virgin fat.
* --- This works. ---
*
* In Minix:
* Not yet ported. See future work section.
*
* FUTURE WORK NEEDED
*
* Write a Modula-2 compiler for Minix. :-)
* anyone who has worked on *nix .DEF files ~please~ drop me a line,
* If I do it, everyone will cuss at ~me.~~
*
* Add command line switches for:
* 1) Drive type.
* 2) Which Drive.
* 3) Reformatting with data intact.
* 4) Robustness, e.g. write protected drive
*
* January 2, 1990.
*
* Overview of future work and program environment.
*
* This program will need to be included by build with fsck and init.
* I have not looked at that code to see what needs to be done.
* My current idea is to compile this 'by hand' or else to obtain
* the newly announced Modula-3 compiler which produces C output,
* and end up with the format0.s and executable Minix files.
* I further understand that the ROM bios interrupt tables and
* hardware initialisation is still in the default state when the
* boot menu is active.
*
* An option, d Diskette format, should be added to the startup menu.
* mkfs will be called by the user from the same startup menu.
*
* A decode file, roughly compatible to 'format0.asm,' is available
* for the intrepid.
*
* REFERENCES
* IBM Technical Reference Manual, pn 6025008.
* Minix 1.1 sources, floppy.c, Prentice Hall.
* NEC uPD765 Data Sheet.
* Logitech users manual.
*)
MODULE Format0;
IMPORT DebugPMD, RTSMain, SYSTEM;
MODULE NEC765;
IMPORT SYSTEM, RTSMain,
panic, Relinquish,
seekStatus, STATUSport, DATAport, RATE;
EXPORT
DoRecalibrate,
DoSeek,
DoSenseInterruptStatus,
DoFormatATrack,
(* *)
SR0Bits, HD;
(* Page 6-4 of 1984 NEC data book.
* Primitive I/O support for the 765.
*
* This module should support anything that the NEC765 will do,
* and could be made into a separate module and submitted to a
* library.
*)
TYPE
MainStatus = ( D0B, D1B, D2B, D3B, CB, EXM, DIO, RQM );
SR0 = ( US0, US1, HD, NR, EC, SE, D6, D7 );
SR1 = ( MA, NW, ND, res13, or, DE, res16, EN );
SR2 = ( MD, BC, SN, SH, WC, DD, CM, res27);
SR3 = ( US03, US13, HD3, TS, T0, RY, WP, FT);
MainStatusBits = SET OF MainStatus;
SR0Bits = SET OF SR0;
SR1Bits = SET OF SR1;
SR2Bits = SET OF SR2;
SR3Bits = SET OF SR3;
PROCEDURE DoRecalibrate( (* fdn : CARDINAL *) );
VAR
results : SR0Bits;
PCN : CARDINAL;
BEGIN
WriteDataRegisterFile( Recalibrate );
WriteDataRegisterFile( SR0Bits { } (* Drive 0 *) );
REPEAT
UNTIL 7 IN seekStatus;
EXCL( seekStatus, 7 );
DoSenseInterruptStatus( results, PCN )
END DoRecalibrate;
PROCEDURE DoSeek( Head, NCN : CARDINAL );
VAR
results : SR0Bits;
PCN : CARDINAL;
BEGIN
WriteDataRegisterFile( Seek );
IF Head = 0
THEN
WriteDataRegisterFile( SR0Bits { } (* Head 0 *) )
ELSE
WriteDataRegisterFile( SR0Bits { HD } (* Head 1 *) )
END;
WriteDataRegisterFile( NCN );
END DoSeek;
PROCEDURE DoSenseInterruptStatus(
VAR st0 : SR0Bits;
VAR PCN : CARDINAL);
BEGIN
WriteDataRegisterFile( SenseInterruptStatus );
ReadDataRegisterFile( st0 );
ReadDataRegisterFile( PCN )
END DoSenseInterruptStatus;
PROCEDURE DoFormatATrack( Head : CARDINAL;
Bytes,
Sectors : CARDINAL );
VAR
aux : CARDINAL;
(*The DMA should be armed before this is called.*)
BEGIN
WriteDataRegisterFile( MFM + FormatATrack );
IF Head = 0
THEN
WriteDataRegisterFile( SR0Bits { } (* Head 0 *) )
ELSE
WriteDataRegisterFile( SR0Bits { HD } (* Head 1 *) )
END;
WriteDataRegisterFile( Bytes );
WriteDataRegisterFile( Sectors );
IF (Bytes = 3) AND (Sectors = 5)
THEN (* 3.5" p. 6-11 in Nec Book for Sony drive *)
WriteDataRegisterFile( 74H )
ELSE
WriteDataRegisterFile( 54H )
END;
WriteDataRegisterFile( 0H );
REPEAT (*relinquish*) UNTIL 7 IN seekStatus;
EXCL( seekStatus, 7 );
ReadDataRegisterFile( aux );
ReadDataRegisterFile( aux );
ReadDataRegisterFile( aux );
(*Manditory read of meaningless (sic) results...*)
ReadDataRegisterFile( aux );
ReadDataRegisterFile( aux );
ReadDataRegisterFile( aux );
ReadDataRegisterFile( aux );
END DoFormatATrack;
PROCEDURE ReadMainStatus(): MainStatusBits;
(* Wait 12 usec or longer for the chip to know what it did and update
* the registers, then read the port. As I read the data sheets,
* it will not do to loop poll the chip -- although that is what
* Minix 1.1 floppy.c in fact does do.
*)
VAR
result : MainStatusBits;
BEGIN
Relinquish( 12 );
SYSTEM.INBYTE ( STATUSport, result );
RETURN result
END ReadMainStatus;
PROCEDURE ReadDataRegisterFile( VAR file : ARRAY OF SYSTEM.WORD );
VAR
count : CARDINAL;
BEGIN
REPEAT
(* This should always conclude. *)
(* Jan 2, 1990.
* To be safe, I should actually do more testing on the
* status bits to be sure I'm not here while the NEC765 is
* waiting for the last byte of a command. But this works
* if the next higher level is correct, and I'm gonna release it.
*)
UNTIL (ReadMainStatus ()
* MainStatusBits{ RQM, DIO })
= MainStatusBits{ RQM, DIO };
count := 0;
WHILE (ReadMainStatus ()
* MainStatusBits{ RQM, DIO} = MainStatusBits { RQM, DIO })
AND ( count <= HIGH(file) )
DO
SYSTEM.INBYTE( DATAport, file[ count ] );
INC( count )
END
(* Jan 2, 1990
* This procedure was designed to be called with a packet parameter.
* Then I broke the higher level up during debugging.
* I stripped out all the packet data definitions.
* After I put them back, I would
* assert( count = HIGH(file));
*)
END ReadDataRegisterFile;
PROCEDURE WriteDataRegisterFile( file : ARRAY OF SYSTEM.WORD );
VAR
count : CARDINAL;
BEGIN
REPEAT
(*wait. This should always conclude. *)
UNTIL (ReadMainStatus ()
* MainStatusBits{ RQM, DIO })
= MainStatusBits{ RQM };
count := 0;
WHILE (ReadMainStatus ()
* MainStatusBits{ RQM, DIO} = MainStatusBits { RQM })
AND ( count <= HIGH(file) )
DO
SYSTEM.OUTBYTE( DATAport, file[ count ] );
INC( count )
END
END WriteDataRegisterFile;
CONST
MT = 80H; (* The multi track bit command (PD7265 only) *)
MFM = 40H;
SK = 20H; (* Skip Deleted sector, read next *)
(*These are listed here in the order that they are introduced
*on page 6-6 in the NEC literature. I don't see the pattern.
*)
ReadData = 06H; (* 00110 *)
ReadDeleted = 0CH; (* 01100 *)
WriteData = 05H; (* 00101 *)
WriteDeleted = 09H; (* 01001 *)
ReadATrack = 02H; (* 00010 *)
ReadId = 0AH; (* 01010 *)
FormatATrack = 0DH; (* 01101 *)
ScanEqual = 11H; (* 10001 *)
ScanLowerEqual = 19H; (* 11001 *)
ScanHighEqual = 1DH; (* 11101 *)
Recalibrate = 07H; (* 00111 *)
SenseInterruptStatus = 08H; (* 01000 *)
Specify = 03H; (* 00011 *)
SenseDriveStatus = 04H; (* 00100 *)
Seek = 0FH; (* 01111 *)
END NEC765;
(* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *)
MODULE DiskAdapter;
(*
* This is board designer stuff, and the nec765 module (should be|
* is purely) applicable to the NEC765 and has no board designer
* modifications in it.
*
* I read the schematics in the IBM Technical Reference,
* pn 6025008, Revised Edition, July 1982. The various values
* agree with that schematic, the NEC 765 Data sheet, and floppy.c
*
* This is not intended to be complete enough for a separate
* module in a library, but just 'nuf to get the code out the door.
*
*)
IMPORT SYSTEM;
EXPORT
STATUSport, DATAport, RATE, seekStatus,
MotorOn, MotorOff;
CONST
(* IBM-PC magic I/O addresses.
* Resolved with floppy.c, BIOS, and schematic.
*)
DOR = 03F2H;
STATUSport= 03F4H;
DATAport = 03F5H;
RATE = 03F7H; (* not on XT *)
ENABLEINT = 0CH;
MOTORMASK = 0F0H;
TYPE
ControlDOR = (
DriveSelect0, DriveSelect1, RST765, DMA2Enable,
Motor1, Motor2, Motor3, Motor4 ,
res0, res1, res2, res3, (*A packed byte*)
res4, res5, res6, res7
);
DORBits = SET OF ControlDOR;
VAR
(*ROM bios accomodation*)
seekStatus [ 0040H:003EH ] : BITSET;
status [ 0040H:003FH ] : DORBits;
BitImage [ 0040H:003FH ] : SYSTEM.BYTE;
PROCEDURE MotorOn;
BEGIN
status := status + DORBits { Motor1 }
- DORBits { Motor2, Motor3, Motor4}
(*Hard coded for drive 0*)
- DORBits { DriveSelect0, DriveSelect1 }
(*Set watchdog timer count at 40:40*)
+ DORBits { res0..res7 };
SYSTEM.OUTBYTE( DOR, BitImage )
END MotorOn;
PROCEDURE MotorOff;
BEGIN
status := status - DORBits { DriveSelect0, DriveSelect1 }
- DORBits { Motor1 .. Motor4 };
SYSTEM.OUTBYTE( DOR, status )
END MotorOff;
BEGIN
(*
(*Hmm, if the machine booted, the controller has been
*initialized ok!
*)
status := DORBits{ DMA2Enable };
SYSTEM.OUTBYTE( DOR, status )
INCL( status, RST765 );
*)
status := DORBits{ RST765 , DMA2Enable };
SYSTEM.OUTBYTE( DOR, status );
END DiskAdapter;
(* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *)
MODULE OtherSysStuff;
(*These are suggestions for other goodies in the library.
*)
IMPORT SYSTEM;
EXPORT panic, Relinquish, SetupDMA;
PROCEDURE panic( msg : ARRAY OF CHAR);
BEGIN
(* I set a breakpoint in the RTD.
* Again, this is prototype activity.
*)
END panic;
PROCEDURE Relinquish( time : CARDINAL );
(* On a blindingly fast machine, this would do a call
* into the scheduler or message system, and let other
* work be done while 12 micro seconds crawled by.
*)
CONST
usec = 5; (* I don't know a correct value. *)
overhead = 0 * usec; (* This'un either *)
VAR
ix : CARDINAL;
BEGIN
FOR ix := overhead TO time * usec DO (*nothing*)
(*Can You say optimizer interference?*)
END;
END Relinquish;
PROCEDURE SetupDMA(
dmaout : BOOLEAN;
VAR buffer : ARRAY OF SYSTEM.WORD);
(*nb
**************************************************
*
* WARNING: ESCAPED HACKER IN YOUR VICINITY.
* RESIDENTS ARE URGED TO ADOPT EXTREEM CAUTION.
* HE IS REPORTED TO EXHIBIT CUTE CODE WITHOUT PROVOCATION.
* ARTIFACTS MAY BECOME DANGEROUS WHEN MOVED TO NEW ENVIRONMENTS.
*
**************************************************
* Not Portable. Uses knowledge of compiler output.
* Be wary of optimizers.
* PROC is almost guaranteed to be the wrong size.
* Be careful if you move variables,
* or even change compiler switches. :-)
**************************************************
* I guess folks do this all the time in C without warnings, and
* call it 'close to the machine' huh?
*)
TYPE
ParamStackPtr = POINTER TO ParamStack;
ParamStack =
RECORD
itself : ParamStackPtr;
BP : CARDINAL;
return : PROC;
Offset : CARDINAL;
Segment: CARDINAL;
Size : CARDINAL
END;
VAR
top : CARDINAL;
aux : CARDINAL;
count: CARDINAL;
hook : ParamStackPtr;
CONST
DMAWRITE = 04AH;
DMAREAD = 046H;
DMAStatus = 00BH;
DMATOP = 081H;
DMAADDR = 004H;
DMACOUNT = 005H;
DMAINIT = 00AH;
BEGIN
hook := SYSTEM.ADR( hook );
WITH hook^ DO
IF Size # HIGH( buffer )
THEN
panic( 'Stack structure error in SetupDMA.' )
END;
aux := (Offset DIV 16) + Segment;
top := aux DIV 1000H;
Offset := (Offset MOD 16) + 16 * (aux MOD 1000H);
IF 0FFFFH - SYSTEM.SIZE(buffer) <= Offset
THEN panic ( "Can't set up DMA." )
END;
IF dmaout
(*For some reason Minix sends the status command to
*two DMA channels. So does the ROM bios listing.
*I don't comprehend why. I don't do it. The code works.
*
*What if I'm using DMA for some other device also?
*)
THEN
SYSTEM.OUTBYTE( DMAStatus, DMAWRITE )
ELSE
SYSTEM.OUTBYTE( DMAStatus, DMAREAD )
END;
SYSTEM.OUTBYTE( DMAADDR, Offset MOD 256 );
SYSTEM.OUTBYTE( DMAADDR, Offset DIV 256 );
SYSTEM.OUTBYTE( DMATOP, top );
count := ((1 + HIGH( buffer )) * 2) - 1; (* Byte Count - 1 *)
SYSTEM.OUTBYTE( DMACOUNT, count MOD 256 );
SYSTEM.OUTBYTE( DMACOUNT, count DIV 256 );
SYSTEM.OUTBYTE( DMAINIT, 2 )
END
END SetupDMA;
END OtherSysStuff;
(* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *)
CONST
(*
Sectors = 5;
Bytes = 3 (* 512 -- Note: this is ln2(size)-7 NOT size/128*);
*)
Sectors = 9;
Bytes = 2 (* 512 -- Note: this is ln2(size)-7 NOT size/128*);
Tracks = 80;
Sides = 2;
Out = TRUE;
VAR
track : ARRAY [ 0 .. 9 * 512-1 ] OF CARDINAL;
continue : BOOLEAN;
tracks : CARDINAL;
sectors : CARDINAL;
sides : CARDINAL;
CHRN : (*This is byte packed -- 4 bytes long*)
ARRAY [ 0..Sectors-1 ] OF
RECORD
CH,
RN : CARDINAL
END;
hackTrack : PROCEDURE( BOOLEAN, VAR ARRAY OF SYSTEM.WORD );
results : SR0Bits;
PCN : CARDINAL;
BEGIN
hackTrack := SetupDMA; (* ... defeat a compiler optimisation...*)
WITH CHRN[0] DO
CH := 0;
RN := Bytes * 100H
END;
FOR sectors := 0 TO Sectors - 1 DO
CHRN[ sectors ] := CHRN [0];
CHRN[ sectors ].RN := (sectors + 1) + 100H * Bytes
END;
continue := TRUE;
(* I've got an RTD, 'continue' changes by magic; this is prototyping! *)
WHILE continue DO
MotorOn;
DoRecalibrate;
FOR tracks := 0 TO Tracks - 1 DO
MotorOn;
FOR sides := 0 TO Sides - 1 DO
DoSeek( sides, tracks );
FOR sectors := 0 TO Sectors - 1 DO
CHRN[ sectors ].CH := tracks + 100H * sides
END;
REPEAT (*wait*)
UNTIL 7 IN seekStatus;
EXCL( seekStatus, 7 );
DoSenseInterruptStatus( results, PCN );
SetupDMA( Out, CHRN );
DoFormatATrack( sides, Bytes, Sectors )
END
END;
continue := FALSE (*A breakpoint hook.*)
END;
MotorOff
END Format0.
--
Aubrey McIntosh Freelance using Modula-2
Real time, embedded, instruments.
Austin, TX 78723 Enquiries welcome
1-(512)-452-1540 aubrey%rpp386.Cactus.org at cs.utexas.edu
More information about the Alt.sources
mailing list