-- DiskDebugImpl.mesa
-- Jim Gasbarro 9-Apr-84 10:25:48
DIRECTORY
ColorVersatecDriver,
ColorVersatecUtils,
DicentraDiskDriver,
Heap USING [systemZone],
OthelloDefs,
ProcessorFace,
String,
Watchdog USING [Deactivate];
DiskDebugImpl: PROGRAM
IMPORTS ColorVersatecDriver, ColorVersatecUtils, DicentraDiskDriver, Heap, OthelloDefs, ProcessorFace, String, Watchdog
= BEGIN
OPEN ColorVersatecDriver,
ColorVersatecUtils,
DicentraDiskDriver,
OthelloDefs;
GoToDebugger: SIGNAL = CODE;
StripeBand: PROC [stripeOffset: CARDINAL, hyperOffset: LONG CARDINAL] =
BEGIN
buffer: ARRAY [0..wordsPerScan) OF CARDINAL;
p: POINTER ← @buffer;
FOR i: CARDINAL IN [0..wordsPerScan) DO
IF i MOD 4 = stripeOffset THEN buffer[i] ← 0F0FFH ELSE buffer[i] ← 0;
ENDLOOP;
FOR i: LONG CARDINAL IN [0..scansPerBand) DO
HyperStore[sourcePtr: p, destOffset: hyperOffset + (i * LENGTH[buffer]), wordCount: LENGTH[buffer]];
ENDLOOP;
END;
SetupBand: PROC [value: CARDINAL, hyperOffset: LONG CARDINAL] =
BEGIN
buffer: ARRAY [0..wordsPerScan) OF CARDINAL;
p: POINTER ← @buffer;
FOR i: CARDINAL IN [0..wordsPerScan) DO
buffer[i] ← value;
ENDLOOP;
FOR i: LONG CARDINAL IN [0..scansPerBand) DO
HyperStore[sourcePtr: p, destOffset: hyperOffset + (i * LENGTH[buffer]), wordCount: LENGTH[buffer]];
ENDLOOP;
END;
CheckBand: PROC [stripeOffset: CARDINAL, hyperOffset: LONG CARDINAL] =
BEGIN
buffer: ARRAY [0..wordsPerScan) OF CARDINAL;
p: POINTER ← @buffer;
FOR i: LONG CARDINAL IN [0..scansPerBand) DO
HyperRead[destPtr: p, sourceOffset: hyperOffset + (i * LENGTH[buffer]), wordCount: LENGTH[buffer]];
FOR j: CARDINAL IN [0..wordsPerScan) DO
IF j MOD 4 = stripeOffset THEN
BEGIN IF buffer[j] # 0F0FFH THEN
BEGIN
OthelloDefs.WriteString["scan: "];
OthelloDefs.WriteLongNumber[i];
OthelloDefs.WriteString[" word: "];
OthelloDefs.WriteLongNumber[j];
OthelloDefs.WriteString[" expected: 170377 got: "];
OthelloDefs.WriteOctal[buffer[j]];
OthelloDefs.NewLine[];
END
END
ELSE IF buffer[j] # 0 THEN
BEGIN
OthelloDefs.WriteString["scan: "];
OthelloDefs.WriteLongNumber[i];
OthelloDefs.WriteString[" word: "];
OthelloDefs.WriteLongNumber[j];
OthelloDefs.WriteString[" expected: 0 got: "];
OthelloDefs.WriteOctal[buffer[j]];
OthelloDefs.NewLine[];
END
ENDLOOP;
ENDLOOP;
END;
ReadBand: PROC [cylinder: Cylinder] =
BEGIN
FOR i: LONG CARDINAL IN [0..sectorsPerBand) DO
[] ← Read[head: CARDINAL[i / sectorsPerTrack], sector: CARDINAL[i MOD sectorsPerTrack], cylinder: cylinder, sectorCount: 1, cmdOffset: 32, dataOffset: 64 + (i * wordsPerSector)];
ENDLOOP;
END;
WriteBand: PROC [cylinder: Cylinder] =
BEGIN
FOR i: LONG CARDINAL IN [0..sectorsPerBand) DO
[] ← Write[head: CARDINAL[i / sectorsPerTrack], sector: CARDINAL[i MOD sectorsPerTrack], cylinder: cylinder, sectorCount: 1, cmdOffset: 32, dataOffset: 64 + (i * wordsPerSector)];
ENDLOOP;
END;
BandTest: PROC [] =
BEGIN
DiskInitialCheckout[];
ShowMP[1000];
StripeBand[stripeOffset: 0, hyperOffset: 64];
ShowMP[2000];
OthelloDefs.WriteLine["Checking band before disk write..."];
CheckBand[stripeOffset: 0, hyperOffset: 64];
[] ← Write[head: 0, sector: 0, cylinder: 0, sectorCount: sectorsPerBand, cmdOffset: 32, dataOffset: 64];
ShowMP[3000];
SetupBand[value: 52525B, hyperOffset: 64];
[] ← Read[head: 0, sector: 0, cylinder: 0, sectorCount: sectorsPerBand, cmdOffset: 32, dataOffset: 64];
ShowMP[4000];
OthelloDefs.WriteLine["Checking band after disk read..."];
CheckBand[stripeOffset: 0, hyperOffset: 64];
ShowMP[5000];
OthelloDefs.WriteLine["Done."];
END;
SeekTest: PROC [] =
BEGIN
success: BOOLEAN ← TRUE;
OthelloDefs.WriteString["Begin Seek Test..."];
FOR i: CARDINAL IN [0..cylindersPerSpindle) DO
success ← success AND Seek[cylinder: i, cmdOffset: 0];
success ← success AND Seek[cylinder: cylindersPerSpindle - i - 1, cmdOffset: 0];
ENDLOOP;
IF NOT success THEN {
OthelloDefs.WriteLine["ERROR: Seek Test Failed"];
}
ELSE {
OthelloDefs.WriteLine["Seek Test Complete"];
}
END;
VerifyTest: PROC [] =
BEGIN
BufferSetup: PROC [ptr: LONG POINTER TO ARRAY [0..wordsPerSector) OF CARDINAL, startValue: CARDINAL] =
BEGIN
FOR i: CARDINAL IN [0..LENGTH[buffer]) DO
ptr↑[i] ← i + startValue;
ENDLOOP;
END;
BufferClear: PROC [ptr: LONG POINTER TO ARRAY [0..wordsPerSector) OF CARDINAL] =
BEGIN
FOR i: CARDINAL IN [0..LENGTH[buffer]) DO
ptr↑[i] ← 0;
ENDLOOP;
END;
BufferOK: PROC [ptr: LONG POINTER TO ARRAY [0..wordsPerSector) OF CARDINAL, startValue: CARDINAL] RETURNS [BOOLEAN] =
BEGIN
FOR i: CARDINAL IN [0..LENGTH[buffer]) DO
IF ptr↑[i] # (i + startValue) THEN RETURN[FALSE];
ENDLOOP;
RETURN[TRUE];
END;
PrintBuffer: PROC [ptr: LONG POINTER TO ARRAY [0..wordsPerSector) OF CARDINAL] =
BEGIN
FOR i: CARDINAL IN [0..LENGTH[buffer]/16) DO
FOR j: CARDINAL IN [0..16) DO
OthelloDefs.WriteLongNumber[ptr↑[i+j]];
ENDLOOP;
OthelloDefs.NewLine[];
ENDLOOP;
END;
p: POINTER ← @buffer;
buffer: ARRAY [0..wordsPerSector) OF CARDINAL;
startCylinder, endCylinder: CARDINAL;
startCylinder ← LOOPHOLE[ReadNumber ["StartCylinder: ", 0, LAST[Cylinder], 0]];
endCylinder ← LOOPHOLE[ReadNumber ["EndCylinder: ", 0, LAST[Cylinder], 822]];
IF startCylinder > endCylinder THEN
BEGIN
OthelloDefs.WriteString["Input Error: StartCylinder greater than EndCylinder."];
RETURN[];
END;
OthelloDefs.WriteLine["VerifyTest: Begin Write Phase"];
FOR i: CARDINAL IN [startCylinder..endCylinder) DO
FOR j: CARDINAL IN [0..tracksPerCylinder) DO
BufferSetup[ptr: p, startValue: i+j];
ColorVersatecUtils.HyperStore[sourcePtr: p, destOffset: 32, wordCount: LENGTH[buffer]];
[] ← Write[sector: j, head: j, cylinder: i, sectorCount: 1, cmdOffset: 0, dataOffset: 32];
ENDLOOP;
ProcessorFace.SetMP[i];
ENDLOOP;
OthelloDefs.WriteLine["VerifyTest: Begin Read Phase"];
FOR i: CARDINAL IN [startCylinder..endCylinder) DO
FOR j: CARDINAL IN [0..tracksPerCylinder) DO
[] ← Read[sector: j, head: j, cylinder: i, sectorCount: 1, cmdOffset: 0, dataOffset: 32];
ColorVersatecUtils.HyperRead[destPtr: p, sourceOffset: 32, wordCount: LENGTH[buffer]];
IF NOT BufferOK[ptr: p, startValue: i+j] THEN
BEGIN
OthelloDefs.WriteString["ERROR: Data Compare Error at sector: "];
OthelloDefs.WriteLongNumber[j];
OthelloDefs.WriteString[" head: "];
OthelloDefs.WriteLongNumber[j];
OthelloDefs.WriteString[" cylinder: "];
OthelloDefs.WriteLongNumber[i];
OthelloDefs.NewLine[];
PrintBuffer[ptr: p];
END;
ENDLOOP;
ProcessorFace.SetMP[i];
ENDLOOP;
OthelloDefs.WriteLine["End ReadWriteTest"];
END;
DiskToPlotterTest: PROC [] =
BEGIN
VersatecInitialCheckout[];
DiskInitialCheckout[];
ShowMP[1000];
StripeBand[stripeOffset: 0, hyperOffset: 64];
[] ← Write[head: 0, sector: 0, cylinder: 0, sectorCount: sectorsPerBand, cmdOffset: 32, dataOffset: 64];
StripeBand[stripeOffset: 1, hyperOffset: 64];
[] ← Write[head: 0, sector: 0, cylinder: 200, sectorCount: sectorsPerBand, cmdOffset: 32, dataOffset: 64];
StripeBand[stripeOffset: 2, hyperOffset: 64];
[] ← Write[head: 0, sector: 0, cylinder: 400, sectorCount: sectorsPerBand, cmdOffset: 32, dataOffset: 64];
StripeBand[stripeOffset: 3, hyperOffset: 64];
[] ← Write[head: 0, sector: 0, cylinder: 600, sectorCount: sectorsPerBand, cmdOffset: 32, dataOffset: 64];
ShowMP[2000];
[] ← Read[head: 0, sector: 0, cylinder: 0, sectorCount: sectorsPerBand, cmdOffset: 32, dataOffset: 64];
SetColorMode[inches: 10, mode: FirstPassOfColor, color: Black, cmdOffset: 0];
PlotBuffer[wordCount: wordsPerBand, hyperOffset: 64];
Rewind[cmdOffset: 0];
ShowMP[3000];
[] ← Read[head: 0, sector: 0, cylinder: 200, sectorCount: sectorsPerBand, cmdOffset: 32, dataOffset: 64];
SetColorMode[inches: 10, mode: IntermediatePassOfColor, color: Cyan, cmdOffset: 0];
PlotBuffer[wordCount: wordsPerBand, hyperOffset: 64];
Rewind[cmdOffset: 0];
ShowMP[4000];
[] ← Read[head: 0, sector: 0, cylinder: 400, sectorCount: sectorsPerBand, cmdOffset: 32, dataOffset: 64];
SetColorMode[inches: 10, mode: IntermediatePassOfColor, color: Magenta, cmdOffset: 0];
PlotBuffer[wordCount: wordsPerBand, hyperOffset: 64];
Rewind[cmdOffset: 0];
ShowMP[5000];
[] ← Read[head: 0, sector: 0, cylinder: 400, sectorCount: sectorsPerBand, cmdOffset: 32, dataOffset: 64];
SetColorMode[inches: 10, mode: IntermediatePassOfColor, color: Yellow, cmdOffset: 0];
PlotBuffer[wordCount: wordsPerBand, hyperOffset: 64];
SendEOT[];
END;
FormatDisk: PROC [] =
BEGIN
c: CHAR;
OthelloDefs.WriteString["Are you sure [Y/N]? "];
c ← OthelloDefs.ReadChar[];
OthelloDefs.WriteChar[c];
OthelloDefs.NewLine[];
IF c # 'y AND c # 'Y THEN RETURN[];
[] ← RawFormat[cmdOffset: 32];
END;
BS: CHARACTER = 10C;
ControlA: CHARACTER = 'A - 100B;
ControlP: CHARACTER = 'P - 100B;
ControlW: CHARACTER = 'W - 100B;
CR: CHARACTER = 15C;
DEL: CHARACTER = 177C;
ESC: CHARACTER = 33C;
SP: CHARACTER = ' ;
NUL: CHARACTER = 0C;
spacesInStringOK: BOOLEAN ← FALSE;
GetName: PUBLIC PROCEDURE [
prompt: STRING ← NIL, dest: POINTER TO LONG STRING,
-- how: OthelloDefs.EchoNoEcho ← echo, signalQuestion: BOOLEAN ← FALSE ] =
how: OthelloDefs.EchoNoEcho ← echo] =
BEGIN
first: BOOLEAN ← TRUE;
EraseChar: PROCEDURE = {
IF dest.length = 0 THEN RETURN;
dest.length ← dest.length - 1;
-- OthelloForgot.EraseTTYChar[IF how = echo THEN dest[dest.length] ELSE '*];
OthelloDefs.WriteChar[BS];
IF dest.length = 0 AND dest.maxlength > 20 THEN {
z.FREE[dest]; dest↑ ← z.NEW[StringBody[10]]; }};
CWriteC: PROCEDURE [c: CHARACTER] = {OthelloDefs.WriteChar[IF how = echo THEN c ELSE '*]};
CWriteString: PROCEDURE = {
FOR i: CARDINAL IN [0..dest.length) DO CWriteC[dest[i]] ENDLOOP};
IF dest↑ = NIL THEN dest↑ ← z.NEW[StringBody[10]];
OthelloDefs.WriteString[prompt]; CWriteString[];
DO
c: CHARACTER = OthelloDefs.ReadChar[];
SELECT TRUE FROM
c = BS, c = ControlA => EraseChar[];
(c = SP AND ~spacesInStringOK), c = CR => {OthelloDefs.NewLine[]; RETURN};
c = DEL => {OthelloDefs.WriteLine[" XXX"L]; -- ERROR TryAgain -- EXIT};
c = ControlW =>
DO
EraseChar[];
IF dest.length=0 THEN EXIT;
SELECT dest[dest.length-1] FROM
IN ['a..'z], IN ['A..'Z], IN ['0..'9] => LOOP;
ENDCASE => EXIT;
ENDLOOP;
-- c = '? AND signalQuestion => {
-- SIGNAL Question; OthelloDefs.WriteString[prompt]; CWriteString[]; LOOP};
c >= SP => {
IF first THEN WHILE dest.length#0 DO EraseChar[] ENDLOOP;
String.AppendCharAndGrow[dest, c, z]; CWriteC[dest[dest.length-1]]};
ENDCASE => OthelloDefs.BlinkDisplay[];
first ← FALSE;
ENDLOOP;
END;
z: UNCOUNTED ZONE = Heap.systemZone;
numberString: LONG STRING ← NIL;
ReadNumber: PUBLIC PROCEDURE [
prompt: STRING, min, max, default: LONG CARDINAL ← LAST[LONG CARDINAL]]
RETURNS [ans: CARDINAL] = {
DO
IF default # LAST[LONG CARDINAL] THEN {
IF numberString=NIL THEN numberString ← z.NEW[StringBody[15]];
numberString.length ← 0; String.AppendLongNumber[numberString, default, 10]};
OthelloDefs.WriteString[prompt];
OthelloDefs.WriteChar['[];
OthelloDefs.WriteLongNumber[min];
OthelloDefs.WriteString[".."L];
OthelloDefs.WriteLongNumber[max];
OthelloDefs.WriteString["]: "L];
GetName[prompt: "", dest: @numberString];
ans ← 0;
FOR i: CARDINAL IN [0..numberString.length) DO
IF numberString[i] NOT IN ['0..'9] THEN EXIT;
ans ← 10*ans + numberString[i] - '0;
REPEAT FINISHED => IF ans IN [min..max] THEN {
z.FREE[@numberString]; RETURN};
ENDLOOP;
OthelloDefs.WriteLine["Bad Number !"L];
ENDLOOP};
ReadSector: PROC [] =
BEGIN
sector: Sector;
head: Head;
cylinder: Cylinder;
count: CARDINAL;
sector ← LOOPHOLE[ReadNumber ["Sector: ", 0, LAST[Sector], 0]];
head ← LOOPHOLE[ReadNumber ["Head: ", 0, LAST[Head], 0]];
cylinder ← LOOPHOLE[ReadNumber ["Cylinder: ", 0, LAST[Cylinder], 0]];
count ← ReadNumber ["Sector Count: ", 1, LAST[CARDINAL], 1];
[] ← Read[head: head, sector: sector, cylinder: cylinder, sectorCount: count, cmdOffset: 32, dataOffset: 64];
END;
WriteSector: PROC [] =
BEGIN
sector: Sector;
head: Head;
cylinder: Cylinder;
count: CARDINAL;
sector ← LOOPHOLE[ReadNumber ["Sector: ", 0, LAST[Sector], 0]];
head ← LOOPHOLE[ReadNumber ["Head: ", 0, LAST[Head], 0]];
cylinder ← LOOPHOLE[ReadNumber ["Cylinder: ", 0, LAST[Cylinder], 0]];
count ← ReadNumber ["Sector Count: ", 1, LAST[CARDINAL], 1];
[] ← Write[head: head, sector: sector, cylinder: cylinder, sectorCount: count, cmdOffset: 32, dataOffset: 64];
END;
Help: PROC [] =
BEGIN
c: CHAR;
OthelloDefs.WriteString["Help (command or ?): "];
c ← OthelloDefs.ReadChar[];
SELECT c FROM
'B, 'b => BEGIN
OthelloDefs.WriteLine["BandTest"];
OthelloDefs.WriteLine["MP=1000 - drive is online"];
OthelloDefs.WriteLine["MP=2000 - generated a pattern in memory 64 sectors long"];
OthelloDefs.WriteLine["MP=3000 - test pattern written to first 64 sectors on disk (single transfer)"];
OthelloDefs.WriteLine["MP=4000 - cleared memory and read first 64 sectors (single transfer)"];
OthelloDefs.WriteLine["MP=5000 - pattern in memory verified"];
OthelloDefs.WriteLine["Takes a few seconds to complete"];
OthelloDefs.NewLine[];
END;
'C, 'c => BEGIN
OthelloDefs.WriteLine["ControllerTest"];
OthelloDefs.WriteLine["This command runs the power-up self test. If successful, status is returned."];
OthelloDefs.WriteLine["If not, the self-test LED will not extinguish and error status may be returned."];
OthelloDefs.NewLine[];
END;
'D, 'd => BEGIN
OthelloDefs.WriteLine["Debugger"];
OthelloDefs.WriteLine["Sends the Dicentra into 915 mode."];
OthelloDefs.NewLine[];
END;
'F, 'f => BEGIN
OthelloDefs.WriteLine["Format"];
OthelloDefs.WriteLine["Formats the disk for 19 heads and 823 cylinders."];
OthelloDefs.WriteLine["Takes about 20 minutes"];
OthelloDefs.NewLine[];
END;
'G, 'g => BEGIN
OthelloDefs.WriteLine["GetStatus"];
OthelloDefs.WriteLine["Returns controller and drive parameters"];
OthelloDefs.NewLine[];
END;
'P, 'p => BEGIN
OthelloDefs.WriteLine["Plot"];
OthelloDefs.WriteLine["MP=1000 - disk and versatec online"];
OthelloDefs.WriteLine["MP=2000 - four color band pattern written to disk"];
OthelloDefs.WriteLine["MP=3000 - black pass transmitted"];
OthelloDefs.WriteLine["MP=4000 - cyan pass transmitted"];
OthelloDefs.WriteLine["MP=5000 - magenta pass transmitted"];
OthelloDefs.WriteLine["MP=6000 - yellow (final) pass transmitted"];
OthelloDefs.WriteLine["Time limited by versatec"];
OthelloDefs.NewLine[];
END;
'R, 'r => BEGIN
OthelloDefs.WriteLine["ReadSector"];
OthelloDefs.WriteLine["Prompts for Sector, Head, Cylinder, and Count then does a disk read"];
OthelloDefs.WriteLine["operation with those prameters"];
OthelloDefs.NewLine[];
END;
'S, 's => BEGIN
OthelloDefs.WriteLine["Seek"];
OthelloDefs.WriteLine["Seeks from [0..822] to [822..0]. No data is transferred. It is not unusual"];
OthelloDefs.WriteLine["(although not correct) for the disk to fail this test."];
OthelloDefs.WriteLine["Takes about two minutes to complete."];
OthelloDefs.NewLine[];
END;
'V, 'v => BEGIN
OthelloDefs.WriteLine["VerifyTest"];
OthelloDefs.WriteLine["Writes one sector on each track (sector number equals track number) for a"];
OthelloDefs.WriteLine["range cylinders on the disk. Data written is a counting pattern starting at"];
OthelloDefs.WriteLine["sector+track. After all cylinders are written, the data is read and verified."];
OthelloDefs.WriteLine["MP=last complete track read or written"];
OthelloDefs.WriteLine["Takes about a second per track per pass."];
OthelloDefs.NewLine[];
END;
'W, 'w => BEGIN
OthelloDefs.WriteLine["WriteSector"];
OthelloDefs.WriteLine["Prompts for Sector, Head, Cylinder, and Count then does a disk write"];
OthelloDefs.WriteLine["operation with those prameters"];
OthelloDefs.NewLine[];
END;
ENDCASE => BEGIN
OthelloDefs.WriteLine[""];
OthelloDefs.WriteLine["options are: BandTest, ControllerTest, Debugger, Format, GetStatus, Plot,"];
OthelloDefs.WriteLine["ReadSector, Seek, VerifyTest, and WriteSector"];
OthelloDefs.NewLine[];
END;
END;
OthelloDefs.NewLine[];
OthelloDefs.WriteLine["What's up doc?"];
Watchdog.Deactivate[];
DO
c: CHAR;
OthelloDefs.WriteString["> "];
c ← OthelloDefs.ReadChar[];
OthelloDefs.WriteChar[c];
OthelloDefs.NewLine[];
SELECT c FROM
'B, 'b => BandTest[];
'C, 'c => SelfTest[];
'D, 'd => SIGNAL GoToDebugger[];
'F, 'f => FormatDisk[];
'G, 'g => ReadDriveStatus[];
'P, 'p => DiskToPlotterTest[];
'R, 'r => ReadSector[];
'S, 's => SeekTest[];
'V, 'v => VerifyTest[];
'W, 'w => WriteSector[];
'? => BEGIN
OthelloDefs.WriteLine["BandTest, ControllerTest, Debugger, Format, GetStatus, Plot, ReadSector, "];
OthelloDefs.WriteLine["Seek, VerifyTest, and WriteSector"];
END;
'H, 'h => Help[];
ENDCASE => OthelloDefs.WriteLine["Learn to type you moron."];
ENDLOOP;
END.