*-----------------------------------------------------------
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];