*-----------------------------------------------------------
Title[AEm0.mc...January 27, 1984  3:08 PM...Taft];
* Alto Emulator initialization and software boot sequence.
*-----------------------------------------------------------

*-----------------------------------------------------------
* Canonical place to restart the Alto Emulator running as DHT or AHT task.
* Display task branches here when it sees the boot button down.
*-----------------------------------------------------------
TopLevel;
Set[XTask, IP[DHT]];
DontKnowRBase;

Boot:	Call[TasksOff];
	Call[EmuInitPC];		* Set emulator PC to "SW"
	LdTPC← T, TaskingOn;
	Block, Branch[.];

*-----------------------------------------------------------
* Start at StartEmulator during a full initialization (from InitMap).
* Start at SW during a self-initiated "hot boot" (forced by display task).
* Start at RestartEmulator for "soft-restart" -- restart I/O devices and
* resume the Alto emulator, without disturbing registers or main memory.
* Start at MBS to start an already-loaded core image whose starting PC is
* in location 0 (this is the convention for Ether-bootable programs).
*-----------------------------------------------------------
Set[XTask, IP[EMU]];
DontKnowRBase;

* For full initialization, reset the default disk partition and
* request "cold boot" (reset memory).
StartEmulator:
	ETemp4← A0, Branch[ResumeEmulator];

