--FormatSA800Impl.mesa (last edited by: Forrest March 24, 1981 5:07 PM) -- A central place for floppy definitions needs to be established. There are too many constants burried in this module -- when formatting, should we write than read a known pattern?? DIRECTORY DiskChannel USING [PVHandle], FormatSA800, FloppyChannel USING [ Context, DiskAddress, GetDeviceAttributes, Nop, SetContext, ReadSectors, Recalibrate, Status, WriteSectors], FloppyChannelInternal USING [DoRequest, OpBlock], Inline USING [DIVMOD], PilotFloppyFormat USING [firstRealCylinder, logicalTrack0], PhysicalVolume USING [ AssertNotAPilotVolume, FinishWithNonPilotVolume, PageNumber], SA800Face USING [DiskAddress, Function]; FormatSA800Impl: PROGRAM IMPORTS FloppyChannel, FloppyChannelInternal, Inline, PhysicalVolume EXPORTS FormatSA800, PhysicalVolume = BEGIN --PhysicalVolume.--Handle: PUBLIC TYPE = DiskChannel.PVHandle; -- Constants track0Context: FloppyChannel.Context = [protect: FALSE, format: IBM, density: single, sectorLength: 64]; trackBufferLength: CARDINAL = 80; floppyCylinders: CARDINAL = 77; firstPilotTrack: CARDINAL = PilotFloppyFormat.logicalTrack0 + PilotFloppyFormat.firstRealCylinder; -- Signals BadSector: PUBLIC SIGNAL [p: PhysicalVolume.PageNumber] = CODE; TrackBufferLengthTooSmall: ERROR = CODE; -- this procedure really belongs in FloppyChannelImpl FormatTracks: PUBLIC PROCEDURE [ handle: Handle, start: FloppyChannel.DiskAddress, trackCount: CARDINAL] RETURNS[status: FloppyChannel.Status, countDone: CARDINAL] = BEGIN b: ARRAY [0..trackBufferLength) OF UNSPECIFIED; req: FloppyChannelInternal.OpBlock _ [ device: handle, function: formatTrack, address: [ cylinder: start.cylinder, head: start.head, sector: start.sector], buffer: [@b, trackBufferLength], incrementDataPtr: FALSE, count: trackCount]; IF FloppyChannel.GetDeviceAttributes[handle].attributes.trackLength > trackBufferLength THEN ERROR TrackBufferLengthTooSmall; [status, countDone] _ FloppyChannelInternal.DoRequest[@req]; END; -- for runtime use e: PROC [c: CHARACTER] RETURNS [[0..400B)] = BEGIN IF c IN ['a..'z] THEN c _ 'A+(c-'a); SELECT c FROM ' => RETURN[64]; IN ['0..'9] => RETURN[240+(c-'0)]; IN ['A..'I] => RETURN[193+(c-'A)]; IN ['J..'R] => RETURN[209+(c-'J)]; IN ['S..'Z] => RETURN[226+(c-'S)]; ENDCASE => RETURN[226+('X-'S)]; END; -- for compile time use E: ARRAY CHARACTER [' ..'Z] OF [0..400B) = [ -- !"#$%&'-- 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, 196, 198, 199, --HIJKLMNO-- 200, 201, 209, 210, 211, 212, 213, 214, --PQRSTUVW-- 215, 216, 217, 226, 227, 228, 229, 230, --XYZ -- 231, 232, 233]; FormatPilotDisk: PUBLIC PROC [ handle: Handle, name: STRING _ NIL, density: FormatSA800.Density _ tryDoubleThenSingle] RETURNS[status: FloppyChannel.Status, result: FormatSA800.PilotResult] = BEGIN count: CARDINAL; context: FloppyChannel.Context _ [ protect: FALSE, format: IBM, density: double, sectorLength: 256]; heads: CARDINAL; sectorsPerTrack: CARDINAL; PhysicalVolume.AssertNotAPilotVolume[handle]; IF density=single OR ~FloppyChannel.SetContext[handle, context] THEN BEGIN context.density _ single; IF density=double OR ~FloppyChannel.SetContext[handle, context] THEN {result _ cantSetContext; GOTO done}; sectorsPerTrack _ 8; END ELSE sectorsPerTrack _ 15; -- format cylinder 0 BEGIN b: PACKED ARRAY [0..128) OF [0..400B); [] _ FloppyChannel.Recalibrate[handle]; IF ~FloppyChannel.SetContext[handle, track0Context] THEN {result _ cantSetContext; GOTO done}; [status, count] _ FormatTracks[handle, [cylinder: 0, head: 0, sector: 1], 2]; IF count#2 THEN {result _ badTrack0; GOTO done}; heads _ IF status.twoSided THEN 2 ELSE 1; FOR i: CARDINAL IN [0..80) DO b[i] _ E[' ] ENDLOOP; FOR i: CARDINAL IN [80..128) DO b[i] _ 0 ENDLOOP; [status, count] _ FloppyChannel.WriteSectors[ handle, [cylinder: 0, head: 0, sector: 1], [@b, 64], heads*26, FALSE]; IF count#heads*26 THEN {result _ badTrack0; GOTO done}; b[0] _ E['E]; b[1] _ E['R]; b[2] _ E['M]; b[3] _ E['A]; b[4] _ E['P]; [status, count] _ FloppyChannel.WriteSectors[ handle, [cylinder: 0, head: 0, sector: 5], [@b, 64], 1, FALSE]; IF count#1 THEN {result _ badTrack0; GOTO done}; b[0] _ E['V]; b[1] _ E['O]; b[2] _ E['L]; b[3] _ E['1]; IF name=NIL THEN name _ "X8000"L; FOR i: CARDINAL IN [0..6) DO b[4+i] _ e[IF i>=name.length THEN ' ELSE name[i]] ENDLOOP; FOR i: CARDINAL IN [10..80) DO b[i] _ E[' ] ENDLOOP; b[71] _ IF context.density=double THEN E['M] ELSE IF status.twoSided THEN E['2] ELSE E[' ]; b[75] _ E['2]; -- 0=>128, 1=>256, 3=>512, 4=>1024 [status, count] _ FloppyChannel.WriteSectors[ handle, [cylinder: 0, head: 0, sector: 7], [@b, 64], 1, FALSE]; IF count#1 THEN {result _ badTrack0; GOTO done}; END; IF ~FloppyChannel.SetContext[handle, context] THEN {result _ cantSetContext; GOTO done}; -- format; check by writing (look for record not found) BEGIN b: PACKED ARRAY [0..512) OF [0..400B); FOR cyl: CARDINAL IN [1..floppyCylinders) DO FOR head: CARDINAL IN [0..heads) DO BEGIN THROUGH [0..10] DO req: FloppyChannelInternal.OpBlock _ [ device: handle, function: writeSector, address: [cylinder: cyl, head: head, sector: 1], buffer: [@b, 256], incrementDataPtr: FALSE, count: sectorsPerTrack]; [status, count] _ FormatTracks[ handle, [cylinder: cyl, head: head, sector: 1], 1]; IF count # 1 THEN EXIT; [status, count] _ FloppyChannelInternal.DoRequest[@req]; -- record not found is the only thing we can get here, right?? IF count=sectorsPerTrack THEN GOTO trackGood; [] _ FloppyChannel.Recalibrate[handle]; ENDLOOP; FOR sec: CARDINAL IN [1..sectorsPerTrack] DO SignalBadSector[ [cylinder: cyl, head: head, sector: sec], heads, sectorsPerTrack ! BadLabelSignal => {result _ badLabelArea; GOTO done}; UNWIND => PhysicalVolume.FinishWithNonPilotVolume[handle]]; ENDLOOP; EXITS trackGood =>NULL; END; ENDLOOP; ENDLOOP; -- write (with seeking) then read disk ForAllPilotSectors[ writeSector, handle, sectorsPerTrack, heads, @status, @b ! BadLabelSignal => {result _ badLabelArea; GOTO done}; UNWIND => PhysicalVolume.FinishWithNonPilotVolume[handle]]; ForAllPilotSectors[ readSector, handle, sectorsPerTrack, heads, @status, @b ! BadLabelSignal => {result _ badLabelArea; GOTO done}; UNWIND => PhysicalVolume.FinishWithNonPilotVolume[handle]]; END; result _ goodDisk; GOTO done; EXITS done => BEGIN PhysicalVolume.FinishWithNonPilotVolume[handle]; IF result=cantSetContext THEN status _ FloppyChannel.Nop[handle]; RETURN[status, result]; END; END; ScanPilotDisk: PUBLIC PROCEDURE [handle: Handle] RETURNS[status: FloppyChannel.Status, result: FormatSA800.PilotResult] = BEGIN heads: [1..2] _ 2; sectorsPerTrack: CARDINAL _ 8; context: FloppyChannel.Context _ [ protect: FALSE, format: IBM, density: single, sectorLength: 256]; PhysicalVolume.AssertNotAPilotVolume[handle]; IF ~FloppyChannel.SetContext[handle, track0Context] THEN {result _ cantSetContext; GOTO done}; -- check track 0 \ get context information BEGIN b: PACKED ARRAY [0..128) OF [0..400B); count: CARDINAL; [status, count] _ FloppyChannel.ReadSectors[ handle, [cylinder: 0, head: 0, sector: 7], [@b, 64], 1, FALSE]; IF count#1 OR b[75]#E['2] THEN {result _ badTrack0; GOTO done}; SELECT b[71] FROM E['M] => { context.density _ double; sectorsPerTrack _ 15; heads _ (IF status.twoSided THEN 2 ELSE 1)}; E['2] => {NULL}; E[' ] => {heads _ 1}; ENDCASE => {result _ badTrack0; GOTO done}; IF heads#(IF status.twoSided THEN 2 ELSE 1) THEN {result _ badTrack0; GOTO done}; END; -- check rest of disk BEGIN b: PACKED ARRAY [0..512) OF [0..400B); IF ~FloppyChannel.SetContext[handle, context] THEN {result _ cantSetContext; GOTO done}; ForAllPilotSectors[ readSector, handle, sectorsPerTrack, heads, @status, @b ! BadLabelSignal => {result _ badLabelArea; GOTO done}; UNWIND => PhysicalVolume.FinishWithNonPilotVolume[handle]]; END; result _ goodDisk; GOTO done; EXITS done => BEGIN PhysicalVolume.FinishWithNonPilotVolume[handle]; IF result=cantSetContext THEN status _ FloppyChannel.Nop[handle]; RETURN[status, result]; END; END; ForAllPilotSectors: PROCEDURE [ op: SA800Face.Function, handle: Handle, sectorsPerTrack: CARDINAL, heads: [1..2], status: POINTER TO FloppyChannel.Status, b: POINTER TO PACKED ARRAY [0..512) OF [0..377B]] = BEGIN countLeft: CARDINAL _ sectorsPerTrack*heads *(floppyCylinders-PilotFloppyFormat.firstRealCylinder); da: SA800Face.DiskAddress _ [cylinder: PilotFloppyFormat.firstRealCylinder, head: 0, sector: 1]; DO UpdateDA: PROC [increment: CARDINAL] = BEGIN quo, rem: CARDINAL; [quotient: quo, remainder: rem] _ Inline.DIVMOD[increment+(da.sector-1), sectorsPerTrack]; da.sector _ rem+1; [quotient: da.cylinder, remainder: da.head] _ Inline.DIVMOD[(da.cylinder*heads)+quo+da.head, heads]; END; req: FloppyChannelInternal.OpBlock _ [ device: handle, function: op, address: da, buffer: [b, 256], incrementDataPtr: FALSE, count: countLeft]; count: CARDINAL; [status^, count] _ FloppyChannelInternal.DoRequest[@req]; IF (countLeft _ countLeft - count)=0 THEN EXIT; UpdateDA[count]; SignalBadSector[da, heads, sectorsPerTrack]; UpdateDA[1]; countLeft _ countLeft - 1; ENDLOOP; END; BadLabelSignal: SIGNAL = CODE; SignalBadSector: PROC [ da: SA800Face.DiskAddress, heads: [1..2], sectorsPerTrack: CARDINAL] = BEGIN IF da.cylinder < firstPilotTrack THEN SIGNAL BadLabelSignal ELSE SIGNAL BadSector[ ((((da.cylinder-firstPilotTrack)*heads)+da.head) *sectorsPerTrack+da.sector-1)]; END; END..... LOG Time: October 2, 1980 5:01 PM By: Jose Action: Create file Time: October 8, 1980 12:36 PM By: Jose Action: Changes to incorporate head runs of pages. Time: October 21, 1980 2:07 PM By: Jose Action: Change order of status selection. Time: January 13, 1981 6:07 PM By: Forrest Action: revamp for 2D 2S. Time: January 31, 1981 10:21 PM By: Jose Action: Add AssertNotAPilotVolume and FinishWithNonPilotVolume to FormatPilotDisk and ScanPilotDisk; make ScanPilotDisk do real read. Time: March 24, 1981 5:03 PM By: Forrest Action: fix numerous bugs, rearrage code to make fast enough. e6(1792)\f8