*-----------------------------------------------------------
Title[PilotLeftovers.mc...May 2, 1984  5:08 PM...Willie-Sue];
* Pilot-related stuff that doesn't seem to belong anywhere else.
* A lot of this originally came from the Alto emulator.
*-----------------------------------------------------------

TopLevel;

% *-----------------------------------------------------------
The microcode is started in one of the following ways:
1. Loaded by Midas and started at InitMap.
2. Self-restarted at Boot by display task in response to 1-push boot.
3. Restarted by BaseBoard at InitMap in response to 2-push boot.
4. Boot-loaded by BaseBoard/Initial and started at BootOrStart.
5. Loaded by software (RunPilot, MesaNetExec) and started at BootOrStart.

In cases 1-4, we want to go through the full memory system initialization
and Germ bootstrap sequence.  In case 5, software has already set up
memory with the appropriate stuff (presumably some flavor of Germ), and
we do NOT want to disturb it.  The problem is to distinguish cases 4 and 5,
since they both enter at BootOrStart.  (This is a consequence of having only
one .eb file for both purposes, and thus only one public starting address.)

We handle this by the following kludge: if page 37002 (the first page
of the Germ) is already mapped then case 5 is assumed; otherwise case 4.
% *-----------------------------------------------------------

*-----------------------------------------------------------
* Display task branches here on a 1-push boot (case 2).
*-----------------------------------------------------------
Set[XTask, IP[DHT]];
DontKnowRBase;

Boot:	Call[TasksOff];
	Call[EmuInitPC];
	LdTPC← T, TaskingOn;
	Block;
* should never awaken again, since we did an I/O Reset.
	Breakpoint, Branch[.];

Subroutine;
EmuInitPC:
	T← EMU, CoReturn;		* Return EMU start PC
TopLevel;
	Branch[InitMap];

*-----------------------------------------------------------
* .eb-format microcode image is started here (cases 4 and 5).
*-----------------------------------------------------------
Set[XTask, IP[EMU]];
	MC[FirstMapDirtyBitsAddr, LSHIFT[360, 10]];	* last 20C pages
	MC[SetVacant, 140000];
	MC[TestVacant, 30000];

