:TITLE[Initialize];*Last edited: 28 April 1981 by Fiala

%RM assignments are subject to a number of constraints:

1) Must not smash the registers needed to continue LoadRAM; these are
LP, LPhi, xfTemp, and xfTemp1 (RM 66, 67, 72, 73); RTemp1 must be
set even before continuing LoadRAM.
2) Must leave PageCount as RM 37 to agree with Initial.
3) Registers needed valid after DeviceInit must not be in the range 40-57,
which is used as a buffer during DeviceInit; nor may any of the constants
initialized by RegInit1 (AllOnes, R400, MDS, MDShi) appear in this area.
4) BootType may not be in the range 0-17 because it is referenced by
BootTask (task 1, 2, or 3).

xCNT (35) is used throughout init; xBuf to xBuf3 (44 - 47),
RTemp and RTemp1 (52 - 53) are also used except during DeviceInit.
%
RV[PageCount,37];
*Count of available real pages in system
**DON’T MOVE--MUST AGREE WITH INITIAL**
RV[BootType,36];
*even => hard boot, odd => soft boot (n.i.);
*negative => ether, positive => disk
*200 disk partition 2
*RM address must not be < 20b nor 40b to 57b.
RV4[iniBf0,iniBf1,iniBf2,iniBf3,14];

*Registers for map and storage initialization
RV[CompFlag,5];
RV2[ZWord,ZWordhi,6];
*Base reg
RV[MapAddr,10];
*current map location
RV[RealPage,11];
*current real storage page

*In addition to the registers below, RTemp, RTemp1, and DMA are used prior
*to DiskBoot/EtherBoot code; xCNT, DevIndex, contemp, DMA, and DMAhi must
*not be in 40-57 area.

RV[contemp,34];
*used in DeviceInit
RV[Assigned,65];
*used in DeviceInit
RV[DevIndex,12];
*used in DeviceInit and DiskBoot
RM[ErrorCnt,IP[RTemp]];
*used in DiskBoot
RM[ErrorCountx,IP[RTemp1]];
*used in DiskBoot

MC[ReturnOnSE,100000];
*FFault bit 0=crash on MC2 errors, 1=return

*The DTab macro formats device table entries. A DTab entry consists of the
*task and uPC value for the device’s init routine (0 if no init routine).
*To add a new controller to the system, it is only necessary to add an entry
*to the device table (and add the controller’s microcode).

