-- DicentraDiskDriverImpl.mesa
-- Driver for Century Data AMS-315 disk drive and Xylogics SMD controller
-- Jim Gasbarro 16-Mar-84 10:11:40
--
-- ************** W A R N I N G **************
-- On the Dicentra, the left byte is even and the right byte is odd. Bits are numbered 0..7
-- from left to right. These conventions are opposite of those found in the Xylogics-450
-- controller manual.
-- *******************************************
DIRECTORY
ColorVersatecUtils,
DicentraDiskDriver,
DicentraInputOutput,
Inline,
OthelloDefs,
Process USING [Pause, SecondsToTicks],
ProcessorFace USING [SetMP];
DicentraDiskDriverImpl: MONITOR
IMPORTS ColorVersatecUtils, DicentraInputOutput, Inline, OthelloDefs, Process, ProcessorFace
EXPORTS DicentraDiskDriver
= BEGIN
Head: TYPE = DicentraDiskDriver.Head;
Sector: TYPE = DicentraDiskDriver.Sector;
Cylinder: TYPE = DicentraDiskDriver.Cylinder;
Unit: TYPE = DicentraDiskDriver.Unit;
tracksPerCylinder: CARDINAL = DicentraDiskDriver.tracksPerCylinder;
sectorsPerTrack: CARDINAL = DicentraDiskDriver.sectorsPerTrack;
cylindersPerSpindle: CARDINAL = DicentraDiskDriver.cylindersPerSpindle;
wordsPerSector: CARDINAL = DicentraDiskDriver.wordsPerSector;
-- Disk Controller Registers
DiskControllerRegister: TYPE = {
iOPBRelocHigh,
iOPBRelocLow,
iOPBAddHigh,
iOPBAddLow,
controllerResetAndUpdate, -- read to reset controller, write to update IOPB
controlStatus
};
-- controlStatus register bit definitions
goBusy: CARDINAL = 80H;
generalError: CARDINAL = 40H;
doubleError: CARDINAL = 20H;
intPending: CARDINAL = 10H;
addMode: CARDINAL = 08H;
attnReq: CARDINAL = 04H;
attnAck: CARDINAL = 02H;
driveReady: CARDINAL = 01H;
-- IOPB Definition
IOPB: TYPE = MACHINE DEPENDENT RECORD [
intMode: IntMode,
diskCommand: DiskCommand,
statusByte2: StatusByte2 ← success,
statusByte1: StatusByte1,
driveTypeAndSelect: DriveTypeAndSelect,
throttle: Throttle,
sectorAdd: [0..256) ← 0,
headAdd: [0..256) ← 0,
cylAddHigh: [0..256) ← 0,
cylAddLow: [0..256) ← 0,
sectorCountHigh: [0..256) ← 0,
sectorCountLow: SectorCountLow ← [writeSectorCountLow[0]],
dataAddHigh: [0..256) ← 0,
dataAddLow: [0..256) ← 0,
dataRelocHigh: [0..256) ← 0, -- can't address above 24 bits
dataRelocLow: [0..256) ← 0,
reserved: [0..256) ← 0,
headOffset: [0..256) ← 0,
nextIOPBAddHigh: [0..256) ← 0,
nextIOPBAddLow: [0..256) ← 0,
eCCMaskPatternLow: [0..256) ← 0,
eCCMaskPatternHigh: [0..256) ← 0,
eCCBitAddHigh: [0..256) ← 0,
eCCBitAddLow: [0..256) ← 0
];
DiskCommand: TYPE = MACHINE DEPENDENT RECORD [
autoUpdate (0: 0..0): BOOLEAN ← FALSE,
relocate (0: 1..1): BOOLEAN ← FALSE,
chainEnable (0: 2..2): BOOLEAN ← FALSE,
intEnable (0: 3..3): BOOLEAN ← FALSE,
command (0: 4..7): Command ← noOp
];
Command: TYPE = MACHINE DEPENDENT {noOp(0), write(1), read(2), writeHeaders(3),
readHeaders(4), seek(5), driveReset(6), writeFormat(7), readHeaderDataECC(8), readDriveStatus(9),
writeHeaderDataECC(10), setDriveSize(11), selfTest(12)};
IntMode: TYPE = MACHINE DEPENDENT RECORD [
reserved (0: 0..0): BOOLEAN ← FALSE,
intOnEachIOPB (0: 1..1): BOOLEAN ← FALSE,
intOnError (0: 2..2): BOOLEAN ← FALSE,
holdDualPort (0: 3..3): BOOLEAN ← FALSE,
autoSeekRetry (0: 4..4): BOOLEAN ← FALSE,
enableExtendedFunc (0: 5..5): BOOLEAN ← FALSE,
eCCMode (0: 6..7): ECCMode ← correct
];
ECCMode: TYPE = MACHINE DEPENDENT {patternAndOffset(0), noFlagOrCorrect(1), correct(2), flagAndNoCorrect(3)};
StatusByte1: TYPE = MACHINE DEPENDENT RECORD [
errorSummary (0: 0..0): BOOLEAN ← FALSE,
reserved (0: 1..2): BOOLEAN ← FALSE,
controllerType (0: 3..5): ControllerType ← type440Controller,
reserved2 (0: 6..6): BOOLEAN ← FALSE,
done (0: 7..7): BOOLEAN ← FALSE
];
ControllerType: TYPE = MACHINE DEPENDENT {type440Controller(0), type450Controller(1), type472Controller(2), nonExistent(3)};
StatusByte2: TYPE = MACHINE DEPENDENT {
success(0),
intPending(1),
busyConflict(3),
operationTimeOut(4),
headerNotFound(5),
hardECCError(6),
illegalCylAdd(7),
sectorSlipError(9),
illegalSectorAdd(0AH),
lastSectorTooSmall(0DH),
slaveACKError(0EH),
cylAndHeadHeaderError(12H),
seekRetry(13H),
writeProtectError(14H),
unimplementedCommand(15H),
driveNotReady(16H),
sectorCountZero(17H),
driveFaulted(18H),
illegalSectorSize(19H),
selfTestA(1AH),
selfTestB(1BH),
selfTestC(1CH),
softECCError(1EH),
softECCErrorRecovered(1FH),
illegalHeadError(20H),
diskSequencerError(21H),
seekError(25H),
(0FFH)
};
Throttle: TYPE = MACHINE DEPENDENT RECORD [
byteMode (0: 0..0): BOOLEAN ← FALSE,
interleaveFactor (0: 1..4): [0..15] ← 0, -- n+1 to 1 interleave factor, 0 => 1:1
throttleSetting (0: 5..7): [0..7] ← 5 -- 2**(n+1) DMA cycles per burst,
]; -- 5 => 32 words per burst
DriveTypeAndSelect: TYPE = MACHINE DEPENDENT RECORD [
driveType (0: 0..1): DriveType ← cyl823Sect32Head19,
reserved (0: 2..5): BOOLEAN ← FALSE,
unit (0: 6..7): Unit ← 0
];
DriveType: TYPE = MACHINE DEPENDENT {cyl823Sect32Head19 (0), cyl823Sect32Head5 (1), cyl842Sect46Head20 (2), cyl2047Sect128Head255 (3)};
SectorCountLow: TYPE = MACHINE DEPENDENT RECORD [
SELECT OVERLAID * FROM
writeSectorCountLow => [bits: [0..256)],
readDriveStatus => [iOPBByteA: IOPBByteA],
ENDCASE];
IOPBByteA: TYPE = MACHINE DEPENDENT RECORD [
notOnCylinder (0: 0..0): BOOLEAN,
diskNotReady (0: 1..1): BOOLEAN,
diskWriteProtect (0: 2..2): BOOLEAN,
dualPortDriveBusy (0: 3..3): BOOLEAN,
hardSeekError (0: 4..4): BOOLEAN,
diskFault (0: 5..5): BOOLEAN,
reserved (0: 6..7): BOOLEAN ← FALSE
];
-- PUBLIC PROCEDURES
ActivateIOPB: PROC [hyperOffset: LONG CARDINAL] =
BEGIN
wordAdd: LONG CARDINAL ← LOOPHOLE[ColorVersatecUtils.hyperStart];
byteAdd: LONG CARDINAL ← (wordAdd + hyperOffset) * 2;
WriteByte[Inline.LowByte[Inline.LowHalf[byteAdd]], iOPBAddLow];
Dally[];
WriteByte[Inline.HighByte[Inline.LowHalf[byteAdd]], iOPBAddHigh];
Dally[];
WriteByte[Inline.LowByte[Inline.HighHalf[byteAdd]], iOPBRelocLow];
Dally[];
WriteByte[Inline.HighByte[Inline.HighHalf[byteAdd]], iOPBRelocHigh];
Dally[];
WriteByte[goBusy, controlStatus];
WHILE DiskControllerBusy[] DO ENDLOOP;
END;
DiskControllerBusy: PROC [] RETURNS [BOOLEAN] =
BEGIN
bits: CARDINAL ← ReadByte[controlStatus];
RETURN[Inline.BITAND[bits, goBusy] # 0];
END;
RawFormat: PUBLIC PROC [unit: Unit ← 0, cmdOffset: CARDINAL] RETURNS [noHardErrors: BOOLEAN] =
-- Formats all available sectors (leaves no spares). Only returns FALSE on a double
-- error. Should never happen. This code only tries to format 32 sectors per track.
-- By changing the drive switches and issuing 'setDriveSize' commands this can be increased to
-- 34 sectors per track. CDC9766 compatability is easier for now since it is wired in the
-- controller EPROM.
BEGIN
CylinderFormat: PROC [cylinder: Cylinder] RETURNS [status: StatusByte2] =
BEGIN
p: LONG POINTER ← @formatPB;
formatPB: IOPB ← [
diskCommand: [autoUpdate: TRUE, command: writeFormat],
intMode: [autoSeekRetry: TRUE],
driveTypeAndSelect: [unit: unit],
headAdd: 0,
sectorAdd: 0,
sectorCountLow: Inline.LowByte[sectorsPerTrack * tracksPerCylinder],
sectorCountHigh: Inline.HighByte[sectorsPerTrack * tracksPerCylinder]
];
formatPB.cylAddLow ← Inline.LowByte[cylinder];
formatPB.cylAddHigh ← Inline.HighByte[cylinder];
ColorVersatecUtils.HyperStore[sourcePtr: p, destOffset: cmdOffset, wordCount: SIZE[IOPB]];
ActivateIOPB[hyperOffset: cmdOffset];
ColorVersatecUtils.HyperRead[destPtr: p, sourceOffset: cmdOffset, wordCount: SIZE[IOPB]];
RETURN [formatPB.statusByte2];
END;
hardError: BOOLEAN ← FALSE;
result: StatusByte2;
OthelloDefs.WriteLine["Begin Format"];
FOR currentCyl: CARDINAL IN [0..cylindersPerSpindle) DO
ProcessorFace.SetMP[currentCyl];
FOR retry: CARDINAL IN [0..3) DO
result ← CylinderFormat [cylinder: currentCyl];
IF DoubleError[] THEN LOOP;
IF GoodCompletionCode[result] THEN EXIT;
OthelloDefs.WriteString["Retry at Cylinder: "];
OthelloDefs.WriteLongNumber[currentCyl];
OthelloDefs.NewLine[];
REPEAT
FINISHED =>
BEGIN
OthelloDefs.WriteLine["ERROR: Hard Error on Format"];
hardError ← TRUE;
END;
ENDLOOP;
ENDLOOP;
OthelloDefs.WriteLine["Format Done"];
RETURN [hardError];
END;
Read: PUBLIC PROC [head: Head, sector: Sector, cylinder: Cylinder, unit: Unit ← 0, sectorCount: CARDINAL, cmdOffset: CARDINAL, dataOffset: LONG CARDINAL] RETURNS [success: BOOLEAN] =
BEGIN
RawRead: PROC [] RETURNS [status: StatusByte2] =
BEGIN
wordAdd: LONG CARDINAL ← LOOPHOLE[ColorVersatecUtils.hyperStart];
byteAdd: LONG CARDINAL ← (wordAdd + dataOffset) * 2;
p: LONG POINTER ← @readPB;
readPB: IOPB ← [
diskCommand: [autoUpdate: TRUE, relocate: TRUE, command: read],
intMode: [autoSeekRetry: TRUE]
];
readPB.driveTypeAndSelect.unit ← unit;
readPB.headAdd ← head;
readPB.sectorAdd ← sector;
readPB.cylAddLow ← Inline.LowByte[cylinder];
readPB.cylAddHigh ← Inline.HighByte[cylinder];
readPB.sectorCountLow ← Inline.LowByte[sectorCount];
readPB.sectorCountHigh ← Inline.HighByte[sectorCount];
readPB.dataAddLow ← Inline.LowByte[Inline.LowHalf[byteAdd]];
readPB.dataAddHigh ← Inline.HighByte[Inline.LowHalf[byteAdd]];
readPB.dataRelocLow ← Inline.LowByte[Inline.HighHalf[byteAdd]];
ColorVersatecUtils.HyperStore[sourcePtr: p, destOffset: cmdOffset, wordCount: SIZE[IOPB]];
ActivateIOPB[hyperOffset: cmdOffset];
ColorVersatecUtils.HyperRead[destPtr: p, sourceOffset: cmdOffset, wordCount: SIZE[IOPB]];
RETURN [readPB.statusByte2];
END;
bits: CARDINAL;
result: StatusByte2;
FOR retry: CARDINAL IN [0..3) DO
result ← RawRead[];
IF DoubleError[] THEN LOOP;
IF GoodCompletionCode[result] THEN EXIT;
OthelloDefs.WriteString["Retry...StatusByte2: "];
OthelloDefs.WriteOctal[bits ← LOOPHOLE[result]];
OthelloDefs.NewLine[];
REPEAT
FINISHED =>
BEGIN
OthelloDefs.WriteString["ERROR: Hard Read Error at Cylinder: "];
OthelloDefs.WriteLongNumber[cylinder];
OthelloDefs.WriteString[" Head: "];
OthelloDefs.WriteLongNumber[head];
OthelloDefs.WriteString[" Sector: "];
OthelloDefs.WriteLongNumber[sector];
OthelloDefs.NewLine[];
ERROR;
END;
ENDLOOP;
RETURN[TRUE];
END;
Write: PUBLIC PROC [head: Head, sector: Sector, cylinder: Cylinder, unit: Unit ← 0, sectorCount: CARDINAL, cmdOffset: CARDINAL, dataOffset: LONG CARDINAL] RETURNS [success: BOOLEAN] =
BEGIN
RawWrite: PROC [] RETURNS [status: StatusByte2] =
BEGIN
wordAdd: LONG CARDINAL ← LOOPHOLE[ColorVersatecUtils.hyperStart];
byteAdd: LONG CARDINAL ← (wordAdd + dataOffset) * 2;
p: LONG POINTER ← @writePB;
writePB: IOPB ← [
diskCommand: [autoUpdate: TRUE, relocate: TRUE, command: write],
intMode: [autoSeekRetry: TRUE]
];
writePB.driveTypeAndSelect.unit ← unit;
writePB.headAdd ← head;
writePB.sectorAdd ← sector;
writePB.cylAddLow ← Inline.LowByte[cylinder];
writePB.cylAddHigh ← Inline.HighByte[cylinder];
writePB.sectorCountLow ← Inline.LowByte[sectorCount];
writePB.sectorCountHigh ← Inline.HighByte[sectorCount];
writePB.dataAddLow ← Inline.LowByte[Inline.LowHalf[byteAdd]];
writePB.dataAddHigh ← Inline.HighByte[Inline.LowHalf[byteAdd]];
writePB.dataRelocLow ← Inline.LowByte[Inline.HighHalf[byteAdd]];
ColorVersatecUtils.HyperStore[sourcePtr: p, destOffset: 0, wordCount: SIZE[IOPB]];
ActivateIOPB[hyperOffset: 0];
ColorVersatecUtils.HyperRead[destPtr: p, sourceOffset: 0, wordCount: SIZE[IOPB]];
RETURN [writePB.statusByte2];
END;
bits: CARDINAL;
result: StatusByte2;
FOR retry: CARDINAL IN [0..3) DO
result ← RawWrite [];
IF DoubleError[] THEN LOOP;
IF GoodCompletionCode[result] THEN EXIT;
OthelloDefs.WriteString["Retry...StatusByte2: "];
OthelloDefs.WriteOctal[bits ← LOOPHOLE[result]];
OthelloDefs.NewLine[];
REPEAT
FINISHED =>
BEGIN
OthelloDefs.WriteString["ERROR: Hard Write Error at Cylinder "];
OthelloDefs.WriteLongNumber[cylinder];
OthelloDefs.WriteString[" Head: "];
OthelloDefs.WriteLongNumber[head];
OthelloDefs.WriteString[" Sector: "];
OthelloDefs.WriteLongNumber[sector];
OthelloDefs.NewLine[];
ERROR;
END;
ENDLOOP;
RETURN[TRUE];
END;
Seek: PUBLIC PROC [head: Head ← 0, cylinder: Cylinder ← 0, unit: Unit ← 0, cmdOffset: CARDINAL] RETURNS [success: BOOLEAN] =
BEGIN
RawSeek: PROC [] RETURNS [status: StatusByte2] =
BEGIN
p: LONG POINTER ← @seekPB;
seekPB: IOPB ← [
diskCommand: [autoUpdate: TRUE, relocate: TRUE, command: seek],
intMode: [autoSeekRetry: TRUE, enableExtendedFunc: TRUE]
];
seekPB.driveTypeAndSelect.unit ← unit;
seekPB.headAdd ← head;
seekPB.cylAddLow ← Inline.LowByte[cylinder];
seekPB.cylAddHigh ← Inline.HighByte[cylinder];
ColorVersatecUtils.HyperStore[sourcePtr: p, destOffset: 0, wordCount: SIZE[IOPB]];
ActivateIOPB[hyperOffset: 0];
ColorVersatecUtils.HyperRead[destPtr: p, sourceOffset: 0, wordCount: SIZE[IOPB]];
RETURN [seekPB.statusByte2];
END;
bits: CARDINAL;
result: StatusByte2;
-- The controller does automatic retries, but I'll do them as well...
FOR retry: CARDINAL IN [0..3) DO
result ← RawSeek[];
IF DoubleError[] THEN LOOP;
IF GoodCompletionCode[result] THEN EXIT;
OthelloDefs.WriteString["Retry...StatusByte2: "];
OthelloDefs.WriteOctal[bits ← LOOPHOLE[result]];
OthelloDefs.NewLine[];
REPEAT
FINISHED =>
BEGIN
OthelloDefs.WriteString["ERROR: Hard Seek Error at Cylinder "];
OthelloDefs.WriteLongNumber[cylinder];
OthelloDefs.WriteString[" Head: "];
OthelloDefs.WriteLongNumber[head];
OthelloDefs.NewLine[];
RETURN[FALSE];
END;
ENDLOOP;
RETURN[TRUE];
END;
DoubleError: PROC [] RETURNS [BOOLEAN] =
BEGIN
bits: CARDINAL;
IF Inline.BITAND[bits ← ReadByte[controlStatus], doubleError] # 0 THEN
BEGIN
ErrorReset[];
DriveReset [];
OthelloDefs.WriteString["ERROR: Double Error...CSR: "];
OthelloDefs.WriteOctal[bits];
OthelloDefs.NewLine[];
RETURN[TRUE];
END;
RETURN[FALSE];
END;
DriveReset: PROC [] =
BEGIN
p: LONG POINTER ← @resetPB;
resetPB: IOPB ← [
diskCommand: [autoUpdate: TRUE, relocate: TRUE, command: driveReset],
intMode: [autoSeekRetry: TRUE]
];
ColorVersatecUtils.HyperStore[sourcePtr: p, destOffset: 0, wordCount: SIZE[IOPB]];
ActivateIOPB[hyperOffset: 0];
END;
ControllerReset: PROC [] =
BEGIN
-- reading has the side effect of resetting the controller, selecting drive 0,
-- and testing the drive ready status
bits: CARDINAL ← ReadByte[controllerResetAndUpdate];
Dally[100];
END;
ErrorReset: PROC [] =
BEGIN
bits: CARDINAL;
WriteByte[generalError, controlStatus];
Dally[];
IF Inline.BITAND[bits ← ReadByte[controlStatus], doubleError] # 0 OR
Inline.BITAND[bits ← ReadByte[controlStatus], generalError] # 0 THEN
OthelloDefs.WriteLine["ERROR ERROR: Could not clear error status"];
END;
GoodCompletionCode: PROC [status: StatusByte2] RETURNS [BOOLEAN] =
BEGIN
bits: CARDINAL;
IF Inline.BITAND[bits ← ReadByte[controlStatus], generalError] # 0 THEN
BEGIN
ErrorReset[];
OthelloDefs.WriteString["ERROR: General Error bit set...StatusByte2: "];
OthelloDefs.WriteOctal[bits ← LOOPHOLE[status]];
OthelloDefs.NewLine[];
END;
SELECT status FROM
success, seekRetry, softECCErrorRecovered => RETURN[TRUE];
operationTimeOut, headerNotFound, hardECCError => RETURN[FALSE];
cylAndHeadHeaderError, driveFaulted, driveNotReady, seekError =>
BEGIN
ControllerReset[];
DriveReset[];
RETURN[FALSE];
END;
intPending, busyConflict, illegalCylAdd, illegalSectorAdd,
unimplementedCommand, sectorCountZero, illegalSectorSize, selfTestA,
selfTestB, selfTestC, illegalHeadError =>
BEGIN
OthelloDefs.WriteLine["ERROR: Program error or hard failure"];
ERROR;
END;
sectorSlipError =>
BEGIN
OthelloDefs.WriteLine["ERROR: Sector Slip Error"];
ERROR;
END;
slaveACKError =>
BEGIN
OthelloDefs.WriteLine["ERROR: XACK timeout"];
ERROR;
END;
lastSectorTooSmall, illegalSectorSize =>
BEGIN
OthelloDefs.WriteLine["ERROR: Formatting Error, check drive configuration"];
ERROR;
END;
writeProtectError =>
BEGIN
OthelloDefs.WriteLine["ERROR: Write Protect Error"];
ERROR;
END;
ENDCASE =>
BEGIN
OthelloDefs.WriteLine["ERROR: Unknown Type"];
ERROR;
END;
END;
ReadWriteTest: PUBLIC 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;
OthelloDefs.WriteLine["ReadWriteTest: Begin Write Phase"];
FOR i: CARDINAL IN [0..50) 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["ReadWriteTest: Begin Read Phase"];
FOR i: CARDINAL IN [0..50) 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;
SeekTest: PUBLIC 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;
Dally: PROC [i: CARDINAL ← 10] =
BEGIN
FOR j: CARDINAL IN [0..i) DO
ENDLOOP;
END;
DiskInitialCheckout: PUBLIC PROC [] =
BEGIN
bits: CARDINAL ← 0;
WHILE TRUE DO
ControllerReset[];
bits ← Inline.BITAND[driveReady, ReadByte[controlStatus]];
Dally[];
IF bits # 0 THEN EXIT;
OthelloDefs.WriteLine["Drive 0 Offline: Make sure drive is spun up and the A-access light is lit"];
Process.Pause[Process.SecondsToTicks[2]];
ENDLOOP;
END;
ReadDriveStatus: PROC [unit: Unit ← 0] RETURNS [] =
BEGIN
bits: CARDINAL;
p: LONG POINTER ← @rdsPB;
rdsPB: IOPB ← [
diskCommand: [autoUpdate: TRUE, relocate: TRUE, command: readDriveStatus],
intMode: [autoSeekRetry: TRUE, enableExtendedFunc: TRUE],
driveTypeAndSelect: [unit: unit]
];
ColorVersatecUtils.HyperStore[sourcePtr: p, destOffset: 0, wordCount: SIZE[IOPB]];
ActivateIOPB[hyperOffset: 0];
ColorVersatecUtils.HyperRead[destPtr: p, sourceOffset: 0, wordCount: SIZE[IOPB]];
OthelloDefs.WriteString["Drive Status: "];
OthelloDefs.WriteOctal[bits ← LOOPHOLE[rdsPB.sectorCountLow]];
OthelloDefs.NewLine[];
END;
SelfTest: PROC [] =
BEGIN
bits: CARDINAL;
p: LONG POINTER ← @stPB;
stPB: IOPB ← [diskCommand: [autoUpdate: TRUE, command: selfTest],
intMode: [autoSeekRetry: TRUE, enableExtendedFunc: TRUE]
];
ColorVersatecUtils.HyperStore[sourcePtr: p, destOffset: 0, wordCount: SIZE[IOPB]];
ActivateIOPB[hyperOffset: 0];
ColorVersatecUtils.HyperRead[destPtr: p, sourceOffset: 0, wordCount: SIZE[IOPB]];
OthelloDefs.WriteString["SelfTest: StatusByte1: "];
OthelloDefs.WriteOctal[bits ← LOOPHOLE[stPB.statusByte1]];
OthelloDefs.WriteString[" StatusByte2: "];
OthelloDefs.WriteOctal[bits ← LOOPHOLE[stPB.statusByte2]];
OthelloDefs.NewLine[];
END;
NoOp: PROC [] =
BEGIN
bits: CARDINAL;
p: LONG POINTER ← @noPB;
noPB: IOPB ← [diskCommand: [autoUpdate: TRUE, command: noOp],
intMode: [autoSeekRetry: TRUE, enableExtendedFunc: TRUE]
];
ColorVersatecUtils.HyperStore[sourcePtr: p, destOffset: 0, wordCount: SIZE[IOPB]];
ActivateIOPB[hyperOffset: 0];
ColorVersatecUtils.HyperRead[destPtr: p, sourceOffset: 0, wordCount: SIZE[IOPB]];
OthelloDefs.WriteString["NoOp: StatusByte1: "];
OthelloDefs.WriteOctal[bits ← LOOPHOLE[noPB.statusByte1]];
OthelloDefs.WriteString[" StatusByte2: "];
OthelloDefs.WriteOctal[bits ← LOOPHOLE[noPB.statusByte2]];
OthelloDefs.NewLine[];
END;
-- BEWARE HACKED TO BE BACKWARDS
baseAddress: DicentraInputOutput.IOAddress = LOOPHOLE[LONG[4000H]];
ReadByte: PROC [y: DiskControllerRegister] RETURNS [CARDINAL] =
BEGIN
byteOffset: CARDINAL = y.ORD;
IF (byteOffset MOD 2) # 0 THEN
RETURN[DicentraInputOutput.InputByteEven[baseAddress+byteOffset/2]]
ELSE
RETURN[DicentraInputOutput.InputByteOdd[baseAddress+byteOffset/2]];
END;
WriteByte: PROC [x: CARDINAL, y: DiskControllerRegister] =
BEGIN
byteOffset: CARDINAL = y.ORD;
IF (byteOffset MOD 2) # 0 THEN
DicentraInputOutput.OutputByteEven[x, baseAddress+byteOffset/2]
ELSE
DicentraInputOutput.OutputByteOdd[x, baseAddress+byteOffset/2];
END;
DiskInitialCheckout[];
END.