--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: JoseAction: Create file
Time: October 8, 1980 12:36 PM
By: JoseAction: Changes to incorporate head runs of pages.
Time: October 21, 1980 2:07 PM
By: JoseAction: Change order of status selection.
Time: January 13, 1981 6:07 PM
By: ForrestAction: revamp for 2D 2S.
Time: January 31, 1981 10:21 PM
By: JoseAction: Add AssertNotAPilotVolume and FinishWithNonPilotVolume to FormatPilotDisk and ScanPilotDisk; make ScanPilotDisk do real read.
Time: March 24, 1981 5:03 PM
By: ForrestAction: fix numerous bugs, rearrage code to make fast enough.