*-----------------------------------------------------------
Title[BootstrapMain.mc...August 11, 1981 2:16 PM...Taft];
* Bootstrap is a microprogram that cooperates with the Baseboard to fill the
* Dorado IM with "Initial" microcode when a boot occurs.
*-----------------------------------------------------------

%
WARNING: This program must be placed in the "last N" words of the Dorado
microstore. Somehow, it must be guaranteed that this code does not share
IM locations with the microcode it bootstraps. Changes in the size or
location of this program must be arranged cooperatively with the
Baseboard processor’s code.

WARNING: This program writes ALUFM; consequently the association between
operator symbols in the micro assembly language (like, "+", "-", "or", "#")
and what ALU function actually occurs when such symbol gets used depends
entirely upon convention. Ie., D1Lang may cause the ALUF of the micro
instructions to contain, say, "5" when + gets used. If the programs writes
into ALUFM, at location 5, a value that causes the processor to perform "-",
then the processor will subtract rather than add. The ALU operations that
are written by Bootstrap are A XOR B, A+1, and NOT A.
Additionally, the BaseBoard writes NOT B before giving control to Bootstrap.
All other operations are verboten in Bootstrap!


Program Overview
----------------

The Baseboard forces this program into IM and releases control to it with
machine errors disabled (when the program gets control RM and T may have
parity errors). Bootstrap assembles IM words that are provided by the
Baseboard and writes them into sequential locations of IM beginning at a
location specified by the Baseboard. When Bootstrap has finished assembling
words provided by the Baseboard it transfers control to "InitialLoc", the
entry point to the Initial microcode that has been loaded, where more
initialization gets done. When program initialization is complete, the
program enables errors (Stack, RM, and T parity errors) via the manifold
system. Then it notifies the baseboard that all is well, and then
finds and loads the appropriate emulator microcode from disk or Ethernet,
which in turn boots the operating system via the disk or Ethernet.

IM layout (see definitions in BootDefs):
pages ~63 - 75: Initial & its friends
page 76:LoadRam -- brought in with Initial
page 77:Bootstrap

Bootstrap is loaded "manually" by the Baseboard. Bootstrap then brings in
Initial and LoadRam from the BaseBoard and starts it. Initial loads some
emulator into main memory and then calls LoadRam to load it into IM.
At that point, Initial and Bootstrap are no longer needed and may be
overlaid by the emulator; only LoadRam need stay around.

Baseboard - Bootstrap Conventions
---------------------------------

Bootstrap reads data from the Baseboard by reading the CPReg. First it reads
a starting address value (two bytes) and a count (two bytes). Then it reads
instructions (four bytes each) and writes them into IM. The last two bytes
the Baseboard transmits to Bootstrap contain a 16 bit checksum that the
"Initial" microcode checks. Whenever the Baseboard transmits bytes to
the Dorado, Bootstrap assembles the bytes left to right. The Baseboard
provides IM bytes in the following format:

0 <7 bits><left half byte>
1 <skip 4 bits><3 bit dispatch><right half byte>

The dispatch encodes the following information:

x00 left half, 17th bit is 0
x01 right half, 17th bit is 1
x10 IM right half, 17th bit is 0
x11 IM right half, 17th bit is 1

If x = 0 THEN use correct parity ELSE write bad parity.

The first two CPReg values that Bootstrap reads from the Baseboard assemble
into the starting IM address where subsequent instructions will be written.
The next two CPReg values assemble into a "hunk" count. Each hunk contains
4 Dorado instructions = 8 half instructions. Thus Bootsrap loads Cnt with a
half-word count that is 8 * hunk count. The 3-bit dispatch is a convention
that applies to reading Dorado instructions only; ie., those two bits are
zero when the Baseboard transmits "data" rather than instructions to the
Dorado.

Bootstrap Initialization
------------------------

The Baseboard writes bootsrap into the Dorado’s IM, and it initializes ALUFM
with "B" (ALUFM[0] ← 25B) Further initialization must be provided by
Bootstrap itself:

Bootstrap must initialize ALUFM values other than "B", and it must
synchronize with the Baseboard. Synchronization occurs by waiting for the
high order bit change value (from zero to one or one to zero). Note, the
program reads these values from CPreg by using the "RWCPreg" function.
The Baseboard starts Bootstrap with CPReg[0] = 1.

Bootstrap must read the starting address and the hunk count. It converts the
hunk count into a half-word count.

Second-stage initialization
---------------------------

The microcode that is loaded and started by Bootstrap is called "Initial".
Its responsibilities are as follows:

It reads a two byte checksum and compares the checksum against the computed
checksum from all other values read from CPReg.

It writes RM, STACK, and T with valid data -- to prevent parity errors.

It initializes ALUFM.

It initializes the memory system enough to prevent unexpected errors.

