*-----------------------------------------------------------
Title[XMFaultTask.mc...September 3, 1980 1:01 PM...Taft];
*-----------------------------------------------------------

%
Simple Alto Emulator fault task.
This version does a partial emulation of an Extended Memory Alto.
Specifically, it supports changing the emulator task’s alternate
bank register (for XMLDA, XMSTA, and BITBLT) and the display task’s
normal bank register (to move the display into XM).
It does NOT support emulating Alto instructions in XM.

If a fault occurs as a result of storing into write-protected page 377,
and the emulator’s or Alto display task’s bank register is the word
addressed, allow the store to proceed and also update the high part
of the appropriate base register. If any other word in page 377 was
addressed, ignore the store.

For any other fault, halts at one of the following breakpoints:

(In fault task, not having reset FaultInfo)
ManyFaultsMore than one fault
NotEmuFaultFault in non-emulator task
NotMapFaultMemory system fault other than map fault
UnknownFaultFault of unknown origin

(In emulator task, having reset FaultInfo)
StackErrorStack error from Alto emulator
MapFaultMap fault from Alto emulator

In the case of faults passed to the emulator task, interesting information
is left in R-registers, as follows:
FltErrorsNOT (Errors’)
FaultInfoNOT (Pipe2’)
FltEmuPCEmulator TPC at time of fault
FaultValDBuf -- value being stored if faulted on Store←
%

* Alto XM bank register addresses
MC[ADispWordTaskReg, 177751];
MC[Task0XMReg, 177740];
MC[XMBankRegArea, 177740];

*-----------------------------------------------------------
* Fault Task
*-----------------------------------------------------------

Set[XTask, IP[FLT]];

Subroutine;
FLTInitPC:
T← FLT, CoReturn;
TopLevel;

T← A0, RBase← RBase[FaultInfo];
TIOA← T, Block;

FaultTask:
FltErrors← NOT (Errors’);* Read this always
FaultInfo← NOT (Pipe2’);* Doesn’t clear FaultInfo

* Test for memory system fault
T← (FaultInfo) AND (fi.numfaults);
PD← T XOR (fi.numFaults);* See if we have all bits set;
T← Pointers, Branch[CheckStackErr, ALU=0]; * All ones => no fault

* Memory system fault, see what kind
PD← (FaultInfo) AND (fi.numFaults); * All zeroes => one fault
PD← (FaultInfo) AND (fi.emuFault), Branch[ManyFaults, ALU#0];
PD← (FltErrors) AND (pipe4.notMapTrouble), Branch[NotEmuFault, ALU=0];
Branch[NotMapFault, ALU#0];

* Emulator map fault. Clear it and pass fault to emulator.
B← FaultInfo’, Branch[EmuFault];

* Not memory system fault, check for stack overflow or underflow
CheckStackErr:
PD← T AND (300C);* 200 = stack overflow, 100 = stack underflow
Branch[UnknownFault, ALU=0];

* Emulator map fault or stack error.
* Save emulator’s state and restart emulator at Fault0.
EmuFault:
FaultVal← DBuf;
RdTPC← EMU;
FltEmuPC← NOT (Link);* TPC data is complemented
Call[GetEmuFaultPC];
LdTPC← T;
Block, Branch[FaultTask];

* Fault conditions that we can’t handle:
ManyFaults:
Branch[.], Breakpoint;* More than 1 fault
NotEmuFault:
Branch[.], Breakpoint;* Not Emulator fault
NotMapFault:
Branch[.], Breakpoint;* Not map fault
UnknownFault:
Branch[.], Breakpoint;* Don’t know what fault occurred

*-----------------------------------------------------------
* Emulator Task
* The emulator is restarted here by the fault task after an emulator
* map fault or stack error.
*-----------------------------------------------------------

Set[XTask, IP[EMU]];

Subroutine;
GetEmuFaultPC:
T← EMU, CoReturn;
TopLevel;

Fault0:
RBase← RBase[EmuBRHiReg];
Q← EmuBRHiReg;
RBase← RBase[FltPipe0];
PD← (FaultInfo) AND (fi.numFaults); * Which kind of fault?
FaultMapVal← NOT (Map’), Branch[StackError, ALU#0];
T← VAHi;
FltPipe0← T AND (7777C);* only want low bits
FltPipe1← VALo;
T← (FltPipe1) AND (177400C);* See if VA = page 377 in MDS
T← T XOR (177400C);
T← T XOR (FltPipe0);
T← T XOR Q;* Q = EmuBRHiReg
T← (FltPipe1) AND (XMBankRegArea), Branch[MapFault, ALU#0];

* check if storing into an XM bank register
PD← T XOR (XMBankRegArea);
PD← (FltPipe1) XOR (Task0XMReg), Branch[IgnoreStore, ALU#0];
PD← (FltPipe1) XOR (ADispWordTaskReg), Branch[Task0XM, ALU=0];
DblBranch[DispXM, XMBStoreOnly, ALU=0];

* Set alternate bank for emulator task
Task0XM: T← (FaultVal) AND (3C);
* [14:15] alternate bank bits
EmuXMBRHiReg← T, Branch[XMBStoreOnly];

* Set normal bank for display task
DispXM: T← LDF[FaultVal, 2, 2];
* [12:13] normal bank bits
T← T+Q, Call[SetDisplayBRHi];* Q = EmuBRHiReg

* Momentarily write-enable page 377 and store the value into the bank register
XMBStoreOnly:
MemBase← MDS;
Flush← FltPipe1;* invalidate possible cache entry
FltTemp← MD, T← TIOAusedMapEntry;
T← FltPipe1, TIOA← T;
Map← T, MapBuf← FaultMapVal;* turn off write protect
T← FltPipe1, Call[WaitForMapBuf];
Store← T, DBuf← FaultVal;* do the actual store
FltTemp← MD, T← TIOAwProtect;* wait for store
Flush← FltPipe1;* clear entry from cache
FltPipe1← MD, T← FltPipe1, TIOA← T; * wait for flush
Map← T, MapBuf← FaultMapVal;* restore wProtect
Call[WaitForMapBuf];

*-----------------------------------------------------------
* Restart the current instruction -- the instruction following the
* one that caused the fault. All instructions must wait for faults before
* changing any permanent state, and instructions that can cause faults
* (presumably only STA) must do so as their last microinstruction, so
* it is guaranteed that a new instruction will have begun by the time
* the fault occurs.
*-----------------------------------------------------------
IgnoreStore:
T← A0, RBase← RBase[AEmRegs];
TIOA← T;
Branch[AEmuReschedule];* whew!!!

*-----------------------------------------------------------
* Faults that can’t be handled.
*-----------------------------------------------------------
StackError:
Branch[.], Breakpoint;
MapFault:
Branch[.], Breakpoint;