%File: Initial.mc

Edited by Jim Frandeen, March 2, 1980 11:27 AM Delete Includes for Integration Procedure
Edited by Joiner, February 28, 1980 2:54 PM recognize TOR for ether booting in
bold
Edited by Johnsson, February 4, 1980 5:00 PM
%

TITLE[Initial];
Insert[D0MPCodes];
*Error Codes for Fault Handler not in d0mpcodes
MC[MOBCrash,202];
*Map Out of Bounds
MC[H4PECrash,203];
*H4PE
MC[MOB&H4PECrash,204];
*MOB and H4PE
MC[MC2Crash,205];
*MC2 error when unable to handle it by RETURNing
MC[MC22Crash,206];
*2 MC2 errors
MC[MC1Crash,207];
*MC1 fault when emulator couldn’t accept it
MC[NStkCrash,166];
*Not Stack over/underflow (8 bits)

SETTASK[17];

RV[REFR,77];
*memory refresh address
RV[PipeReg,60]; *Pipe Ram Entry goes here
MC[pPipeReg,360];
MC[pPipeReg2,362];
RV[PipeReg1,61];
RV[PipeReg2,62];
RV[PipeReg3,63];
RV[PipeReg4,64];
RV[PipeReg5,65];

SET[H4Disp,240];
SET[MC2ErDisp,260];

*The following registers hold the volatile state of the processor on a fault:
RV[RXALU,76];
*ALU result and SALUF
RV[RXAPC,75];
*APCTask&APC
RV[RXCTASK,74];
*CTASK.NCIA
RV[RXPPB,73];
*Page,Parity,BootReason
RV[RXSTK,72];
*Stackpointer

RV[RTMP,71];
*temporary


RV[FFAULT,66];

SetTask[0];
RV[BootType, 20];
MC[pRTEMP1,IP[RTEMP1]];