When done with all this, Initial sets a bit in the Baseboard using
the manifold system, telling the Baseboard that this stage of the boot
has been successful. It then does more complete initialization
and loads and starts the appropriate emulator microcode from the disk
or Ethernet.
%

TopLevel;
OnPage[BootstrapPage];
Set[BootstrapAddr, LShift[BootstrapPage, 6]];

*-----------------------------------------------------------
Bootstrap: At[BootstrapLoc],
* Started here by BaseBoard
*-----------------------------------------------------------
TaskingOff;

* Initialize ALUFM for A XOR B, A+1, and NOT A. (Baseboard already loaded B.)
* (Assembling this microcode will give a "Field ALUF already set" error
* if the ALUFM addresses for the operations don’t agree with the
* ones in D1Alu.mc.)
T← AFM10;
ALUFMRW← T, ALUF[10], A XOR B;

T← AFM12;
ALUFMRW← T, ALUF[12], A+1;

T← AFM16;
ALUFMRW← T, ALUF[16], NOT A;

*-----------------------------------------------------------
* Read beginning loc and hunk count.
* We don’t care which RBase we use, but we must init chkSum, loc, cnt.
*-----------------------------------------------------------
ChkSum← T XOR T;* ChkSum← A0
Tag← T XOR T, Call[ReadBB];* Tag← A0, for BaseBoard sync
Loc← LSH[T, 10], Call[ReadBB];* Bytes 0, 1 = loc
T← LDF[T, 10, 0];
Loc← (Loc) XOR T, Call[ReadBB];* Really OR -- bits are disjoint
Byte1← LSH[T, 10], Call[ReadBB]; * Bytes 2, 3 = hunk count
T← LDF[T, 10, 0];
Byte1← (Byte1) XOR T;* Hunk count * 8 = half-word count
Byte1← LSH[Byte1, 3];
Cnt← Byte1;

*-----------------------------------------------------------
* This is the main loop that reads bytes from the base board and then
* writes them into IM. Note that each half word gets assembled by
* reading two bytes. The second byte (right half) of each word contains
* extra bits that distinguish whether to set the 17th bit of IM
* and whether or not to use good parity when writing IM.
*-----------------------------------------------------------
BootByteL:
Branch[BootStage2, Cnt=0&-1];* Branch if count ran out
Nop;* Placement
Call[ReadBB];* Get left half byte
Byte1← LSH[T, 10], Call[ReadBB]; * Get dispatch & right half byte
BTemp← LDF[T, 3, 10];* BTemp← 3 dispatch bits
BTemp← LSH[BTemp, 1];* Spread targets (for placement)
T← LDF[T, 10, 0];* Construct full data word
T← T XOR (Byte1);
BigBDispatch← BTemp;
Link← Loc, Branch[Write000];* Link← IM address to write

Set[WriteX, Add[BootstrapAddr, 20]];
* 0 mod 20

Write000: At[WriteX, 0],
IMLHR0’POK← T;* Left half, 17th bit = zero.
Branch[BootByteL];
Write001: At[WriteX, 2],
IMLHR0POK← T;* Left half, 17th bit = one.
Branch[BootByteL];
Write010: At[WriteX, 4],
IMRHB’POK← T;* Right half, 17th bit = zero.
Loc← (Loc)+1, Branch[BootByteL];
Write011: At[WriteX, 6],
IMRHBPOK← T;* Right half, 17th bit = one.
Loc← (Loc)+1, Branch[BootByteL];
Write100: At[WriteX, 10],
IMLHR0’PBad← T;* Left half, 17th bit = zero.
Branch[BootByteL];
Write101: At[WriteX, 12],
IMLHR0PBad← T;* Left half, 17th bit = one.
Branch[BootByteL];
Write110: At[WriteX, 14],
IMRHB’PBad← T;* Right half, 17th bit = zero.
Loc← (Loc)+1, Branch[BootByteL];
Write111: At[WriteX, 16],
IMRHBPBad← T;* Right half, 17th bit = one.
Loc← (Loc)+1, Branch[BootByteL];

*-----------------------------------------------------------
* Exit from main loop -- go run the Initial microcode we have loaded.
*-----------------------------------------------------------
BootStage2:
BranchExternal[InitialLoc];

*-----------------------------------------------------------
ReadBB: Subroutine, At[ReadBBLoc],
* Read a byte from Baseboard.
* Enter with Tag containing sync bit.
* Exit with ChkSum and Tag updated and T = data from BaseBoard.
*-----------------------------------------------------------

Q← Link;* Save return link

* Caution: RWCPReg puts unsynchronized data on the BMux!
* Therefore, load it into a register before testing the tag bit,
* and read it again before believing the data.
T← RWCPReg;
PD← (Tag) XOR T;
T← RWCPReg, Branch[.-2, ALU<0];* Wait until CPReg[0] = Tag[0]

Tag← NOT (Tag), Link← Q;
ChkSum← (ChkSum) XOR T, Return;