-- 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.