M@[DTab,IMData[LH[#1] RH[LShift[#2,4],#3] At[DTabLoc]] Set[DTabLoc,Add[DTabLoc,1]]];

Set[DTabLoc,DTabBase];

DTab[12000,0,0];
*DES board
DTab[127000,0,0];
*FP board
**NOTE: The CDC is an optional device; perhaps we should require software to
**manually start the controller’s microcode with JRAM 50000b+cdcInitLoc and
**not initialize the device here, so that this table won’t change when the
**uCode is not present.
DTab[127400,cdcInitLoc,cdcTask];
*Color display = 53400b;
DTab[3400,EtherInitLoc,eiTask]; *New Ethernet input = 3400b
DTab[3000,0,EOTask];
*New Ethernet output=3000b(No init required)
DTab[1000,DisplayInitLoc,DpTask]; *Display (UTVFC) = 1000b
DTab[1400,DiskInitLoc,rdcTask];
*Disk (Alto RDC) = 1400b
DTab[2400,DiskInitLoc,rdcTask];
*Disk (Alto RDC) = 2400b (kludge if service late is on)
DTab[0,0,0];
*final table entry must be zero

OnPage[InitPage];

%KGO, EGO, and KGOP2 are Midas starting addresses which can be entered in
any task. Initial sends control to KGO if the disk is ready, else to EGOx,
where EGOx and KGOP2x are suitable starting addresses only if the current
task is the emulator (or tasks 1 to 3?).
***EGOx AND KGOx PLACEMENT IS KNOWN TO MAKELOADERFILE COMMAND FILES***

On keyboard boot, Display.Mc leaves KB0 word in T (T registers of unused
tasks safely hold data across a boot; possibly MNBR or SALUF also are
unsmashed but not sure). 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.
"0" (177577b) is interpreted here as a partition 2 disk boot;
BS (177776b) is ether boot;
all other values do a partition 1 disk boot.
%

KGOP2:
xBuf ← LoA[Add[InitBase,0]], GoTo[.+3];
EGO:
xBuf ← LoA[Add[InitBase,4]], Skip;
KGO:
xBuf ← LoA[Add[InitBase,6]], At[InitBase,3];
xBuf ← (xBuf) or (HiA[InitBase,BootTask]);
XNotify:
APCTask&APC ← xBuf, GoTo[iniRET];
*BootTask .le. 3, so it can address all emulator RM registers except
*RM 0 to 17b, but SetTask here checks against illegal RM refs.
SetTask[BootTask];
BootType ← T, At[InitBase,6];
T ← (BootType) xnor (200C);*Must modify T so next boot not same
LU ← (BootType) xnor (1C), Skip[ALU#0];*Par 2 boot on "0" key
KGOP2x:
BootType ← 200C, GoTo[Start], At[InitBase,0];*KGO on partition 2
BootType ← T ← 0C, GoTo[Start,ALU#0];*Ether boot on BS key
EGOx:
BootType ← 100000C, GoTo[Start], At[InitBase,4];*Ether boot

*SoftGO:
BootType ← 1C, GoTo[?], At[InitBase,2];

*Boot failures loop after putting code in maintenance panel;
*repeats previous kind of boot remembered in BootType.
InitFail:
Call[iPNIP];
GoTo[Start];

SetTask[0];

*Begin here as any task. Quiesce tasks 15 to 1 by notifying each one at Qx,
*which clears device register 0 and notifies the next task until ctask is 0.
*All devices are supposed to be disabled by outputting 0 to register 0, but
*the EtherNet controller has a bug requiring an extra output, which is done
*first below for all tasks.

Start:
xBuf ← IP[xBuf]C, At[InitBase,5];
StkP ← xBuf;
Stack ← HiA[Qloc,15];
Stack ← (Stack) or (LoA[Qloc]);
QNotify:
Stack&+1 ← 0C;
Stack&+1 ← 300C;
*Output a 300 to device 0 for this task (in case this is the ethernet task);
*then output a 0 to device 0; finally point task’s TPC at BadWakeup.
Output[Stack,0];
Nop;
Output[Stack,0];
APCTask&APC ← Stack;
LoadPageExternal[InitPage], Return;

*Start and QNext notify here.
Qx:
T ← LdF[Stack,0,4], CallP[QNext], At[Qloc];
*BadWakeup on non-overlay page to remain intact after init ucode is
*overwritten. Wakeup from a device that isn’t reset properly comes here.
BadWakeup:
SetFault, GoTo[.];

OnPage[InitPage];

QNext:
Stack ← (Stack) - (10000C), GoTo[QNotify,ALU#0];
*Now do notify for timer initialization.
xBuf ← LoA[TimerInitLoc];
xBuf ← (xBuf) or (HiA[TimerInitLoc,TTask]), Call[XNotify];
*Return here in task 0 after timer task blocks.

:IF[NoOverlays]; *******************************

*Test the map as a memory, then determine the amount of real storage and
*set up the first N map entries to point to this storage (initialize
*remaining map entries to VACANT), then clear storage.

iMap:
CompFlag ← (Zero) - 1;
*CompFlag is originally -1, so iRWMap tests map entries with LogSE=WP=0,
*Dirty=Ref=1, and complement of address; then CompFlag is 0 to test with
*these bits complemented.
imCompx:
MapAddr ← T ← 140000C;
imAloop:
T ← (CompFlag) xor T;
xBuf ← T, Call[iRWMap];*T ← xBuf on Return from iRWMap
*RealPage ← max real page + 1 for later; this second map write reads back
*what was written with the first map write.
RealPage ← 10000C, Call[iRWMap];
PageCount ← IP[FFault]C, Call[imCheckMap];*Crash if data bad
LU ← CompFlag, GoTo[imAloop,Carry’];
T ← CompFlag ← Zero, GoTo[imCompx,ALU#0];
StkP ← PageCount, PageCount ← T, NoRegILockOK;
MapAddr ← 140000C;*carries beyond max VM cause ALUCY

*At this point the map has been tested somewhat with each bit correctly
*assuming both its 1 and 0 states. Next, write each map entry with 0 flags
*and the corresponding real page number, and fill first 5 quadwords of each
*real page with their page numbers and complements and some constants
*selected to make all the check bits 1 and 0. Go through storage backwards
*so that hole in 96k modules will not screw up non-hole banks.
imFloop:
RealPage ← T ← (RealPage) - 1, Call[imFloop1];
Call[BlockSet];*fills iniBf with T
PStore4[ZWord,iniBf0,0];*store page number
T ← (Zero) xnor T, Call[BlockSet];
PStore4[ZWord,iniBf0,4], Call[ZBlockSet];*Store page no. complement
iniBf0 ← 100000C, Call[iniRET];*Wait for ZWord write
PStore4[ZWord,iniBf0,10], Call[ZBlockSet];*Store 100000,0,0,0
iniBf1 ← 1C, Call[iniRET];*Wait for ZWord1 write
PStore4[ZWord,iniBf0,14], Call[ZBlockSet];*Store 0,1,0,0
iniBf2 ← 40000C;
T ← 20C;
PStore4[ZWord,iniBf0], GoTo[imFloop];*Store 0,0,40000,0

imFloop1:
xBuf ← T, Skip[ALU>=0];
T ← RealPage ← 170000C, GoTo[imTloop];
*SUBROUTINE iRWMap writes the data in xBuf into map location MapAddr
*and returns xBuf in T, map entry in xBuf1 to xBuf3.
iRWMap:
T ← (MapAddr) and (37400C);
ZWordhi ← T;
T ← LSh[MapAddr,10];
ZWord ← T;
XMap[ZWord,xBuf,0];
xBuf ← T ← xBuf, Return; *interlock

*Sweep upward through storage and map and use any real pages discovered.
*Set up base register, set map entry, LogSE on (FFAULT[0] ← 1). This informs
*the fault handler that the test program is willing to take the fault; the
*fault handler RETURNs rather than sending control to Midas.
imTloop:
T ← (RealPage) and not (70000C);
xBuf ← T, Call[iRWMap];
Stack ← (Stack) or (ReturnOnSE), Call[iChkPg];

*Return here on fault, or when iChkPage detects a problem.
imPageBad:
T ← RealPage ← (RealPage) + 1;
Stack ← (Stack) and not (ReturnOnSE), GoTo[imTloop,Carry’];
*Fall through here after handling the maximum amount of real storage
Nop;
*This loop marks that portion of the map with no corresponding storage vacant.
imMarkVacant:
xBuf ← 60000C;
Call[iRWMap];
MapAddr ← (MapAddr) + 1;
*Loop over all map entries
T ← LHMask[PageCount], GoTo[imMarkVacant,Carry’];

*Zap all storage by filling with zeroes; initialize ZWord/ZWordhi to point
*one larger than the largest legal address.
ZWordhi ← T;
T ← LSh[PageCount,10];
ZWord ← T, Call[ZBlockSet];
*Loop zeroing all storage
ZWord ← (ZWord) - (4C);
GoTo[ZapS1,Carry];
ZWordhi ← (ZWordhi) - (400C);
LU ← (PageCount) - (MinPageCount), Skip[ALU<0];
PStore4[ZWord,iniBf0,0], Return;
T ← NotEnoughMemory, DblGoTo[InitFail,RegInit1,ALU<0];
ZapS1:
PStore4[ZWord,iniBf0,0], Return;

iChkPg:
PFetch4[ZWord,iniBf0,0];*Fetch will cause fault if page bad
T ← LdF[RealPage,4,14];*page address
LU ← (iniBf0) xor T;
PFetch4[ZWord,iniBf0,4], Skip[ALU=0];
LU ← iniBf0, Return;*page number didn’t compare
LU ← (iniBf0) xnor T;*check page complement
*fetch from other 3 quadwords to provoke a fault
PFetch4[ZWord,iniBf0,10], Skip[ALU=0];
LU ← iniBf0, Return;
PFetch4[ZWord,iniBf0,14];
T ← 20C;
PFetch4[ZWord,iniBf0];
LU ← iniBf0;
*Page is good.
***Remove the xBuf ← to enable single-error logging***
xBuf ← (xBuf) and not (100000C), Call[iRWMap]; *turn off LogSE
MapAddr ← (MapAddr) + 1;*go to the next map location
PageCount ← (PageCount) + 1, GoTo[imPageBad];

*SUBROUTINE imCheckMap compares (MapAddr xor CompFlag) against xBuf
imCheckMap:
T ← LSh[xBuf3,10];*flags, card, blk.0 bits
T ← (RHMask[xBuf1]) or T;
T ← (MapAddr) xor T;
T ← (CompFlag) xnor T;*note, Map data is complemented, so we xnor
UseCTask, Skip[ALU=0];
T ← BadMap, GoTo[InitFail]; *Some map entry was bad
MapAddr ← T ← (MapAddr) + 1, Return;

:ELSE; *****************************************

*Memory initialization was supposed to have been completed by Initial, but
*zero 0-777b and 177000b-177777b here because of apparent Initial bug.
ZWordhi ← 0C;
ZWord ← 177000C, Call[ZBlockSet];
PStore4[ZWord,iniBf0,0];
ZWord ← (ZWord) + (4C);
Skip[Carry];
Return;*Loop
ZWord ← 1000C, Call[.+1];
ZWord ← (ZWord) - (4C);
Skip[Carry’];
PStore4[ZWord,iniBf0,0], Return;*Loop
Nop;
*Memory initialization was completed by Initial.
*Wait for user to view MP left by Initial or previous boot that failed.
*Outer loop repeats 2↑14 times, so wait is 2↑14 * 13.7 usec ~ 0.22 sec
T ← xBuf ← 40000C, Call[MPWait];
xBuf ← (xBuf) + 1, GoTo[RegInit1,R<0];
*This subroutine accepts 0 in T and executes 135 cycles before returning
MPWait:
xBuf1 ← (Zero) + T;
xBuf1 ← (xBuf1) + (2000C), GoTo[.,Carry’];*Execute 65 times
Return;

:ENDIF; ****************************************

*Here after devices are quiescent, RM is zeroed, timer task initialized, and
*(debugging system only) map and storage are initialized. Initialize RM
*constants and start 256 us clock update.

RegInit1:
AllOnes ← (Zero) - 1;
R400 ← 400C;
MDShi ← T ← 0C;
MDS ← T;*MDS = RMZero
**High Base registers = MDShi and common to both Alto and Mesa emulators are
**initialized here so that eventually a procedure which moves MDShi can be
**written.
*TimerBasehi must be initialized before making RTCLOW even.
RTemp ← Sub[IP[TimerBasehi],1]C, Call[IniTS];
RTemp ← Add[LShift[eiTask,4],6]C, Call[IniTS];*eMDS600hi
RTemp ← Add[LShift[cdcTask,4],12]C, Call[IniTS];*cdcMDS400hi
RTemp ← Add[LShift[And[DpTask,14],4],76]C, Call[IniTS];*vMDShi
Stack&-2 ← T;*vMDS420hi
Stack&-2 ← T;*vMDS177000hi
Stack&-2 ← T;*rdcMDS520hi
RTemp ← Add[LShift[rdcTask,4],16]C, Call[IniTS];*rdcDCBhi
*making RTCLOW even starts RTC updating, which is safe now since storage has
*been initialized and the timer reference to VM 430 will not cause a fault.
RTemp ← Sub[IP[RTCLOW],1]C, Call[IniTS];
*Copy the page count into RTCLOW+1 (RM 326) for the Lisp emulator.
T ← PageCount, Call[IniSp1];
DeviceInit:
T ← StartDeviceInit, CallP[iPNIP];
:UNLESS[NoOverlays]; ***************************
*Wait for user to view StartDeviceInit, indicating that Initial is complete
*and that this microcode has commenced.
T ← xBuf ← 40000C, Call[MPWait];*Wait for user to view MP
xBuf ← (xBuf) + 1, Skip[R<0];
GoTo[MPWait];
:ENDIF; ****************************************

%RM 40-57 are a "slot table" with one entry per potential io controller.
First, the table is filled with dummy task numbers which are clocked out to
the controllers. Then, each task is interrogated for it’s Device ID, and
these names are put in the table. Next, for each slot, the device ID is
looked up in the DTab table (in IM) of potential devices, and if a match is
found, the DTab entry is put into the slot table. When all slots have been
looked up, the task numbers are clocked out to the controllers, and the
associated initialization routines are called in turn.
%
xCNT ← 57C;
xCNT ← T ← (StkP ← xCNT) + 1, Call[.+1];
*StkP = 57b, xCNT = T = 60b here; write 60-77 into RM 40-57 (StkP counts
*mod 20b, so StkP+1 when StkP .eq. 57 is 40b).
LU ← (xCNT) xor (77C);
Stack&+1 ← T, Skip[ALU=0];
xCNT ← T ← (xCNT) + 1, Return;
Assigned ← 0C;*Bit mask of asigned tasks
*Send dummy controller addresses to devices; wind up with (n lsh 14b) + 3 in
*RM (40b+n).
xCNT ← 57C, Call[ClockOutPattern];
*StkP = 57b here; read controller ID’s from register 0 of all devices
xCNT ← T ← 177400C, Call[iniRET];*allow xCNT & T to be written
Input[Stack];
xCNT ← T ← (xCNT) + (20C), Skip[R>=0];
DMA ← 400C, Return;*Advance to next device; init DMA for later
*StkP is now back at 40b since it wraps around the last time it was bumped.
*Have 3000b, 3400b, 1055b, 1417b, etc. followed by 177777b for all undefined
*slots.

*Look up each slot table entry in the device table
*Scan devices nearest the CPU first
xCNT ← 17C;
DI4x:
T ← DevIndex ← 0C;*base of device table in IM
DI4y:
DMA ← (DMA) or (200C), Call[GetCon];*get device ID from table
LU ← (LHMask[Stack]) xor T;*compare to high 8 bits of slot table entry
LU ← T, GoTo[DevFound,ALU=0];
*check for end of table (zero entry)
T ← DevIndex ← (DevIndex) + (2C), GoTo[DI4y,ALU#0];
DI4u:
Stack ← 17C; *end of table reached without match - set slot’s task to 17 (unused)
DI4z:
xCNT ← (xCNT) - 1;*check for all slots processed
Stack&+1, DblGoTo[DI4x,DI5,ALU>=0]; *set to next slot

DevFound:
Nop;
T ← (DevIndex) + 1, Call[GetCon];
Stack ← T;
Stack ← LSh[Stack,4];*10:13b ← task number about to be assigned
CycleControl ← Stack, Stack ← T, NoRegILockOK;
T ← WFA[AllOnes];
LU ← (Assigned) and T;
*Replace slot table entry with device table entry if task available
Assigned ← (Assigned) or T, GoTo[DI4z,ALU=0];
GoTo[DI4u];*Keep looking if task already assigned

*Have 6, 174427b, 174172b, 174070b, and 17b to end of table here
DI5:
xCNT ← 57C, Call[ClockOutPattern];*Clock out new controller ID’s

%Here the table has task and uPC for existing controllers and 170000b for
non-existent or undefined controllers. NOTE: StkP is 57b, so entries are
handled in the order 57, 56, ..., 41. Since DisplayInit may jump to LoadRAM,
**OLD LOADRAM**
RTemp1 (53) must be even and xBuf-xBuf3 and RTemp (44-47 and 52) will be
smashed, so the display controller must be in chasis slots 0 to 3 or LoadRAM
will smash table entries not yet handled, and there must be fewer than 13b
controllers mounted or RTemp1 might not be even.
**NEW LOADRAM**
RTemp1 (53) must be even and yBuf-yBuf2 (50-52) will be smashed, so the
display controller must be in chasis slots 0 to 7, and there must be fewer
than 13b controllers mounted or RTemp1 might not be even.
%
T ← 17C;
*DpTask transfers to task 0 to roll in or pass over the CSL monitor overlay.
*It continues initialization by transferring to DI6 with xCNT in T rather
*than by simply returning as other device initialization routines do.
DI6:
xCNT ← T, Call[.+1];*Setup TPC for loop below
*Loop here to call all the init routines
T ← xCNT ← (xCNT) - 1, Skip[R>=0];
ErrorCnt ← 10C, GoTo[BootEmulators];*Set up retry count
*Unless InitPC = 0 (no init required), call device init routine and loop
LU ← LdF[(Stack),4,14];
APCTask&APC ← Stack&-1, Skip[ALU#0];
MNBR ← BootType;
iniRET:
Return;

IniTS:
StkP ← RTemp;
IniSp1:
Stack&+1 ← T, Return;

ZBlockSet:
iniBf0 ← T ← 0C, Skip;
BlockSet:
iniBf0 ← T;
iniBf1 ← T;
iniBf2 ← T;
iniBf3 ← T, GoTo[iniRET];

iPNIP:
LoadPage[PNIPPage];
GoToP[PNIP];

ClockOutPattern:
*Call with 57C in xCNT
StkP ← xCNT;
xCNT ← 17C;*go through the slot table backwards
COP1:
DevIndex ← 3C;*DevIndex used for loop count
COP2:
T ← (Stack) xor (1C);*complement bit
DevIndex ← (DevIndex) - 1, GenSRClock;*send bit
Stack ← Rcy[Stack,1], GoTo[COP2,ALU>=0];*get next bit
xCNT ← (xCNT) - 1;*all slot table entries done?
Stack&-1, GoTo[COP1,ALU>=0];*get next word
DMAhi ← 0C, Return;*DMAhi ← 0 for EtherBoot and DiskBoot

GetCon:
contemp ← T;*word index into Dtab
contemp ← (contemp) + (And[LShift[DTabBase,1],17400]C);
contemp ← (contemp) + (And[LShift[DTabBase,1],377]C);
contemp ← RSh[contemp,1];*instruction address in CS
T ← (LdF[AllOnes,17,1]) and T;*low bit tells which half
APCTask&APC ← contemp;
ReadCS;
T ← CSData, Return, DispTable[1,1,0]; *Must be even placement

BootEmulators:
BootType, T ← StartEtherBoot, NoRegILockOK, GoTo[DiskBoot,R>=0];
*Setup here is VM 604 ← 400, VM 605 ← 1, VM 610 ← 377, VM 600 ← 0;
*then start the Ethernet controller and wait for VM 600 # 0.
*DMAhi,,DMA were setup as 0,,600 earlier for this code.
EtherBoot:
xBuf1 ← 1C, Call[iPNIP];
xBuf ← 400C;
EtherBootx:
PStore2[DMA,xBuf,4], Task;*VM 604 = eiCLoc ← 400, eiBLoc ← 1
xBuf2 ← 377C;
*ESLOC ← 377 (serial no. for breath-of-life packets)
PStore1[DMA,xBuf2,10], Call[iniRET];
PStore1[DMA,RMZero,0];*ePLoc ← 0 (status word)
RTempLoA[eiStartLoc], Call[eStartRead];
*Here (in task 0) after Ether has started and tasked
T ← (DMA) + (2C);
PFetch1[DMA,AC1,0], Call[iniRET];
LU ← AC1;
AC1 ← (AC1) xor (377C), GoTo[.-3,ALU=0];*Wait for packet
PFetch1[MDS,AC2,2];
AC2 ← (AC2) - T;*AC2 ← (AC2) - (Breath-of-life)
AC0 ← cEtherBoot, GoTo[EtherBootx,ALU#0];
*got the breath of life!!!! start Alto emulator with PC=5 and complement
*of KB1 word in AC0 (=10b for NetExec, =100b for MesaNetExec);
PCB ← 5C;
Booted:
T ← PageCount, Call[iPNIP];
:IF[FinalOverlay]; *****************************
LoadPageExternal[LRJPage];
RTemp1 ← 0C, GoToExternal[LRJContinue];
:ELSE; *****************************************
LoadPage[neStartPage];
GoToP[StartNova];
:ENDIF; ****************************************

EStartRead:
RTemp ← (RTemp) or (HiA[eiStartLoc,eiTask]);
LoadPage[eePage];
RTemp1 ← 300C, GoTo[eIOReset];*Disable EtherNet input/output

DiskBoot:
T ← StartDiskBoot;
DMA ← 1000C, Call[iPNIP];
*Read disk Sector 0 into page 0 (starting at location 1).
DiskBootx:
ErrorCountx ← 20C, Call[ZBlockSet];*word 520 - not used by disk
*word 521 - IOCB pointer
*word 522 - disk status
*word 523 = -1 to force a seek
T ← (R400) or (120C);
PStore4[MDS,iniBf0], Call[iniRET]; *520-523 ← 0,0,0,0

*Set up the IOCB at 1000b
iniBf2 ← 44000C;*disk command goes at location 1002 (read, read, read)
iniBf3 ← 2000C;*header goes at 2000 (unlike ALTO)
PStore4[DMA,iniBf0,0], Call[iniRET]; *1000-1003 ← 0,0,44000,2000
iniBf2 ← 400C;
iniBf2 ← (iniBf2) + (2C); *label goes at 402
iniBf3 ← 1C;*data goes at 1
PStore2[DMA,iniBf2,4], Call[iniRET]; *1004-1005 ← 402,1

*Since we will initialize the interrupt system later, we do not need to worry
*about 1006 or 1007; 1008 is unused
PStore1[DMA,iniBf3,11];
*iniBf1 = 1.. Disk address 0, with RESTORE bit at 1009
*Start the disk
iniBf1 ← 1000C, Call[iniRET];*word 521 - IOCB pointer
iniBf2 ← 0C;
T ← (R400) + (120C);
PStore4[MDS,iniBf0], Call[iniRET]; *520-523 ← 0,1000,0,1
*Wait for the disk to store good status in the DCB, retry if status is bad
DWSet:
DevIndex ← 40000C;*loop count for status wait
DiskWait:
PFetch1[DMA,xCNT,1];*fetch status word at 1001b
T ← 17C, Call[iniRET];
LU ← (LdF[xCNT,4,4]) xor T;
LU ← LdF[xCNT,10,10], GoTo[StatusStored,ALU=0];
DevIndex ← (DevIndex) - 1, GoTo[DiskWait,R>=0];
ErrorCountx ← (ErrorCountx) - 1, GoTo[DWSet,R>=0];
T ← NoDiskStatus, GoTo[InitFail];*timed out waiting for disk to store status

StatusStored:
ErrorCnt ← (ErrorCnt) - 1, Skip[ALU#0];
PCB ← 1C, GoTo[Booted];*Good status--send control to VM 1
T ← BadBoot, Skip[ALU<0];
GoTo[DiskBootx];
GoTo[InitFail];

%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).
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 Fault.Mc, 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’s.
**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.
%
OnPage[PNIPPage];

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[PFExit];
LU ← LdF[RTemp1,0,4];
Skip[ALU=0];*Skip if emulator (tasking allowed)
IncMPanel, GoTo[PNIPl];*else non-skip
IncMPanel, Return;


%DoInt ORs bits from T into NWW and sets IntPending. Uses registers 0 and 1
in whatever task calls. DoIntR is the same, but with the bits from register
0 rather than T.
%
RV[IntTemp1,0];
RV[IntTemp2,1];

DoInt:
IntTemp1 ← T, At[DoIntLoc];*Abs placement for CSLKeyboard overlay
DoIntR:
IntTemp2 ← IP[NWW]C;
T ← (SStkP&NStkP) xor (377C);
StkP ← IntTemp2, IntTemp2 ← T, NoRegILockOK;
T ← (IntTemp1) and not (100000C);
Stack ← (Stack) or T, Skip[ALU#0];*set bits in NWW
StkP ← IntTemp2, Return;*Restore StkP and return
IntTemp1 ← IP[RSImage]C;
StkP ← IntTemp1;
T ← Stack ← (Stack) or (IntPendingBit);*Set IntPending
LU ← StkP ← IntTemp2, RS232 ← T, Return;

:END[Initialize];