* For emulator soft-restart, request "hot boot" (don't disturb memory).
RestartEmulator: At[RestartEmulatorLoc],
	Call[TasksOff];
	ETemp4← T-T-1, Branch[InitMapWarm];

* for starting a core image loaded by Midas
MBS: At[MBEmulatorLoc],
	Call[TasksOff];			* Returns with T=0
	ETemp4← T+1, Branch[InitMapWarm]; * ETemp4← odd, start existing core image

Subroutine;
EmuInitPC:
	T← EMU, CoReturn;		* Return EMU start PC
TopLevel;
DontKnowRBase;
SW:
	T← 2C;
	ETemp4← T;			* Full boot but don't change partition

* Back here from InitMapWarm
* ETemp4 signals what to do:
* -1 => soft restart (resume emulator after microcode initialization)
* 0 => full boot
* 1 => start core image that has been loaded manually (e.g., by Midas)
* 2 => full boot without changing disk partition
ResumeEmulator:
	TaskingOff;
	RBase← RBase[AEmRegs];
	R400← 400C, Call[SetupBRs];	* returns with MemBase set up
	T← T-T-1, ETemp4, Branch[InitTasks, R<0]; * Skip following stuff if hot boot
	Cry← T← A0, NoReschedule;
	InsSetOrEvent← T;		* Disable event counters
	NWW← 100000C;			* Start with interrupts disabled
	spAC0← T← Add[nspAC0]C;		* Set up alto emulator RM constants
	spAC1← T← T+1, IFUReset;
	spAC2← T← T+1, Cnt← 2S;
	spAC3← T+1, Call[RestoreALUFM];	* Restore ALUFM variables

* make sure keys are all 1's -- core image does not contain page 376b
	T← (R400) XOR (177434C);
	T← (Store← T) + 1, DBuf← -1C, Branch[., Cnt#0&-1]; * 177034 .. 177036
	Store← T, T← DBuf← -1C;		* 177037

*-----------------------------------------------------------
* 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.  T = -1 here.
	ETemp0← 17C;
	Link← T;
	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.

	Nop;				* Placement
	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[AEmuNext, R<0]; * Want to boot?
	PD← ETemp4, Branch[ABoot, R Even]; * Yes, Alto emulator
	Branch[StartMB];		* starting midas loaded memory

*-----------------------------------------------------------
* Alto software boot sequence.
* Read keyboard to decide whether to boot from disk or Ethernet.
*-----------------------------------------------------------

ABoot:
* If appropriate, reset the disk partition to the maximum possible.
	RBase← RBase[DefaultPartition], Branch[.+2, ALU#0];
	DefaultPartition← MaxPartition;
	RBase← RBase[AEmRegs];

* Wait at least 100 ms to allow terminal to update all keyboard words.
* There are 5 of these, sent at 17 ms intervals.
	T← (R400)+(30C);		* RTC = VM 430
	ETemp0← (Fetch← T)-(10C);
	Store← ETemp0, DBuf← 0C;	* Zero the display list (VM 420)
	ETemp0← (3S)+MD;		* now + 3*39 ms
	PD← (ETemp0)-MD;
	Fetch← T, Branch[.-1, ALU>=0];

	ETemp3← A0, IFUReset;		* ETemp3 used in DiskBoot
	T← (R400) XOR (177434C);	* VM 177034 = first keyboard word
	T← (Fetch← T)+1;
	T← (Fetch← T)+(2C), ETemp0← MD; * ETemp0← word 0
	T← (Fetch← T)-1, ETemp1← MD;	* ETemp1← word 1
	Fetch← T, T← A0, ETemp2← MD,	* ETemp2← word 3
		ETemp0, Branch[EBoot, R even];	* Branch if BS key was down


*-----------------------------------------------------------
* Disk boot.
*-----------------------------------------------------------

* If any of the digits 1 through 9 is pressed down, reset the default disk
* partition as specified (1 through 5 => partitions 1 through 5;
* 6 through 9 => partitions 16 through 19).
	PD← MD, Call[SelectPartitionIfKey]; * "1" -- MD = word 2 here
	PD← LSH[ETemp1, 1], Call[SelectPartitionIfKey]; * "2"
	PD← ETemp1, Call[SelectPartitionIfKey]; * "3"
	PD← LSH[ETemp0, 1], Call[SelectPartitionIfKey]; * "4"
	PD← ETemp0, Call[SelectPartitionIfKey]; * "5"
	T← 17C;
	PD← LSH[ETemp0, 2], Call[SelectPartitionIfKey]; * "6" => 16
	PD← LSH[ETemp0, 4], Call[SelectPartitionIfKey]; * "7" => 17
	PD← LSH[ETemp2, 5], Call[SelectPartitionIfKey]; * "8" => 18
	PD← LSH[ETemp1, 6], Call[SelectPartitionIfKey]; * "9" => 19

* Disk boot (cont'd)

* Make up disk command starting at location 431 (cursor bit map).
* Code depends on command block address being odd. ETemp3=0 here.
DiskBoot:
	ETemp2← 17C;			* Init retry count
DiskBootRetry:
	T← (R400)+(31C);
	T← (Store← T)+1, DBuf← ETemp3;	* next CB pointer = 0
	T← (Store← T)+1, DBuf← ETemp3;	* initial status = 0
	ETemp0← (Store← T)+1, DBuf← ACmmdSeal; * read command
	T← (R400)+(2C);
	ETemp0← (Store← ETemp0)+1, DBuf← T, * Store both header and label at 402
		Branch[., R even];	* This instruction is executed twice
	ETemp0← (Store← ETemp0)+1, DBuf← 1C; * Store data at 1
	ETemp0← (Store← ETemp0)+1, DBuf← 0C, * Normal and error interrupts = 0
		Branch[., R odd];	* This instruction is executed twice
	PD← (ETemp2) AND (7C);		* Every 8 retries do a restore first
	T← (ETemp0)+1, Branch[.+2, ALU=0]; * Unused word
	Store← T, DBuf← 0C, Branch[.+2]; * diskAddr = 0
	Store← T, DBuf← 1C;		* diskAddr = 0 and restore

* Issue the disk command.
	T← (R400)+(123C);		* 523B
	T← (Store← T)-1, DBuf← -1C;	* previous diskAddr unknown
	ETemp1← (Store← T)-1, DBuf← 0C;
	T← (R400)+(31C);
	Store← ETemp1, DBuf← T;		* 521b← 431b -- address of disk command

* Wait up to 1 second for disk status to appear in location 432
	T← (R400)+(30C);		* VM 430 = real time clock
	Fetch← T, ETemp0← 33C;
	ETemp0← (ETemp0)+MD;		* Now + 27*39 ms
KWait:
	ETemp1← (Fetch← T)+(2C);	* VM 432 = status for disk command
	PD← (ETemp0)-MD-1;
	Fetch← ETemp1, ETemp1← DoneStatus, Branch[KBootTimeout, ALU<0];
	PD← (ETemp1) AND (MD), ETemp1← MD;
	PD← (ETemp1) AND (377C), Branch[KWait, ALU=0]; * error bits in status word

	ETemp2← (ETemp2)-1, Branch[.+2, ALU#0];
	T← 1C, Branch[Start];		* Successful, PC←1 and run the code

	Branch[DiskBootRetry, ALU>=0];	* too many tries?
DiskBootError:
	Branch[EBoot];			* If hard error, do an Ether boot instead
KBootTimeout:
	Branch[EBoot];			* If timeout, do an Ether boot instead


*-----------------------------------------------------------
SelectPartitionIfKey:
* Facilitates testing keys for partition selection.
* Increments T; then, if ALU>=0 upon entry, sets the disk partition to T
* and branches to DiskBoot instead of returning.
*-----------------------------------------------------------
Subroutine;

	T← T+1, Branch[.+2, ALU>=0];
	Return;
	DefaultPartition← T, Branch[DiskBoot];

*-----------------------------------------------------------
SetupBRs:
* Initialize all Base Registers.
* EmuBRHiReg contains the high part of MDS, the BR defining the 64K region
* within which the Alto Emulator executes.  It was set by InitMap. 
* Clobbers T and ETemp0.
*-----------------------------------------------------------
Subroutine;

	T← LShift[37, 10]C;		* MemBase addressed from A[3:7]
DoBRs:	ETemp0← A0, MemBase← T;
	BRHi← EmuBRHiReg;
	T← T-(400C);
	BRLo← ETemp0, Branch[DoBRs, ALU>=0];

* IO base registers used for negative indexing {EmuBRHiValX,,xxx}
	T← (EmuBRHiReg)-1, MemBase← EIBR;
	BRHi← T;
	MemBase← EOBR;
	BRHi← T;
	MemBase← MDS, 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, T=0.
*-----------------------------------------------------------
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;
	T← A0, UseDMD, 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];