:TITLE[Initial];
%
Edit by 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.
Edit by 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.
Edit by HGM, October 3, 1981 9:31 PM Add debugging option.
Edit by HGM, January 24, 1981 10:22 PM Change for CSL style LF displays.
Edit by Ed Fiala 18 March 1981: Fix up MapEntry and QuadAddr in
memory error reporting; delete RM defs redundant in GlobalDefs;
move task 16 code.
Edit by HGM, October 13, 1980 12:35 PM Add crash on H4PE entries.
Edit by Jim Frandeen, September 4, 1980 9:36 AM Move defs to Globaldefs Fix H4PE code.
Edit by Ev Neely Aug 18, 1980 9:27 AM New net numbers
Edit by Jim Frandeen, March 2, 1980 11:27 AM Delete Includes for Integration Procedure
Edit by Joiner, February 28, 1980 2:54 PM recognize TOR for ether booting in bold
Edit by 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"177577bAlto emulator partition 2 disk boot.
BS177776bAlto emulator ether boot.
"P"177757bPilot emulator disk boot.
The intended arrangement is for the user to install InitialAlto.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. Consequently, only "P" is 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. 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);
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];*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.
*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
505171280 cycles 4 ms
512172560 cycles 8 ms*emulator value
524175120 cycles16 ms
517173840 cycles12 ms*used during storage test
%
RTimer ← HiA[51717];*Storage diagnostic value
RTimer ← (RTimer) or (LoA[51717]);
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];
MC2ErARet:
APCTask&APC ← Stack, GoTo[PNRet];
MC2ErBRet:
APCTask&APC ← Stack, GoTo[PNRet];
*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];