:TITLE[Initial]; % 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 MP codes used by Initial are defined in GlobalDefs.Mc. Source files in Initial are: D0Lang.Mc, GlobalDefs.Mc, EPROMOccupied.Mc, LoadRAM.Mc, Initial.Mc, MemInit.Mc, SA4000Loader.Mc, RDCDefs.Mc, RDC.Mc, EtherLoad.Mc; D0Lang.Mc, GlobalDefs.Mc, RDCDefs.Mc, and RDC.Mc are sources shared with Pilot. MicroDInitial.Cm builds Initial.Mb. InitialBootFiles.Cm, which uses Initial.Mlf, builds InitialPilot.Eb and Initial.Eb; the AMesa system also uses Initial.Mb to build InitialAlto.Eb. SaveInitialToAD0.Cm, InitialFiles.Cm, SaveInitial.Cm, VerifyInitial.Cm, and InitialMap.Cm are other command files used by SDD. DumpInitial.Cm is a command file used by Fiala. % SetTask[0]; RV[BootType,20]; RV[RCnt,51]; Loca[InitBase,InitialPage,100]; Set[Qloc,Add[InitBase,30]]; Set[QretLoc,Add[InitBase,32]]; Set[BootTaskLoc,Add[InitBase,34]]; *Place Task 16 code on a page that will not be smashed by Pilot1 *because Initial's timer task must still be running to handle Midas *breakpoints after Pilot1 is loaded and before Pilot1's timer task *is running. Loca[Task16Start,11,0]; *does a call => needs two locations Loca[MidasStopLoc,11,3]; *uses two locations ***Used to have here: ***Set[Task16Start,Add[InitBase,22]]; ***Set[MidasStopLoc,Add[InitBase,25]]; Set[Task17Start,Add[InitBase,20]]; Set[DeviceDispatch,Add[InitBase,40]]; OnPage[InitialPage]; SAAltoStart: BootType _ 0C, GoTo[QTask], At[InitBase,0]; SAPilotStart: BootType _ 1C, GoTo[QTask], At[InitBase,1]; EtherAltoStart: BootType _ 2C, GoTo[QTask], At[InitBase,2]; EtherPilotStart: BootType _ 3C, GoTo[QTask], At[InitBase,3]; AltAltoStart: BootType _ 7C, GoTo[QTask], At[InitBase,7]; *Set crash on H4PE flag, then do normal stuff SAAltoStartH4PE: BootType _ 0C, GoTo[HTask], At[InitBase,10]; SAPilotStartH4PE: BootType _ 1C, GoTo[HTask], At[InitBase,11]; EtherAltoStartH4PE: BootType _ 2C, GoTo[HTask], At[InitBase,12]; EtherPilotStartH4PE: BootType _ 3C, GoTo[HTask], At[InitBase,13]; *Spare for testing things EtherTestStart: BootType _ 17C, GoTo[QTask], At[InitBase,17]; HTask: RTemp _ IP[FFault]C; StkP _ RTemp; Stack _ (Stack) or (20000C); %The entry point above determines how the 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?) 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 emulator partition 2 disk boot. BS 177776b Alto emulator ether boot. "P" 177757b Pilot emulator disk boot. "7" 173777b Storage test boot. The intended arrangement is for the user to install InitialAltoD0.eb on his disk as "initial microcode". If he boots with no keys depressed, the Alto emulator starts from partition 1. If he depresses nothing, "0", or BS, the Alto emulator starts from disk partition 1, partition 2, or the net exec; if he depresses "P", Alto microcode is abandoned and Pilot microcode and germ are obtained from the Pilot volume. If he depresses "7", MemInit.Mc will repeat its storage test until some failure is detected; then it will repeatedly display the failure information from that pass of the diagnostic. Consequently, only "P" and "7" are checked for here; if "p" is depressed, then BootTask's T register is set to 177777b and initialization continues as though the SAPilotStart entry point had been used originally. If "7" is depressed, BootTask's T register is set to 177777b and initialization continues but will hang in the storage test. For any other value in BootTask's T, the boot proceeds unchanged and BootTask's T will be decoded by the Alto emulator. % QTask: RTemp _ LoA[BootTaskLoc]; RTemp _ (RTemp) or (HiA[BootTaskLoc,BootTask]), GoTo[Qloop]; SetTask[BootTask]; RTemp _ T, At[BootTaskLoc]; LU _ (RTemp) + (21C); LU _ (RTemp) + (4000C) + 1, Skip[ALU#0]; *"P" depressed; must reset T to no keys down; otherwise, T must not change. T _ (RTemp) or not (0C), GoTo[SAPilotStart]; RTemp _ LoA[Qloc], GoTo[.+3,ALU#0]; *Quiesce tasks 15b - 1 *"7" depressed; must reset T to no keys down. T _ (RTemp) or not (0c); BootType _ 400C; *Indicate "loop storage test" 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. *Stack points at RTemp1. 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 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]; *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]; *EtherLoad takes a microcode boot file index (bfi) in T. The index *is used to select a boot file number (bfn) in the range 3000-3777. EtherAlto: BootType _ 11C, GoTo[EtherTail], At[DeviceDispatch,2]; EtherPilot: BootType _ 21C, GoTo[EtherTail], At[DeviceDispatch,3]; AltEtherAlto: BootType _ 31C, GoTo[EtherTail], At[DeviceDispatch,7]; EtherTail: BootType _ (BootType) + (400C), GoTo[EBCommon]; EtherTest: BootType _ 17C, GoTo[EBGo], At[DeviceDispatch,17]; %We know whether we want Alto or Pilot code. We must decide what io devices are on the machine. Only the monitor and keyboard are interesting now. The choices are: LF monitor, Star keyboard, UTVFC (bit clock rate 3) TOR display ??? CSL monitor, microswitch keyboard, UTVFC (bit clock rate 5) LF monitor, microswitch keyboard, UTVFC (bit clock rate 11) The number entering in temp is incremented by: 0 to select Dallas kbd, or 1 to select CSL display or CSL LF (both with microswitch kbds), or 2 to select TOR display. % EBCommon: T _ 0C; RTemp _ 60C, Call[SrShift]; *Set all device tasks to 17 T _ 20C; RCnt _ (Zero) - T; *Don't look forever 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 BootType _ (BootType) + (2C), GoTo[EBGo]; *TOR display LU _ (LHMask[RTemp]) xor T; RCnt _ (RCnt) + 1, Skip[ALU=0]; 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 RTemp _ LdF[RTemp,10,5]; *get bit clock rate LU _ (RTemp) xor (3C); Skip[ALU=0]; BootType _ (BootType) + 1; *CSL keyboard, either monitor % *BootType seems to contain 400b+(11b, 21b, or 31b)+(2 if TOR) here. EBGo: T _ (BootType) and (77C); *Get rid of the 400 to bring MPC into range. RTemp _ T; *Double to allow for MPC increment on Ether fail. RTemp _ LSh[RTemp,1]; *This seems to show, [(11b, 21b, or 31b)+(0 or 2)] * 2 + 740d, *depending upon whether the EtherAlto, EtherPilot, *or AltEtherAlto entry points were used and the kind of terminal. T _ (RTemp) + (StartEtherBoot), Call[ShowNumber]; LoadPage[EtherPage]; T _ BootType, GoToP[EtherLoad]; NoDisplay: T _ NoUTVFC, GoTo[InitFail]; MicrocodeLoaded: LP _ MicrocodeAddress, At[MicrocodeLoadedLoc]; LPhi _ 0C; *Preserve refresh sequence during LoadRAM. xfTemp1 _ IP[Refr]C; StkP _ xfTemp1; T _ Stack; xfTemp1 _ T, LoadPage[LRJPage]; RTemp1 _ 0C, GoToP[LRJEnter]; *Enter with value in T, shift count in RTemp. *Value is rotated right after each shift. SrShift: RTemp1 _ T; RTemp _ (RTemp) - 1, GenSrClock; T _ RTemp1 _ RCy[RTemp1,1], GoTo[.-1, ALU#0]; Return; 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)\f5