BootOrStart: At[BootOrStartLoc],
	RBase← RBase[RTemp0];
	Call[TasksOff];
	T← 37000C;
	T← T OR (2C);
	Call[SetBRForPage];		* Read Map[37002B]
	RMap← RTemp0, Call[TestForVacant];
	branch[.+2, alu#0];
	 Branch[InitMap];		* vacant, do full map/mem init

	Fetch← RTemp0, T← 3000C;	* test if page contains valid data
	T← T OR (354C);
	pd← T XOR (Md);			* word 0 of germ is 3354C on Dorado
	 branch[.+2, alu = 0];		* branch if valid
	 Branch[InitMap];		* invalid (word 0 # 3354C)

	RBase← RBase[RealPages];
	Call[GetMemConfig];		* registers not set
	RBase← RBase[RTemp0], T← T-T-1, Branch[.+2];	* not vacant, fall through

*-----------------------------------------------------------
* InitMap returns here when done.
*-----------------------------------------------------------
StartEmulator:
	T← A0;				* Full initialization
	RBase← RBase[AEmRegs];
	ETemp4← T, TaskingOff;
	R400← 400C, Call[SetupBRs];	* returns with MemBase set up
	T← A0, NoReschedule;
	InsSetOrEvent← T;		* Disable event counters
	MaintPanel← A0, IFUReset;
	Call[RestoreALUFM];		* Restore ALUFM variables
* make sure keys are all 1's -- core image does not contain page 376b
	T← (R400) XOR (177433C);
	ETemp1← T-T-1, Cnt← 6S;		* Initialize 177033B..177041B
	T← (Store← T)+1, DBuf← ETemp1, Branch[., Cnt#0&-1];

*-----------------------------------------------------------
*  appropriate the last 64K of virtual memory, and use the last 16 pages for the extra
*   map dirty bits
*  start from the low end of virtual emmory and find the first vacant page, then then use
*   the preceeding pages of real memory for the map dirty bits.
*-----------------------------------------------------------

	RBase← RBase[RTemp0];
	Membase ← MapBitsBR, RTemp1← A0;
*  check if MapBitsBR has real already been assigned
	RMap← RTemp1;
	Call[WaitForMap];
	T← VaHi;
	RBase← RBase[RealPages], T← T + 1;
	PD← (VirtualBanks) XOR T;
	 branch[.+2, alu#0], T← (VirtualBanks) - 1;
	 branch[InitTasks];	* don't do again
	BrHi← T;
	T← RealPages, RBase← RBase[RTemp0];
	RTemp5← RSH[T, 14];			* no. of pages needed for dirty bits
	T← FirstMapDirtyBitsAddr;
	BrLo← T, RTemp0← A0;
	Membase← LPtr, T← RTemp1← A0;
	RTemp2← (BrLo← T);

Find1:
	T← (BrHi← RTemp1);
Find2:
	RMap← RTemp2;
	Call[TestForVacant];
	branch[FoundVacant, alu=0], RTemp2← (RTemp2) + (400C);
	branch[Find2, alu#0];
	RTemp1← (RTemp1) + 1, branch[Find1];

* RTemp2 now points 2 pages (1000C) beyond the last page mapped into memory
* RTemp1 has hi part of address in LPtr
* RTemp0 still has 0
* use RTemp4 to address relative to MapDirtyBR

FoundVacant:
	RTemp4← A0;
	RTemp3← SetVacant;
	RTemp2← (RTemp2) - (1000C);
Found1:
	branch[.+2, carry], RTemp1← (RTemp1) - 1;
	BrHi← RTemp1;
	BrLo← RTemp2;
* Flush all munches in this page before setting vacant
	RTemp6← A0, Cnt← 17S;
	RTemp6← Flush← RTemp6, Carry20, Branch[., Cnt#0&-1];
	TIOA← RTemp3;
	Map← 0s, Mapbuf← RTemp0;		* set real page to zero, mark as vacant
	Call[WaitForMap];

* returns with previous real page in T
	Membase← MapBitsBR;
	TIOA← RTemp0;				* set flag to zero
	Map← RTemp4, Mapbuf← T;
	Call[WaitForMap];
	RTemp5← (RTemp5) - 1;
	branch[Found2, alu<=0];
	RTemp4← (RTemp4) + (400C);
	Membase← LPtr;
	RTemp2← (RTemp2) - (400C), branch[Found1];

Found2:
	RBase← RBase[ETemp0], Branch[InitTasks];
*-----------------------------------------------------------
* Wait for map, returns current real page in T
*-----------------------------------------------------------
		Subroutine;
WaitForMap:
	PD← T - T - 1;
	T← PRef, branch[., alu<0];		* wait for map
	Return, T← Not (Map');

* Returns with alu=0 test for vacant
TestForVacant:
	PD← PRef;
	T← NOT (Map'), branch[.+2, alu>=0];	* wait for map
	 PD← PRef, branch[.-1];
	T← NOT (Errors');			* flags
	nop;
	T← T AND (TestVacant);
	PD← T XOR (TestVacant), Return;

Toplevel;

*-----------------------------------------------------------
* Task initialization routines all work according to the following pattern:
* XXXInitPC:
*	T← XXX, CoReturn;		* T← task number
*	first instruction of task initialization;
* Thus, calling XXXInitPC loads Link with the PC of the first instruction
* of the init routine and T with the task number.  These are precisely
* the arguments needed to do a LdTPC!
* Note: leave FF free in calls to the XXXInitPC routines.
* ETemp4 = 0 if booting, -1 if restarting emulator.
*-----------------------------------------------------------

InitTasks:
* First, init all non-emulator task PCs to -1.  ETemp1 = -1 here.
	ETemp0← 17C;
	Link← ETemp1;
	ETemp0← (ETemp0)-1, LdTPC← ETemp0;
	Branch[.-2, ALU#0];

* Now init specific task PCs
	Call[JNKInitPC];
	LdTPC← T, Wakeup[JNK];

	Call[EOTInitPC];
	LdTPC← T, Wakeup[EOT];

	Call[EITInitPC];
	LdTPC← T, Wakeup[EIT];

	Call[DSKInitPC];
	LdTPC← T, Wakeup[DSK];

	Call[FLTInitPC];
	LdTPC← T, Wakeup[FLT];

	Call[AUTInitPC];
	LdTPC← T, Wakeup[AUT];

* Display task initialization is slightly complicated, because the tasks
* must be set up according to whether the Alto terminal is hooked to the
* DispY board or the DispM board.
* DisplayInitConfig figures out what the configuration is, and sets a flag.
* Next, DHTInitPC and DWTInitPC return the starting PCs and task numbers
* for special (non-Alto terminal) microcode that may be present, or for
* dummy microcode in DisplayMain otherwise.
* Finally, THTInitPC and TWTInitPC return the starting PCs and task numbers
* for the Alto terminal microcode; the task numbers will be either AHT/AWT
* or DHT/DWT, depending on whether or not the DispM board is installed.
* If no DispM board is installed, this initialization will override the
* earlier DHT/DWT task initialization.
* Note: THTInitPC handles its own wakeup, since there's no way to
* issue Wakeup to a task given as a variable.

	IFUReset;			* Here to break consecutive .+1 constraints
	Call[DisplayInitConfig];
KnowRBase[TWTRegion];

	Call[DHTInitPC];		* For special display microcode
	LdTPC← T, Wakeup[DHT];
	Call[DWTInitPC];
	LdTPC← T;

	Call[THTInitPC];		* For Alto terminal microcode
	LdTPC← T;
	Call[TWTInitPC];
	LdTPC← T, RBase← RBase[AEmRegs];
	ETemp4, TaskingOn, Branch[.+2, R<0]; * Want to boot?
	Branch[GermBoot];		* Yes, go boot the Germ
	Branch[MGo];			* No, just start the Mesa emulator

*-----------------------------------------------------------
SetupBRs:
* Initialize all Base Registers.
* Clobbers T and ETemp.
*-----------------------------------------------------------
Subroutine;

	T← LShift[37, 10]C;		* MemBase addressed from A[3:7]
DoBRs:	ETemp← A0, MemBase← T;		* Init all registers to {0, 0}
	BRHi← ETemp;
	T← T-(400C);
	BRLo← ETemp, Branch[DoBRs, ALU>=0];
	MemBase← IOBR, Return;		* return with correct MemBase

*-----------------------------------------------------------
TasksOff:
* Reset all I/O devices.
* This is now accomplished simply by issuing an IOReset.
* IOReset is controlled by the manifold register addressed by 2240-2257,
* which has the following things in it (DMAdr[0:11]):
*	Bit 8:	EclUp		(normally 1)
*	Bit 9:	EnableRfPd'	(normally 0)
*	Bit 10:	IOReset'	(normally 1)
*	Bit 11:	RunRfsh		(normally 1)
* Returns with TaskingOff, RBase=AEmRegs.
*-----------------------------------------------------------
Subroutine;

	TaskingOff;
	T← A0, RBase← RBase[ETemp4];
	ETemp4← Link;
TopLevel;
	TIOA← T;			* Don't address any IO register
	ETemp1← 2000C;
	T← (ETemp1) OR (251C), Call[SetDMuxAddress]; * IOReset' ← 0
	UseDMD;
	T← (ETemp1) OR (253C), Call[SetDMuxAddress]; * IOReset' ← 1
Subroutine;
	Link← ETemp4;
	UseDMD, Return;

*-----------------------------------------------------------
RestoreALUFM:
* Restores the ALUFM variables to their standard values.
* Clobbers T
*-----------------------------------------------------------
Subroutine;

	T← AFM15;
	ALUFMRW← T, ALUF[15];
	T← AFM17;
	ALUFMRW← T, ALUF[17], Return;

*-----------------------------------------------------------
* some locations for doing code patching
* make sure FF is not used for LONGGO
*-----------------------------------------------------------
LX0:	TaskingOn;
	TaskingOn, PD← T;
	TaskingOn, Branch[.+2, ALU=0];
	TaskingOn;
	TaskingOn, PD← T;
	TaskingOn, Branch[.+2, ALU#0];
	TaskingOn;
LX7:	TaskingOn, Branch[LX0];

TopLevel;