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