<> <> <> DIRECTORY Basics USING [bytesPerWord, DivMod, LowHalf], Floppy USING [Density, FileID, maxCharactersInLabel, nullFileID, PageCount, PageNumber, Sides], FloppyChannel USING [Context, DiskAddress]; FloppyFormat: DEFINITIONS IMPORTS Basics SHARES Floppy = BEGIN <> Sector: TYPE = CARDINAL; <> <> nullSector: Sector = 0; nullBYTE: BYTE = 0; bytesPerWord: CARDINAL = Basics.bytesPerWord; tracksPerCylinder: ARRAY Floppy.Sides[one..two] OF CARDINAL = [one: 1, two: 2]; AsciiToEbcdic: ARRAY CHARACTER [' ..'Z] OF BYTE = [ -- !"#$%&'-- 64, 126, 90, 123, 91, 108, 124, 125, --()*+,-./-- 77, 93, 92, 78, 107, 96, 75, 97, --01234567-- 240, 241, 242, 243, 244, 245, 246, 247, --89:;<=>?-- 248, 249, 122, 94, 76, 126, 110, 111, --@ABCDEFG-- 124, 193, 194, 195, 196, 197, 198, 199, --HIJKLMNO-- 200, 201, 209, 210, 211, 212, 213, 214, --PQRSTUVW-- 215, 216, 217, 226, 227, 228, 229, 230, --XYZ -- 231, 232, 233]; DigitToEbcdic: ARRAY [0..10) OF BYTE = [ AsciiToEbcdic['0], AsciiToEbcdic['1], AsciiToEbcdic['2], AsciiToEbcdic['3], AsciiToEbcdic['4], AsciiToEbcdic['5], AsciiToEbcdic['6], AsciiToEbcdic['7], AsciiToEbcdic['8], AsciiToEbcdic['9]]; blankBYTE: BYTE = AsciiToEbcdic[' ]; SectorToDiskAddress: PROCEDURE [sector: Sector, cylinders: CARDINAL, tracksPerCylinder: CARDINAL, sectorsPerTrack: CARDINAL] RETURNS [diskAddress: FloppyChannel.DiskAddress] = INLINE BEGIN temp: CARDINAL; <> [quotient: temp, remainder: diskAddress.sector] _ Basics.DivMod[sector-1, sectorsPerTrack]; diskAddress.sector _ diskAddress.sector+1; -- sectors begin at 1 [quotient: diskAddress.cylinder, remainder: diskAddress.head] _ Basics.DivMod[temp, tracksPerCylinder]; END; DiskAddressToSector: PROCEDURE [diskAddress: FloppyChannel.DiskAddress, cylinders: CARDINAL, tracksPerCylinder: CARDINAL, sectorsPerTrack: CARDINAL] RETURNS [sector: Sector] = INLINE {RETURN[diskAddress.sector + sectorsPerTrack * (diskAddress.head + tracksPerCylinder * diskAddress.cylinder)]}; <> <> <> < <80*SP><48*NULL>>> < ERMAP<75*SP><48*NULL> (1D)>> < ERMAP<75*SP><48*SP> (2D)>> <>> <<3*SP>2<3*SP><48*SP> ("X8000 " is our optional fill in)>> <> <> < in position 87 means that we have non-IBM labels>> < as trailing bytes for 1D>> <> <00512 01001274008<4*SP>E<30*SP>01001 <48*NULL>>> <> <<(Also for head 1, sectors 1-26, 2S1D. Gleaned from IBM part # 2736700.)>> <<48*NULL>>> <> <512 01001274115<4*SP>E<30*SP>01001<49*SP>>> <> <<13*SP>512 75001274115<4*SP>E<30*SP>75001<49*SP>>> <> <<13*SP>512 75001274115<4*SP>E<30*SP>75001<49*SP>>> <<13*SP>512 75001274115<4*SP>E<30*SP>75001<49*SP>>> <> <> <> <> <> <> <> minTrackZeroSectors: CARDINAL = 9 + badSpotSectors; <> trackZeroContext: FloppyChannel.Context = [protect: FALSE, format: IBM, density: single, sectorLength: 64]; -- (64 words) trackZeroAddress: FloppyChannel.DiskAddress = [cylinder: 0, head: 0, sector: 1]; TrackZero: TYPE = LONG DESCRIPTOR FOR PACKED ARRAY CARDINAL [1..minTrackZeroSectors] OF TrackZeroSector; -- interesting part of track zero TrackZeroSector: TYPE = PACKED ARRAY [0..trackZeroContext.sectorLength*bytesPerWord) OF BYTE; SectorNine: TYPE = MACHINE DEPENDENT RECORD [ <> <> <> <> <> seal (0): CARDINAL _ FloppySeal, version (1): CARDINAL _ FloppyVersion, cylinders (2): CARDINAL, tracksPerCylinder (3): CARDINAL, sectorsPerTrack (4): CARDINAL, fileList (5): Sector _ nullSector, fileListID (6): Floppy.FileID _ Floppy.nullFileID, fileListSize (8): ImplementedFileSize _ 0, rootFile (9): Floppy.FileID _ Floppy.nullFileID, fill(11): CARDINAL _ 0, <> pilotMicrocode (12): Sector _ nullSector, diagnosticMicrocode (13): Sector _ nullSector, germ (14): Sector _ nullSector, pilotBootFile (15): Sector _ nullSector, firstAlternateSector (16): Sector, countBadSectors (17): CARDINAL _ 0, nextUnusedFileID (18): LONG CARDINAL _ 1, changing (20: 0..0): BOOLEAN _ FALSE, pad (20: 1..15): CARDINAL [0..77777B) _ 0, labelSize (21) : CARDINAL _ 0, label (22): PACKED ARRAY [0..Floppy.maxCharactersInLabel) OF CHARACTER _ ALL[' ], sectorOnePad (42): ARRAY [0..64-42) OF WORD _ ALL[0] <> ]; BadSpotSectors: TYPE = PACKED ARRAY [0..maxBadSectors) OF Alternate; <> <> <> <> FloppySeal: CARDINAL = 141414B; -- Must never change! FloppyVersion: CARDINAL = 1; -- Must be incremented every time that the format of track zero or track one changes Format: TYPE = MACHINE DEPENDENT { singleSidedSingleDensity(AsciiToEbcdic[' ]), doubleDensity(AsciiToEbcdic['M]), -- may be single or double sided doubleSidedSingleDensity(AsciiToEbcdic['2]), (255) -- place holder for enumeration }; badSpotSectors: CARDINAL = 2; -- This number may only be increased! badSpotSector: CARDINAL = 10; maxBadSectors: CARDINAL = (trackZeroContext.sectorLength*badSpotSectors)/SIZE[Alternate]; Alternate: TYPE = MACHINE DEPENDENT RECORD [bad (0): Sector, alternate (1): Sector]; nullAlternate: Alternate = [0, 0]; -- Must NOT be changed or future expansion of bad spot table will not be possible. FillTrackZeroSector: PROCEDURE [sector: LONG POINTER TO TrackZeroSector, format: Format, sectorID: Sector] = INLINE BEGIN SELECT sectorID FROM 1, 2, 3, 4, 6 => FillSectorOne[sector, format]; 5 => FillSectorFive[sector, format]; 7 => FillSectorSeven[sector, format]; 8 => FillSectorEight[sector, format]; 9 => ERROR; -- the client must do this himself >= 10 => FillSectorTen[sector, format]; ENDCASE => ERROR; END; FillSectorOne: PROCEDURE [sector: LONG POINTER TO TrackZeroSector, format: Format] = INLINE BEGIN FOR i: CARDINAL IN [0..80) DO sector[i] _ blankBYTE; ENDLOOP; FOR i: CARDINAL IN [80..128) DO sector[i] _ nullBYTE; ENDLOOP; END; FillSectorFive: PROCEDURE [sector: LONG POINTER TO TrackZeroSector, format: Format] = INLINE BEGIN sector[0] _ AsciiToEbcdic['E]; sector[1] _ AsciiToEbcdic['R]; sector[2] _ AsciiToEbcdic['M]; sector[3] _ AsciiToEbcdic['A]; sector[4] _ AsciiToEbcdic['P]; FOR i: CARDINAL IN [5..80) DO sector[i] _ blankBYTE; ENDLOOP; SELECT format FROM singleSidedSingleDensity, doubleSidedSingleDensity => FOR i: CARDINAL IN [80..128) DO sector[i] _ nullBYTE; ENDLOOP; doubleDensity => FOR i: CARDINAL IN [80..128) DO sector[i] _ blankBYTE; ENDLOOP; ENDCASE => ERROR; END; FillSectorSeven: PROCEDURE [sector: LONG POINTER TO TrackZeroSector, format: Format] = INLINE BEGIN sector[0] _ AsciiToEbcdic['V]; sector[1] _ AsciiToEbcdic['O]; sector[2] _ AsciiToEbcdic['L]; sector[3] _ AsciiToEbcdic['1]; sector[4] _ AsciiToEbcdic['X]; sector[5] _ AsciiToEbcdic['8]; sector[6] _ AsciiToEbcdic['0]; sector[7] _ AsciiToEbcdic['0]; sector[8] _ AsciiToEbcdic['0]; sector[9] _ blankBYTE; FOR i: CARDINAL IN [10..71) DO sector[i] _ blankBYTE; ENDLOOP; sector[71] _ LOOPHOLE[format]; FOR i: CARDINAL IN [72..75) DO sector[i] _ blankBYTE; ENDLOOP; sector[75] _ AsciiToEbcdic['2]; FOR i: CARDINAL IN [76..80) DO sector[i] _ blankBYTE; ENDLOOP; SELECT format FROM singleSidedSingleDensity, doubleSidedSingleDensity => FOR i: CARDINAL IN [80..128) DO sector[i] _ blankBYTE; ENDLOOP; doubleDensity => FOR i: CARDINAL IN [80..128) DO sector[i] _ nullBYTE; ENDLOOP; ENDCASE => ERROR; END; FillSectorEight: PROCEDURE [sector: LONG POINTER TO TrackZeroSector, format: Format] = INLINE BEGIN sector[0] _ AsciiToEbcdic['H]; sector[1] _ AsciiToEbcdic['D]; sector[2] _ AsciiToEbcdic['R]; sector[3] _ AsciiToEbcdic['1]; sector[4] _ blankBYTE; sector[5] _ AsciiToEbcdic['D]; sector[6] _ AsciiToEbcdic['A]; sector[7] _ AsciiToEbcdic['T]; sector[8] _ AsciiToEbcdic['1]; FOR i: CARDINAL IN [9..22) DO sector[i] _ blankBYTE; ENDLOOP; <> sector[24] _ AsciiToEbcdic['5]; sector[25] _ AsciiToEbcdic['1]; sector[26] _ AsciiToEbcdic['2]; sector[27] _ blankBYTE; sector[28] _ AsciiToEbcdic['0]; sector[29] _ AsciiToEbcdic['1]; sector[30] _ AsciiToEbcdic['0]; sector[31] _ AsciiToEbcdic['0]; sector[32] _ AsciiToEbcdic['1]; sector[33] _ AsciiToEbcdic['2]; sector[34] _ AsciiToEbcdic['7]; sector[35] _ AsciiToEbcdic['4]; <> FOR i: CARDINAL IN [39..43) DO sector[i] _ blankBYTE; ENDLOOP; sector[43] _ AsciiToEbcdic['E]; FOR i: CARDINAL IN [44..74) DO sector[i] _ blankBYTE; ENDLOOP; sector[74] _ AsciiToEbcdic['0]; sector[75] _ AsciiToEbcdic['1]; sector[76] _ AsciiToEbcdic['0]; sector[77] _ AsciiToEbcdic['0]; sector[78] _ AsciiToEbcdic['1]; <> SELECT format FROM singleSidedSingleDensity, doubleSidedSingleDensity => BEGIN sector[22] _ AsciiToEbcdic['0]; sector[23] _ AsciiToEbcdic['0]; sector[36] _ AsciiToEbcdic['0]; sector[37] _ AsciiToEbcdic['0]; sector[38] _ AsciiToEbcdic['8]; sector[79] _ blankBYTE; FOR i: CARDINAL IN [80..128) DO sector[i] _ nullBYTE; ENDLOOP; END; doubleDensity => BEGIN sector[22] _ blankBYTE; sector[23] _ blankBYTE; sector[36] _ AsciiToEbcdic['1]; sector[37] _ AsciiToEbcdic['1]; sector[38] _ AsciiToEbcdic['5]; FOR i: CARDINAL IN [79..128) DO sector[i] _ nullBYTE; ENDLOOP; END; ENDCASE => ERROR; END; FillSectorTen: PROCEDURE [sector: LONG POINTER TO TrackZeroSector, format: Format] = INLINE BEGIN FOR i: CARDINAL IN [0..128) DO sector[i] _ 0; ENDLOOP; END; <> trackOneContext: ARRAY Floppy.Density[single..double] OF FloppyChannel.Context = [ single: [protect: FALSE, format: IBM, density: single, sectorLength: 64], -- lengths in words double: [protect: FALSE, format: IBM, density: double, sectorLength: 128]]; trackOneAddress: FloppyChannel.DiskAddress = [cylinder: 0, head: 1, sector: 1]; trackOneSectorSize: ARRAY Floppy.Density[single..double] OF CARDINAL = [single: 128, double: 256]; --bytes TrackOneSector: TYPE = PACKED ARRAY [0..256) OF BYTE; -- actually PACKED ARRAY [0..trackOneSectorSize[diskDensity]) OF BYTE FillTrackOneSector: PROCEDURE [sector: LONG POINTER TO TrackOneSector, format: Format, sectorID: CARDINAL [1..26]] = INLINE BEGIN SELECT format FROM singleSidedSingleDensity => ERROR; doubleSidedSingleDensity => BEGIN sector[1] _ AsciiToEbcdic['D]; FOR i: CARDINAL IN [2..81) DO sector[i] _ blankBYTE; ENDLOOP; FOR i: CARDINAL IN [2..81) DO sector[i] _ nullBYTE; ENDLOOP; END; doubleDensity => FOR base: CARDINAL _ 0, base+128 WHILE base < 129 DO sector[base+0] _ AsciiToEbcdic['D]; sector[base+1] _ AsciiToEbcdic['D]; sector[base+2] _ AsciiToEbcdic['R]; sector[base+3] _ AsciiToEbcdic['1]; sector[base+4] _ blankBYTE; sector[base+5] _ AsciiToEbcdic['D]; sector[base+6] _ AsciiToEbcdic['A]; sector[base+7] _ AsciiToEbcdic['T]; sector[base+8] _ AsciiToEbcdic['1]; SELECT base FROM 0 => BEGIN sector[base+9] _ DigitToEbcdic[(27+2*(sectorID-1))/10]; sector[base+10] _ DigitToEbcdic[(27+2*(sectorID-1)) MOD 10]; END; 128 => BEGIN sector[base+9] _ DigitToEbcdic[(28+2*(sectorID-1))/10]; sector[base+10] _ DigitToEbcdic[(28+2*(sectorID-1)) MOD 10]; END; ENDCASE => ERROR; FOR i: CARDINAL IN [0..13) DO sector[base+11+i] _ blankBYTE; ENDLOOP; sector[base+24] _ AsciiToEbcdic['5]; sector[base+25] _ AsciiToEbcdic['1]; sector[base+26] _ AsciiToEbcdic['2]; sector[base+27] _ blankBYTE; sector[base+28] _ AsciiToEbcdic['7]; sector[base+29] _ AsciiToEbcdic['5]; sector[base+30] _ AsciiToEbcdic['0]; sector[base+31] _ AsciiToEbcdic['0]; sector[base+32] _ AsciiToEbcdic['1]; sector[base+33] _ AsciiToEbcdic['2]; sector[base+34] _ AsciiToEbcdic['7]; sector[base+35] _ AsciiToEbcdic['4]; sector[base+36] _ AsciiToEbcdic['1]; sector[base+37] _ AsciiToEbcdic['1]; sector[base+38] _ AsciiToEbcdic['5]; FOR i: CARDINAL IN [0..4) DO sector[base+39+i] _ blankBYTE; ENDLOOP; sector[base+43] _ AsciiToEbcdic['E]; FOR i: CARDINAL IN [0..30) DO sector[base+44+i] _ blankBYTE; ENDLOOP; sector[base+74] _ AsciiToEbcdic['7]; sector[base+75] _ AsciiToEbcdic['5]; sector[base+76] _ AsciiToEbcdic['0]; sector[base+77] _ AsciiToEbcdic['0]; sector[base+78] _ AsciiToEbcdic['1]; FOR i: CARDINAL IN [0..49) DO sector[base+76+i] _ blankBYTE; ENDLOOP; ENDLOOP; ENDCASE => ERROR; END; <> dataContext: ARRAY Floppy.Density[single..double] OF FloppyChannel.Context = [single: [protect: FALSE, format: IBM, density: single, sectorLength: 256], -- length in words double: [protect: FALSE, format: IBM, density: double, sectorLength: 256]]; firstDataAddress: FloppyChannel.DiskAddress = [cylinder: 1, head: 0, sector: 1]; <> MarkerPage: TYPE = MACHINE DEPENDENT RECORD [ seal (0): CARDINAL _ MarkerSeal, version (1): CARDINAL _ MarkerPageVersion, previous (2): MarkerPageEntry, next (129): MarkerPageEntry]; MarkerPageEntry: TYPE = MACHINE DEPENDENT RECORD [ length (0): Floppy.PageCount, body (2): SELECT type(2:0..15): MarkerPageEntryType [free..badSectors] FROM free => [pad (3): ARRAY [0..124) OF WORD _ ALL[0]], file => [file (3): Floppy.FileID, type (5): -- File.Type -- CARDINAL, pad (6) : ARRAY [0..121) OF WORD _ ALL[0]], fileList => [file (3): Floppy.FileID, type (5): -- File.Type -- CARDINAL, pad (6): ARRAY [0..121) OF WORD _ ALL[0]], badSectors => [pad (3): ARRAY [0..124) OF WORD _ ALL[0]] ENDCASE]; MarkerSeal: CARDINAL = 031313B; MarkerPageVersion: CARDINAL = 1; -- must be changed whenever the format of a marker page changes MarkerPageEntryType: TYPE = MACHINE DEPENDENT {free(0), file (1), fileList(2), badSectors(3), (177777B)}; MarkerPageSize: [256..256] = SIZE[MarkerPage]; <> InitialMicrocodeDiskAddress: FloppyChannel.DiskAddress = [cylinder: 5, head: 0, sector: 1]; <> FileList: TYPE = MACHINE DEPENDENT RECORD [ seal (0): CARDINAL _ FileListSeal, version (1): CARDINAL _ FileListVersion, count (2): CARDINAL _ 0, maxEntries (3): CARDINAL, files (4): SEQUENCE COMPUTED CARDINAL OF FileListEntry]; FileListEntry: TYPE = MACHINE DEPENDENT RECORD [ file (0): Floppy.FileID _ Floppy.nullFileID, type (2): -- File.Type -- CARDINAL _ -- FileTypes.tUntypedFile -- 0, location (3): Sector _ nullSector, size (4): ImplementedFileSize _ 0]; ImplementedFileSize: TYPE = CARDINAL; ConvertPageCount: PROCEDURE [size: Floppy.PageCount] RETURNS [ImplementedFileSize] = INLINE {RETURN[Basics.LowHalf[size]]}; ConvertPageNumber: PROCEDURE [num: Floppy.PageNumber] RETURNS [ImplementedFileSize] = INLINE {RETURN[Basics.LowHalf[num]]}; FileListSeal: CARDINAL = 131313B; FileListVersion: CARDINAL = 1; -- Must be incremented whenever the format of a FileList changes END.