:TITLE[Initial]; %Ed Fiala 12 March 1984: Complete germ request initialization for 10 mb Etherboot; make partition 2 Alto disk boot independent of default Alto booting. Ed Fiala 6 February 1984: Changes for 10 mb Ethernet booting. Ed Fiala 11 January 1984: Comment edits. Add 3 and 10 mb etherboot code for both PilotD0.eb/D0.eg and AlphaMesaPilotD0.eb/AlphaMesaD0.eg with CSL keyboard switches for these. Move most definitions to InitialDefs.mc. Changed Alto etherboot to obtain AltoD0.eb from ethernet. Arrange code to work for Rubicon, Trinity, or Klamath through assembly switches. Change the device initialization so that all calls to device loaders are preceded by zeroing the task assignments here. Ed Fiala 10 January 1983: Package and preserve some syndrome and quadword address bits for PNIP display by MemInit on imperfect storage boards. Parameterize the timer periods used both during and after the storage test on the RefreshPeriod parameter in GlobalDefs. Add control for storage test loop boot ("7" key depressed; BootType = 400b). Ed Fiala 23 April 1982: Slow refresh clock from 2 ms period to 12 ms period for better storage test (emulators use 8 ms period); decode "P" key boot for Pilot; get fault handler changes from Pilot; preserve refresh sequence during exit LoadRAM. Ed Fiala 26 January 1982: Incorporate HGM's edits for additional Initial starting addresses; eliminate pTemp1, LowHalf, HighHalf, QxL, QxH, QretL, QretH, H4Disp, MC2ErDisp, MP code defs, insert of D0MPCodes; further standardize formatting; failure MP codes now the same as those for Pilot or AMesa (offset by InitialMPOffset .eq. 0); change to PNIP; change interpretation of FFault bit 0 for MemInit. HGM, October 3, 1981 9:31 PM Add debugging option. HGM, January 24, 1981 10:22 PM Change for CSL style LF displays. Ed Fiala 18 March 1981: Fix up MapEntry and QuadAddr in memory error reporting; delete RM defs redundant in GlobalDefs; move task 16 code. HGM, October 13, 1980 12:35 PM Add crash on H4PE entries. Jim Frandeen, September 4, 1980 9:36 AM Move defs to Globaldefs Fix H4PE code. Ev Neely Aug 18, 1980 9:27 AM New net numbers Jim Frandeen, March 2, 1980 11:27 AM Delete Includes for Integration Procedure Joiner, February 28, 1980 2:54 PM recognize TOR for ether booting in bold Johnsson, February 4, 1980 5:00 PM Command files for Initial are: SaveInitialSources.cm make an FTP dump file of Initial sources. MicroInitial.cm assemble sources. Rubicon, Trinity, and Klamath assembly switches in InitialDefs.mc must be set appropriately before running this command file. MicroDInitial.cm run MicroD to build Initial.Mb. InitialBootFiles.cm AltoD0.mb, CSLOverlay.mb, and MicOverlay.mb (from [Indigo]Alto>) must be present on your disk. The following files are produced: AltoD0.eb & Initial.eb for 3mb ethernet boot servers InitialAltoD0.eb to install on disk default Alto boot InitialPilotD0.eb to install on disk default Pilot boot. MP codes used by Initial are defined in GlobalDefs.Mc. The entry point below determines how an emulator is loaded and started when the "keyboard boot" feature isn't used. However, if an emulator is running normally, the user of a CSL keyboard Dolphin can depress a selection of keys and then push the boot button. In this case, the UTVFC task stores KB0 in BootTask's (task 1's) T register. Here the boot is redirected if a special value occurs in BootTask's T. 1's in KB0 represent keys up, 0's keys down; bits are: 5, 4, 6, E, 7, D, U, V, 0, K, -, P, /, \, LF, BS. Interpreted values are: 0 177577b Alto partition 2 disk boot. AltoD0 is obtained from the default boot device (i.e., if Initial defaulted the boot to SA4000, AltoD0 must follow Initial.eb in the initial microcode file; if Initial was obtained from a 3 mb boot server, AltoD0 will be obtained from the 3 mb boot server, and if Initial was obtained from a 10 mb boot server (presently senseless), AltoD0 will be obtained from a 10 mb boot server. P 177757b Pilot disk boot. 7 173777b Storage test boot. BS 177776b Alto 3 mb etherboot. BS+P 177756b Pilot 3 mb etherboot. BS+V 177376b AlphaMesa Pilot 3 mb etherboot E 167777b Alto 10 mb etherboot (pretty useless since the Alto emulator has no 10 mb ethernet microcode). E+P 167757b Pilot 10 mb etherboot. E+V 167377b AlphaMesa Pilot 10 mb etherboot D 175777b Alto partition 1 disk boot. D+P 175757b Pilot disk boot. The intended arrangement is for the user to install a .eb file on his disk as "initial microcode" which is the concatenation of Initial and AltoD0.eb. The default starting address of Initial should be either a partion 1 Alto disk boot or a Pilot disk boot. If he boots with no keys down or if he pushes the power on button, the default boot takes place. If BS is depressed, the boot uses the 3 mb boot servers to get Alto, Pilot, or experimental Pilot booting as described above; if "E" is depressed, then 10 mb boot servers are used as described above; and the other keyboard combinations are as indicated. If he depresses "7", MemInit.Mc will repeat its storage test until some failure is detected, after which it will repeatedly display failure information from that pass of the diagnostic. Only the valid keyboard combinations given above are decoded here; if one of these combinations occurs, boot task's T register is reset to 177777b, and Initial is restarted at the modified starting address. If some other key combination is depressed, BootTask's T register is untouched, so other combinations can be decoded downstream by the target emulator. The Alto will interpret BS and "0," respectively, as directives for a 3mb etherboot or partition 2 disk boot, for example. When booting Pilot, both the germ and microcode image must be loaded into storage; then the germ is modified to tell it how to boot; finally, the microcode is loaded and started by a jump to LoadRAM. On 4 January 1984, the block of words which controls the germ is described for the Klamath release in [Idun]11.0>Pilot>*>Boot.mesa, Device.mesa, and DeviceTypes.Mesa. The important modification is as follows: 3 mb 10 mb SA4000 SA800 0 RequestBasicVersion 3456b 3456b 3456b 3456b 1 Action _ inLoad 0 0 - - Action _ physVolumeBoot - - 2 2? 2 Location _ deviceType 7 6 100b 1 3 deviceOrdinal 0 0 0 0 4-15b device specific boot information 16b Switches 0 0 0 0 For 3 mb: 4 Boot file number 5 Net number (0) 6 Host number (0) 15b requestExtensionVersion (7123b for 10.0 and 11.0 D0.eg); mismatch on this causes 933 MP code when booting the germ; will change with Pilot releases. For 10 mb: 4-6 Boot file number (0, 125002b, x) 7-10b Destination net number (0, 0) 11-13b Destination host number (-1, -1, -1 = broadcast destination) 14b Destination socket number (12b) For SA4000: All words irrelevant E3Load takes a microcode boot file index (BFI) in T as an argument. The boot servers automatically add 3000b to this number. The following BFI's are of interest: 3400b Ether boot gets this file (which should be Initial.Eb with the EtherAltoStart entry point; could change the entry point to EtherPilotStart at some point) 3411b AltoD0.eb Alto emulator + Alto Mesa emulator for UTVFC terminal 3413b Alto5700.eb Alto emulator + Alto Mesa emulator for UIB terminal 3431b Alternate AltoD0.eb Alto emulator + Alto Mesa emulator ?? 3421b PilotD0.eb (current Pilot microcode with UTVFC terminal controller and either Dallas or CSL keyboard) 3423b PilotTor.eb (current Pilot microcode with UIB terminal controller) 4010b D0.eg (current Pilot germ) 4011b OthelloD0.pb (current Pilot Othello) 43001b AlphaMesaPilotD0.eb (Pilot microcode being tested with UTVFC terminal and either Dallas or CSL keyboard) 43002b AlphaMesaD0.eg (corresponding germ) 43003b AlphaMesaOthelloD0.pb (corresponding boot file) 3425b CedarD0.eb (current Cedar microcode with UTVFC terminal and either Dallas or CSL keyboard) 45002b Cedar5D0.eg (corresponding germ) 45003b BasicCedarD0.pb (corresponding boot file) 40004b Fiala.eb The various entry points below are used to choose which form of emulator boot should be used in the absence of a keyboard controlled selection. The BootType register remembers the entry point while all devices are zapped, and the storage diagnostic runs. Then another dispatch takes place. On 3mb and 10mb ethernet boots, information required later is setup in the following registers: BFIMicrocode BFI for the microcode file. BFIGerm BFI for the germ, if any; -1 if no germ needed. BFNBootFile BFN for Othello (Pilot boot only). The original value put in BFIMicrocode is modified according to terminal configuration because different microcode images are needed for UIB and UTVFC terminals. Possibilities are: LF monitor, Dallas keyboard, UTVFC (bit clock rate 3) CSL monitor, microswitch keyboard, UTVFC (bit clock rate 5) LF monitor, microswitch keyboard, UTVFC (bit clock rate 11) UIB terminal ??? UTVFC Pilot or Alto microcode adapts to the keyboard and monitor combination, so only one version of microcode is needed for all UTVFC configurations. The code here sets up the IniBaseLo/Hi base register pointing at the place in storage where the boot file should be put and passes the BFI in T to E3Load. The boot server eventually adds E3BFIOffset to the BFI to get a boot file number (BFN). The BFI is offet because Initial's BFI is wired into the Dolphin EPROMs, and it might be necessary to change the BFN someday. % SetTask[0]; SAAltoStart: BootType _ 0C, GoTo[QTask], At[InitBase,0]; *On InitialPage SAPilotStart: BootType _ 1C, GoTo[QTask], At[InitBase,1]; E3AltoStart: BootType _ 2C, GoTo[QTask], At[InitBase,2]; E3PilotStart: BootType _ 3C, GoTo[QTask], At[InitBase,3]; E3AMPStart: BootType _ 4C, GoTo[QTask], At[InitBase,4]; E3AltAltoStart: BootType _ 5C, GoTo[QTask], At[InitBase,5]; E10AltoStart: BootType _ 6C, GoTo[QTask], At[InitBase,6]; E10PilotStart: BootType _ 7C, GoTo[QTask], At[InitBase,7]; E10AMPStart: BootType _ 10C, GoTo[QTask], At[InitBase,10]; E10AltAltoStart: BootType _ 11C, GoTo[QTask], At[InitBase,11]; *Come to HTask instead of QTask to enable H4 parity error checking by both *Initial and the emulator. This code is not used at present. HTask: RTemp _ IP[FFault]C; StkP _ RTemp; Stack _ (Stack) or (20000C); QTask: RTemp _ LoA[BootTaskLoc]; RTemp _ (RTemp) or (HiA[BootTaskLoc,BootTask]), GoTo[Qloop]; SetTask[BootTask]; RTemp _ T, At[BootTaskLoc]; *If an interpreted keyboard combination is found, reset T to -1 = all *keys up; otherwise, T must not change here. LU _ (RTemp) + (20C) + 1; LU _ (RTemp) + (4000C) + 1, Skip[ALU#0]; T _ (RTemp) or not (0C), GoTo[SAPilotStart]; *P RTemp _ (RTemp) + (1C) + 1, GoTo[.+3,ALU#0]; T _ (RTemp) or not (0C); *7 BootType _ 400C; *Indicate "loop storage test" LU _ (RTemp) + (20C), Skip[ALU#0]; T _ (RTemp) or not (0C), GoTo[E3AltoStart]; *BS LU _ (RTemp) + (400C), Skip[ALU#0]; T _ (RTemp) or not (0C), GoTo[E3PilotStart]; *BS+P RTemp _ (RTemp) - (1C) - 1, Skip[ALU#0]; T _ (RTemp) or not (0C), GoTo[E3AMPStart]; *BS+V :UNLESS[Rubicon]; ******************************************** RTemp _ (RTemp) + (10000C) + 1; LU _ (RTemp) + (20C), Skip[ALU#0]; T _ (RTemp) or not (0C), GoTo[E10AltoStart]; *E (useless) LU _ (RTemp) + (400C), Skip[ALU#0]; T _ (RTemp) or not (0C), GoTo[E10PilotStart]; *E+P RTemp _ (RTemp) - (10000C) - 1, Skip[ALU#0]; T _ (RTemp) or not (0C), GoTo[E10AMPStart]; *E+V :ENDIF; ****************************************************** RTemp _ (RTemp) + (2000C) + 1; LU _ (RTemp) + (20C), Skip[ALU#0]; T _ (RTemp) or not (0C), GoTo[SAAltoStart]; *D RTemp _ (RTemp) - (2000C) - 1, Skip[ALU#0]; T _ (RTemp) or not (0C), GoTo[SAPilotStart]; *D+P LU _ (RTemp) + (200C) + 1; LU _ (BootType) xor (1C), GoTo[IniKeyCheckDone,ALU#0]; *0 = partition 2 Alto boot. Compel Alto boot if not already Alto booting. *Leave 177577b in T (i.e., the "0") for Alto emulator to decode at entry. LU _ (BootType) xor (3C), Skip[ALU#0]; *Convert Pilot disk boot to Alto disk boot BootType _ 0C, GoTo[IniKeyCheckDone]; LU _ (BootType) xor (4C), Skip[ALU#0]; *Convert Pilot 3mb boot to Alto 3 mb boot BootType _ 2C, GoTo[IniKeyCheckDone]; *Since the Alto emulator presently has no 10 mb capability, the combination of *a 10 mb Initial and an Alto boot seems senseless, so comment this code out. % LU _ (BootType) xor (7C), Skip[ALU#0]; *Convert AlphaMesa Pilot 3 mb boot to Alto 3 mb boot BootType _ 2C, GoTo[IniKeyCheckDone]; LU _ (BootType) xor (10C), Skip[ALU#0]; *Convert Pilot 10 mb boot to Alto 10 mb boot (senseless) BootType _ 6C, GoTo[IniKeyCheckDone]; Skip[ALU#0]; *Convert AlphaMesa Pilot 10 mb boot to Alto 10 mb boot (senseless) BootType _ 6C, GoTo[IniKeyCheckDone]; % Skip[ALU#0]; *Convert AlphaMesa Pilot 3 mb boot to Alto 3 mb boot BootType _ 2C, GoTo[IniKeyCheckDone]; Nop; IniKeyCheckDone: RTemp _ LoA[Qloc]; *Quiesce tasks 15b - 1 RTemp _ (RTemp) or (HiA[Qloc,15]); RTemp1 _ IP[RTemp1]C; StkP _ RTemp1; RTemp1 _ LoA[QretLoc]; RTemp1 _ (RTemp1) or (HiA[QretLoc]); Qloop: APCTask&APC _ RTemp; *goes to Qx initRET: Return; *Notify here to leave task's TPC pointing at Qxy. *StkP points at RTemp1; RTemp1 contains QretLoc. Qx: APCTask&APC _ Stack, Call[initRET], At[Qloc]; Qxy: GoTo[initRET]; *must spend two instructions in the task SetTask[0]; Qret: LU _ LdF[RTemp,0,3], At[QretLoc]; *RTemp1 points to this location RTemp _ (RTemp) - (10000C), GoTo[Qloop,ALU#0]; %Zap devices. Any device is supposed to be made passive by outputting 0 to register 0 of the device. However, the 3 mb Ethernet controllers must have output of 300b to register 0 to make it passive (and subsequently outputting 0 to the 3 mb ethernet controller doesn't make it active again). So the code below first outputs 300b to each device, then 0. Finally, to be doubly safe, each device is assigned to task 0, so any interrupts will be harmless. Also, assigning to task 0 is a necessary part of the initialization which will later locate the controller and initialize it for booting. % T _ RTemp1 _ 177400C; RTemp _ 300C; ZapDloop1: Output[RTemp]; *send 300 to register 0 of all devices T _ RTemp1 _ (RTemp1) + (20C); GoTo[ZapDloop1,ALU<0]; T _ RTemp1 _ 177400C; RTemp _ 0C; ZapDloop2: Output[RTemp]; *send 0 to register 0 of all devices T _ RTemp1 _ (RTemp1) + (20C); GoTo[ZapDloop2,ALU<0]; ZapD3: RTemp1 _ T _ (RTemp1) or not (0C); *T_-1 means task 0 RTemp _ 60C, Call[SrShift]; *Initialize tasks 17 and 16 RTemp _ HiA[Task17Start,17]; RTemp _ (RTemp) or (LoA[Task17Start]); APCTask&APC _ RTemp, Call[initRET]; %Timers are cleared, refresh is running, start reason in BootType. Writing the mi at microstore location 1 by hand rather than including it in the original load ensures that there will be an intact fault handler except during the few instructions below. % Task0: RTemp _ 50000C; *Write fault instruction At[1] RTemp1 _ 1C; T _ 15C; *15b (T has data 2) RTemp _ (RTemp) or (150C); *50150b LU _ RTemp; APCTask&APC _ RTemp1; WriteCS0&2; RTemp _ 65000C; RTemp _ (RTemp) + 1; *65001b LU _ RTemp; APCTask&APC _ RTemp1; WriteCS1; * T _ StartTests, Call[ShowNumber]; *SALUF Test *MB BC Test *CYCLE Test *PCF Test *PCF[] Test *SB Test *SB[] Test *DB Test *DB[] Test *BBFA Test *BBFB Test *BBFBX Test *MNBR Test *ReadCS,CSDATA Test *GenSRClock Test *ResetWDT Not Tested *CTASK Test *CIA Test *WFA Test *WFB Test *RF Test *RS232 Test *NextInst Test (includes PCX, SStkP) *NIRet Test *NextData Test *IntPending BC Test *Ovf' BC Test *BPCChk BC Test *QuadOvf BC Test *Timeout BC Test *IOAtten BC Test *R Odd BC Test *R<0 BC Test *H2Bit8' BC Test *Cycler/masker Function Tests (Dispatch, LdF, LSh, RSh, RCy, etc.) *LoadTimer Test *AddToTimer Test *LU _ Timer Test *Timer Test *SetFault/fault entry Test *ResetErrors Test *UseCTask Test *UseCOutAsCIn Test T _ StartMapInit, Call[ShowNumber]; GoTo[IMAP]; MemInitDone: %Among the machine features not tested by the EPROM code are the following: PFetch1/2 and PStore1/2 task=0, task#0, with/without DF2 addressing; % *ReadPipe Test *ResetMemErrs Test Dispatch[BootType,14,4]; Disp[SAAlto]; *SA4000loader has two entry points depending on whether you want *Alto boot or Pilot boot. SAAlto: T _ StartDiskBoot, GoTo[SACommon], At[DeviceDispatch,0]; @SAPilot: T _ StartDiskBootPilot, GoTo[SACommon], At[DeviceDispatch,1]; SACommon: Call[ShowNumber]; LoadPage[SalLoaderPage]; BootType, DblGoTo[SA4000Load,SA4000LoadPilot,R Even]; @E3Alto: BFIMicrocode _ LoA[E3AUCodeBFI], At[DeviceDispatch,2]; BFIMicrocode _ (BFIMicrocode) or (HiA[E3AUCodeBFI]), GoTo[E3Tail]; @E3Pilot: BFIMicrocode _ LoA[E3PUCodeBFI], At[DeviceDispatch,3]; *PilotD0.eb BFIMicrocode _ (BFIMicrocode) or (HiA[E3PUCodeBFI]); BFIGerm _ LoA[E3GermBFI]; *D0.eg BFIGerm _ (BFIGerm) or (HiA[E3GermBFI]); BFNBootFile _ LoA[E3OthelloBFN]; *OthelloD0.pb BFNBootFile _ (BFNBootFile) or (HiA[E3OthelloBFN]), GoTo[E3Common]; **Note that the BFN for AlphaMesaOthelloD0.pb conflicts with that for **AlphaMesa UIB microcode, so UIB terminals cannot be tested with the **AlphaMesa krock. @E3AMPilot: BFIMicrocode _ LoA[E3AMPUCodeBFI], At[DeviceDispatch,4]; BFIMicrocode _ (BFIMicrocode) + (HiA[E3AMPUCodeBFI]); BFIGerm _ LoA[E3AMGermBFI]; BFIGerm _ (BFIGerm) or (HiA[E3AMGermBFI]); BFNBootFile _ LoA[E3AMOthelloBFN]; BFNBootFile _ (BFNBootFile) or (HiA[E3AMOthelloBFN]), GoTo[E3Common]; @E3AltAlto: BFIMicrocode _ LoA[E3AltAUCodeBFI], At[DeviceDispatch,5]; BFIMicrocode _ (BFIMicrocode) or (HiA[E3AltAUCodeBFI]), GoTo[E3Tail]; :UNLESS[Rubicon]; ******************************************** @E10Alto: *Alto 10 mb etherboot not presently implemented. * BFIMicrocode _ LoA[E10AUCodeBFN], At[DeviceDispatch,6]; * BFIMicrocode _ (BFIMicrocode) or (HiA[E10AUCodeBFN]), GoTo[E10Tail]; GoTo[.], At[DeviceDispatch,6]; @E10Pilot: BFIMicrocode _ LoA[E10PUCodeBFN], At[DeviceDispatch,7]; *PilotD0.eb BFIMicrocode _ (BFIMicrocode) or (HiA[E10PUCodeBFN]); BFIGerm _ LoA[E10GermBFN]; *D0.eg BFIGerm _ (BFIGerm) or (HiA[E10GermBFN]); BFNBootFile _ LoA[E10OthelloBFN]; *OthelloD0.pb BFNBootFile _ (BFNBootFile) or (HiA[E10OthelloBFN]), GoTo[E10Common]; @E10AMPilot: BFIMicrocode _ LoA[E10AMPUCodeBFN], At[DeviceDispatch,10]; BFIMicrocode _ (BFIMicrocode) + (HiA[E10AMPUCodeBFN]); BFIGerm _ LoA[E10AMGermBFN]; BFIGerm _ (BFIGerm) or (HiA[E10AMGermBFN]); BFNBootFile _ LoA[E10AMOthelloBFN]; BFNBootFile _ (BFNBootFile) or (HiA[E10AMOthelloBFN]), GoTo[E10Common]; @E10AltAlto: *Alto 10 mb etherboot not presently implemented. * BFIMicrocode _ LoA[E10AltAUCodeBFN], At[DeviceDispatch,11]; * BFIMicrocode _ (BFIMicrocode) or (HiA[E10AltAUCodeBFN]), GoTo[E10Tail]; GoTo[.], At[DeviceDispatch,11]; E10Tail: BFIGerm _ (BFIGerm) or not (0C); *-1 = no germ wanted E10Common: UseCTask, Call[FixBFI]; *Unlike the 3 mb ethernet boot servers, the 10 mb boot servers do not *flush the leader page of a .eb file, so that must be done by the code *here. It is done by reading the file into a memory address one page *smaller than the address from which the microcode is loaded. T _ BFIMicrocode, LoadPage[E10Page]; IniBaseLo _ Sub[MicrocodeAddress!,400]C, CallP[E10Load]; LU _ (BFIGerm) + 1, Call[ShowGerm]; *Assign all devices to task 0 again. RTemp1 _ T _ (RTemp1) or not (0C); RTemp _ 60C, Call[SrShift]; *Unlike the 3 mb etherboot servers, the 10 mb boot servers deal with *a .germ file rather than a .eg file, so there is no extra page at the *beginning. The overall file checksum is made 0 by fudging one of the *entries in the germ's SD. T _ BFIGerm, LoadPage[E10Page]; IniBaseLo _ (IniBaseLo) + (LoA[GermAddress]), CallP[E10Load]; ***For Rubicon, more code would be needed here to initialize IniPageCount ***as is done for E3Common below. UseCTask, Call[FixGerm]; PStore1[IniBaseLo,RTemp,ReqActionOffset], Task; *Germ request device type. RTemp _ E10DevType; PStore1[IniBaseLo,RTemp,ReqDevTypeOffset], Call[initRET]; *Germ request boot file number _ E10BFNHi, E10BFNMid, [BFNBootFile] RTemp _ HiA[E10BFNHi]; RTemp _ (RTemp) or (LoA[E10BFNHi]); PStore1[IniBaseLo,RTemp,Add[E10ReqBFN,0]], Call[initRET]; RTemp _ HiA[E10BFNMid]; RTemp _ (RTemp) or (LoA[E10BFNMid]); PStore1[IniBaseLo,RTemp,Add[E10ReqBFN,1]], Call[initRET]; PStore1[IniBaseLo,BFNBootFile,Add[E10ReqBFN,2]], Call[initRET]; *Germ request destination host number _ -1, -1, -1. RTemp _ (RTemp) or not (0C); PStore1[IniBaseLo,RTemp,E10ReqHostNum], Call[initRET]; PStore1[IniBaseLo,RTemp,Add[E10ReqHostNum,1]], Call[initRET]; PStore1[IniBaseLo,RTemp,Add[E10ReqHostNum,2]], Call[initRET]; *Germ request destination net number _ 0, 0. RTemp _ 0C; PStore1[IniBaseLo,RTemp,E10ReqNetNum], Call[initRET]; PStore1[IniBaseLo,RTemp,Add[E10ReqNetNum,1]], Call[initRET]; *Germ request destination socket number _ 12b RTemp _ 12C, Call[initRET]; PStore1[IniBaseLo,RTemp,E10ReqSocketNum], GoTo[MicrocodeLoaded]; :ENDIF; ****************************************************** *Alto emulator 3 mb boot comes here to indicate "no germ wanted". E3Tail: BFIGerm _ (BFIGerm) or not (0C); *-1 = none *Pilot emulator 3 mb ethernet boot comes here. E3Common: UseCTask, Call[FixBFI]; *Although the .eb file contains an extra page at the beginning, the boot *server will flush it, so no correction needs to be made for that here. T _ BFIMicrocode, LoadPage[E3Page]; IniBaseLo _ MicrocodeAddress, CallP[E3Load]; *For an Alto etherboot, there is no germ, and ShowGerm will exit through *MicrocodeLoaded. LU _ (BFIGerm) + 1, Call[ShowGerm]; *Assign all the devices to task 0 again. RTemp1 _ T _ (RTemp1) or not (0C); RTemp _ 60C, Call[SrShift]; %Although the .eg file contains an extra page at the beginning, the boot server will flush it, so no pages need be skipped here. Note that for Rubicon (which Cedar still used on 5 Jan 84), the germ is read into bank 0 (where real storage is known to exist under the virtual pages) but must then be moved to high VM; this is done by exchanging the real pages assigned to the virtual pages. The FixGerm subroutine requires the first address after the germ (which should be location 0 in a page) to be passed in the IniPageCount register; this is used in computing the number of pages in the germ. % T _ BFIGerm, LoadPage[E3Page]; IniBaseLo _ (IniBaseLo) + (LoA[GermAddress]), CallP[E3Load]; :IF[Rubicon]; ************************************************ T _ WordOffset; T _ (IniBaseLo) + T; IniPageCount _ T, UseCTask, Call[FixGerm]; :ELSE; ******************************************************* UseCTask, Call[FixGerm]; :ENDIF; ****************************************************** PStore1[IniBaseLo,RTemp,ReqActionOffset], Task; RTemp _ E3DevType; PStore1[IniBaseLo,RTemp,ReqDevTypeOffset], Call[initRET]; PStore1[IniBaseLo,BFNBootFile,E3ReqBFN], GoTo[MicrocodeLoaded]; IniSaveRet: IReturn _ T, Return; FixBFI: T _ APCTask&APC, Call[IniSaveRet]; T _ 20C; RCnt _ (Zero) - T; *Don't look forever RTemp1 _ T _ 3C; *Use task 14 for test IDLoop: RTemp _ 4C, Call[SrShift]; T _ LShift[14,4]C; Input[RTemp]; T _ 5000C; *UIB ID LU _ (LHMask[RTemp]) xor T; T _ 1000C, Skip[ALU#0]; *UTVFC ID BFIMicrocode _ (BFIMicrocode) + (2C), GoTo[FixBFIRet]; *UIB LU _ (LHMask[RTemp]) xor T; RCnt _ (RCnt) + 1, Skip[ALU=0]; RTemp1 _ T _ 0C, DblGoTo[IDLoop,NoDisplay,ALU<0]; %We have found a UTVFC. The 3 monitor/keyboard combinations that might be connected are distinguished by the "bit clock rate": 3: LF monitor with some form of Star keyboard 5: CSL monitor with microswitch keyboard 11: LF monitor with microswitch keyboard The code here for distinguishing keyboards is no longer used because all emulators accept either keyboard. RTemp _ LdF[RTemp,10,5]; *get bit clock rate LU _ (RTemp) xor (3C); Skip[ALU=0]; BFIMicrocode _ (BFIMicrocode) + 1; *CSL keyboard, either monitor Now reassign devices to task 0 (possibly useless). % FixBFIRet: RTemp1 _ T _ (RTemp1) or not (0C); RTemp _ 60C, Call[SrShift]; %Show 740d + 2 * (low 4 bits of BFI in the MP. The BFI for the UIB microcode is assumed to be 2+BFI for UTVFC microcode. If the etherboot fails, the MP will be incremented by 1. Only one BFI is shown on an Alto boot; for a Pilot boot, one number is shown for the microcode, then another for the germ. % T _ (BFIMicrocode) and (17C); RTemp _ T; RTemp _ LSh[RTemp,1]; T _ (RTemp) + (StartEtherBoot), Call[ShowNumber]; APCTask&APC _ IReturn; IniBaseHi _ 1C, Return; *For an Alto ethernet boot, there is no germ to load here. ShowGerm: IniBaseHi _ T _ 0C, GoTo[MicrocodeLoaded,ALU=0]; IniBaseHi _ (LSh[IniBaseHi,10]) + T + 1; IniBaseLo _ HiA[GermAddress]; T _ (BFIGerm) and (17C); RTemp _ T; RTemp _ LSh[RTemp,1]; *This also shows 740d + 2 * (low 4 bits of BFI of germ file). T _ (RTemp) + (StartEtherBoot), GoTo[ShowNumber]; MicrocodeLoaded: LP _ MicrocodeAddress; MicrocodeLoaded1: LPhi _ 0C; xfTemp _ 0C; *Offset to base register *Preserve refresh sequence during LoadRAM. xfTemp1 _ IP[Refr]C; StkP _ xfTemp1; T _ Stack; xfTemp1 _ T, LoadPageExternal[LRJPage]; RTemp1 _ 0C, GoToExternal[LRJContinue]; *Now do common setup of the germ request for 3 mb, 10 mb, and SA4000 *booting. The germ goes in bank 76b for Rubicon; bank 0, Trinity or later. *If necessary, move the germ from lower storage, where it was read in, to *its running location (which might not have real storage underneath the *virtual pages); then zero the germ request area and initialize non-zero *words. FixGerm: T _ APCTask&APC, Call[IniSaveRet]; RTemp _ 0C; :IF[Rubicon]; ************************************************ %MemInit concentrated good real pages contiguously in the lowest virtual pages; now put real storage underneath the virtual pages into which the germ will be moved (This is a problem for Rubicon only--the germ was relocated into low VM for Trinity and later Pilot releases). Do this by first exchanging the highest map entries with real pages underneath and with those where the germ will be moved. Then exchange map entries where the germ was read from the disk with those at its running location. This winds up with all real pages except those under the germ concentrated under the lowest virtual pages (a requirement?) and with the germ in its running location. The final exchange cannot be avoided by reading the germ directly into its running location because the number of pages in the germ is not known in advance. Trinity and later germs run in bank 0, so they can be read directly into the running location--MemInit does not accept storage configurations with fewer than 64k words. IniPageCount holds the address after the last word in use for the germ; this is word 0 on the next page. Determine the number of germ pages by subtracting GermAddress from this and right-shifting 8. % *IniFrom _ 1st page number in the germ - 1. IniFrom _ LoA[Sub[RShift[GermAddress,10],1]]; IniTo _ HiA[Sub[Add[GermMDSPage!,GermStartOffset!],1]]; IniTo _ (IniTo) + (LoA[Sub[Add[GermMDSPage!,GermStartOffset!],1]]); *PageCount, initialized by MemInit, contains the number of good real pages. T _ PageCount; *page to move from = good page count - GermPages IniExchPage _ T; IniPageCount _ (IniPageCount) - (HiA[GermAddress]); IniPageCount _ T _ RSh[IniPageCount,10]; IniExchPage _ (IniExchPage) - T; *Create a base register pair from the next page number. IniMoveNextPage: IniMap0 _ 60000C; *Vacant *The following XMap instruction replaces the map entry at IniExchPage with *the contents of IniMap0, which will be vacant in the flag bits and zero in *the address bits. It then writes the original contents of the map entry *into IniMap1, 2, and 3. IniXMapFix reformats the bits in IniMap1, 2, and *3 into IniMap0, so that they can be used with the next XMap. T _ IniExchPage, Call[IniXMapFix]; T _ IniFrom _ (IniFrom) + 1, Call[IniXMapFix]; T _ IniTo _ (IniTo) + 1, Call[IniXMapFix]; *Restore old flags IniPageCount _ (IniPageCount) - 1; *Decrement count IniExchPage _ (IniExchPage) + 1, GoTo[IniMoveNextPage,ALU#0]; IniBaseHi _ T _ LoA[RealGermAddressHi]; IniBaseHi _ (LSh[IniBaseHi,10]) + T + 1; IniBaseLo _ HiA[GermSwitchesOffset]; IniBaseLo _ (IniBaseLo) + (LoA[GermSwitchesOffset]); *Zero three words of germ switches PStore1[IniBaseLo,RTemp,0], Call[initRET]; PStore1[IniBaseLo,RTemp,1], Call[initRET]; PStore1[IniBaseLo,RTemp,2], Call[InitRET]; :ELSE; ******************************************************* IniBaseHi _ 1C; *0,,1 :ENDIF; ****************************************************** IniBaseLo _ HiA[GermRequestOffset]; IniBaseLo _ (IniBaseLo) + (LoA[GermRequestOffset]); *Zero the Germ Request RTemp1 _ LoA[RequestSize], Call[.+1]; T _ RTemp1 _ (RTemp1) - 1; PStore1[IniBaseLo,RTemp], Skip[ALU=0]; Return; :UNLESS[Rubicon]; ******************************************** RTemp _ HiA[RequestVersion]; RTemp _ (RTemp) or (LoA[RequestVersion]); PStore1[IniBaseLo,RTemp,ReqVersionOffset]; *Setting up ReqExtVersion is not required but is harmless for SA4000 boot. RTemp _ HiA[ReqExtVersion], Task; RTemp _ (RTemp) or (LoA[ReqExtVersion]); PStore1[IniBaseLo,RTemp,ReqExtVersionOffset], Call[initRET]; :ENDIF; ****************************************************** APCTask&APC _ IReturn; RTemp _ inLoad, Return; :IF[Rubicon]; ************************************************ IniXMapFix: IniBaseLo _ T; IniBaseHi _ T; T _ IniBaseHi _ LHMask[IniBaseHi]; IniBaseHi _ (RSh[IniBaseHi,10]) + T + 1; IniBaseLo _ LSh[IniBaseLo,10]; XMap[IniBaseLo,IniMap0,0]; T _ LSh[IniMap3,10]; *Put flags,,card,,blk0 in left byte *Put blk1,,rowaddr in low byte T _ IniMap1 _ (RHMask[IniMap1]) or T; IniMap0 _ (Zero) or not T, Return; *IniMap0 _ old flags and page :ENDIF; ******************************************************* *Enter with value in both RTemp1 and T, shift count in RTemp. *Value is rotated right after each shift. SrShift: RTemp _ (RTemp) - 1, GenSRClock; T _ RTemp1 _ RCy[RTemp1,1], GoTo[.-1, ALU#0]; Return; NoDisplay: T _ NoUTVFC, GoTo[InitFail]; InitFail: RTemp _ T, Call[SNx]; GoTo[.]; ShowNumber: RTemp _ T; SNx: LoadPage[0]; T _ (RTemp) + (MPOffset), GoToP[PNIP]; SetTask[17]; RTMP _ 400C, At[Task17Start]; *Set Printer idle, don't drive bus Printer _ RTMP; RTMP _ 100000C; *7 mi needed between LoadTimer/AddToTimer operations ClearTimers: LoadTimer[RTMP]; *Clear out all Timers ResetMemErrs; *Clear any pending memory errors RTMP _ (RTMP) + 1; %For the refresh timer, the emulators use a 2560 cycle timer (8 ms refresh period at 100 ns/cycle). Ideally, MemInit should be run with a slower refresh period to catch storage RAMs that are failing for this reason. However, the period should be changed to the standard value after running the storage diagnostic to avoid subsequent failures. Interesting values of the refresh timer are as follows (for slot 17b, value 10d simple timer): 50257 640 cycles 2 ms 50517 1280 cycles 4 ms 51217 2560 cycles 8 ms *emulator value 52417 5120 cycles 16 ms 51717 3840 cycles 12 ms *used during storage test % Set[TestRefConstant,Add[50017, LShift[RShift[RefreshPeriod,6],4], LShift[RShift[RefreshPeriod,7],4]]]; RTimer _ HiA[TestRefConstant]; *Storage diagnostic value RTimer _ (RTimer) or (LoA[TestRefConstant]); Nop; LU _ (RTMP) and (17C); *there are 16d timers REFR _ 0C, GoTo[ClearTimers,ALU#0]; LU _ Timer; *Set up the Refresh timer LoadTimer[RTimer]; *Notify task 16 to set up timer task RTMP _ HiA[Task16Start,16]; RTMP _ (RTMP) or (LoA[Task16Start]); APCTask&APC _ RTMP, GoTo[InitRet]; SetTask[16]; Call[TimerRet], At[Task16Start]; *Set TPC[16] to TimerTask *The simple timer task assumes slot 17 expired, since all others were cleared. TimerTask: Refresh[REFR]; LU _ Timer; *read timer to clear the wakeup REFR _ (REFR) + (20C); AddToTimer[RTimer]; CheckStop: T _ (FFault) and (10000C); LU _ (Printer) AND T ; GoTo[MidasStop,ALU#0] ; TimerRet: Return; *Midas recognizes a mouse halt as a task 16 breakpoint that was *not set by the user. It continues from (absolute) MidasStop+1 MidasStop: LU _ T, GoTo[.], SetFault, At[MidasStopLoc]; MidasRestart: Return, At[MidasStopLoc,1]; %The fault handler here replaces that in Kernel or the EPROM performing the same function and is similar to the fault handler in AMesa or Pilot. On crashes, the MP codes displayed are identical to those for Pilot except offset by the value of InitialMPCode. Optional treatment of different kinds of faults is controlled by bits in FFault, as follows: 0: MC2 errors send control to the task and address at Stack, crash if 0 (This option is used by MemInit during storage testing) 2: H4 parity errors ignored if 0, crash if 1. With a 3 MB Ethernet controller, this bit must be 0 because bogus H4PEs occur. MC1 doesn't start a pending reference properly when an H4PE occurs due to a hardware bug; extra NOPs in the 3 MB Ethernet microcode ensure that another reference isn't started when an H4PE might occur. However, if a "real" H4PE occurs in some other context, the machine should crash. The option here essentially gives up H4PE protection altogether. It would be possible to check that the task of an H4PE was, in fact, a 3 MB Ethernet task, but this would require an extra NOP after each IOStore4 and Input in the 3 MB Ethernet microcode (to ensure that the 3 MB task was still running when the H4PE fault occurred), and on gateways with more than one 3 MB controller, the check would be more complicated, so the code here treats all H4PE's the same. 3: Midas is present (1), so "crash" means breakpoint, else put a code in MP and GoTo[.] until booted. 15: MC1/StackOvf errors handled by notifying PFEntry in emulator (1), or by crashing (0)--ALWAYS CRASH HERE. Fault service begins at microlocation 1, but we don't assemble that mi here. Instead, the EPROM code loads Initial, which doesn't overwrite the EPROM fault handler; then Initial manually overwrites microlocation 1 with the mi commented below. By doing this there is always an intact fault handler. % SetTask[17]; * LoadPageExternal[0], GoToExternal[377], At[0]; *Buffer refill trap * T _ APCTask&APC, At[1]; *Must save APC first RXAPC _ T, At[100]; T _ (CTask&NCIA) xnor (170000C); RXCTask _ T; *Must ensure StkP .ne. 17b since another stack overflow error will occur *immediately after ResetErrors below if StkP remains .eq. 17b here. T _ (SStkP&NStkP) xor (377C); RXSTK _ 20C; StkP _ RXSTK, RXSTK _ T, NoRegILockOK; *ALUResult and SALUF are both read complemented T _ (ALUResult&NSALUF) xnor (0C); RXALU _ T; *This LoadPage is necessary because, after ResetErrors, the Page *register will no longer be disabled by the error condition. T _ Page&Par&Boot, LoadPage[0]; RXPPB _ T, ResetErrors; *Test first for time critical MC1/2 error without any accompanying StkOvf, *CSPE, or RMPE. Can't change ALU branch conditions until after ResetErrors. OnPage[0]; LU _ (LdF[RXPPB,4,4]) - 1; *Get pipe A (Timing for this mi = 8 cycles on MC12Err) ReadPipe[PipeReg], FreezeResult, GoTo[MC12Err,ALU=0]; LU _ (RXPPB) and (3000C), GoTo[BadHWErr,ALU>=0]; *Assume Midas breakpoint. T _ BrkPCrash, GoTo[CTaskCrash]; BadHWErr: T _ RMCSCrash, GoTo[.+3,ALU#0]; *Jump if CS or RM PE *ResetMemErrs in case stack overflow occurred with MC1/MC2 error. ResetMemErrs; *StkOvf only T _ StkCrash, GoTo[Crash]; *CS or RM parity error, possibly in combination with other errors. T _ (LdF[RXPPB,4,4]) + T, GoTo[Crash]; CTaskCrash: T _ (LdF[RXCTask,0,4]) + T, GoTo[Crash]; *The computation here is CrashCode+PipeTask = CrashCode+(PipeTask' xor 17b) *= CrashCode+(17b-PipeTask') = (CrashCode+17b)-PipeTask'. The value in T *when we get here is CrashCode+17b. PipeTaskCrash: T _ (LdF[PipeReg2,10,4]) - T; T _ (Zero) - T, GoTo[Crash]; %Display InitialMPOffset+T on MP (MP code must be .ls 400b if the pipe registers are of interest). Then, if Midas is present, save memory error information in RM 100-107 for Midas and transfer control to the Midas Kernel. However, RM 100-107 are not clobbered for simple breakpoints since these registers might be in use by some task (usually task 4). If Midas is not present, spin in a storage refresh loop, allowing storage to be examined by connecting with Midas later. % Crash: PipeReg5 _ (LSh[PipeReg5,10]) or T; RTMP _ HiA[InitialMPOffset]; RTMP _ (RTMP) or (LoA[InitialMPOffset]); T _ (RTMP) + T; ***NOTE: RM 352-353 will be smashed by PNIP. RTMP _ Or[And[IP[MapEntry],360],And[Sub[IP[MapEntry],1],17]]C, Call[PNIP]; *Reformat saved Pipe into RM 100-107 for Midas. Note that pipe info (other *than crash code and Task number) is only interesting if CrashCode is 200d *to 215d (an MC2 error). StkP _ RTMP; LU _ LdF[FFault,3,1]; LU _ LdF[RXPPB,4,4], Skip[ALU#0]; *If Midas not connected, wait until booted again. GoTo[.]; T _ LdF[PipeReg,11,7], GoTo[.+3,ALU#0]; *Map row address' LoadPageExternal[MidasPage]; RXCTask _ (RXCTask) xnor (170000C), GoToExternal[MidasBreakLoc]; PipeReg1 _ (LSh[PipeReg1,7]) xnor T; *Map row'' u Map column'' T _ LdF[PipeReg1,2,16], Call[FltPsh]; *MapEntry_page no. T _ (LdF[PipeReg2,10,4]) xor T, Call[FltPsh]; *TaskNumber T _ (LdF[PipeReg2,14,4]) xor T, Call[FltPsh]; *RefType *CrashCode (not offset by InitialMPOffset) T _ RHMask[PipeReg5], Call[FltPsh]; *Card no. (0..7) into CardNumber; offset by 5 to get actual board *number in card cage. NOTE: 14b in Card implies that this part of *the pipe is not filled by the reference. (X xor 7) + 5 = 14b - X. T _ 14C; T _ (LdF[PipeReg5,4,3]) - T; T _ (Zero) - T, Call[FltPsh]; *CardNumber *Map Flags (LogSE, WP, Dirty, Ref) into MapFlags T _ (LdF[PipeReg5,0,4]) xor T, Call[FltPsh]; T _ LdF[PipeReg4,12,6]; *Main column address (6 bits) PipeReg3 _ (LSh[PipeReg3,6]) or T; *x,x,Blk.1',,main row addr PipeReg5 _ LdF[PipeReg5,7,1]; T _ LdF[PipeReg3,2,16]; PipeReg5 _ (LSh[PipeReg5,16]) or T; *And Blk.0... *This is the (15-bit) quadword number within a 128k card. *Bits 1 and 2 give the block number. T _ (PipeReg5) xnor (100000C), Call[FltPsh]; *QuadAddr T _ RSh[PipeReg,10], Call[FltPsh]; *Interesting syndrome into 107 LoadPageExternal[MidasPage]; **Unfixup RXCTask for Kernel (should fixup Kernel and then remove **this mi in all software systems. RXCTask _ (RXCTask) xnor (170000C), GoToExternal[MidasFaultLoc]; FltPsh: UseCTask, Stack&+1 _ T; T _ 17C, Return; %There are a number of bugs and non-features in the MC1/MC2 error reporting hardware which account for the peculiar way things are done here; the comments here are based upon my reading of the hardware drawings and might be wrong: 1) ResetMemErrs resets the H4PE, MOB, MC1ErA, MC1ErB, MC2ErA, and MC2ErB flipflops. Also, the next reference reloads the MC1ErA and MC1ErB flipflops. The next reference using the same pipe will reload the MC2ErA or MC2ErB flipflop. H4PE can only be reset by ResetMemErrs. 2) H4PE's do not set MC1ErA or MC1ErB, so it is impossible to report the reference and task number for these with any certainty. Hence, the MP code uses +CTask rather than +PipeTask. 3) I am not sure whether MOB errors are indicated correctly in MC1ErA and MC1ErB or not. Hence, they report +CTask rather than +PipeTask in the MP. 4) MC2ErA and MC2ErB have pipe-specific clocks, so an error indication will remain true until another reference uses the same pipe. This means that the reference after one causing an MC2 error won't disturb its error indication. 5) MC1ErA and MC1ErB have a common clock, and only one of these can be indicated at a time. The hardware is SUPPOSED to fault before another reference starts, but if the preceding reference was a PFetch4 with error correction which didn't fault, and if the transport for that reference occurred between the faulting reference and the fault, then one more instruction will be executed before the fault task executes at location 1. This instruction could be another reference. If an extraneous reference does take place, the original MC1ErA/B indication would be replaced by the results of the extraneous reference, possibly getting the MCNoneCrash MP code. 6) MC2 is never started if MC1 gets a fault, so it is impossible to have both MC1ErX and MC2ErX indicated at one time. Timing = 32 cycles from loc 1 to here. % OnPage[FaultPage]; MC12Err: Dispatch[PipeReg,4,2]; *Dispatch on H4pe, MapBnd ***This Dispatch is only useful on the MC1/MC2 path. *Dispatch on MC2ErA', MC2ErB', and MC1ErA' bits Dispatch[PipeReg,0,4], Disp[.+1]; StkP _ RXSTK, Disp[MC2ErAB], DispTable[4]; *None *23rd or 24th? bit of memory address = 1 causes MOB. T _ MOBCrash, GoTo[CTaskCrash]; *MOB %Ignore improbably legit MOB&H4PE on IOStore4 to flush frequently occurring fake MOB&H4PE by 3MB Ethernet input task. Some 3MB Ethernet controllers cause H4PE's on Input's and IOStore4's erroneously; XWTask keeps control in xiTask so that the H4PE will be reported no later than the 1st mi of the next task to run, so that LoadPage errors won't happen. We could refine this check by continuing from H4PE's only when xiTask is running, but this would require one additional NOP in xiTask after IOStore4's or Input's, and it wouldn't work on gateways with more than one Ethernet controller. % LU _ LdF[FFault,2,1], Skip; *H4PE LU _ LdF[FFault,2,1]; *H4PE&MOB *Check 'ignore H4PE' bit in FFault. ResetMemErrs, Skip[ALU=0]; T _ H4PECrash, GoTo[CTaskCrash]; StkP _ RXSTK; %Restoring control to a task, as done here, is safe against every type of interruption except between LoadPage and the subsequent mi or between a reference and the next mi using the bypass kludge. However, the error check here will crash distinctively for a LoadPage problem, and since a following reference is aborted if a page or write protect fault is about to happen for a PREVIOUS reference, intervention between a reference and the bypass kludge should only be possible in one of the following three situations: 1) A Preceding PFetch4 experiences error correction with all 8 cycles of suspension for its transport occurring between a reference and the next mi using the bypass kludge, and that reference itself page faults; but page faults by io tasks aren't allowed, so this won't happen. 2) Correctable error logging occurs between a reference and the bypass kludge (we don't ever use LogSE). 3) An H4PE intervenes between a reference and the bypass kludge; this is illegal except for the 3mb Ethernet where enough Nop's after each Input and IOStore4 ensure that any H4PE happens safely. % T _ LdF[RXCTask,4,4]; *Compare page bits T17RestoreB: LU _ (LdF[RXPPB,0,4]) xor T; *with saved page register T _ RXALU, Skip[ALU=0]; *result register T _ LPCrash, GoTo[CTaskCrash]; *LoadPage error APCTask&APC _ RXCTask; Return, Restore, A _ RXAPC, LU _ T, NoRegILockOK; *back to faulted Task MC2ErAB: *Entries with ** comments are impossible. T _ MC22Crash, GoTo[Crash], At[MC12,0]; **All 4 errors T _ MC22Crash, GoTo[Crash], At[MC12,1]; **MC2A/B & MC1A T _ MC22Crash, GoTo[Crash], At[MC12,2]; **MC2A/B & MC1B T _ MC22Crash, GoTo[Crash], At[MC12,3]; *MC2A/B ResetMemErrs, FFault, DblGoTo[MC2ErARet,MC2ErA,R<0], At[MC12,4]; **MC2A & MC1A/B ResetMemErrs, FFault, DblGoTo[MC2ErARet,MC2ErA,R<0], At[MC12,5]; **MC2A & MC1A ResetMemErrs, FFault, DblGoTo[MC2ErARet,MC2ErA,R<0], At[MC12,6]; *MC2A & MC1B ResetMemErrs, FFault, DblGoTo[MC2ErARet,MC2ErA,R<0], At[MC12,7]; *MC2A ReadPipe[PipeReg,,FFault], ResetMemErrs, DblGoTo[MC2ErBRet,MC2ErB,R<0], At[MC12,10]; **MC2B & MC1A/B ReadPipe[PipeReg,,FFault], ResetMemErrs, DblGoTo[MC2ErBRet,MC2ErB,R<0], At[MC12,11]; *MC2B & MC1A ReadPipe[PipeReg,,FFault], ResetMemErrs, DblGoTo[MC2ErBRet,MC2ErB,R<0], At[MC12,12]; **MC2B & MC1B ReadPipe[PipeReg,,FFault], ResetMemErrs, DblGoTo[MC2ErBRet,MC2ErB,R<0], At[MC12,13]; *MC2B ResetMemErrs, GoTo[MC1Die], At[MC12,14]; **MC1A/B ResetMemErrs, GoTo[MC1Die], At[MC12,15]; *MC1A ReadPipe[PipeReg], ResetMemErrs, GoTo[MC1Die], At[MC12,16]; *MC1B T _ MCNoneCrash, GoTo[Crash], At[MC12,17]; *None MC1Die: T _ MC1Crash, GoTo[PipeTaskCrash]; *Old code commented out *MC2ErARet: * APCTask&APC _ Stack, GoTo[PNRet]; *MC2ErBRet: * APCTask&APC _ Stack, GoTo[PNRet]; MC2ErARet: T _ RSh[MemSyndrome,10], Skip; MC2ErBRet: T _ RHMask[MemSyndrome]; PipeReg5 _ (LSh[PipeReg5,12]) or T; *Position Blk.0' in bit 5 PipeReg3 _ LSh[PipeReg3,2]; *Position Blk.1' in bit 6 T _ (PipeReg3) and (1000C); PipeReg5 _ (LdF[PipeReg5,5,13]) or T; T _ (PipeReg5) xor (3000C); *Position Blk.0 & 1 in bits 5-6 *Resume task 0 at special location. APCTask&APC _ Stack; *Save block number & syndrome in xStorageFaults for final PNIP sequence. The *bit arrangement is so that, when the octal number is displayed on the MP, *the first character is Blk0-1 and the next three characters are the syndrome. xStorageFaults _ T, Return; *Shouldn't get any MC2 errors except during the storage test by MemInit, and *in that case control goes to MC2ErARet or MC2ErBRet above, so crash. MC2ErA: T _ LHMask[MemSyndrome], Skip; MC2ErB: T _ LSh[MemSyndrome,10]; PipeReg _ (RHMask[PipeReg]) or T; T _ MC2Crash, GoTo[PipeTaskCrash]; %LoadPageExternal[0]; GoToExternal[CrashLoc]; crashes any task. Give the MP code for a breakpoint with the MP code in SALUF, if WithMidas=1, else show the MP code in T. % LU _ LdF[FFault,3,1], At[CrashLoc]; SALUF _ T, Skip[ALU#0]; *Skip if Midas connected GoTo[.+2]; BugHalt: SetFault, GoTo[.]; *Give breakpoint if Midas connected Call[PNIP]; GoTo[.]; *Dummy version of NotifyInterrupt. SetTask[0]; NotifyInterrupt: Return; %PNIP displays the number in T in the maintenance panel and returns, where T is meaningfully in the range 0 to 9999d (0 to 23417b). It does not task unless called from task 0. Its registers (RTemp and RTemp1) should not conflict with those for the Midas Kernel or with any used by tasks 14 to 17 because of calls from the fault handler, which might subsequently go to Midas; any io task that calls PNIP and expects to continue should be wary of the fact that PNIP's registers are defined for task 0 and might conflict. The loop below uses the top bits of RTemp to space successive IncMPanel functions; as the code stands, the spacing is 15 or 16 cycles between each IncMPanel. ClearMPanel and IncMPanel may be illegal in the same mi with branch burp. For large numbers, map/storage refresh may fail when called by an io task. *Old spacing of IncMPanels was 23 cycles, but 15 seems ok. % PNIP: UseCTask, RTemp _ T; T _ APCTask&APC, ClearMPanel, Call[.+1]; PNIPl: RTemp _ (RTemp) + (40000C), GoTo[.,R>=0]; RTemp _ (LdF[RTemp,2,16]) - 1; RTemp1 _ T, Skip[ALU>=0]; APCTask&APC _ RTemp1, GoTo[PNRet]; LU _ LdF[RTemp1,0,4]; Skip[ALU=0]; IncMPanel, GoTo[PNIPl]; IncMPanel, Return; PNRet: Return; :End[Initial]; (2048)\f2