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