mirror of
https://github.com/livingcomputermuseum/Darkstar.git
synced 2026-03-07 11:50:02 +00:00
39 lines
52 KiB
Plaintext
39 lines
52 KiB
Plaintext
head 1.1;
|
|
branch 1.1.1;
|
|
access ;
|
|
symbols start:1.1.1.1 Xerox:1.1.1;
|
|
locks ; strict;
|
|
comment @# @;
|
|
|
|
|
|
1.1
|
|
date 2001.08.12.22.22.08; author freier; state Exp;
|
|
branches 1.1.1.1;
|
|
next ;
|
|
|
|
1.1.1.1
|
|
date 2001.08.12.22.22.08; author freier; state Exp;
|
|
branches ;
|
|
next ;
|
|
|
|
|
|
desc
|
|
@@
|
|
|
|
|
|
|
|
1.1
|
|
log
|
|
@Initial revision
|
|
@
|
|
text
|
|
@{ Copyright (C) 1980 by Xerox Corporation. All rights reserved. }
|
|
|
|
|
|
{This is microcode used to test the Dandelion Shugart disk controller and disk. There are two main functions. The first times the index and sector pulses from the disk. The second tests the data wrap-around facilities in the controller.}
|
|
|
|
{constants which define the address marks for the SA1000}
|
|
Set[CAddrMkHi, 0A1];
|
|
Set[CHeaderAddrMkLo, 041];
|
|
Set[CLabDatAddrMkLo, 043];
|
|
{Command used to start the disk task running (has only FirmwareEnable and DriveSelect set).}
|
|
Set[CDiskStartCmdHi, 04];
|
|
Set[CDiskStartCmdLo, 20];
|
|
{Command used to find the index mark}
|
|
Set[CFindIndexCmdHi, 04];
|
|
Set[CFindIndexCmdLo, 24];
|
|
{bit used to make "find index mark" command into "find Sector mark" command}
|
|
Set[CFindSectorMkLo, 2];
|
|
{The Firmware Enable bit in the disk command register}
|
|
Set[CFirmwareEnable, 20];
|
|
{Bit used to detect if disk task is still active. This bit is in the upper status byte.}
|
|
Set[CFirmwareBusyHi, 01];
|
|
{tag bit inserted into the address marks of Label and Data fields}
|
|
Set[CLabDatTag, 2];
|
|
{Status bit used for index flag}
|
|
Set[CIndexFlag, 80];
|
|
{Lower byte of write command}
|
|
Set[CWriteCmdLo, 33];
|
|
{Status bit used for sector flag}
|
|
Set[CSectorFlag, 40];
|
|
|
|
{This task's job is to enable the disk task and wait. In its current form, it waits for Firmware Enable to drop as a signal the test is done. }
|
|
|
|
|
|
SetTask[0]; StartAddress[RecieveU];
|
|
TERROR: R7¬8,ClrIntErr,CANCELBR[Exit32,0F], c1, at[0];
|
|
|
|
Start: RA ¬ TEST, c1; {}
|
|
RA ¬ RA LRot12, c2; {}
|
|
UNITKCTL¬ RA , c3; {}
|
|
|
|
Xbus ¬ UNITKCTL, XDisp , c1;
|
|
DISP4[SUnit], c2;
|
|
|
|
SUnit: RA¬ 0F8,GOTO[SetUnit], c3, at[0, 10, SUnit];
|
|
RA¬ 0F4,GOTO[SetUnit], c3, at[1, 10, SUnit];
|
|
RA¬ 0F2,GOTO[SetUnit], c3, at[2, 10, SUnit];
|
|
RA¬ 0F1,GOTO[SetUnit], c3, at[3, 10, SUnit];
|
|
RA¬ 0F8,GOTO[SetUnit], c3, at[4, 10, SUnit];
|
|
RA¬ 0F8,GOTO[SetUnit], c3, at[5, 10, SUnit];
|
|
RA¬ 0F8,GOTO[SetUnit], c3, at[6, 10, SUnit];
|
|
RA¬ 0F8,GOTO[SetUnit], c3, at[7, 10, SUnit];
|
|
RA¬ 0F8,GOTO[SetUnit], c3, at[8, 10, SUnit];
|
|
RA¬ 0F8,GOTO[SetUnit], c3, at[9, 10, SUnit];
|
|
RA¬ 0F8,GOTO[SetUnit], c3, at[0A, 10, SUnit];
|
|
RA¬ 0F8,GOTO[SetUnit], c3, at[0B, 10, SUnit];
|
|
RA¬ 0F8,GOTO[SetUnit], c3, at[0C, 10, SUnit];
|
|
RA¬ 0F8,GOTO[SetUnit], c3, at[0D, 10, SUnit];
|
|
RA¬ 0F8,GOTO[SetUnit], c3, at[0E, 10, SUnit];
|
|
RA¬ 0F8,GOTO[SetUnit], c3, at[0F, 10, SUnit];
|
|
|
|
|
|
SetUnit: UNITKCTL ¬ RA, c1; {}
|
|
RA ¬ RA and 0F, c2; {}
|
|
UNITKSTAT ¬ RA , c3; {}
|
|
|
|
Xbus¬TEST, XDisp , c1;
|
|
RA ¬ 10,DISP4[StartTest], c2;
|
|
|
|
StartTest: R7¬0FF,GOTO[NotLf], c3, at[0, 10, StartTest];
|
|
R7¬0FF,GOTO[NotLf], c3, at[1, 10, StartTest];
|
|
R7¬0FF,GOTO[NotLf], c3, at[2, 10, StartTest];
|
|
R7¬0FF,GOTO[NotLf], c3, at[3, 10, StartTest];
|
|
R7¬0FF,GOTO[NotLf], c3, at[4, 10, StartTest];
|
|
R7¬0FF,GOTO[NotLf], c3, at[5, 10, StartTest];
|
|
R7¬0FF,GOTO[NotLf], c3, at[6, 10, StartTest];
|
|
ClrKFlags,GOTO[LfReset], c3, at[7, 10, StartTest];
|
|
RB ¬ UINITIAL,ClrKFlags,GOTO[LfData], c3, at[8, 10, StartTest];
|
|
ClrKFlags,GOTO[LfTest1], c3, at[9, 10, StartTest];
|
|
RB ¬ 8,ClrKFlags,GOTO[LfTest2], c3, at[0A, 10, StartTest];
|
|
ClrKFlags,GOTO[LfTest3], c3, at[0B, 10, StartTest];
|
|
R0¬UNITKSTAT,GOTO[DiskInit], c3, at[0C, 10, StartTest];
|
|
R0¬UNITKSTAT,GOTO[DiskInit], c3, at[0D, 10, StartTest];
|
|
R0¬UNITKSTAT,GOTO[DiskInit], c3, at[0E, 10, StartTest];
|
|
R0¬UNITKSTAT,GOTO[DiskInit], c3, at[0F, 10, StartTest];
|
|
|
|
|
|
NotLf: RD ¬ CDiskStartCmdHi, c1; {compose disk start command}
|
|
RD ¬ RD LRot8, c2; {align upper command byte}
|
|
RD ¬ RD or 24, c3; {finish disk starting command}
|
|
|
|
RE ¬ CDiskStartCmdHi, c1; {compose disk start command}
|
|
RE ¬ RE LRot8, c2; {align upper command byte}
|
|
RE ¬ RE or 30, c3; {finish disk starting command}
|
|
|
|
R9 ¬ CDiskStartCmdHi, c1; {compose disk start command}
|
|
R9 ¬ R9 LRot8, c2; {align upper command byte}
|
|
R9 ¬ R9 or 32, c3; {finish disk starting command}
|
|
|
|
R2 ¬ CDiskStartCmdHi, c1; {compose disk start command}
|
|
R2 ¬ R2 LRot8, c2; {align upper command byte}
|
|
R2 ¬ R2 or CDiskStartCmdLo, c3; {finish disk starting command}
|
|
|
|
R4 ¬ CDiskStartCmdHi, c1; {compose disk start command}
|
|
R4 ¬ R4 LRot8, c2; {align upper command byte}
|
|
R4 ¬ R4 or 60, c3; {finish disk starting command}
|
|
|
|
R5 ¬ CDiskStartCmdHi, c1; {compose disk start command}
|
|
R5 ¬ R5 LRot8, c2; {align upper command byte}
|
|
R5 ¬ R5 or 0E0, c3; {finish disk starting command}
|
|
|
|
R6 ¬ CDiskStartCmdHi, c1; {compose disk start command}
|
|
R6 ¬ R6 LRot8, c2; {align upper command byte}
|
|
R6 ¬ R6 or 0A0, c3; {finish disk starting command}
|
|
|
|
R3 ¬ 4, c1;
|
|
R3 ¬ R3 LRot8, c2; {align upper command byte}
|
|
R1¬TEST, c3;
|
|
|
|
R0¬ R1 and 10, c1;
|
|
R0¬ R0 , ZeroBr, c2;
|
|
BRANCH[NotLf1,NotLf4], c3;
|
|
|
|
|
|
|
|
NotLf1: R1¬ R1 xor 16, c1;
|
|
R1¬ R1 , ZeroBr, c2;
|
|
R0 ¬ 0A0,BRANCH[NotLf3,NotLf2], c3;
|
|
|
|
NotLf2: RD ¬ RD or 26, c1; {Start the disk Task}
|
|
R0¬ 0C0, c2;
|
|
Noop, c3; {prepare to sense end of disk test}
|
|
|
|
|
|
NotLf3: KCtl ¬ R2 LRot0, c1; {Start the disk Task}
|
|
UNITKCTL¬0, c2;
|
|
LEXPECTED¬ R0,GOTO[Delay], c3; {prepare to sense end of disk test}
|
|
|
|
NotLf4: KCtl ¬ R2 LRot0, c1; {Start the disk Task}
|
|
Noop, c2;
|
|
GOTO[Delay], c3;
|
|
|
|
|
|
LfReset: Noop ,c1;
|
|
Noop ,c2;
|
|
R9 ¬ ~KTest ,GOTO[LfDataCk] ,c3;
|
|
|
|
|
|
{KCtl gets AAA0 pattern }
|
|
|
|
LfData: RB ¬ RB LRot8 ,c1;
|
|
RA ¬ LINITIAL ,c2;
|
|
KCtl ¬ (RB or RA ) LRot0 ,c3;
|
|
|
|
|
|
RA ¬ RB LRot8 ,c1;
|
|
KCmd ¬ (RB or RA)LRot0 ,c2;
|
|
R9 ¬ ~KTest ,GOTO[LfDataCk] ,c3;
|
|
|
|
|
|
|
|
LfTest1: RB ¬ 0C0 , c1;
|
|
Noop ,c2;
|
|
KCtl ¬ RB LRot0 ,c3;
|
|
|
|
|
|
RB ¬ 40 ,c1;
|
|
KCtl ¬ RB LRot0 ,c2;
|
|
GOTO[Delay] ,c3;
|
|
|
|
LfTest2: R7¬0FF , c1;
|
|
KCtl ¬ 0 ,c2;
|
|
KCmd ¬ RB LRot8,GOTO[Delay] ,c3;
|
|
|
|
LfTest3: RE¬0AA, c1;
|
|
RE¬(RE LRot8) or RE , c2;
|
|
Noop ,c3;
|
|
RF¬55, c1;
|
|
RF¬(RF LRot8) or RF , c2;
|
|
Noop ,c3;
|
|
RB¬28, c1;
|
|
RB¬RB LRot8 , c2;
|
|
RB¬RB or 80 ,c3;
|
|
KCmd ¬ RB LRot0, c1;
|
|
KCtl ¬ 0 , c2;
|
|
R7¬0FF,GOTO[Delay] ,c3;
|
|
|
|
Delay: RB¬ UDELAY, c1;
|
|
Noop, c2;
|
|
Delay1: RA¬ LDELAY, c3;
|
|
DelayL: Noop, c1;
|
|
RA¬RA-1, NZeroBr, c2;
|
|
DelayL1: BRANCH[DelayL3, DelayL], c3;
|
|
DelayL3: RB¬RB-1, ZeroBr, c1;
|
|
BRANCH[Delay1, Delay2], c2;
|
|
|
|
Delay2: R7 ¬ R7, NZeroBr, c3;
|
|
BRANCH[Exit32F, Stopit], c1;
|
|
|
|
Stopit: RA¬ 0F, c2;
|
|
RB¬UNITKCTL ,c3;
|
|
KCmd¬0 ,c1;
|
|
Stopit1: Noop, c2;
|
|
RA¬RA-1, ZeroBr ,c3;
|
|
KCtl ¬ RB LRot8,BRANCH[Stopit1, Exit32], c1;
|
|
|
|
|
|
Exit32: R8 ¬1, c2;
|
|
Exit3: R8 ¬1 ,c3;
|
|
Exit31: R8 ¬1 ,c1;
|
|
Exit32F: FAULTTYPE ¬ R7 ,c2;
|
|
R8 ¬ R8-1,ZeroBr, GOTO[CPassDone], c3;
|
|
|
|
|
|
|
|
|
|
CPassDone: R3¬UNITKCTL,BRANCH[CPassDone1, CPassDone2], c1;
|
|
CPassDone1: KCmd¬0, c2;
|
|
KCtl ¬ R3 LRot8,GOTO[Start], c3;
|
|
|
|
CPassDone2: KCmd¬0, c2;
|
|
KCtl ¬ R3 LRot8,GOTO[CStop], c3;
|
|
|
|
|
|
CStop: [] ¬ STOPONERR,CANCELBR[$],ZeroBr, c1;
|
|
BRANCH[CStop1, CStop2], c2;
|
|
CStop1: R8¬PASSCOUNT,GOTO[Start], c3;
|
|
|
|
CStop2: GOTO[End], c3;
|
|
|
|
|
|
End: GOTO[SendU], c1;
|
|
|
|
|
|
|
|
|
|
|
|
RecieveU: CANCELBR[$,0F], c1; {Clear flags}
|
|
IOPCtl ¬ 5 , c2; {Set mode of IOP port, + Attn to indicate proceed to IOP}
|
|
R1¬0, c3; {Clear data register}
|
|
|
|
WaitIn: Xbus ¬ IOPStatus, XLDisp , c1; {Is IOPReq true?, Put R0 on Y bus}
|
|
BRANCH [WaitIn1, In, XOdd], c2; {XOdd => IOPReq, Put R0 on Y bus}
|
|
WaitIn1: GOTO[WaitIn], c3;
|
|
|
|
In: IOPCtl ¬ 1 , c3; {Set mode of IOP port, clear Attn}
|
|
R0¬IOPIData , c1; {Input value}
|
|
R3¬10, c2;
|
|
GOTO[StoreU], c3;
|
|
|
|
|
|
|
|
|
|
StoreU: Noop , c1;
|
|
[]¬ R1, AltUaddr, c2;
|
|
TEST¬ R0, GOTO[CHECKLU] , c3;
|
|
|
|
|
|
CHECKLU: R1 ¬ R1 +1 , c1;
|
|
[] ¬ R1 and R3, ZeroBr , c2;
|
|
BRANCH [CHECKLU2, CHECKLU1] , c3;
|
|
|
|
CHECKLU1: Noop, c1;
|
|
GOTO[WaitIn1], c2; {Not Done}
|
|
|
|
CHECKLU2: FAULTTYPE¬R7¬0, c1;
|
|
IOPCtl ¬ 0, c2;
|
|
R8¬PASSCOUNT,GOTO[Start], c3; {Done}
|
|
|
|
|
|
SendU: R1¬0, c2;
|
|
IOPCtl ¬ 2 , c3; {Set mode of IOP port}
|
|
R3¬10, c1;
|
|
Noop, c2;
|
|
GOTO[GetU], c3;
|
|
|
|
WaitOut: Xbus ¬ IOPStatus, XLDisp, c1; {Is IOPReq true?, Put R0 on Y bus}
|
|
BRANCH [WaitOut1, Out, XOdd], c2; {XOdd => IOPReq, Put R0 on Y bus}
|
|
WaitOut1: GOTO[WaitOut], c3;
|
|
|
|
Out: IOPOData ¬ R0 LRot0,GOTO[GetU], c3; {Output value}
|
|
|
|
GetU: Noop , c1;
|
|
[]¬ R1, AltUaddr , c2;
|
|
R0¬ TEST,GOTO[CHECKSU] , c3;
|
|
|
|
CHECKSU: [] ¬ R1 and R3, ZeroBr , c1;
|
|
BRANCH [CHECKSU2, CHECKSU1] , c2;
|
|
|
|
|
|
CHECKSU1: R1 ¬ R1 +1,GOTO[WaitOut], c3; {Not Done}
|
|
|
|
CHECKSU2: IOPCtl ¬ 0,GOTO[RecieveU], c3; {Done}
|
|
|
|
SetTask[5];
|
|
StartAddress[Task5];
|
|
Task5: CANCELBR[Task5,0F], c*;
|
|
|
|
SetTask[3];
|
|
StartAddress[Task3];
|
|
Task3: CANCELBR[Task3,0F], c*;
|
|
|
|
SetTask[2];
|
|
StartAddress[Task2];
|
|
Task2: CANCELBR[Task2,0F], c*;
|
|
|
|
SetTask[1];
|
|
StartAddress[Task1];
|
|
Task1: CANCELBR[Task1,0F], c*;
|
|
|
|
SetTask[4];
|
|
StartAddress[TestDisp];
|
|
|
|
|
|
TestDisp: Xbus¬TEST, XDisp ,CANCELBR[$, 0F],c1;
|
|
RCTEMP ¬ 10,DISP4[RunTest], c2;
|
|
|
|
RunTest: RCTEMP ¬ RCTEMP and ~KStatus,GOTO[ReadyTest], c3, at[0, 10, RunTest];
|
|
GOTO[IndexTest], c3, at[1, 10, RunTest];
|
|
GOTO[SectorLenTest], c3, at[2, 10, RunTest];
|
|
GOTO[NumSectorTest], c3, at[3, 10, RunTest];
|
|
GOTO[SA4DataTest], c3, at[4, 10, RunTest];
|
|
R1¬ TEST,GOTO[SA1OneTest], c3, at[5, 10, RunTest];
|
|
R1 ¬ TEST,GOTO[SA1ZeroTest], c3, at[6, 10, RunTest];
|
|
R7 ¬ 8,GOTO[TestDisp], c3, at[7, 10, RunTest];
|
|
R7 ¬ 8,GOTO[TestDisp], c3, at[8, 10, RunTest];
|
|
R7 ¬ 8,GOTO[TestDisp], c3, at[9, 10, RunTest];
|
|
R7 ¬ 7,GOTO[TEST2], c3, at[0A, 10, RunTest];
|
|
GOTO[TEST3], c3, at[0B, 10, RunTest];
|
|
R7 ¬ 8,GOTO[TestDisp], c3, at[0C, 10, RunTest];
|
|
R7 ¬ 8,GOTO[TestDisp], c3, at[0D, 10, RunTest];
|
|
GOTO[CkWakeUp], c3, at[0E, 10, RunTest];
|
|
GOTO[CkWakeUp], c3, at[0F, 10, RunTest];
|
|
|
|
ReadyTest: R7 ¬ RCTEMP LRot12,GOTO[Exit2], c1; {ready bit}
|
|
|
|
{Index Pulse Test.}
|
|
{This test must be run by the disk task, not the emulator task. This is so the number of clicks per round is known exactly. We use the number of clicks executed as a time base. When this test finishes, R0 should hold 26E8+-4% (the rotational period has a 3% variation.)}
|
|
|
|
{First, find an index pulse, returning if none is found.}
|
|
IndexTest: R0 ¬ 0, c1; {clear pulse count}
|
|
ClrKFlags, c2; {turn off index pulse latch}
|
|
R1 ¬ CIndexFlag, c3; {Prepare to sense index flag}
|
|
|
|
{Now wait for an index pulse. We do not have the index pulse cause a wakeup directly because the microcode would lock up if no index pulse arrived.}
|
|
|
|
Wait1stIndex: Ybus ¬ R1 and ~KStatus, ZeroBr, c1; {has first index pulse been found yet?}
|
|
R0 ¬ R0+1, CarryBr, BRANCH[FirstIndexFound, FirstIndexWait], c2; {add one to waiting count and decide if first index pulse has been found yet}
|
|
|
|
FirstIndexWait: BRANCH[Wait1stIndex, NoIndexError], c3; {either keep waiting for first index pulse or give up}
|
|
|
|
{the first index pulse has been found. We now clear its flag and count the number of 2.05 uS rounds until the next one.}
|
|
|
|
FirstIndexFound: R0 ¬ 0, ClrKFlags, CANCELBR[$], c3;
|
|
R0 ¬ R0 or R0, ZeroBr, GOTO[Wait2IndexC2], c1;
|
|
|
|
{Wait for the next index pulse, timing the interval between pulses.}
|
|
Wait2ndIndex: Ybus ¬ R1 and ~KStatus, ZeroBr, c1; {has 2nd index pulse been found yet?}
|
|
|
|
Wait2IndexC2: R0 ¬ R0+1, CarryBr, BRANCH[LastIndexFound, LastIndexWait], c2; {add one to waiting count and decide if 2nd index pulse has been found yet}
|
|
|
|
LastIndexWait: BRANCH[Wait2ndIndex, No2ndIndexError], c3; {either keep waiting for 2nd index pulse or give up}
|
|
|
|
{At this point the second index pulse has been found. The count in R0 should be compared with the legal bounds for the SA4000 or SA1000.}
|
|
|
|
LastIndexFound: CANCELBR[Bounds], c3;
|
|
|
|
NoIndexError: R7¬2,GOTO[Exit2], c1;
|
|
No2ndIndexError: R7¬3,GOTO[Exit2], c1;
|
|
|
|
|
|
{Sector Length Test}
|
|
{This test should only be executed when an SA4000 disk is connected. It is quite similar to the test for the index pulse. Note that the length of the first sector on the track is tested. The length of the last sector is slightly longer that the others and if any sector length were tested, that one might be found. Note we find the index pulse by simply having the microcode wake up when it arrives. We assume the index Pulse test has been run to ensure the index pulse exists. When this test finishes, R0 should hold 163'X+-4%.}
|
|
SectorLenTest: R1 ¬ CFindIndexCmdHi, c1;
|
|
R1 ¬ R1 LRot8, c2;
|
|
R1 ¬ R1 or CFindIndexCmdLo, c3; {finish composing find index mark command}
|
|
|
|
KCtl ¬ R1 LRot0, c1; {next click will start on index pulse}
|
|
R0 ¬ 0, ClrKFlags, c2; {clear sector length count and recorded index flag}
|
|
R1 ¬ R1 and ~0F, c3; {compose the "always run" command so we can count the number of rounds between sector pulses.}
|
|
|
|
{the index pulse has been detected, start counting the rounds until the next sector pulse. Sector zero's pulse is co-incident with the index pulse.}
|
|
ClrKFlags, c1; {clear out first sector pulse so only the NEXT one will be sensed.}
|
|
KCtl ¬ R1 LRot0, c2; {have microcode awaken every round.}
|
|
R1 ¬ CSectorFlag, c3; {prepare to sense sector pulse.}
|
|
|
|
{Wait for the next Sector pulse, timing the interval between pulses.}
|
|
|
|
WaitSectorEnd: Ybus ¬ R1 and ~KStatus, NZeroBr, c1; {has 2nd sector pulse been found yet?}
|
|
WaitSectorEndC2: R0 ¬ R0+1, CarryBr, BRANCH[SectorEndWait,SectorEndFound], c2; {add one to waiting count and decide if 2nd sector pulse has been found yet}
|
|
|
|
SectorEndWait: BRANCH[WaitSectorEnd, NoSectorEnd], c3; {either keep waiting for second Sector pulse or give up}
|
|
|
|
{At this point the second sector pulse has been found. The count in R0 should be compared with the legal bounds for the SA4000.}
|
|
|
|
SectorEndFound: CANCELBR[Bounds], c3;
|
|
|
|
|
|
NoSectorEnd: R7¬6,GOTO[Exit2], c1;
|
|
|
|
|
|
{Number of Sectors Test}
|
|
{This code counts the number of sectors on a track. It should only be invoked when an SA4000 is connected as only the SA4000 has sector marks. When this test finishes, R0 should hold 1C'X = 28'D.}
|
|
|
|
NumSectorTest: R1 ¬ CFindIndexCmdHi, c1;
|
|
R1 ¬ R1 LRot8, c2;
|
|
R1 ¬ R1 or CFindIndexCmdLo, c3; {finish composing find index mark command}
|
|
|
|
KCtl ¬ R1 LRot0, c1; {next click will start on index pulse (= 1st sector pulse)}
|
|
R0 ¬ 0, ClrKFlags, c2; {clear sector length count and old index flag.}
|
|
R1 ¬ R1 or CFindSectorMkLo, c3; {OR in bits used to make command used to find the sector marks}
|
|
|
|
{The index mark has been found. Change the command to one that wakes the microcode up when a sector mark is found, load the mask used to detect an index mark and enter the main loop.}
|
|
KCtl ¬ R1 LRot0, c1;
|
|
R1 ¬ CIndexFlag, GOTO[WaitEndTrack], c2; {prepare to test for index}
|
|
|
|
{Loop to count sectors. We look for the index flag and increment the count of sectors in each iteration. The loop runs once per sector. On exit, R0 should contain the number of sector marks per track.}
|
|
CountSectors: Ybus ¬ R1 and ~KStatus, NZeroBr, c1; {found end of track yet?}
|
|
R0 ¬ R0+1, BRANCH[WaitEndTrack, FoundEndTrack], c2; {incr sector count and decide about end of track}
|
|
WaitEndTrack: ClrKFlags, GOTO[CountSectors], c3; {wait until next sector}
|
|
|
|
{The end of the track has been found. Turn off the disk task. The number of sectors is in R0}
|
|
FoundEndTrack: LOBSERVED ¬ R0, GOTO[DataCk], c3;
|
|
|
|
|
|
{SA4000 WrapAround Test for Ones}
|
|
{This tests the ability of the controller to send and receive 1's. An SA4000 type disk must be connected in order for this test to work. This test will write on the disk, though the damage should be confined to sector 0 of the track. The diagnostic code should have moved the heads to the proper cylinder before beginning this test. The number of the track to be used should be assembled into the most significant 5 bits of CFindIndexCmdHi above. For example, if track 7 is to be used, CFindIndexCmdHi would be 00111 100 or 3C (Drive Select is the other bit turned on).
|
|
This code finds the index mark then starts writing DATA. It then reads the data being written. This is returned to be compared with the proper values. The index mark is found first so the damage done by testing is confined to sector 0. When this test finishes, R0 should hold DATA.}
|
|
|
|
SA4DataTest: RCTEMP ¬ UEXPECTED, c1;
|
|
R0 ¬ LEXPECTED, c2;
|
|
RCTEMP ¬ RCTEMP LRot8, c3;
|
|
|
|
R1 ¬ CFindIndexCmdHi, c1;
|
|
R1 ¬ R1 LRot8, c2;
|
|
R1 ¬ R1 or CFindIndexCmdLo, c3; {finish composing "find index mark" command}
|
|
|
|
KCtl ¬ R1 LRot0, c1; {next click will start on index pulse (= 1st sector pulse)}
|
|
R0 ¬ R0 or RCTEMP, ClrKFlags, c2; {clear old index flag. Prepare to write FFFF.}
|
|
R1 ¬ R1 and ~0FF, c3; {Save portion of command that is also used to write on the disk.}
|
|
|
|
{The index mark has been found. Complete the write command and start writing DATA.}
|
|
R1 ¬ R1 or CWriteCmdLo, c1; {make a write command}
|
|
KCtl ¬ R1 LRot0, c2; {start the write}
|
|
KOData ¬ R0 LRot0, c3; {start writing DATA}
|
|
|
|
{Wait for another word to go out to make sure everything is stable.}
|
|
Noop, c1;
|
|
Noop, c2;
|
|
KOData ¬ R0 LRot0, c3;
|
|
|
|
{Read the test data back in and stop the operation}
|
|
Noop, c1;
|
|
R0 ¬ KIData, c2;
|
|
LOBSERVED ¬ R0, GOTO[DataCk], c3;
|
|
|
|
|
|
|
|
|
|
{SA1000 WrapAround Test for Ones}
|
|
{This tests the ability of the controller to send and receive 1's. No disk need be connected for this test to function. If an SA1000 disk is connected, sector 0 of some track will be destroyed. As with the SA4000 tests, the controlling diagnostic microcode should have moved the heads to the proper cylinder before beginning this test. It is assumed that the least significant two bits of the head address for the SA1000 match those if the SA4000. For example, if the SA4000 uses track 7 for testing, the SA1000 will use track 3 (the more significant head select lines will be ignored).
|
|
Since this test may be run without a disk, it cannot try to find the index mark. It starts by composing the proper address mark then writes a synchronization gap followed by that address mark and a couple if zeros. It then stops the operation and reads the Status word into R0. If the test is successful, there will be a 1 in bit 9. (R0=40'X)}
|
|
SA1OneTest: R0 ¬ CAddrMkHi, c1; {create the address mark}
|
|
R0 ¬ R0 LRot8, c2;
|
|
R0 ¬ R0 or CLabDatAddrMkLo, c3;
|
|
|
|
{Now wait for the phase locked loop to lock on. If Disk is connected, PLL locks on to disk data. If no disk is connected, SeekComplete is always inactive so the PLL sees the calibrated clock. DriveSelect was turned on by the emulator task as part of the DiskStartCmd.}
|
|
SA1DataTest: R1¬ R1 and 10, c1;
|
|
R1¬ R1 , ZeroBr, c2;
|
|
R1 ¬ 0,BRANCH[Recal, PLLWaitLp], c3; {wait 64k rounds (~128 ms)}
|
|
|
|
Recal: R1¬2, c1; {compose disk start command}
|
|
R1¬R1 LRot8, c2; {align upper command byte}
|
|
R1¬R1 or R4, c3; {finish disk starting command}
|
|
|
|
ClrKFlags, c1;
|
|
KCtl ¬ R1 LRot0, c2;
|
|
R0¬11, c3;
|
|
|
|
RunIn: R0 ¬ R0-1, ZeroBr, c1;
|
|
BRANCH[RunIn1, SWait], c2;
|
|
RunIn1: KCtl ¬ R5 LRot0, c3;
|
|
R1¬40, c1;
|
|
RCTEMP¬ 1D, c2;
|
|
KCtl ¬ R4 LRot0,GOTO[RunIn], c3;
|
|
|
|
SWait: R1 ¬ R1-1, ZeroBr, c3;
|
|
UEXPECTED¬ RCTEMP,BRANCH[SWait1,SComp], c1;
|
|
SWait1: GOTO[SWait], c2;
|
|
|
|
SComp: Ybus ¬ R3 and ~KStatus, NZeroBr, c2;
|
|
BRANCH[SComp1,CKTRE ], c3;
|
|
SComp1: GOTO[SComp], c1;
|
|
CKTRE: R1 ¬ 2,GOTO[CKTR2], c1;
|
|
|
|
CKTR: R1 ¬ 2, c1;
|
|
CKTR2: R1 ¬ R1 LRot8, c2;
|
|
ClrKFlags, c3;
|
|
Ybus ¬ R1 and ~KStatus, NZeroBr, c1;
|
|
BRANCH[CKTR1,SeekCyc], c2;
|
|
CKTR1: ClrKFlags,GOTO[StepOut], c3;
|
|
|
|
|
|
StepOut: ClrKFlags, c1; {compose disk start command}
|
|
KCtl ¬ R2 LRot0, c2; {align upper command byte}
|
|
R0¬ 2, c3; {finish disk starting command}
|
|
|
|
StepOutX:R0 ¬ R0-1, ZeroBr, c1;
|
|
BRANCH[StepOut1,SPWait], c2;
|
|
StepOut1:KCtl ¬ R6 LRot0, c3;
|
|
R1¬40, c1;
|
|
Noop, c2;
|
|
KCtl ¬ R2 LRot0,GOTO[StepOutX], c3;
|
|
|
|
SPWait: R1 ¬ R1-1, ZeroBr, c3;
|
|
BRANCH[SPWait1,SPComp], c1;
|
|
SPWait1: GOTO[SPWait], c2;
|
|
|
|
SPComp: Ybus ¬ R3 and ~KStatus, NZeroBr, c2;
|
|
BRANCH[SPComp1, CKTR], c3;
|
|
SPComp1: GOTO[SPComp], c1;
|
|
|
|
|
|
SeekCyc:R0¬UHIGHLIMIT, c3; {compose disk start command}
|
|
R1 ¬ LHIGHLIMIT, c1; {align upper command byte}
|
|
R0¬ R0 LRot8 , c2; {finish disk starting command}
|
|
|
|
R0¬ R0 + R1, c3; {compose disk start command}
|
|
KCtl ¬ R4 LRot0, c1; {align upper command byte}
|
|
R0¬ R0+1, c2; {finish disk starting command}
|
|
|
|
|
|
SeekIn: R0 ¬ R0-1, ZeroBr, c3;
|
|
BRANCH[SeekIn1, SSWait], c1;
|
|
SeekIn1: KCtl ¬ R5 LRot0, c2;
|
|
R1¬40, c3;
|
|
Noop, c1;
|
|
KCtl ¬ R4 LRot0,GOTO[SeekIn], c2;
|
|
|
|
SSWait: R1 ¬ R1-1, ZeroBr, c2;
|
|
BRANCH[SSWait1,SSComp], c3;
|
|
SSWait1: GOTO[SSWait], c1;
|
|
|
|
SSComp: Ybus ¬ R3 and ~KStatus, NZeroBr, c1;
|
|
R1 ¬ TEST, BRANCH[SSComp1,SATest], c2;
|
|
SSComp1: GOTO[SSComp], c3;
|
|
|
|
SATest: Noop, c3;
|
|
R1¬ R1 xor 16, c1;
|
|
R1¬ R1 , ZeroBr, c2;
|
|
KCtl ¬ RD LRot0,BRANCH[WaitOnIndex,AWaitOnIndex], c3;
|
|
|
|
|
|
|
|
|
|
WaitOnIndex: R1 ¬ CIndexFlag, c1;
|
|
ClrKFlags, c2;
|
|
WaitOnIndex1: KCtl ¬ RD LRot0, c3; {Prepare to sense index flag}
|
|
|
|
Ybus ¬ R1 and ~KStatus, ZeroBr, c1;
|
|
R0¬ 6,BRANCH[FieldS,WaitOnIndex1], c2;
|
|
|
|
|
|
|
|
FieldS: R0 ¬ R0-1, ZeroBr, c3;
|
|
BRANCH[FieldS1, FieldS2], c1;
|
|
FieldS1: GOTO[FieldS], c2;
|
|
|
|
|
|
FieldS2: KCtl ¬ RE LRot0, c2;
|
|
R0¬ 31, c3;
|
|
|
|
FieldSkip: R0 ¬ R0-1, ZeroBr, c1;
|
|
R1¬ KIData,BRANCH[FieldSkip1, ReadField], c2;
|
|
FieldSkip1:KCtl ¬ R2 LRot0, c3;
|
|
|
|
|
|
ClrKFlags, c1;
|
|
KCtl ¬ RE LRot0, c2;
|
|
GOTO[FieldSkip], c3;
|
|
|
|
ReadField: Noop , c3;
|
|
|
|
ReadField1: Noop, c1;
|
|
R3¬ KIData, c2;
|
|
Noop, c3;
|
|
|
|
Noop, c1;
|
|
R4¬ KIData, c2;
|
|
GOTO[ReadDone], c3;
|
|
|
|
|
|
|
|
|
|
AWaitOnIndex: R1 ¬ CIndexFlag, c1;
|
|
ClrKFlags, c2;
|
|
AWaitOnIndex1: KCtl ¬ RD LRot0, c3; {Prepare to sense index flag}
|
|
|
|
Ybus ¬ R1 and ~KStatus, ZeroBr, c1;
|
|
R0¬ 6,BRANCH[BWaitOnIndex,AWaitOnIndex1], c2;
|
|
|
|
BWaitOnIndex: ClrKFlags , c3;
|
|
R1 ¬ CIndexFlag, c1;
|
|
ClrKFlags, c2;
|
|
BWaitOnIndex1: KCtl ¬ RD LRot0, c3; {Prepare to sense index flag}
|
|
|
|
Ybus ¬ R1 and ~KStatus, ZeroBr, c1;
|
|
R0¬ 6,BRANCH[AWaitOnSector,BWaitOnIndex1], c2;
|
|
|
|
|
|
AWaitOnSector: R1 ¬ CSectorFlag, c3;
|
|
|
|
AWaitOnSector1: Noop, c1; {Prepare to sense sector flag}
|
|
|
|
Ybus ¬ R1 and ~KStatus, ZeroBr, c2;
|
|
R0¬ 5,BRANCH[AFieldS,AWaitOnSector1], c3;
|
|
|
|
|
|
AFieldS: R0 ¬ R0-1, ZeroBr, c1;
|
|
BRANCH[AFieldS1,AReadField], c2;
|
|
AFieldS1: GOTO[AFieldS], c3;
|
|
|
|
|
|
AReadField: KCtl ¬ RE LRot0, c3;
|
|
|
|
Noop, c1;
|
|
R1¬ KIData, c2;
|
|
|
|
|
|
GOTO[ReadField1] , c3;
|
|
|
|
|
|
|
|
ReadDone: R5¬1D ,c1;
|
|
KCtl ¬ R2 LRot0, c2;
|
|
R5¬ R5 LRot8, c3;
|
|
|
|
RCTEMP ¬ ~KStatus, c1;
|
|
R5¬ R5 or 0FE, c2;
|
|
R5 ¬ R5 and RCTEMP, c3;
|
|
|
|
|
|
RCTEMP¬UINITIAL ,c1;
|
|
R6¬ LINITIAL, c2;
|
|
RCTEMP¬ RCTEMP LRot8, c3;
|
|
|
|
RCTEMP¬ RCTEMP or R6 , c1;
|
|
[]¬RCTEMP xor R1,ZeroBr, c2;
|
|
R6¬ LHIGHLIMIT,BRANCH[SyncError,CheckHeader], c3;
|
|
SyncError: R7¬ 24, GOTO[SaveError], c1;
|
|
|
|
CheckHeader: RCTEMP¬UHIGHLIMIT ,c1;
|
|
R1¬ R3, c2;
|
|
RCTEMP¬ RCTEMP LRot8, c3;
|
|
|
|
RCTEMP¬ RCTEMP or R6 , c1;
|
|
[]¬RCTEMP xor R1,ZeroBr, c2;
|
|
R6¬ LLOWLIMIT,BRANCH[HeaderError,CheckHeader1], c3;
|
|
HeaderError: R7¬ 25, GOTO[SaveError], c1;
|
|
|
|
CheckHeader1: RCTEMP¬ULOWLIMIT ,c1;
|
|
R1¬ R4, c2;
|
|
RCTEMP¬ RCTEMP LRot8, c3;
|
|
|
|
RCTEMP¬ RCTEMP or R6 , c1;
|
|
[]¬RCTEMP xor R1,ZeroBr, c2;
|
|
R6¬ LEXPECTED,BRANCH[HeaderError1,CheckStatus], c3;
|
|
HeaderError1: R7¬ 26, GOTO[SaveError], c1;
|
|
|
|
CheckStatus: RCTEMP¬UEXPECTED ,c1;
|
|
R1¬ R5, c2;
|
|
RCTEMP¬ RCTEMP LRot8, c3;
|
|
|
|
RCTEMP¬ RCTEMP or R6 , c1;
|
|
[]¬RCTEMP xor R1,ZeroBr, c2;
|
|
|
|
R0 ¬ TEST,BRANCH[StatusError,SATest1], c3;
|
|
StatusError: R7¬ 27, GOTO[SaveError], c1;
|
|
|
|
|
|
SATest1: R0¬ R0 xor 16, c1;
|
|
R0¬ R0 , ZeroBr, c2;
|
|
BRANCH[VWaitOnIndex,AVWaitOnIndex], c3;
|
|
|
|
VWaitOnIndex: R1 ¬ CIndexFlag, c1;
|
|
ClrKFlags, c2;
|
|
VWaitOnIndex1: KCtl ¬ RD LRot0, c3; {Prepare to sense index flag}
|
|
|
|
Ybus ¬ R1 and ~KStatus, ZeroBr, c1;
|
|
R0¬ 6,BRANCH[VFieldS,VWaitOnIndex1], c2;
|
|
|
|
|
|
|
|
VFieldS: R0 ¬ R0-1, ZeroBr, c3;
|
|
R1¬31,BRANCH[VFieldS1, VFieldS2], c1;
|
|
VFieldS1: GOTO[VFieldS], c2;
|
|
|
|
|
|
VFieldS2: KCtl ¬ R9 LRot0, c2;
|
|
KOData ¬ R3 LRot0, c3;
|
|
|
|
VFieldSkip: R1 ¬ R1-1, ZeroBr, c1;
|
|
BRANCH[VFieldSkip1, VReadField], c2;
|
|
VFieldSkip1:KCtl ¬ R2 LRot0, c3;
|
|
|
|
|
|
ClrKFlags, c1;
|
|
KCtl ¬ R9 LRot0, c2;
|
|
KOData ¬ R3 LRot0,GOTO[VFieldSkip], c3;
|
|
|
|
VReadField: KOData¬ R4 LRot0,c3;
|
|
|
|
VReadField1: Noop, c1;
|
|
Noop, c2;
|
|
KCtl ¬ R9 LRot0, c3;
|
|
|
|
|
|
Noop, c1;
|
|
Noop, c2;
|
|
KCtl ¬ R9 LRot0,GOTO[VReadDone], c3;
|
|
|
|
|
|
AVWaitOnIndex: R1 ¬ CIndexFlag, c1;
|
|
ClrKFlags, c2;
|
|
AVWaitOnIndex1: KCtl ¬ RD LRot0, c3; {Prepare to sense index flag}
|
|
|
|
Ybus ¬ R1 and ~KStatus, ZeroBr, c1;
|
|
R0¬ 6,BRANCH[AVWaitOnSector,AVWaitOnIndex1], c2;
|
|
|
|
AVWaitOnSector: R1 ¬ CSectorFlag, c3;
|
|
|
|
AVWaitOnSector1: Noop, c1; {Prepare to sense index flag}
|
|
|
|
Ybus ¬ R1 and ~KStatus, ZeroBr, c2;
|
|
R0¬ 5,BRANCH[AVFieldS,AVWaitOnSector1], c3;
|
|
|
|
|
|
AVFieldS: R0 ¬ R0-1, ZeroBr, c1;
|
|
BRANCH[AVFieldS1,AVReadField], c2;
|
|
AVFieldS1: GOTO[AVFieldS], c3;
|
|
|
|
|
|
AVReadField: Noop, c3;
|
|
|
|
KCtl ¬ R9 LRot0, c1;
|
|
Noop, c2;
|
|
KOData ¬ R3 LRot0, c3;
|
|
|
|
Noop, c1;
|
|
Noop, c2;
|
|
KOData¬ R4 LRot0,GOTO[VReadField1],c3;
|
|
|
|
|
|
|
|
|
|
|
|
VReadDone: R1¬01D ,c1;
|
|
R1¬ R1 LRot8, c2;
|
|
KCtl ¬ R2 LRot0, c3;
|
|
|
|
RCTEMP ¬ ~KStatus, c1;
|
|
R1¬ R1 or 0FF, c2;
|
|
R1 ¬ R1 and RCTEMP, c3;
|
|
|
|
|
|
|
|
|
|
|
|
VCheckStatus: RCTEMP¬UEXPECTED ,c1;
|
|
R6¬ LEXPECTED, c2;
|
|
RCTEMP¬ RCTEMP LRot8, c3;
|
|
|
|
RCTEMP¬ RCTEMP or R6 , c1;
|
|
[]¬RCTEMP xor R1,ZeroBr, c2;
|
|
BRANCH[VStatusError,HeaderGood], c3;
|
|
VStatusError: R7¬ 28, GOTO[SaveError], c1;
|
|
HeaderGood: R7¬ 0,GOTO[Exit2], c1;
|
|
|
|
|
|
|
|
SaveError:LOBSERVED ¬ R1, c2;
|
|
R1¬ R1 LRot8, c3;
|
|
UOBSERVED ¬ R1, c1;
|
|
|
|
|
|
LEXPECTED ¬ RCTEMP, c2;
|
|
RCTEMP¬ RCTEMP LRot8, c3;
|
|
UEXPECTED ¬ RCTEMP, GOTO[Exit2],c1;
|
|
|
|
|
|
|
|
|
|
PLLWaitLp: Noop, c1;
|
|
PLLWaitLp1: R1 ¬ R1-1, ZeroBr, c2;
|
|
BRANCH[PLLWaitLp2, PLLLockedOn], c3; {quit if PLL locked on now}
|
|
PLLWaitLp2:GOTO[PLLWaitLp1], c1;
|
|
|
|
|
|
PLLLockedOn: R1 ¬ CFindIndexCmdHi, c1;
|
|
R1 ¬ R1 LRot8, c2;
|
|
R1 ¬ R1 or CWriteCmdLo, c3; {finish composing "write" command}
|
|
|
|
{The index mark is ignored. Start writing sync pattern.}
|
|
ClrKFlags, c1; {get rid of old Label/Data tag.}
|
|
Noop, c2;
|
|
KCtl ¬ R1 LRot0, c3; {start the write}
|
|
|
|
{Load length of sync pattern-1 and enter sync pattern loop}
|
|
R1 ¬ 6, GOTO[WriteSyncC2], c1;
|
|
|
|
{Loop to write sync pattern}
|
|
WriteSync: Noop, c1;
|
|
WriteSyncC2: R1 ¬ R1-1, ZeroBr, c2;
|
|
KOData ¬ 0, BRANCH[WriteSync, WriteAddrMk], c3;
|
|
|
|
{The end of sync pattern has been reached so the board's Phase locked loop should be locked on to the wrap-around data. Write the address mark, wait for it to be received and return the status word.}
|
|
WriteAddrMk: Noop, c1;
|
|
R1 ¬ 2, c2; {load number of word times to wait for addr mk to be re-received.}
|
|
KOData ¬ R0 LRot0, c3; {write the address mark}
|
|
|
|
{Wait for Addr mark to go out and return.}
|
|
AddrMkWait: Noop, c1;
|
|
R1 ¬ R1-1, ZeroBr, c2;
|
|
KOData ¬ 0, BRANCH[AddrMkWait, AddrMkDone], c3; {write data and decide if done yet}
|
|
|
|
{It should be back by now so stop and inspect it.}
|
|
AddrMkDone: Noop, c1;
|
|
R1 ¬ CFirmwareEnable, c2;
|
|
KCtl ¬ R1 LRot0, c3; {stop the writing}
|
|
|
|
R0 ¬ 40, c1; {load Label/Data tag mask}
|
|
R0 ¬ R0 and ~KStatus, c2; {R0 gets label/data tag}
|
|
LOBSERVED ¬ R0, GOTO[DataCk], c3;
|
|
|
|
|
|
{SA1000 WrapAround Test for Zeros}
|
|
{This tests the ability of the controller to send and receive 0's. No disk need be connected for this test to function. If an SA1000 disk is connected, sector 0 of some track will be destroyed. As with the SA4000 tests, the controlling diagnostic microcode should have moved the heads to the proper cylinder before beginning this test. It is assumed that the least significant two bits of the head address for the SA1000 match those if the SA4000. For example, if the SA4000 uses track 7 for testing, the SA1000 will use track 3 (the more significant head select lines will be ignored).
|
|
This test finds the index mark, writes a synchronization gap and an address mark containing no Label/Data tag. It then stops the operation and reads the Status word into R0. If the test is successful, R0 will hold 0000.}
|
|
SA1ZeroTest: R0 ¬ CAddrMkHi, c1; {create the address mark}
|
|
R0 ¬ R0 LRot8, c2;
|
|
R0 ¬ R0 or CHeaderAddrMkLo, GOTO[SA1DataTest], c3; {use previous code to do this test.}
|
|
|
|
DataCk: RCTEMP¬ R0 LRot8 c1;
|
|
UOBSERVED¬ RCTEMP, c2;
|
|
RCTEMP¬ UEXPECTED, c3;
|
|
R5¬ LEXPECTED, c1;
|
|
RCTEMP¬ RCTEMP LRot8, c2;
|
|
RCTEMP¬ RCTEMP or R5, c3;
|
|
Noop, c1;
|
|
RCTEMP¬RCTEMP xor R0,ZeroBr, c2;
|
|
BRANCH[DataCk1, DataCk2], c3;
|
|
DataCk1: R7¬ 7, GOTO[Exit2], c1;
|
|
DataCk2: R7¬ 0,GOTO[Exit2], c1;
|
|
|
|
|
|
|
|
Bounds: LOBSERVED ¬ R0 c1;
|
|
R3¬ R0 LRot8, c2;
|
|
UOBSERVED ¬ R3 c3;
|
|
R3¬ UHIGHLIMIT, c1;
|
|
R5¬ LHIGHLIMIT, c2;
|
|
R3¬ R3 LRot8, c3;
|
|
R3¬ R3 or R5, c1;
|
|
R4¬ ULOWLIMIT, c2;
|
|
R5¬ LLOWLIMIT, c3;
|
|
R4¬ R4 LRot8, c1;
|
|
R4¬ R4 or R5, c2;
|
|
[] ¬ R3 - R0,NegBr, c3;
|
|
BRANCH[Bounds1, Bounds2], c1;
|
|
Bounds2: R7¬ 4, GOTO[Exit23], c2;
|
|
Bounds1: [] ¬ R0 - R4,NegBr, c2;
|
|
BRANCH[Bounds3, Bounds4], c3;
|
|
Bounds4: R7¬ 5, GOTO[Exit2], c1;
|
|
Bounds3: R7¬ 0,GOTO[Exit2], c1;
|
|
|
|
|
|
Exit23: FAULTTYPE ¬ R7 c3;
|
|
Exit21: FAULTTYPE ¬ R7 c1;
|
|
Exit2: FAULTTYPE ¬ R7 c2;
|
|
KCtl ¬ 0, GOTO[TestDisp], c3;
|
|
|
|
Exit4: FAULTTYPE ¬ R7 ,c3;
|
|
Exit41: FAULTTYPE ¬ R7, c1;
|
|
Exit42: FAULTTYPE ¬ R7, c2;
|
|
Noop, c3;
|
|
KCmd ¬ 0, c1;
|
|
KCtl ¬ 0, c2;
|
|
GOTO[TestDisp], c3;
|
|
|
|
TEST2: R0 ¬ 0C1 , c1;
|
|
KCmd ¬0 LRot0 ,c2;
|
|
KCtl ¬ R0 LRot0 ,c3;
|
|
|
|
TEST2L: R7 ¬ R7 - 1, KStrobe ,c1;
|
|
R7 ¬ R7 , ZeroBr ,c2;
|
|
R5 ¬ 0FF ,BRANCH[TEST2L, TEST2End] ,c3;
|
|
|
|
TEST2End: [] ¬ R7 xor R5 , ZeroBr ,c1;
|
|
BRANCH[TEST2ERR, TEST2End1], ,c2;
|
|
|
|
TEST2End1: GOTO[TestDisp], ,c3;
|
|
|
|
TEST2ERR: R7 ¬ 9, GOTO[Exit41], ,c3;
|
|
|
|
|
|
|
|
TEST3: R4¬2 ,c1;
|
|
R5 ¬ 8 ,c2;
|
|
R5 ¬ R5 LRot8 ,c3;
|
|
TEST3L: R6 ¬ 28 ,c1;
|
|
R6 ¬ R6 LRot8, ClrKFlags ,c2;
|
|
R6 ¬ R6 or 80 ,c3;
|
|
{Load KOData register with "AAAA" pattern twice to ensure that the 8-bit shift register is preloaded with proper data and that we start with register A.}
|
|
KOData ¬ RE LRot0 ,c1;
|
|
Noop ,c2;
|
|
KOData ¬ RE LRot0 ,c3;
|
|
{Enable data drivers and load sequencer to Test1 Routine and set DataReq WU. Also set Selectn line.}
|
|
KCmd ¬ R6 LRot0 ,c1;
|
|
R6 ¬ 0C1 or R5 ,c2;
|
|
KCtl ¬ R6 LRot0 ,c3;
|
|
{Write word A.}
|
|
WrWdA: KStrobe ,c1;
|
|
R6 ¬ R5 or 41 ,c2;
|
|
KOData ¬ RE LRot0 ,c3;
|
|
{Write word B.}
|
|
WrWdB: KStrobe ,c1;
|
|
KCtl ¬ R6 LRot0 ,c2;
|
|
KOData ¬ RF LRot0 ,c3;
|
|
{Read and prepare test word A.}
|
|
RdWdA: KStrobe ,c1;
|
|
R0 ¬ KIData ,c2;
|
|
R0 ¬ RE xor R0, ZeroBr ,c3;
|
|
{Testing transfer of word A and reading word B.}
|
|
RdWdB: BRANCH[WdAErr, WdAOK], KStrobe ,c1;
|
|
WdAErr: R7 ¬ 0A, GOTO[Exit4] ,c2;
|
|
WdAOK: R0 ¬ KIData ,c2;
|
|
R0 ¬ RF xor R0, ZeroBr ,c3;
|
|
{Testing transfer of word B.}
|
|
WdBTest: BRANCH[WdBErr, WdBOK], KStrobe ,c1;
|
|
WdBErr: R7 ¬ 0B, GOTO[Exit4] ,c2;
|
|
WdBOK: R4 ¬ R4 - 1, ZeroBr ,c2;
|
|
R1 ¬ 80, BRANCH[InvTEST3, EndTEST3] ,c3;
|
|
{..... and setting FirmwareEn WU and leave the Selectn line on.}
|
|
InvTEST3: R0 ¬ 2 ,c1;
|
|
InvTEST3C2: R0 ¬ R0 - 1, KStrobe, ZeroBr ,c2;
|
|
KCtl ¬ R5 LRot0, BRANCH[TEST3Lp, TEST3EndLp] ,c3;
|
|
{Invert pattern in RE and RF registers for 2nd pass.}
|
|
TEST3Lp: R1 ¬ ~RE xor 0, GOTO[InvTEST3C2] ,c1;
|
|
TEST3EndLp: RE ¬ R1 ,c1;
|
|
R1 ¬ ~RF xor 0 ,c2;
|
|
RF ¬ R1 ,c3;
|
|
{Invert pattern in UScratch for compare in 2nd pass.}
|
|
KOData ¬ RE LRot0 ,c1;
|
|
Noop ,c2;
|
|
KOData ¬ RE LRot0, GOTO[TEST3L] ,c3;
|
|
|
|
{Check for TEST3 completion.}
|
|
EndTEST3: R5 ¬ RShift1 R5 ,c1;
|
|
[] ¬ R5 and R1, NZeroBr ,c2;
|
|
KCtl ¬ 0, BRANCH[TEST3NEXT, StartTEST4] ,c3;
|
|
|
|
TEST3NEXT: R4 ¬ 2 ,c1;
|
|
Noop ,c2;
|
|
GOTO[TEST3L] ,c3;
|
|
|
|
{Prepare to test for VrfError. Set load sequencer constant into TT and test for VrfError constant into R0.}
|
|
|
|
StartTEST4: R4 ¬ 80 ,c1;
|
|
R0 ¬ 8 ,c2;
|
|
R0 ¬ R0 LRot8 ,c3;
|
|
{Test VrfError: for verify miscompare, if OK set ECCError constant into R0.}
|
|
|
|
TEST4NComp: [] ¬ ~KTest and R0, NZeroBr ,c1;
|
|
KCtl ¬ R4 LRot0, BRANCH[NVrfError, NVrfOK] ,c2;
|
|
NVrfError: R7 ¬ 0C, GOTO[Exit41] ,c3;
|
|
NVrfOK: R0 ¬ 4 ,c3;
|
|
|
|
{Test for VrfError FF reset with load sequencer function; if test OK set constant into R0 to test for ECCError.}
|
|
|
|
TEST4Comp: [] ¬ ~KTest and R0, ZeroBr ,c1;
|
|
KCtl ¬ 0, BRANCH[VrfFFError, VrfFFOK] ,c2;
|
|
VrfFFError: R7 ¬ 0D, GOTO[Exit41] ,c3;
|
|
VrfFFOK: R0 ¬ R0 LRot8, GOTO[StartTEST5] ,c3;
|
|
|
|
{Test ECC FF reset; load sequencer into Test2 routine to deliver 2 words of zeros.}
|
|
|
|
StartTEST5: [] ¬ ~KTest and R0, ZeroBr ,c1;
|
|
BRANCH[ECCRstError, ECCRstOK] ,c2;
|
|
ECCRstError: R7 ¬ 0E, GOTO[Exit41] ,c3;
|
|
ECCRstOK: KCtl ¬ 0 ,c3;
|
|
|
|
{Load sequencer into Test2 routine to deliver two zero words.}
|
|
|
|
StartTEST5Zr: ClrKFlags ,c1;
|
|
R6 ¬ 0C9 ,c2;
|
|
KCtl ¬ R6 LRot0 ,c3;
|
|
{Deliver first zero word.}
|
|
KStrobe ,c1;
|
|
Noop ,c2;
|
|
KOData ¬ 0 ,c3;
|
|
{Deliver second zero word.}
|
|
KStrobe ,c1;
|
|
Noop ,c2;
|
|
KOData ¬ 0 ,c3;
|
|
{Reset DataRq line with 3rd KStrobe and switch to FirmwareEn WU.}
|
|
KStrobe ,c1;
|
|
KCtl ¬ 0 ,c2;
|
|
Noop ,c3;
|
|
{Set sequencer into ECCXfer routine.}
|
|
|
|
ECCXferZr: R6 ¬ 0C8 ,c1;
|
|
KCtl ¬ R6 LRot0 ,c2;
|
|
Noop ,c3;
|
|
{Deliver the first zero syndrom word.}
|
|
KStrobe ,c1;
|
|
R4 ¬ KIData ,c2;
|
|
R1 ¬ 13 ,c3;
|
|
{Deliver the second zero syndrom word.}
|
|
KStrobe ,c1;
|
|
R4 ¬ KIData ,c2;
|
|
R1 ¬ (R1 LRot8) or R1 ,c3;
|
|
{Test for ECC zero syndrom.}
|
|
R0 ¬ ~KTest and R0, ZeroBr ,c1;
|
|
R4 ¬ 8, BRANCH[ECCZrError, ECCZrOK] ,c2;
|
|
ECCZrError: R7 ¬ 0F, GOTO[Exit41] ,c3;
|
|
ECCZrOK: R0 ¬ RE ,c3;
|
|
{Reset DataRq line with 3rd KStrobe, reset LdSequencer bit, set sequencer to Idle.}
|
|
KStrobe ,c1;
|
|
KCtl ¬ 0 ,c2;
|
|
ClrKFlags ,c3;
|
|
{Load sequencer again into Test2 routine for ECC logic test.}
|
|
TEST5Lp: R6 ¬ 0C9 ,c1;
|
|
KCtl ¬ R6 LRot0 ,c2;
|
|
Noop ,c3;
|
|
{Write first word}
|
|
KStrobe ,c1;
|
|
Noop ,c2;
|
|
KOData ¬ R0 LRot0 ,c3;
|
|
{Modiy data and then write second word.}
|
|
R0 ¬ R0 + R1, KStrobe ,c1;
|
|
Noop ,c2;
|
|
KOData ¬ R0 LRot0 ,c3;
|
|
{Delay by one click.}
|
|
KStrobe ,c1;
|
|
KCtl ¬ 0 ,c2;
|
|
Noop ,c3;
|
|
{Modify data and then test for end of the loop.}
|
|
R0 ¬ R0 + R1 ,c1;
|
|
R4 ¬ R4 - 1, ZeroBr ,c2;
|
|
KCtl ¬ 0, BRANCH[TEST5Lp, TEST5EndLp] ,c3;
|
|
{Load first test ECCword '37F6' into R5.}
|
|
TEST5EndLp: R5 ¬ 37 ,c1;
|
|
R5 ¬ R5 LRot8 ,c2;
|
|
R5 ¬ R5 or 0F6 ,c3;
|
|
{Load the second test ECC word '4CFD' into L.}
|
|
R4 ¬ 32 ,c1;
|
|
R4 ¬ R4 LRot8 ,c2;
|
|
R4 ¬ R4 or 0BF ,c3;
|
|
{Load sequencer intoECCXfer routine.}
|
|
ECCXferDt: R6 ¬ 0C8 ,c1;
|
|
KCtl ¬ R6 LRot0 ,c2;
|
|
Noop ,c3;
|
|
{Xfer and prepare to test first ECC syndrom.}
|
|
KStrobe ,c1;
|
|
R0 ¬ KIData ,c2;
|
|
R0 ¬ R5 xor R0, ZeroBr ,c3;
|
|
{Testing transfer of syndrom A and reading syndrom B.}
|
|
|
|
SyndATest: BRANCH[ECCSyndAErr, ECCSyndAOK], KStrobe ,c1;
|
|
ECCSyndAErr: R7 ¬ 10, GOTO[Exit4] ,c2;
|
|
ECCSyndAOK: R0 ¬ KIData ,c2;
|
|
R0 ¬ R4 xor R0, ZeroBr ,c3;
|
|
{Testing transfer of syndrom B. If test OK disable disk drivers; R1 register is loaded with FF to write the ECC pattern.}
|
|
SyndBTest: BRANCH[ECCSyndBErr, ECCSyndBOK], KStrobe ,c1;
|
|
ECCSyndBErr: R7 ¬ 11, GOTO[Exit4] ,c2;
|
|
ECCSyndBOK: KCtl ¬0 ,c2;
|
|
R1 ¬0FF, GOTO[ECCRdDiag] ,c3;
|
|
{R5 is loaded with 4540 (to check first ECC word).}
|
|
ECCRdDiag: R5 ¬ 45 ,c1;
|
|
R5 ¬ R5 LRot8 ,c2;
|
|
R5 ¬ R5 or 40 ,c3;
|
|
{R1 is loaded with FAB0 (to check 2nd ECC word).}
|
|
R4 ¬ 0FA ,c1;
|
|
R4 ¬ R4 LRot8 ,c2;
|
|
R4 ¬ R4 or 0A0 ,c3;
|
|
{Reset and then load sequencer intoTest1 routine .}
|
|
ClrKFlags ,c1;
|
|
R6 ¬ 0C1 ,c2;
|
|
KCtl ¬ R6 LRot0 ,c3;
|
|
{Write word A = 0.}
|
|
KStrobe ,c1;
|
|
R6 ¬ 41 ,c2;
|
|
KOData ¬ 0 ,c3;
|
|
{Write word B =FF.}
|
|
KStrobe ,c1;
|
|
KCtl ¬ R6 LRot0 ,c2;
|
|
KOData ¬ R1 LRot0 ,c3;
|
|
{Read word A (=0) into R0 register.}
|
|
KStrobe ,c1;
|
|
R0 ¬ KIData ,c2;
|
|
Noop ,c3;
|
|
{Read word B (=FF) into R0 register.}
|
|
KStrobe ,c1;
|
|
R0 ¬ KIData ,c2;
|
|
Noop ,c3;
|
|
{Reading EECRd1 (=6060) and preparing to test it.}
|
|
ECCRd1: KStrobe ,c1;
|
|
R0 ¬ KIData ,c2;
|
|
R0 ¬ R5 xor R0, ZeroBr ,c3;
|
|
{Testing ECRdC1 and reading ECRdC2 (=FF).}
|
|
ECCRd2: BRANCH[ECC1RdErr, ECCRd1OK], KStrobe ,c1;
|
|
ECC1RdErr: R7 ¬ 12, GOTO[Exit4] ,c2;
|
|
ECCRd1OK: R0 ¬ KIData ,c2;
|
|
R0 ¬ R4 xor R0, ZeroBr ,c3;
|
|
{Testing ECCRd2. If test OK go to test overrun conditions.}
|
|
|
|
TestECCRd2: BRANCH[ECCRd2Err, ECCRd2OK], KStrobe ,c1;
|
|
ECCRd2Err: R7 ¬ 13, GOTO[Exit4] ,c2;
|
|
ECCRd2OK: KCtl ¬ 0 ,c2;
|
|
R6 ¬ 89, GOTO[StartTEST6] ,c3;
|
|
{Load sequencer into Test2 routine with WU: FirmwareEn to check for overrun.}
|
|
StartTEST6: R0 ¬ 2, ClrKFlags ,c1;
|
|
KCtl ¬ R6 LRot0 ,c2;
|
|
R0 ¬ R0 LRot8 ,c3;
|
|
{Issue KStrobe to set the overrun condition. Set a delay constant into R1.}
|
|
KStrobe ,c1;
|
|
KCtl ¬ 0 ,c2;
|
|
R1 ¬ 6 ,c3;
|
|
{Test for overrun FF = 1.}
|
|
R0 ¬ ~KTest and R0, NZeroBr ,c1;
|
|
BRANCH[OvrError, OvrOK] ,c2;
|
|
OvrError: R7 ¬ 14, GOTO[Exit41] ,c3;
|
|
OvrOK: R6 ¬ 0C9 ,c3;
|
|
{Load sequencer into Test2 with WU: DataRq routine to check for underrun.}
|
|
R0 ¬ 2, ClrKFlags ,c1;
|
|
KCtl ¬ R6 LRot0 ,c2;
|
|
R0 ¬ R0 LRot8 ,c3;
|
|
{Delay KStrobe loop to set the underrun condition.}
|
|
DelKStrb: R6 ¬ 8 ,c1;
|
|
R1 ¬ R1 - 1, ZeroBr ,c2;
|
|
BRANCH[DelKStrb, DelKStrbEnd] ,c3;
|
|
{Test for underrun FF = 1. Reset FirmwareEn bit in KCmd, e.g. task 4 goes asleep.}
|
|
DelKStrbEnd: R0 ¬ ~KTest and R0, NZeroBr ,c1;
|
|
BRANCH[UndrError, EndTask4C3] ,c2;
|
|
UndrError: R7 ¬ 15, GOTO[Exit41] ,c3;
|
|
EndTask4C3: R7 ¬ 0, GOTO[Exit41] ,c3;
|
|
|
|
|
|
|
|
{The main purpose of this code is to test portions of the LDC hardware and its communication with the Trident disk drive. Only a few functions are tested by this microcode, e.g. disk selection, counting of sector pulses (30), and all disk WU conditions (SectorFound, IndexFound, Rdy and AnyAttention). Carriage motion is also performed (although not checked) by this microde. The microcode starts in task 0.}
|
|
|
|
{Power-on the drive, set the TermIn bit and TestCtl bits in KCmd registers.}
|
|
|
|
DiskInit: RA ¬ UNITKCTL ,c1;
|
|
KCtl ¬ RA ¬ RA LRot8 ,c2;
|
|
RB ¬ UDELAY ,c3;
|
|
RB ¬ RB LRot8 ,c1;
|
|
DiskInit1: R1 ¬ 14 ,c2;
|
|
KCmd ¬ R1 ¬ R1 LRot8 ,c3;
|
|
{Wait for drive On. RA saves 0F800 and 1 saves 1400 constant.}
|
|
DiskNotOn: [] ¬ ~KStatus and R0, ZeroBr ,c1;
|
|
R6 ¬ 0F,pCall0,BRANCH[DiskNotOn1, StartTEST0D] ,c2;
|
|
DiskNotOn1: ClrKFlags,CALL[DelTestWU] ,c3,at[0,10];
|
|
|
|
DiskOnWait: RB ¬ RB-1,GOTO[DiskInit1] ,c1, at[0,10,RBNotZRet];
|
|
DiskOnErr: R7 ¬ 16, GOTO[Exit32] ,c1, at[0,10,RBZRet];
|
|
|
|
|
|
{TEST0 will test disk 0 selection mechanism. Deselect disk 0.}
|
|
StartTEST0D: KCtl ¬ R6 LRot12 ,c3;
|
|
R0 ¬ R0 LRot12 ,c1;
|
|
{Test for disk 0 deselected. If deselect OK select disk 0.}
|
|
DeselTest: [] ¬ ~ KStatus and R0, ZeroBr ,c2;
|
|
KCtl ¬ RA LRot0, BRANCH[DeselError, DeselOK] ,c3;
|
|
DeselError: R7 ¬ 17, GOTO[Exit32] ,c1;
|
|
DeselOK: Noop ,c1;
|
|
{Delay.}
|
|
Noop ,c2;
|
|
ClrKFlags ,c3;
|
|
{Test for Disk 0 selected.}
|
|
SelTest: [] ¬ ~ KStatus and R0, NZeroBr ,c1;
|
|
BRANCH[SelError, SelOK] ,c2;
|
|
SelError: R7 ¬ 18, GOTO[Exit31] ,c3;
|
|
SelOK: R0 ¬ 8,ClrKFlags ,c3;
|
|
{Test for disk NotRdy. If NotRdy post an Error code (41).}
|
|
[] ¬ ~KStatus and R0, ZeroBr ,c1;
|
|
BRANCH[NotOnLine, OnLine] ,c2;
|
|
NotOnLine: R7 ¬ 19, GOTO[Exit31] ,c3;
|
|
OnLine: ClrKFlags ,c3;
|
|
|
|
StartDISK: Xbus¬TEST, XDisp , c1;
|
|
R9 ¬ 0,DISP4[StartDISP], c2;
|
|
|
|
R7 ¬ 0,GOTO[Exit31], c3, at[0C, 10, StartDISP];
|
|
RB ¬ 1,ClrKFlags,GOTO[StartTEST1D], c3, at[0D, 10, StartDISP];
|
|
RB ¬ 0F,GOTO[StartTEST2D], c3, at[0E, 10, StartDISP];
|
|
RB ¬ 0F,GOTO[StartTEST3D], c3, at[0F, 10, StartDISP];
|
|
|
|
{TEST1 will wait for index paulse start a counter wait for second index paulse.}
|
|
StartTEST1D: R0 ¬ 2 ,c1;
|
|
R4 ¬ 80 ,c2;
|
|
R6 ¬ LShift1 R4 ,c3;
|
|
|
|
R5 ¬ R6 or 80 ,c1;
|
|
StartTEST1D1: [] ¬ ~KTest and R5, ZeroBr, ,c2;
|
|
BRANCH[GotIt, NoGotIt] ,c3;
|
|
|
|
NoGotIt: R3 ¬ 0,ZeroBr,GOTO[SecFnd1] ,c1;
|
|
|
|
|
|
GotIt: R3 ¬ ~KTest ,c1;
|
|
[] ¬ R3 and R6, ZeroBr, ,c2;
|
|
ClrKFlags,BRANCH[IdxFnd, SecFnd] ,c3;
|
|
|
|
IdxFnd: R0 ¬ R0-1, NZeroBr ,c1;
|
|
R3 ¬ 20 ,BRANCH[LFBounds, NotSdIdx] ,c2;
|
|
|
|
|
|
NotSdIdx: R3 ¬ R3 -1, ZeroBr,c3;
|
|
ClrKFlags,BRANCH[SkipDelay, SkipDelay1], ,c1;
|
|
|
|
SkipDelay: RB ¬ 1,GOTO[NotSdIdx] ,c2;
|
|
SkipDelay1: R9 ¬ 0 , c2;
|
|
R3 ¬ 0 ,GOTO[SecFnd] ,c3;
|
|
|
|
|
|
|
|
|
|
IdxFndCnt: RB ¬ RB+1,GOTO[StartTEST1D1] ,c1, at[1,10,RBNotZRet];
|
|
NoIdxError: [] ¬ R0-1, ZeroBr ,c1, at[1,10,RBZRet];
|
|
BRANCH[NoFdIdxFnd, NoSdIdxFnd] ,c2;
|
|
|
|
NoFdIdxFnd: R7 ¬ 2, GOTO[Exit31] ,c3;
|
|
NoSdIdxFnd: R7 ¬ 3, GOTO[Exit31] ,c3;
|
|
|
|
SecFnd: [] ¬ R3 and R4, ZeroBr ,c1;
|
|
SecFnd1: pCall0,R3 ¬ 0,BRANCH[SectorFnd, NoSectorFnd] ,c2;
|
|
|
|
NoSectorFnd: RF¬LDELAY,CALL[DelTestWU] ,c3,at[1,10];
|
|
|
|
SectorFnd: R9 ¬ R9+1,GOTO[SecFnd] ,c3;
|
|
|
|
|
|
|
|
{Start TEST2. Initialize R0 to 0. Set up an about 26 msec delay in R6 register.}
|
|
|
|
{Delay testing for IdxFnd wake-up by about 26 msec. Set WU: IdxFnd.}
|
|
StartTEST2D: RF¬0,ClrKFlags ,c1;
|
|
R5 ¬ 20,pCall0 ,c2;
|
|
KCtl ¬ (R5 or RA) LRot0, CALL[DelTestWU] ,c3,at[2,10];
|
|
|
|
IdxFndDELAY: RF ¬0,GOTO[IdxFndDELAY2] ,c1, at[2,10,RBNotZRet];
|
|
IdxFndDELAY1: RF ¬0,GOTO[IdxFndDELAY2] ,c1, at[2,10,RBZRet];
|
|
|
|
IdxFndDELAY2: RF¬LDELAY,pCall0 ,c2;
|
|
CALL[DelTestWU] ,c3,at[3,10];
|
|
|
|
IdxFndErr: R7 ¬1A,GOTO[Exit32] ,c1, at[3,10,RBNotZRet];
|
|
TestIdxFnd: R5 ¬ 30 ,c1, at[3,10,RBZRet];
|
|
RF¬0FF,pCall0 ,c2;
|
|
KCtl ¬ (R5 or RA) LRot0, CALL[DelTestWU] ,c3,at[4,10];
|
|
|
|
SecFndErr: R7 ¬1B,GOTO[Exit32] ,c1, at[4,10,RBNotZRet];
|
|
FinishTEST2D: R7 ¬0,GOTO[Exit32F] ,c1, at[4,10,RBZRet];
|
|
|
|
|
|
StartTEST3D:Noop ,c1;
|
|
pCall0 ,c2;
|
|
R0 ¬ 10, CALL[BusyTest] ,c3, at[1,10];
|
|
{Set R6 and R4 registers to do the 1st recalibrate. R6 gets the bus value...}
|
|
R2 ¬ 2 ,c2, at[1,10,BusyTestRet];
|
|
R6 ¬ 2 ,c3;
|
|
{... and R4 gets the Tag constant for the subroutine.}
|
|
|
|
1stRecal: R4 ¬ 20 ,c1;
|
|
R4 ¬ R4 LRot8, pCall0 ,c2;
|
|
RB ¬ 0F,CALL[BusSet] ,c3, at[0,10];
|
|
|
|
{Set WU to Rdy (=6); retain Sequence.0-.3 and Select0 bits in KCtl register. Delay until disk busy (call BusyTest).}
|
|
SetWURdy: R6 ¬ 60 ,c1, at[0,10,BusSetRet];
|
|
KCtl ¬ (RA or R6) LRot0, pCall0 ,c2;
|
|
R0 ¬ 10, CALL[BusyTest] ,c3, at[2,10];
|
|
{Delay before testing for WU.}
|
|
|
|
DelTestWURdy: RF ¬ 0FF, pCall0 ,c2, at[2,10,BusyTestRet];
|
|
CALL[DelTestWU] ,c3, at[5,10];
|
|
|
|
{Return from BusyTest subroutine. CALL TestforWU subroutine.}
|
|
{There are two returns from TestForWU subroutine: WURdyOK and WURdyErr. In case of an error R7 is loaded with error code . If OK test for unsafe (DvcCk and SkInc) and if safe start seeking.}
|
|
WURdyErr: R7 ¬ 1C, GOTO[Exit32] ,c1, at[5,10,RBNotZRet];
|
|
WURdyOK: [] ¬ ~KStatus and R2, ZeroBr ,c1, at[5,10,RBZRet];
|
|
R2 ¬ 2, BRANCH[Unsafe, NotUnsafe] ,c2;
|
|
Unsafe: R7 ¬ 1D, GOTO[Exit31] ,c3;
|
|
NotUnsafe: R6 ¬ 0 ,c3;
|
|
{Set up Head Seek for head = 0, and then call BusSet subroutine.}
|
|
R4 ¬ 40 ,c1;
|
|
R4 ¬ R4 LRot8, pCall0 ,c2;
|
|
CALL[BusSet] ,c3, at[1,10];
|
|
{After return go and seek to cylinder "FF". Set the bus value for the subroutine...}
|
|
1stCylSeek: R2 ¬ 2 ,c1, at[1,10,BusSetRet];
|
|
R6 ¬ 0FF ,c2;
|
|
Noop ,c3;
|
|
{ and the Tag value into R4. Call BusSet subroutine.}
|
|
R4 ¬ 80 ,c1;
|
|
R4 ¬ R4 LRot8, pCall0 ,c2;
|
|
RB ¬ 0F,CALL[BusSet] ,c3, at[2,10];
|
|
{After first seek set WU: AnyAtt and then go to subroutine to test for busy. Call BusyTest subroutine.}
|
|
SetWUAnyAtt: R6 ¬ 10 ,c1, at[2,10,BusSetRet];
|
|
KCtl ¬ (R6 or RA) LRot0, pCall0 ,c2;
|
|
R0 ¬ 10, CALL[BusyTest] ,c3, at[3,10];
|
|
{Delay before testing for WU.}
|
|
DelTestWUAtt: pCall0, RF ¬ 0FF ,c2, at[3,10,BusyTestRet];
|
|
CALL[DelTestWU] ,c3, at[6,10];
|
|
|
|
{There are two returns from TestFor WU subroutine. WUAnyAttErr and WUAnyAttOK. In case of an error R2 gets 44 error code. If there is no error check for SeekIncompl and then start the second seek.}
|
|
|
|
WUAttErr: R7 ¬ 1E, GOTO[Exit32] ,c1, at[6,10,RBNotZRet];
|
|
WUAttOK: [] ¬ ~KStatus and R6, ZeroBr ,c1, at[6,10,RBZRet];
|
|
R2 ¬ 2, pCall0, BRANCH[SeekInc, NotSeekInc] ,c2;
|
|
SeekInc: R7 ¬ 1F, GOTO[Exit31] ,c3;
|
|
NotSeekInc: R6 ¬ 5 ,c3;
|
|
{Start a Head Seek with head address = 5, which results in EOC for T80..}
|
|
R4 ¬ 40 ,c1;
|
|
R4 ¬ R4 LRot8, pCall0 ,c2;
|
|
R2 ¬ 2, CALL[BusSet] ,c3, at[3,10];
|
|
{Test for type of the disk (T80/T300). T register gets 8 in c2 for device check reset function in BusSet subroutine.}
|
|
T80Test: Xbus ¬ KStatus, XwdDisp ,c1, at[3,10,BusSetRet];
|
|
R6 ¬ 8, DISP2[T80Disk, 1] ,c2;
|
|
NotT80: R0 ¬ 13, GOTO[DevCheckRst] ,c3, at[3,4,T80Disk];
|
|
T80: R0 ¬ 5 ,c3, at[1,4,T80Disk];
|
|
|
|
{Reset potential device check cauesed by EOC in T80.}
|
|
|
|
DevCheckRst: R4 ¬ 20 ,c1;
|
|
R4 ¬ R4 LRot8, pCall0 ,c2;
|
|
R2 ¬ 2, CALL[BusSet] ,c3, at[4,10];
|
|
{Issue head seeks to the disk starting with head address = 0.}
|
|
SeqHdSeekStart: R6 ¬ 0 ,c1, at[4,10,BusSetRet];
|
|
Noop ,c2;
|
|
Noop ,c3;
|
|
{Issue sequntial head seeks.}
|
|
SeqHdSeek: R4 ¬ 40 ,c1;
|
|
R4 ¬ R4 LRot8, pCall0 ,c2;
|
|
R2 ¬ 2, CALL[BusSet] ,c3, at[5,10];
|
|
{Test for EOC.}
|
|
|
|
EOCTest: Xbus ¬ KStatus, XwdDisp ,c1, at[5,10,BusSetRet];
|
|
DISP2[DiskEOC, 1] ,c2;
|
|
NotEOC: R6 ¬ R6 + 1, GOTO[SeqHdSeek] ,c3, at[3,4,DiskEOC];
|
|
EOC: Noop ,c3, at[1,4,DiskEOC];
|
|
{Test if the EOC condition is generated properly (RF = R6). If EOCValid proceed with Recal & Device check reset.}
|
|
|
|
EOCValidTest: R0 ¬ R6 xor R0, ZeroBr ,c1;
|
|
BRANCH[EOCError, EOCValid] ,c2;
|
|
EOCError: R7 ¬ 20, GOTO[Exit31] ,c3;
|
|
EOCValid: R6 ¬ 8 ,c3;
|
|
{Issue device check reset to reset T80 conditions.}
|
|
2ndDvcCkRst: R4 ¬ 20 ,c1;
|
|
R4 ¬ R4 LRot8, pCall0 ,c2;
|
|
R2 ¬ 2, CALL[BusSet] ,c3, at[6,10];
|
|
{Test for Busy before issueing MaxCylSeek}
|
|
2ndTestForBusy: Noop ,c1, at[6,10,BusSetRet];
|
|
R6 ¬ 3, pCall0 ,c2;
|
|
R0 ¬ 10, CALL[BusyTest] ,c3, at[4,10];
|
|
{Issue cylinder seek to CylAdrMax (=815), which will result in SeekCompl status. Set the Bus value = 32E ...}
|
|
MaxCylSeek: R6 ¬ R6 LRot8 ,c2, at[4,10,BusyTestRet];
|
|
R6 ¬ R6 or 2E ,c3;
|
|
{... and set the Tag value for the subroutine.}
|
|
R4 ¬ 80 ,c1;
|
|
R4 ¬ R4 LRot8, pCall0 ,c2;
|
|
R2 ¬ 2, CALL[BusSet] ,c3, at[7,10];
|
|
{After return from subroutine test for Busy (motion completed).}
|
|
3rdTestForBusy: Noop ,c1, at[7,10,BusSetRet];
|
|
pCall0 ,c2;
|
|
R0 ¬ 10, CALL[BusyTest] ,c3, at[5,10];
|
|
{After motion is completed test for seek incomplete.}
|
|
Noop ,c2, at[5,10,BusyTestRet];
|
|
R6 ¬ 2 ,c3;
|
|
{If seek is completed then R6 gets the bus value (Recal) to issue the 2nd Recal to clear device conditiuons. If seek incomplete post error code into R2 register}
|
|
SeekIncTest: [] ¬ ~KStatus and R6, NZeroBr ,c1;
|
|
BRANCH[SeekCompl, SeekIncompl] ,c2;
|
|
SeekCompl: R6 ¬ 2, GOTO[2ndRecal] ,c3;
|
|
SeekIncompl: R7 ¬ 21, GOTO[Exit31] ,c3;
|
|
{.. and R4 gets the Tag constant for the subroutine.}
|
|
2ndRecal: R4 ¬ 20 ,c1;
|
|
R4 ¬ R4 LRot8, pCall0 ,c2;
|
|
R2 ¬ 2, CALL[BusSet] ,c3, at[8,10];
|
|
{After recalibrate wait for motion completed (drive not busy).}
|
|
4thTestForBusy: Noop ,c1, at[8,10,BusSetRet];
|
|
pCall0 ,c2;
|
|
R0 ¬ 10, CALL[BusyTest] ,c3, at[6,10];
|
|
{After motion is completed test for OK = Not(EOC or Offset or SeekInc or DvcCk).}
|
|
TestForOK: R6 ¬ 63 ,c2, at[6,10,BusyTestRet];
|
|
Noop ,c3;
|
|
{Test for OK. Recalibrate should reset all of the above conditions.}
|
|
[] ¬ ~KStatus and R6, ZeroBr ,c1;
|
|
R2 ¬ 0, BRANCH[NotOK, OK] ,c2;
|
|
NotOK: R7 ¬ 22, GOTO[Exit31] ,c3;
|
|
OK: Noop ,c3;
|
|
R7 ¬ 0, GOTO[Exit32F] ,c1;
|
|
|
|
|
|
|
|
{Subroutines Task 0 }
|
|
{This subroutine delays until the arm motion is not completed.Before entry R0 must be loaded with '10'.}
|
|
|
|
BusyTest: RF ¬ UDELAY ,c1;
|
|
RE ¬ RF LRot8 ,c2;
|
|
BusyTest1: RF ¬ RF - 1, ZeroBr ,c3;
|
|
BusyTest5: BRANCH[BusyTest2, BusyTest4] ,c1;
|
|
BusyTest4: RE ¬ RE - 1, ZeroBr ,c2;
|
|
RF ¬ RF - 1, ZeroBr,BRANCH[BusyTest5, BusyTestERR] ,c3;
|
|
BusyTest2: [] ¬ ~KStatus and R0, ZeroBr ,c2;
|
|
pRet0,BRANCH[BusyTest3, BusyTestEnd] ,c3;
|
|
BusyTest3: CANCELBR[$] ,c1;
|
|
GOTO[BusyTest1] ,c2;
|
|
BusyTestEnd: RET[BusyTestRet] ,c1;
|
|
BusyTestERR:R7 ¬ 23, CANCELBR[Exit32] ,c1;
|
|
|
|
{This subroutine toggles the bus and tag lines. Upon entry R2 must be loaded with 2. T register has the bus value and and R4 has the given tag constant. First set bus bits.}
|
|
BusSet: KCmd ¬ R6 ¬ (R6 or R1) LRot0 ,c1;
|
|
BusSetC2: Ybus ¬ R2, ZeroBr ,c2;
|
|
KCmd ¬ (R6 or R4) LRot0, BRANCH[TagRstDelay, TagReset] ,c3;
|
|
{Reset the tag line in c2 and restore bus value in T in c3.}
|
|
TagRstDelay: R2 ¬ R2 - 1, GOTO[BusSetC2] ,c1;
|
|
TagReset: R2 ¬ 2 ,c1;
|
|
KCmd ¬ (~R4 and R6) LRot0, pRet0 ,c2;
|
|
R6 ¬ ~R1 and R6, RET[BusSetRet] ,c3;
|
|
|
|
{This subroutine delays the WU test so task 4 microcode has time to wake-up.}
|
|
DelTestWU: RF ¬ RF - 1, ZeroBr ,c1;
|
|
BRANCH[DelWULoop, TestRB] ,c2;
|
|
DelWULoop: GOTO[DelTestWU] ,c3;
|
|
TestRB: Noop ,c3;
|
|
[] ¬ RB, ZeroBr ,c1;
|
|
pRet0, BRANCH[RBNOTZERO, RBZERO] ,c2;
|
|
RBNOTZERO: RET[RBNotZRet] ,c3;
|
|
RBZERO: RET[RBZRet] ,c3;
|
|
|
|
LFBounds: LOBSERVED ¬ RB ,c3;
|
|
R3¬ RB LRot8, c1;
|
|
UOBSERVED ¬ R3 c2;
|
|
R3¬ UHIGHLIMIT, c3;
|
|
R5¬ LHIGHLIMIT, c1;
|
|
R3¬ R3 LRot8, c2;
|
|
R3¬ R3 or R5, c3;
|
|
R4¬ ULOWLIMIT, c1;
|
|
R5¬ LLOWLIMIT, c2;
|
|
R4¬ R4 LRot8, c3;
|
|
R4¬ R4 or R5, c1;
|
|
[] ¬ R3 - RB,NegBr, c2;
|
|
BRANCH[LFBounds1, LFBounds2], c3;
|
|
LFBounds2: R7¬ 4, GOTO[Exit32], c1;
|
|
LFBounds1: Noop, c1;
|
|
[] ¬ RB - R4,NegBr, c2;
|
|
BRANCH[LfDataCk, LFBounds4], c3;
|
|
LFBounds4: R7¬ 5, GOTO[Exit32], c1;
|
|
|
|
|
|
LfDataCk: LOBSERVED¬ R9, c1;
|
|
RA¬ R9 LRot8 c2;
|
|
UOBSERVED ¬ RA, c3;
|
|
RA¬ UEXPECTED, c1;
|
|
RB¬ LEXPECTED, c2;
|
|
RA¬ RA LRot8, c3;
|
|
RA¬ RA or RB, c1;
|
|
RA¬RA xor R9,ZeroBr, c2;
|
|
BRANCH[LfDataCk1, LfDataCk2], c3;
|
|
LfDataCk1: R7¬ 7, GOTO[Exit32], c1;
|
|
LfDataCk2: GOTO[Exit32F], c1;
|
|
|
|
{Start Task 4 uDaignostics}
|
|
|
|
{This Task 4 uDiag microcode is first time awaken with IndexFound FF set by index mark. After wake-up change the WU condition to FirmwareEn and reset IdxFnd FF.}
|
|
|
|
CkWakeUp: ClrKFlags ,c1;
|
|
KCtl ¬ RA LRot0 ,c2;
|
|
RB ¬ 0,GOTO[TestDisp] ,c3;
|
|
@
|
|
|
|
|
|
1.1.1.1
|
|
log
|
|
@first add
|
|
@
|
|
text
|
|
@@
|