{File name: Phase0.mc Description: PROM uCode used in starting booting sequence, Dennis Grundler: 2-Sep-84 15:52:16, add copyright notice. Last Edited: Dan Davies, February 17, 1982 10:23 AM: Clarify code, eliminate unmasked branches, fix recal code for Quantum drive (recal over 576 cylinders in, not 512). Last Edited: Amy Fasnacht, January 21, 1982 3:57 PM: Change boot file numbers to 3-word quantity. Last Edited: Amy Fasnacht, January 12, 1982 4:33 PM: Change uBootFileType values. Last Edited: Amy Fasnacht, January 12, 1982 9:08 AM: Change comments to jive with new bootDevice values. Last Edited: Jozef Furst, January 7, 1982 9:54 AM: Change register rE to RAdr in last click. Last Edited: Amy Fasnacht, January 5, 1982 9:54 AM: Change BootDevice values. Last Edited: Amy Fasnacht, January 5, 1982 9:06 AM: Change ordering. Last Edited: Amy Fasnacht, December 21, 1981 4:00 PM: Add Task 4 to check for disk type. Last Edited: Jozef Furst, December 18, 1981 2:56 PM: Trident power reset added. Last Edited: Jozef Furst, December 11, 1981 11:55 AM: Trident2 & 3 added. Last Edited: Jozef Furst, December 3, 1981 3:25 PM: Test for SAX000/Trident added. Last Edited: Jim Frandeen, November 24, 1981 5:14 PM: Change rD to rE for TridentBoot0. Last Edited: Amy Fasnacht, November 24, 1981 9:57 AM: Add bootDevice = 7 code Last Edited: Amy Fasnacht, November 16, 1981 10:15 AM: Delete setting of KCtl register Last Edited: Amy Fasnacht, November 13, 1981 10:59 AM: Reduce code by 13 instructions Last Edited: Amy Fasnacht, November 9, 1981 4:13 PM: Fix allocation error caused by addition of Trident Last Edited: Jozef Furst, November 4, 1981 2:08 PM: Trident boot microcode added Last Edited: Amy Fasnacht, September 14, 1981 12:19 PM: Change clock and retry count to R registers Last Edited: Jim Frandeen, September 10, 1981 1:28 PM: Add Ether booting Last Edited: Ogus, July 10, 1981 12:55 PM Last Edited: Jarvis, March 19, 1981 6:33 PM Author: Jarvis, Created: August 25, 1980, } { Copyright (C) 1980, 1981, 1982 by Xerox Corporation. All rights reserved.} {IOP and CP use real memory locations 0 and 1 for communication during booting. Any boot microcode must first disable the IOP and clear those locations. The CP uses location 0 to indicate which devices for booting are present. Devices are coded one bit per device (0 indicates not initialized) 1 SA4000 2 SA1000 4 Ethernet 8 Trident After initializing location 0, the CP enables the IOP task and waits for the IOP to preload the necessary U registers. After the IOP loads U registers, the IOP task recieves the boot device from the IOP. The CP then enables the boot device and loads the boot file into main storage starting at location 100. If floppy booting is specified, the CP just loops in tče protected area. After the CP loads the boot file, the location 1 gets non-zero to indicate the completion code (boot file loaded or error). If the high byte is non-zero, location 1 is the real address of the boot file. If the čigh byte is zero, the low byte contains an error code. The boot time error codes include 1 device error 2 null germ 3 broken boot chain 4 illegal command sent to IOP 5 processor error trapped through control store location 0 After completing the boot file loading the CP loops infinitely in the protected area.} {DEFINITIONS} Reserve[ProtectStart, ProtectFence], Reserve[0FE0, 0FFF]; {save room for boot kernel} { Phase0Protected (Protected.mc, IOPBoot.mc) resides in 0 - 00FF Phase0 (Phase0.mc, DiskBootDLion.mc, EtherBoot.mc) resides in 0100 - 0FDF The BootKernel resides in 0FE0 - 0FFF Part of the BootKernel that can be overlaid resides in 0FD8 - 0FDF } {Note the DiskBootDlion code for the Shugart disks uses Link registers 4 and 5.} SetTask[0], StartAddress[go]; {The boot kernel resets the CP I/O registers and enables memory refresh} go: IOPCtl ¬ 0, rD ¬ 0, rDrh ¬ 0, CANCELBR[$, 0F], c1; {disable IOP port} dbUStatus ¬ 0, rE ¬ 0, c2; {clear disk status register} rErh ¬ 1, c3; {clear the first 128K of memory, includes the IO page, takes 54 msec} clear0: MAR ¬ [rDrh, rD+0], c1; MDR ¬ rE, rD ¬ rD + 1, ZeroBr, c2; passTraps ¬ rE, BRANCH[clear0, $], c3; {die on faults} MAR ¬ [rErh, rE + 0], GOTO[clear2], c1; clear1: MAR¬ [rErh, rE+0], c1; clear2: MDR¬ rD, rE¬ rE+1, ZeroBr, c2; bootDevice ¬ 0, BRANCH[clear1, Trident/SA], c3; {Test for controller type. NOTE: Any HSIO boards using this code must have the HSIO-e engineering change. If it is not present, the code may mistake a Shugart or Quantum drive for a Trident. This is because the WriteGate bit is the one tested and boards without the fix MAY come up with WriteGate active.} Trident/SA: Xbus ¬ KTest, XDisp, c1; uEtherBootDone ¬ 0, DISP4[diskType, 0E], c2; Trident: rE ¬ 0C, GOTO[enableIOP], c3, at[0F,10,diskType]; SA: GOTO[pollDevices], c3, at[0E,10,diskType]; pollDevices: Xbus ¬ KStatus, XwdDisp, c1; {SA4000 or SA1000?} rC ¬ 20, {set up for disk loop} BRANCH[SA1000, SA4000, 2], c2; SA4000: rE ¬ 5 {SA4000 = Ethernet}, GOTO[enableIOP], c3, at[3, 4, SA4000]; SA1000: rE ¬ 6 {SA1000 = Ethernet}, GOTO[enableIOP], c3, at[2, 4, SA4000]; enableIOP: MAR ¬ [rDrh, rD + 0], c1; {non-zero in zero=> ready} MDR ¬ CPBootDevice ¬ rE, c2; IOPCtl ¬ IOPInMode, c3; { Wait for the IOP to inform the CP what the BootDevice is. U-register bootDevice will become nonzero. bootDevice = 0 (not valid yet), = 1 (SA4XXX), = 2 (SA100X), = 3 (Ethernet), = 4 (Floppy), = 5 (Alt. Ethernet), = 6 (Trident0), = 7 (Trident1), = 8 (Trident2), = 9 (Trident3).} here: rG ¬ 0FF, {so Protected won't timeout right away} c1, at[0, 10, here]; Xbus ¬ bootDevice, XDisp, c2; uTimeout ¬ 0, DISP4[here], c3; {Set up the third word of the 3-word boot file number of the file being requested.} rE ¬ 0, GOTO[EtherBoot], c1, at[3, 10, here]; rE ¬ 1, GOTO[EtherBoot], c1, at[5, 10, here]; EtherBoot: rEtherBootRetries ¬ 0, uEtherBootStatus ¬ 0, c2; uFileNumber2 ¬ rE, c3; NotifyEtherBoot: {Notify EtherTask by sending Attention that it should start or restart} EICtl ¬ 2 {Notify the EtherTask}, CANCELBR[$,1], c1; TestTimeout: Ybus ¬ uTimeout, NZeroBr, CANCELBR[$,1], c2; Ybus ¬ uEtherBootDone, ZeroBr, BRANCH[$, NotifyEtherBoot], c3; Ybus ¬ uEtherBootStatus, NZeroBr, BRANCH[$, TestTimeout], c1; Noop, BRANCH[EtherBootSuccessful, EtherBootFailed], c2; EtherBootSuccessful: dbUStatus ¬ 0, GOTO[FileReady], c3; EtherBootFailed: acR ¬ bootDeviceError, GOTOABS[Maintenance1Loc], c3; floppyBoot: GOTOABS[IdleLoc], c1, at[4, 10, here]; diskBoot4: rE ¬ faultClearCmd, {boot from SA4000}, c1, at[1, 10, here]; KCtl ¬ rE LRot8, c2; KCtl ¬ 0, GOTO[diskBoot1], c3; diskBoot1: Xbus ¬ KStatus, XRefBr, c1, at[2, 10, here]; rE ¬ driveSelectBit, BRANCH[$, recalibrate], c2; {check for drive ready} rE ¬ KCtl ¬ rE LRot8, GOTO[diskBoot1], c3; {disk is ready} recalibrate: rE ¬ driveSelectBit, c3; {step in first} rE ¬ rE LRot8, c1; rE ¬ rE or inBit, c2; KCtl ¬ rE LRot0, c3; {Step bit must be high for at least one microsecond and then low for at least one microsecond. Since a click is 411 ns, stepBit can change only once every third click.} WaitForSeekComplete: rD ¬ ~KStatus, CANCELBR[$, 1], c1, at[0B, 10, WaitForSeekComplete]; rD ¬ rD LRot8, XDisp, c2; {check for seek complete} Ybus ¬ rD and 2, ZeroBr, DISP4[WaitForSeekComplete, 0B], c3; {check for Cylinder 0 flag, loop waiting for SeekComplete.} {Heads are now steady, if now at Cylinder 0, start disk microcode. Otherwise step the heads in or out.} seekComplete: rE ¬ rE or stepBit, BRANCH[at00, $], c1, at[0F, 10, WaitForSeekComplete]; KCtl ¬ rE LRot0, c2; rD ¬ 3, c3; {Wait 3 clicks so Step pulse is active long enough.} stepWait: rE ¬ rE and ~stepBit, CANCELBR[$, 1], c1; rD ¬ rD - 1, ZeroBr, c2; Ybus ¬ rC, ZeroBr, BRANCH[stepWait, $], c3; {See if finished stepping in this direction (rC=0)} KCtl ¬ rE LRot0, BRANCH[$, countedIn], c1; {lower step line and continue only if there is more to go.} rC ¬ rC - 1, c2; GOTO[WaitForSeekComplete], c3; {At this point, we have gone as far as necessary in the current direction. If this is the first time through, we have moved the heads far enough towards the center of the disk that Cylinder 0 must be out from here. If this is the second time through, Cylinder 0 can't be found (we have gone 32 Cylinder inwards and 562 cylinders out) so give up.} countedIn: rD ¬ rE and inBit, c2; {select DirectionIn bit} Ybus ¬ rD, ZeroBr, c3; {did we just finish going in?} rE ¬ rE xor inBit, BRANCH[$, recalLost], c1; {flip direction, quit if we were going out} rC ¬ 0FF + 1, {max is 256 cylinders for SA1000} c2; rC ¬ LShift1 rC or 20, GOTO[WaitForSeekComplete], c3; {make sure we go far enough out for a 512 Cylinder Quantum drive. Use "or" instead of "+" for timing reasons.} recalLost: acR ¬ bootDeviceError, GOTOABS[Maintenance2Loc], c2; {Here recalibration has been successful. We turn on the disk microcode and wait for it to complete.} at00: rD ¬ firmwareEnable, c2; KCtl ¬ rD LRot0, c3; transferWait: rD ¬ ~KStatus, c1, at[0F, 10, transferWait]; Xbus ¬ rD LRot8, XDisp, c2; {test firmware busy} rDrh ¬ 0, BRANCH[FileReady, transferWait, 0E], c3; {This section of the code is for Trident device 0 ,1, 2 and 3.} TridentBoot0: rE ¬ 0F8,GOTO[TridentCont], c1, at[6, 10, here]; TridentBoot1: rE ¬ 0F4, GOTO[TridentCont], c1, at[7, 10, here]; TridentBoot2: rE ¬ 0F2, GOTO[TridentCont], c1, at[8, 10, here]; TridentBoot3: rE ¬ 0F1, c1, at[9, 10, here]; TridentCont: KCtl ¬ rE ¬ rE LRot8, c2; KCmd ¬ bU0C00, c3; {Test for firmware busy. If not busy finish phase0 boot sequence.} TridentWait: rD ¬ ~KTest, c1, at[0F, 10, TridentWait]; [] ¬ rD LRot4, XDisp, c2; bUBitSignAdr ¬ rE, BRANCH[TridentEnd, TridentWait, 0E], c3; TridentEnd: rE¬ dbUStatus, ZeroBr,GOTO[EtherBootCont] c1, at[0E, 10, TridentWait]; FileReady: rE¬ dbUStatus, ZeroBr,GOTO[EtherBootCont] c1, at[0E,10,transferWait]; EtherBootCont: rD ¬ 1, BRANCH[$, setReady], c2; acR ¬ bootDeviceError, GOTOABS[Maintenance1Loc], c3; setReady: acR ¬ 0FF+1, c3; {first location of boot file} MAR ¬ [rDrh, rD + 0], c1; {indicate boot file read} MDR ¬ acR, GOTOABS[IdleLoc], c2; {Determine the disk type and jump to the starting address of either DiskBootDLion or TridentBootDLion accordingly. We must test this here because we cannot have two different starting addresses for Task 4. When we arrive here, CPBootDevice is 5 or 6 for a Shugart disk and 0C for a Trident.} SetTask[4], StartAddress[FindDiskType]; FindDiskType: RAdr ¬ CPBootDevice, CANCELBR[$, 0F], c1; Ybus ¬ RAdr, YDisp, c2; BRANCH[DiskStart, {SAx000} StartBoot, {Trident} 7], c3;