-- DiskDebugImpl.mesa
-- Jim Gasbarro 19-Feb-85 14:01:51
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
WriteString["scan: "];
WriteLongNumber[i];
WriteString[" word: "];
WriteLongNumber[j];
WriteString[" expected: 170377 got: "];
WriteOctal[buffer[j]];
NewLine[];
END
END
ELSE IF buffer[j] # 0 THEN
BEGIN
WriteString["scan: "];
WriteLongNumber[i];
WriteString[" word: "];
WriteLongNumber[j];
WriteString[" expected: 0 got: "];
WriteOctal[buffer[j]];
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];
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];
WriteLine["Checking band after disk read..."];
CheckBand[stripeOffset: 0, hyperOffset: 64];
ShowMP[5000];
WriteLine["Done."];
END;
SeekTest: PROC [] =
BEGIN
success: BOOLEAN ← TRUE;
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 ~success THEN WriteLine["ERROR: Seek Test Failed"]
ELSE WriteLine["Seek Test Complete"];
END;
seed: WORD ← 0;
eachWord: WORD ← 1;
eachSector: WORD ← 256;
eachTest: WORD ← 1;
VerifyTest: PROC [] =
BEGIN
BufferSetup: PROC [ptr: LONG POINTER TO ARRAY [0..wordsPerSector) OF CARDINAL] =
BEGIN
temp: WORD ← seed;
FOR i: CARDINAL IN [0..LENGTH[buffer]) DO
ptr[i] ← temp;
temp ← temp + eachWord;
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] RETURNS [BOOLEAN] =
BEGIN
temp: WORD ← seed;
FOR i: CARDINAL IN [0..LENGTH[buffer]) DO
IF ptr[i] # temp THEN RETURN[FALSE];
temp ← temp + eachWord;
ENDLOOP;
RETURN[TRUE];
END;
PrintBuffer: PROC [ptr: LONG POINTER TO ARRAY [0..wordsPerSector) OF CARDINAL] =
BEGIN
FOR i: CARDINAL ← 0, i+16 UNTIL i >= LENGTH[buffer] DO
FOR j: CARDINAL IN [0..16) DO
temp: STRING = [20];
String.AppendNumber[temp, ptr↑[i+j], 16];
FOR i: CARDINAL IN [temp.length..5) DO WriteChar[' ]; ENDLOOP;
WriteString[temp];
ENDLOOP;
NewLine[];
ENDLOOP;
END;
p: POINTER ← @buffer;
buffer: ARRAY [0..wordsPerSector) OF CARDINAL;
startCylinder, endCylinder: CARDINAL;
savedSeed: WORD ← seed;
startCylinder ← LOOPHOLE[ReadNumber ["StartCylinder: ", 0, LAST[Cylinder], 0]];
endCylinder ← LOOPHOLE[ReadNumber ["EndCylinder: ", 0, LAST[Cylinder], 822]];
seed ← LOOPHOLE[ReadNumber ["Seed: ", 0, LAST[WORD], seed]];
eachWord ← LOOPHOLE[ReadNumber ["Word Incr: ", 0, LAST[WORD], eachWord]];
eachSector ← LOOPHOLE[ReadNumber ["Sector Incr: ", 0, LAST[WORD], eachSector]];
IF startCylinder > endCylinder THEN
BEGIN
WriteLine["Input Error: StartCylinder greater than EndCylinder."];
RETURN[];
END;
WriteLine["VerifyTest: Begin Write Phase"];
FOR i: CARDINAL IN [startCylinder..endCylinder) DO
FOR j: CARDINAL IN [0..tracksPerCylinder) DO
BufferSetup[ptr: p];
ColorVersatecUtils.HyperStore[sourcePtr: p, destOffset: 32, wordCount: LENGTH[buffer]];
ColorVersatecUtils.HyperRead[destPtr: p, sourceOffset: 32, wordCount: LENGTH[buffer]];
IF ~BufferOK[ptr: p] THEN
BEGIN
WriteLine["MEMORY ERROR before writing to disk, sector:"];
WriteLongNumber[j];
WriteString[" head: "];
WriteLongNumber[j];
WriteString[" cylinder: "];
WriteLongNumber[i];
WriteLine["..."];
PrintBuffer[ptr: p];
END;
[] ← Write[sector: j, head: j, cylinder: i, sectorCount: 1, cmdOffset: 0, dataOffset: 32];
IF ~BufferOK[ptr: p] THEN
BEGIN
WriteLine["MEMORY ERROR after writing to disk, sector:"];
WriteLongNumber[j];
WriteString[" head: "];
WriteLongNumber[j];
WriteString[" cylinder: "];
WriteLongNumber[i];
WriteLine["..."];
PrintBuffer[ptr: p];
END;
seed ← seed + eachSector;
ENDLOOP;
ProcessorFace.SetMP[i];
ENDLOOP;
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 ~BufferOK[ptr: p] THEN
BEGIN
WriteString["ERROR: Data Compare Error at sector: "];
WriteLongNumber[j];
WriteString[" head: "];
WriteLongNumber[j];
WriteString[" cylinder: "];
WriteLongNumber[i];
NewLine[];
PrintBuffer[ptr: p];
END;
seed ← seed + eachSector;
ENDLOOP;
ProcessorFace.SetMP[i];
ENDLOOP;
seed ← seed + eachTest;
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
IF GotYes["Are you sure [Y/N]? "] THEN [] ← RawFormat[cmdOffset: 32];
END;
GotYes: PROC [t: STRING] RETURNS[BOOL] =
BEGIN
c: CHAR;
WriteString[t];
c ← ReadChar[];
WriteChar[c];
NewLine[];
IF c = 'y OR c = 'Y THEN RETURN[TRUE] ELSE RETURN[FALSE];
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: EchoNoEcho ← echo, signalQuestion: BOOLEAN ← FALSE ] =
how: 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 '*];
WriteChar[BS];
IF dest.length = 0 AND dest.maxlength > 20 THEN {
z.FREE[dest]; dest↑ ← z.NEW[StringBody[10]]; }};
CWriteC: PROCEDURE [c: CHARACTER] = {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]];
WriteString[prompt]; CWriteString[];
DO
c: CHARACTER = ReadChar[];
SELECT TRUE FROM
c = BS, c = ControlA => EraseChar[];
(c = SP AND ~spacesInStringOK), c = CR => {NewLine[]; RETURN};
c = DEL => {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; 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 => 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]};
WriteString[prompt];
WriteChar['[];
WriteLongNumber[min];
WriteString[".."L];
WriteLongNumber[max];
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;
WriteLine["Bad Number !"L];
ENDLOOP};
LoopRead: 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 ["Loop Count: ", 1, LAST[CARDINAL], 1];
FOR i: CARDINAL IN [0..count) DO
[] ← Read[head: head, sector: sector, cylinder: cylinder, sectorCount: 1000, cmdOffset: 32, dataOffset: 64];
ENDLOOP;
END;
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;
WriteString["Help (command or ?): "];
c ← ReadChar[];
SELECT c FROM
'B, 'b => BEGIN
WriteLine["BandTest"];
WriteLine["MP=1000 - drive is online"];
WriteLine["MP=2000 - generated a pattern in memory 64 sectors long"];
WriteLine["MP=3000 - test pattern written to first 64 sectors on disk (single transfer)"];
WriteLine["MP=4000 - cleared memory and read first 64 sectors (single transfer)"];
WriteLine["MP=5000 - pattern in memory verified"];
WriteLine["Takes a few seconds to complete"];
NewLine[];
END;
'C, 'c => BEGIN
WriteLine["ControllerTest"];
WriteLine["This command runs the power-up self test. If successful, status is returned."];
WriteLine["If not, the self-test LED will not extinguish and error status may be returned."];
NewLine[];
END;
'D, 'd => BEGIN
WriteLine["Debugger"];
WriteLine["Sends the Dicentra into 915 mode."];
NewLine[];
END;
'F, 'f => BEGIN
WriteLine["Format"];
WriteLine["Formats the disk for 19 heads and 823 cylinders."];
WriteLine["Takes about 20 minutes"];
NewLine[];
END;
'G, 'g => BEGIN
WriteLine["GetStatus"];
WriteLine["Returns controller and drive parameters"];
NewLine[];
END;
'L, 'l => BEGIN
WriteLine["LoopRead"];
WriteLine["Reads first 1000 sectors a specified number of times"];
NewLine[];
END;
'P, 'p => BEGIN
WriteLine["Plot"];
WriteLine["MP=1000 - disk and versatec online"];
WriteLine["MP=2000 - four color band pattern written to disk"];
WriteLine["MP=3000 - black pass transmitted"];
WriteLine["MP=4000 - cyan pass transmitted"];
WriteLine["MP=5000 - magenta pass transmitted"];
WriteLine["MP=6000 - yellow (final) pass transmitted"];
WriteLine["Time limited by versatec"];
NewLine[];
END;
'R, 'r => BEGIN
WriteLine["ReadSector"];
WriteLine["Prompts for Sector, Head, Cylinder, and Count then does a disk read"];
WriteLine["operation with those prameters"];
NewLine[];
END;
'S, 's => BEGIN
WriteLine["Seek"];
WriteLine["Seeks from [0..822] to [822..0]. No data is transferred. It is not unusual"];
WriteLine["(although not correct) for the disk to fail this test."];
WriteLine["Takes about two minutes to complete."];
NewLine[];
END;
'V, 'v => BEGIN
WriteLine["VerifyTest"];
WriteLine["Writes one sector on each track (sector number equals track number) for a"];
WriteLine["range cylinders on the disk. Data written is a counting pattern starting at"];
WriteLine["sector+track. After all cylinders are written, the data is read and verified."];
WriteLine["MP=last complete track read or written"];
WriteLine["Takes about a second per track per pass."];
NewLine[];
END;
'W, 'w => BEGIN
WriteLine["WriteSector"];
WriteLine["Prompts for Sector, Head, Cylinder, and Count then does a disk write"];
WriteLine["operation with those prameters"];
NewLine[];
END;
ENDCASE => BEGIN
WriteLine[""];
WriteLine["options are: BandTest, ControllerTest, Debugger, Format, GetStatus, Plot,"];
WriteLine["ReadSector, Seek, VerifyTest, and WriteSector"];
NewLine[];
END;
END;
NewLine[];
WriteLine["What's up doc?"];
Watchdog.Deactivate[];
DO
c: CHAR;
WriteString["> "];
c ← ReadChar[];
WriteChar[c];
NewLine[];
SELECT c FROM
'B, 'b => BandTest[];
'C, 'c => SelfTest[];
'D, 'd => SIGNAL GoToDebugger[];
'F, 'f => FormatDisk[];
'G, 'g => ReadDriveStatus[];
'L, 'l => LoopRead[];
'P, 'p => DiskToPlotterTest[];
'R, 'r => ReadSector[];
'S, 's => SeekTest[];
'V, 'v => VerifyTest[];
'W, 'w => WriteSector[];
'? => BEGIN
WriteLine["BandTest, ControllerTest, Debugger, Format, GetStatus, LoopRead, Plot, "];
WriteLine["ReadSector, Seek, VerifyTest, and WriteSector"];
END;
'H, 'h => Help[];
ENDCASE => WriteLine["Learn to type you moron."];
ENDLOOP;
END.