: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]<D0>Alto>) must be present on your
disk. The following files are produced:
AltoD0.eb & Initial.ebfor 3mb ethernet
boot servers
InitialAltoD0.ebto install on disk
default Alto boot
InitialPilotD0.ebto 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:
0177577bAlto 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.
P177757bPilot disk boot.
7173777bStorage test boot.
BS177776bAlto 3 mb etherboot.
BS+P177756bPilot 3 mb etherboot.
BS+V177376bAlphaMesa Pilot 3 mb etherboot
E167777bAlto 10 mb etherboot (pretty useless since the
Alto emulator has no 10 mb ethernet microcode).
E+P167757bPilot 10 mb etherboot.
E+V167377bAlphaMesa Pilot 10 mb etherboot
D175777bAlto partition 1 disk boot.
D+P175757bPilot 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]<APilot>11.0>Pilot>*>Boot.mesa, Device.mesa, and
DeviceTypes.Mesa. The important modification is as follows:

3 mb10 mbSA4000SA800
0
RequestBasicVersion3456b3456b3456b3456b
1
Action ← inLoad00--
Action ← physVolumeBoot--22?
2
Location ← deviceType76100b1
3
deviceOrdinal0000
4-15b
device specific boot information
16b
Switches0000

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
505171280 cycles 4 ms
512172560 cycles 8 ms*emulator value
524175120 cycles16 ms
517173840 cycles12 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];