Macro[LowHalf, and[#1,377]c];
Macro[HighHalf, and[#1,177400]c];

Set[InitBase, add[lshift[InitialPage, 10],100]];

SET[Qloc,ADD[InitBase,30]];
MC[QxL,AND[Qloc,377]];
MC[QxH,OR[150000,AND[Qloc,7400]]];

SET[QretLoc,Add[InitBase,32]];
MC[QRetL,AND[QretLoc,377]];
MC[QretH,AND[QretLoc,7400]];

Set[Task17Start, add[InitBase, 20]];
Set[Task16Start, add[InitBase, 22]]; *does a call => needs two locations
Set[MidasStopLoc, add[InitBase, 25]]; *uses two locations
Set[DeviceDispatch, add[InitBase, 40]];

OnPage[InitialPage];
SAAltoStart:
BootType ← 0c, goto[Qtask], at[InitBase, 0];
SAPilotStart:
BootType ← 1c, goto[Qtask], at[InitBase, 1];
EtherAltoStart:
BootType ← 2c, goto[Qtask], at[InitBase, 2];
EtherPilotStart:
BootType ← 3c, goto[Qtask], at[InitBase, 3];
EtherTestStart:
BootType ← 17c, goto[Qtask], at[InitBase, 17];

Qtask:
RTEMP ← QxL; *Quiesce tasks 15b - 1
RTEMP ← (RTEMP) or (QxH);
RTEMP1 ← pRTEMP1;
stkp ← RTEMP1;
RTEMP1 ← QRetL;
RTEMP1 ← (RTEMP1) or (QRetH);
Qloop:
APC&APCTASK ← RTEMP;
initRET:
return; *goes to Qx

Qx:
APC&APCTASK ← stack,call[initRET], AT[Qloc]; *Notify comes here. Leave task’s TPC pointing at Qxy. Stack points at RTEMP1.
Qxy:
goto[initRET]; *must spend two instructions in the task

Qret:
lu ← ldf[RTEMP,0,3], AT[QretLoc]; *RTEMP1 points to this location
RTEMP ← (RTEMP) - (10000c), dblgoto[ZapDevices, Qloop, alu=0];

ZapDevices:
T ← RTEMP1 ← 177400C;
RTEMP ← 300c;
ZapDloop1:
OUTPUT[RTEMP];*send 300 to register 0 of all devices
T ← RTEMP1 ← (RTEMP1) + (20c);
goto[ZapDloop1,ALU<0];
T ← RTEMP1 ← 177400C;
RTEMP ← 0c;
ZapDloop2:
OUTPUT[RTEMP];*send 0 to register 0 of all devices
T ← RTEMP1 ← (RTEMP1) + (20c);
goto[ZapDloop2,ALU<0];


* Initialize tasks 17 and 16
RTEMP ← HighHalf[or[Task17Start,170000]];
RTEMP ← (RTEMP) or (LowHalf[Task17Start]);
APC&APCTASK ← RTEMP, call[initRET];

RV[temp,51];
RV[initr0,52];
RV[initr1,53];
RV[initr2,64];
RV[initr3,65];

*Timers are cleared, refresh is running, start reason in BootType
Task0:
initr0 ← (50000C); * write fault instruction at[1]
initr0 ← (initr0) or (150c);
initr1 ← (65000C);
initr1 ← (initr1) or (1c);
initr2 ← (15C);
initr3 ← (1C);
t ← initr2 ;
LU ← initr0;*T has data 2
APC&APCTASK ← initr3;
WRITECS0&2;
LU ← initr1;
APC&APCTASK ← initr3;
WRITECS1;
T ← StartMapInit, call[ShowNumber];
goto[IMAP];
MemInitDone:
Dispatch[BootType,14,4];
Disp[SAAlto];

* SA loader has two entry points depending on whether you want
* Alto boot or Pilot boot.
SAAlto:
T ← StartDiskBoot, goto[SACommon], at[DeviceDispatch,0];
SAPilot:
T ← StartDiskBootPilot, goto[SACommon], at[DeviceDispatch,1];
SACommon:
call[ShowNumber];
LoadPage[SalLoaderPage];
BootType, dblgoto[SA4000Load, SA4000LoadPilot, REven];

* Ether loader takes a microcode boot file index (bfi) in T. The index
* is used to select a boot file number (bfn) in the range 3000-3777.
EtherAlto:
BootType ← 1c, goto[EBCommon], at[DeviceDispatch,2];
EtherPilot:
BootType ← 3c, goto[EBCommon], at[DeviceDispatch,3];
EtherTest:
BootType ← 17c, goto[EBGo], at[DeviceDispatch,17];

* We know whether we want Alto or Pilot code. We must decide what IO
* devices are on the machine. Only Display is interesting now. The
* choices are:
*
UTLF, Dallas keyboard, UTVFC (bit clock rate 3)
*
CSL display & keyboard, UTVFC (bit clock rate 5)
* The number entering in temp is incremented by 1 to select CSL display.

EBCommon:
T ← 0c;
RTEMP ← 60c, call[SrShift]; * set all device tasks to 17
T ← 20c;
RCNT ← (zero) - (T); * don’t look forever
T ← 3c;* use task 14 for test
IDLoop:
RTEMP ← 4c, call[SrShift];
T ← lshift[14,4]c;
Input[RTEMP];
T ← 5000c;* UIB ID
lu ← (lhmask[RTEMP]) xor (T);
T ← 1000c, skip[alu#0];* UTVFC ID
GOTO[EBGo], BootType ← (BootType) + (4c);* TOR display
lu ← (lhmask[RTEMP]) xor (T);
RCNT ← (RCNT) + 1, skip[alu=0];
T ← 0c, dblgoto[IDLoop, NoDisplay, alu<0];
RTEMP ← ldf[RTEMP,10,5];* get bit clock rate
lu ← (RTEMP) xor (5c);
skip[alu#0];
BootType ← (BootType) + 1;* CSL display
EBGo:
T ← (BootType) + (StartEtherBoot);
T ← (BootType) + (T), call[ShowNumber];* StartEtherBoot+(2*bfi)
LoadPage[EtherPage];
T ← BootType, gotop[EtherLoad];

NoDisplay:
T ← NoUTVFC, goto[InitFail];

* return here with address of loaded code in T.
MicrocodeLoaded:
LP ← MicrocodeAddress, at [MicrocodeLoadedLoc];
T ← LPhi ← 0c;
xfTemp1 ← T, LoadPage[LRJPage];
RTEMP1 ← 0c, gotop[LRJEnter];

* Enter with value in T, shift count in RTEMP.
* Value is rotated right after each shift.
SrShift:
RTEMP1 ← T;
RTEMP ← (RTEMP) - 1, GenSrClock;
T ← RTEMP1 ← rcy[RTEMP1,1], goto[.-1, alu#0];
return;

InitFail:
RTEMP ← T, call[SNx];
goto[.];

ShowNumber:
RTEMP ← T;
SNx:
LoadPage[0];
T ← (RTEMP) + (MPOffset), gotop[PNIP];

SetTask[17];

RTMP ← (400C), AT[Task17Start];*set Printer idle, don’t drive bus
Printer ← RTMP;

RTMP ← (100000C);
ClearTimers:
LOADTIMER[RTMP];*Clear out all Timers
RESETMEMERRS;*Clear any pending memory errors
RTMP ← (RTMP) + 1;
LU ← (RTMP) AND (17C);*there are 16d timers
REFR ← (0C), GOTO[ClearTimers, ALU#0];

LU ← TIMER;*Set up the Refresh timer
RTMP ← (50000C);
RTMP ← (RTMP) OR (257C);*simple timer,value 10d,slot 17b
LoadTimer[RTMP];

*Notify task 16 to set up timer task
RTMP ← HighHalf[or[Task16Start,160000]];
RTMP ← (RTMP) OR (LowHalf[Task16Start]);
APC&APCTASK ← RTMP, goto[InitRet];

SetTask[16];
Call[TimerRet], AT[Task16Start]; *Set TPC[16] to TimerTask

*The simple timer task assumes slot 17 expired, since all others were cleared.
TimerTask:
Refresh[REFR];
lu ← Timer;*read timer to clear the wakeup
REFR ← (REFR) + (20c);
RTMP ← (50000C);*build timer constant
RTMP ← (RTMP) OR (257C);*simple timer,value 10d,slot 17b
AddToTimer[RTMP];
CheckStop:
T ← (FFault) and (10000c);
LU ← (Printer) AND (T) ;
GOTO[MidasStop,ALU#0] ;
TimerRet:
RETURN;

*Midas recognizes a mouse halt as a task 16 breakpoint that was
*not set by the user. It continues from (absolute) MidasStop+1
MidasStop:
LU ← T, goto[.], SetFault, at[MidasStopLoc];
MidasRestart:
return, at[MidasStopLoc,1];


*Fault handler
*Determine what to do based on the type of error and bits in FFAULT RM 366).
*Bits in FFAULT are:
*
0: MC2 errors RETURN if 1, crash if 0
*
2: H4PE errors from task 7 Return to the task that faulted rather
*
than crashing (because of Ethernet problem of delivering H4PE’s
*
if a malformed packet arrives)
*
3: Midas is present (1), so "crash" means breakpoint, else put a
*
code in MP and halt.
*
15: MC1/StackOvf errors handled by notifying PFEntry in emulator (1),
*
or by crashing (0)

*The following code (nearly a copy of the page 0 code in Kernel) sends
*control to FaultStart after saving state, and FaultStart figures out whether
*Midas is present and whether to send a breakpoint or a fault message.
SetTask[17];
*Page Zero stuff
*
T ← APCTASK&APC, AT[1];*Fault entry. Save APC first, then the other volatile regs.
RXAPC ← T, At[100];
T ← CTask&NCIA, At[101];
RXCTask ← T, At[102];
T ← (SStkP&NStkP) xor (377C), At[103];*uncomplement StkP
RXStk ← T, At[104];
RTMP ← 20C, At[105]; *Set StkP to 20 in case stk ovf was pending
StkP ← RTMP, At[106];
T ← (ALUResult&SALUF) xnor (0C), At[107];*aluresult, saluf both read complemented
RXALU ← T, At[110];
T ← Page&Par&Boot, LoadPage[0], At[111]; *page, parity, bootreason
RXPPB ← T, ResetErrors, Goto[FaultStart], At[112];

FaultStart: lu ← (RXPPB) and (3000C), At[120]; *test R & CS parity
Goto[RCSErr,ALU#0], lu ← (RXPPB) and (400C);*test memory error
Goto[MC12Err,ALU#0], lu ← (RXPPB) and (4000C);*test stack ovf
Goto[TryBP,ALU=0];
StkEr:
Goto[Crash], T ← StkCrash;

RCSErr:
T ← RCSCrash, Goto[Crash];

TryBP:
T ← BPCrash, Goto[Crash];

*Get here with error code in T. If Midas is present, breakpoint. Otherwise,
*put the code into the maintenance panel and halt.
Crash:
lu ← LdF[FFAULT,3,1];
Goto[Midas,ALU#0], PipeReg5 ← (Lsh[PipeReg5,10]) or T; *save error code in right half of PipeReg5
RTMP ← MPOffset;
T ← (RTMP) + (T), call[PNIP]; *add offset to fault code and then display it
Goto[.];

Midas:
RTMP ← 117c;
*Reformat saved Pipe into RM 100-105 for Midas. Note that pipe info (other
*than crash code and task number) is only interesting if CrashCode=205
StkP ← RTMP;

SetTask[4]; *To allow symbolic names for RM 100-106
RV[MapEntryNumber,0];
RV[TaskNumber,1];
RV[RefType,2];
RV[CrashCode,3];
RV[CardNumber,4];
RV[MapFlags,5];
RV[QuadAddr,6];
RV[Syndrome,7];
SetTask[17];

T ← LdF[PipeReg,11,7]; *map row address
PipeReg1 ← (Lsh[PipeReg1,7]) or T;
*Map location (page number) in bits 2-17b...
*goes into location 100 (but the bits are inverted)
T ← LdF[PipeReg1,2,16], Call[FltPsh];
Stack ← (Stack) xnor (140000C); *now contains the virtual page number

T ← 17C;*task number (upright)...
T ← (LdF[PipeReg2,10,4]) xor T, Call[FltPsh]; *into location 101

T ← 17C;*reference type (upright)...
T ← (LdF[PipeReg2,14,4]) xor T, Call[FltPsh]; *into location 102

T ← RHMask[PipeReg5], Call[FltPsh]; *Crash code into 103

T ← 7C;
T ← (LdF[PipeReg5,4,3]) xor T, Call[FltPsh]; *Card no. (0..7) into 104

T ← 17C;
T ← (LdF[PipeReg5,0,4]) xor T, Call[FltPsh]; *Map Flags (4 bits) into 105

T ← LdF[PipeReg4,12,6];*Main column address (6 bits)
T ← (Lsh[PipeReg3,6]) or T;*And Blk.1,,main row address
T ← (Lsh[PipeReg5,16]) or T;*And Blk.0...
*The (15-bit) quadword number within a 128k card. Bits 1:2 give block number.
T ← (Zero) xnor T, Call[FltPsh];*All upright into 106

T ← Rsh[PipeReg,10], Call[FltPsh];*Interesting syndrome into 107

lu ← LdF[RXPPB,4,4];*test parity register
RTMP ← 177400C, Skip[ALU#0];*Notify Midas at 7510b or 7512b
RTMP ← (RTMP) or (110C), Goto[MidasNotify];*Go overlay ’Break’
RTMP ← (RTMP) or (112C);*Go overlay ’MidasFault’
MidasNotify:
APCTask&APC ← RTMP, Goto[PNret];
FltPsh:
UseCTask, Stack&+1 ← T, Goto[PNret];

MC12Err:
StkP ← RXSTK;*not stack error, restore pointer
ReadPipe[PipeReg];*get A pipe
Dispatch[PipeReg,4,2];*dispatch on H4pe, MapBnd
Dispatch[PipeReg,0,2], Disp[NoH4BndEr];*dispatch on MC2ErA’, MC2ErB’

NoH4BndEr: *test MC1ErA’ bit
lu ← (PipeReg) and (20000C), Disp[MC2ErAB], AT[H4Disp,0];
BndEr:
T ← MOBCrash, Goto[Crash], AT[H4Disp,1];*MOB error only
H4Er:
RTMP ← H4PECrash, Goto[Crash], AT[H4Disp,2];
*Note: the following is not quite correct, since a REAL MOB error will be
*continued if it occurs with an H4PE. Life is hard...
H4BndEr:
RTMP ← MOB&H4PECrash, Goto[Crash], AT[H4Disp,3];*H4PE & MOB



*Both MC2 A & B error--crash
MC2ErAB:T ← MC22Crash, Goto[Crash], AT[MC2ErDisp,0];
T ← LHMask[MemSyndrome], Goto[MC2Er], AT[MC2ErDisp,1];*MC2A error
ReadPipe[PipeReg], ResetMemErrs, Goto[MC2ErB1], AT[MC2ErDisp,2];*MC2B error--read pipe entry
Skip[ALU=0], ResetMemErrs, AT[MC2ErDisp,3];*Branch if MC1ErA’ = 0
ReadPipe[PipeReg], ResetMemErrs;*MC1B error--read pipe entry
MC1Er:
FFAULT, T ← MC1Crash, goto[Crash];

MC2ErB1:T ← Lsh[MemSyndrome,10];
MC2Er:
ResetMemErrs;
lu ← LdF[FFAULT,0,1]; *check for Return (1) or crash (0)
*Stash the proper syndrome in PipeReg[0:7]
PipeReg ← (RHMask[PipeReg]) or T, Skip[ALU#0];
T ← MC2Crash, Goto[Crash];
Return;


*dummy version of DoInt. Task iff T<0 on entry.
SetTask[0];
RV[R0,0];
DoInt:
R0 ← T;
R0, skip[R<0];
UseCTask;
return;

PNIP:
usectask, RTEMP ← T;
T ← APC&APCTask;
RCNT ← T, ClearMPanel, call[.+1];
PNloop:
RTEMP1 ← 4C;
RTEMP1 ← (RTEMP1)-1, dblgoto[.+1,.,ALU<0];
RTEMP ← (RTEMP) - 1;
lu ← ldf[RCNT,0,4], goto[PNdone, ALU<0];
skip[alu#0];
IncMPanel, return; * task =0, tasking ok
IncMPanel, goto[PNloop]; * task #0, tasking not allowed
PNdone:
APC&APCTask ← RCNT;
PNRet:
return;

:End[Initial];