%
Page Numbers: Yes First Page: 1
Heading:
memPipeAndFaultA.mcJune 17, 1981 8:49 AM%
title[memPipeAndFaultA];
top level;

%
June 17, 1981 8:20 AM
add iapMap to make it easy to cause faults -- they occurred by chance before.
June 16, 1981 5:22 PM
Change apMakeNFlts to avoid reusing same address and yet to stay in same cache row.
June 16, 1981 4:07 PM
Change faulttask to wait one more cycle after B←FaultInfo before blocking.
June 15, 1981 11:28 AM
Change faultTasks to save FaultInfo in Q. Remove faultTaskContinueLoc.
June 1, 1981 3:07 PM
More fixes to pipe for model 1.
May 29, 1981 11:12 AM
Remove comments around various pieces of code -- they were commented-out
to accommodate MicroD placement. This is first step in rejuvenating this test.
May 4, 1979 5:11 PM
Change code to use WriteMap instead of defunct xWriteMap, and change it to use sUseDefaultMcr instead of defunct saSetMcr.
May 4, 1979 3:40 PM
Convert to model 1 from model 0 sources.
%
%
A FEW RULES

Subroutines clobber rscr, rscr2 and T unless otherwise specified at both point of call and in subroutine description. Subroutines return single values in T, and they accept single values in T. Two parameter subroutines accept their values in rscr and rscr2.
Global values for S board

Abbreviations used herein
iInit
MMap
colColumn
SStorage
aAll
pPipe
apAllPipe (test pipe, use all of memory system)
nextFooincrements foo loop variable, returns with fast branch condition to check for done w/ loop
getFooreturns current value of loop variable, foo
getFooRtnsubroutine that returns in T the saved value of foo’s return link
iFooCtrlinitialize foo loop control
%

* June 19, 1978 5:59 PM
%
Memory Pipe And Fault Test
testPipeAndFault: PROCEDURE =
BEGIN
initFaultTask[];
FOR testTask IN [1..14] DO
FOR srn IN [ 1..15] DO
setUpMemory[];-- mem[0..17] in cache, cache row1 dirty, mem[20..37] absent.
TPC[testTask] ← @pipeTaskCode;
NOTIFY[testTask, srn];
ENDLOOP;
ENDLOOP:
disableFaultTask[];
END
pipeTaskCode: PROCEDURE[taskX, srn: CARDINAL]; =
BEGIN
--check RefType: 0 =>undefined, 1 =>storage read, 2 => storage write, 3 => map or non-storage op
-- check task, subtask, nFaults, faultSRN

setRBASE[defaultRegion];
taskingOn[];
aSetAsrnForWrite[srn];
* since this code makes faults it must xqt as taskX for faultTask to do right thing
t← FaultInfo[];* this clears the faultInfo data in the pipe
SETBR[0,0];
t ← mem[0];
-- ref 0
aIncAsrn[];
mem[1] ← 1;
-- ref 1
aIncAsrn[];
t ← 20c;
-- ref 2: miss & force storage write (see setUpMemory)
FETCH ← t;
t ← MD;
useSrn ← srn;
FOR i IN [0..2] DO
setPROCSRN[useSRN];
myPipe2 ← PIPE2[];
refType ← IF i = 2 THEN 2 ELSE 1;
IF myPipe2.ref # refType THEN SIGNAL[pipe2.refTypeErr, myPipe2, refType];
IF myPipe.subTask#0 THEN SIGNAL[pipe2.SubTaskErr, myPipe2, 0];
IF myPipe2.task # taskX THEN SIGNAL[pipe2.taskErr, myPipe2, taskX];
IF myPipe2.emuFault THEN SIGNAL[pipe2.emuFaultErr, myPipe2, 0];
myPipe4 ← PIPE4[];
IF myPipe4.ref #1 THEN SIGNAL[pipe4.refErr, 1];
myFaultInfo ← FAULTINFO[];
IF myFaultInfo.emuFault THEN SIGNAL[faultInfo.emuFaultErr, myPipe, 0];
IF myFaultInfo.nFaults # 7 THEN SIGNAL[faultInfo.nFaultsErr, myPipe, i];
useSRN ← incSRN[useSrn];
ENDLOOP;
FOR nFlts IN [1..6] DO
aSetAsrnForWrite[srn];
useSrn ← srn;
makeNfaults[nFlts];
FOR i IN [1..nFlts] DO
setProcSRN[useSrn];
myPipe2 ← Pipe2;
IF myPipe2.emulatorFault THEN SIGNAL[pipe2.emuFaultErr, myPipe2,0];
IF myPipe2.nFaults # nflts THEN SIGNAL[pipe2.nFaultsErr, myPipe2, i];
IF myPipe2.FaultSRN #srn THEN SIGNAL[pipe2.FaultSrnErr, myPipe2, useSRN];
myPipe← FaultInfo[];
IF myFaultInfo.emuFault THEN SIGNAL[faultInfo.emuFaultErr, myPipe, 0];
IF myFaultInfo.nFaults # nflts THEN SIGNAL[faultInfo.nFaultsErr, myPipe, i];
IF myFaultInfo.FaultSRN #srn THEN SIGNAL[faultInfo.faultSrnErr, myPipe, useSrn];
useSrn ← incSRN[useSrn];
ENDLOOP;
ENDLOOP;
RETURN;
END;
initFaultTask: PROCEDURE =
BEGIN
noWakeOff[];
-- default = allow memory wakeups
saSetMcr[getSMcrVictim[] ] ;
-- set mcr for diagnostic
TPC[faultTaskX] ← @faultCode;
NOTIFY[faultTaskX];
RETURN;
faultCode:-- This code executes when a memory fault occurs
taskingOn[];
setRBASE[rbaseOf[makingFaults]];
DO
BLOCK;-- wait here for next fault to occur
IF aMakingFaults = 1 THEN
BEGIN
TPC[testTask] ← @makeNfaultsContinue
END;
ELSE IF aMakingFaults = 2 THEN
BEGIN
TPC[testTask] ← @aSetAsrnContinue;
END;
ELSE ERROR[];-- awakened unexpectedly
ENDLOOP;
END;
disableFaultTask: PROCEDURE=
BEGIN
faultInfo ← FAULTINFO[];
-- clear out waiting wakeups
noWakeOn[]
saSetMcr[getSMcrVictim[] ];
TPC[faultTaskX] ← 7776B;
END;
makeNfaults: PROCEDURE[n] =
BEGIN
setBR[377B, 0];
aMakingFaults ← 1;
-- global value visible to fault handler
FOR i IN [1..n] DO
t ← mem[i];
makeNfaultsContinue:-- fault task will force us to continue here
ENDLOOP;
makingFaults ← FALSE;
END;
setUpMemory: PROCEDURE=
BEGIN
-- This procedure forces mem[0..17B] into the cache, and backgrounds row 1 of the cache w/ munches that don’t include mem[20B..37B]. This enables the test to make a reference that is guaranteed to cause a miss and a dirty write. Recall that 20B addresses the first row of the cache and that increments of 1000B will not change the row address.

FOR i IN [0..17B] DO mem[i] ← i; ENDLOOP;
FOR i ← 10020B, i + 1000B UNTIL 20000B DO
mem[i] ← i;
ENDLOOP;
END;
incSrn: PROCEDURE[oldSrn] RETURNS[newSrn] =
BEGIN
newSrn ← oldSrn + 1;
IF newSrn > 15 THEN newSrn ← 1;
RETURN;
aSetAsrnForWrite: PROCEDURE[srn] =
BEGIN
aMakingFaults ← 2;
setBR[-1,0];
UNTIL config.Asrn = srn DO
FETCH ← 0;
T ← MD;
aSetAsrnContinue:
ENDLOOP;
aMakingFaults ← 0;
setBR[0,0];
END;
aIncAsrn: PROCEDURE=
BEGIN
xWriteMap[0,0];
-- write the map w/ virtual page 0 mapped
-- onto real page 0 (default state for diagnostics). Map writes cause Asrn to increment.

IF aMakingFaults # 0 THEN setBR[377B,0] ELSE setBR[0,0];
-- a side effect of xWriteMap is to clobber the current BR, so it must be regenerated.

END;
%

* June 9, 1981 10:22 AM
%
Pipe test
This code runs in different tasks and causes various sorts of memory references: Three normal memory references and a series of references that cause faults. The point of the t est is to fill the pipe with different sorts of entries and to make sure that the pipe data reporting logic really works. The test has two phases. In the first phase three normal references occur and the data in the pipe gets checked. In the second phase a series of faults occur and then all the entries in the pipe are checked.
The "main program" for this test iterates through the various tasks and the various srn values. It sets up the pc for the correct task and causes it to run. The code at apPipeTest actually makes the references and checks the pipe.
%
aPipeTestCtrl:
pushReturn[];
call[disableConditionalTask];* don’t run HOLD simulator
call[iSboard];* init Sboard in case its not happened already
call[getMemState];
t AND (memState.PipeTest);* see if our test is enabled
branch[apTestCtrlXit, ALU=0];
noop;

call[iapMap];* setup map for making page faults conveniently
call[iapFltTask];
call[iapTestTask];

apTestCtrlL:
call[apNextTestTask];
skpif[alu#0];
branch[apTestCtrlXit];
noop;
call[iapSrn];

apCtrlL2:
call[apNextSrn];
skpif[alu#0];
branch[apTestCtrlL];
noop;
call[apGetTestGo];
rscr←link;
call[apGetTestTask];
subroutine;
link ← rscr;
top level;
LdTPC ← t;
call[notifyTask];
noop;* give it time to awaken
branch[apCtrlL2];* try the next Srn

apTestCtrlXit:
returnP[];

apGetTestGo:subroutine;
coreturn;
branch[apTest];

* June 4, 1981 2:07 PM
apTest: * This code runs at various task levels.
set[xtask, 1];
top level;

RBASE ← rbase[defaultRegion];* init task specific things
taskingOn;
call[setMbase], t←a0;* use BR 0
rscr ← a0;* set BR 0 to zero
call[setBR], rscr2 ← a0;
call[iapMemory];* init cache in case it has changed

call[apGetSrn];
call[aSetAsrnForWrite];* Since this routine makes faults to cause Asrn to have the proper value, it must execute at the aTestTaskX level.

noop;* for MicroD
t ← FaultInfo’[];* clear out faultInfo
call[setMcr],t←mcr.noSeWake;

rscr ← a0;* set current BR to zero
call[setBR], rscr2← a0;

t ← a0;
FETCH ← t;* ref 0
rscr ← MD, t ← t+1;

call[apGetSrn];
aUseSrn←ProcSRN←t;

rscr← a0;* no faults
rscr2← 1c;* reftype=1
apTest1:
call[apChkPipe2];* rscr=numFaults=7=none, rscr2=ref type=1

* check procSrn for correctness, keep FaultInfo in rscr

rscr← not(FaultInfo’);
apTest2:
call[apChkProcSrn], rscr2← aUseSrn;
call[apChkAsrn], rscr2← aUseSrn;
call[apChkFaults], rscr2← a0;* no faults

t← a0;
ProcSRN← t;
t ← 20c;* ref 2: cause dirty miss (see iapMemory)
FETCH ← t;
rscr← MD;

rscr←a0;
rscr2←1c;* ref type=1=read missing munch
ProcSRN← aUseSrn;
apTest3:
call[apChkPipe2];
rscr← not(FaultInfo’);
apTest4:
call[apChkProcSrn], rscr2← aUseSrn;
call[apIncSrn], t← aUseSrn;* must increment aSrn twice
call[apIncSrn];* since dirty miss writes two entries
apTest5:
call[apChkAsrn], rscr2← t;
call[apChkFaults], rscr2← a0;

call[apIncSrn],t← aUseSrn;
ProcSRN← t;
rscr← a0;* no faults
rscr2← 2c;* storage type=2=write dirty munch
call[apChkPipe2];

ProcSRN←r0;

* June 4, 1981 12:59 PM
* Now cause a series of faults and check the pipe
*
CHECK OTHER PIPE VALUES, TOO!

noop;* for placement.
call[setMcr], t←mcr.noWake;

cnt←10s;* clear-out row 0 so that page faults
t←1000c;* won’t get any dirty victims in the cache
loopUntil[CNT=0&-1, .], t← (Fetch←t)+t;* thereby avoid problems computing
* expected value of ASRN.

call[iapNFlts];
apFltL:
call[apNextFltX];
skpif[alu#0], t←a0;
branch[apFltXitL];
ProcSRN← t;

* cause nFaults to appear in the pipe beginning
call[apGetSrn];* begin faulting at proper place in pipe
call[aSetAsrnForWrite];* IE. firstFaultSrn= this value

call[apGetFltX];* make aNfaultsX errors
call[apMakeNFlts];
noop;* for MicroD
call[apGetSrn];* point to right place in pipe to read
aUseSrn← ProcSrn← t;

* Check FaultInfo values. Remember that ←FaultInfo resets nFaults to 7

rscr←not(FaultInfo’);* check code needs rscr=faultInfo
rscr2← aUseSrn;
apFltsP1:
call[apChkProcSrn];
call[apGetFltX];
t← t-1;
cnt←t, call[apGetSrn];

noop;* for placement.
call[apIncSrn];* proper Asrn=(starting Asrn+nFlts)
loopUntil[CNT=0&-1, .-2];

apFltsP2:
call[apChkAsrn], rscr2← t;

call[apGetFltX];
call[apGetSrn], rscr2←t;* t← firstFaultSRN
apFltsP3:
call[apChkFaults], t← aUseSrn;

call[iapNflts2];* FOR i IN [1..nFaults] check EACH pipe entry
apFltChkL:
noop;* here for placement problems
call[apNextFlt2];
skpif[alu#0];
branch[apFltL];* try outer, nFlts, loop again

procSRN ← aUseSrn;
rscr←a0;* nfaults
rscr2← 1c;* refType=read
apFltsP4:
call[apChkPipe2], t← aUseSrn;


call[apIncSrn], t ← aUseSrn;
aUseSrn ← t;
branch[apFltChkL];
apFltXitL:
call[setMcr], t←mcr.noSeWake;
ProcSRN← t;* reset ProcSrn to zero
branch[.], block;* done w/ current test. allow emulator to run.
set[xtask, 0];


* June 3, 1981 5:46 PM
%
This subroutine checks to see if the contents of Pipe2 are correct:
numFaults, firstFaultSRN, refType, subTask (must be 0), task (must
be current task), EmuFault (must be 0)

ENTRY:
rscr=numFaults we expect
rscr2=refType we expect
t=firstFaultSRN (if numFaults #7)

on ERROR:
Arlink points to the caller of this subroutine

USE:
T, rscr, rscr2, rscr3, Arlink, Q
%

apChkPipe2: subroutine;* rscr=numFaults, rscr2=ref type, t=1st FaultSRN
rscr3←t;* save firstFaultSRN for a while
SaveReturn[Arlink];
t← not(Pipe2’);

* Check nFaults for correctness

t←t and (pipe2.nFaults);
rscr← (rscr)-1;* mem system keeps nFaults-1 in pipe
rscr← (rscr)AND (7c);* so we decrement and mask to do same
rscr← lsh[rscr, pipe2.nFaultsShift];
t # (rscr);
skpif[ALU=0];
apChkP2Err1:* nFaults in Pipe2 does not match expected
error;* value. See caller of subroutine.

* IF nFaults=7 (same as mask value) then we don’t check firstFaultSRN

t # (pipe2.nFaults);
branch[apChkP2Cont, ALU=0], t← not(Pipe2’);
t← t and (pipe2.faultSrn);
t # (rscr3);* rscr3=expected value of firstFaultSRN
skpif[ALU=0];
apChkP2Err2:* firstFaultSRN does not match expected
error;* value. See caller of subroutine.
t←not(Pipe2’);

apChkP2Cont:
rscr3← t;* copy Pipe2 into rscr3.

* check task=current task

call[apGetTestTask];
rscr← lsh[t, pipe2.taskShift];* we’re done w/ numFaults so rscr is free
t← (rscr3) and (pipe2.task);
(rscr)#t;
skpif[ALU=0];
apChkP2Err3:* Expected task (rscr, shifted) is not
error;* same as one in Pipe2 (t). See caller of subroutine.

* Check subtask=0;

t← (rscr3) AND (pipe2.subTask);
skpif[ALU=0];
apChkP2Err4:* Subtask should always be zero in
error;* memPipeAndFaultA. See caller of subroutine.

* Check refType= rscr2;

t← (rscr3) AND (pipe2.refType);
rscr2← lsh[rscr2, pipe2.refTypeShift];
t#(rscr2);
skpif[ALU=0];
apChkP2Err5:* ref type (rscr2, shifted) does not match
error;* value in Pipe2.

* Check EmuFault=0

t← (rscr3) AND (pipe2.emuFault);
skpif[ALU=0];
apChkP2Err6:* Emulator fault bit is true, should be false.
error;* see caller of subroutine.

returnUsing[Arlink];

* June 3, 1981 5:46 PM
%
Check FaultInfo

These routines check the values in faultInfo. ALL OF THEM ASSUME rscr=FaultInfo. Examine subroutine caller to determine how error was invoked.

apChkProcSrn checks that rscr2=expected ProcSrn= faultInfo.procSrn
apChkAsrn checks that rscr2=expected Asrn=faultInfo.asrn
apChkFaults checks
rscr2=numFaults=faultInfo.numFaults
t=firstFaultSRN=faultInfo.firstFaultSRN (if numFaults#7)
emuFault is 0

%

mc[faultInfo.ProcSrn, b0,b1,b2,b3];
set[faultInfo.ProcSrnShift, 14];

apChkProcSrn: subroutine;* ENTER: rscr=FaultInfo, rscr2=expected ProcSrn
saveReturn[Arlink];
rscr2← lsh[rscr2, faultInfo.ProcSrnShift];
t← (rscr) AND (faultInfo.ProcSRN);
t # (rscr2);
skpif[ALU=0];
apChkProcSrnErr:* ProcSRN should be same as expected val.
error;* see caller of subroutine.

returnUsing[Arlink];

apChkAsrn: subroutine;* rscr=faultInfo, rscr2=expected Asrn
saveReturn[Arlink];
rscr2← lsh[rscr2, faultInfo.asrnShift];
t← (rscr) and (faultInfo.asrn);
t#(rscr2);
skpif[ALU=0];
apChkAsrnErr:* expected ASrn (rscr2, shifted) not same
error;* as one in FaultInfo (t). See caller of subroutine;

returnUsing[Arlink];

apChkFaults: subroutine;* rscr=faultInfo, rscr2=numFaults, t=
rscr3←t;* SRN for first fault. NOTE: if numFaults
saveReturn[Arlink];* is 7 (means no faults) then don’t check
* firstFaultSRN
rscr2← (rscr2)-1;* Memsystem uses nFaults-1, so we do
rscr2← (rscr2) and (7c);* the same thing!
rscr2← lsh[rscr2, FaultInfo.nFaultsShift];
t← (rscr) AND (faultInfo.nFaults);
t # (rscr2);
skpif[ALU=0];
apChkFaultsErr1:* expected num faults (rscr2, shifted)
error;* doesn’t match faultInfo (t). See caller of subroutine.

(rscr2) # (faultInfo.nFaults);* if nfaults=mask value, then don’t
branch[apChkFaultsCont, ALU=0];* check value of firstFaultSRN.

t← (rscr) AND (faultInfo.faultSrn);
t # (rscr3);
skpif[ALU=0];
apChkFaultsErr2:* expected first fault srn doesn’t match
error;* fault info. See caller of subroutine.
noop;* for placement limitation

apChkFaultsCont:
t← (rscr) and (faultInfo.emuFault);
skpif[ALU=0];
apChkFaultsErr3:* don’t expect emulator faults
error;

returnUsing[Arlink];


*August 24, 1978 3:18 PM
%
iapMemory
Force the munch containing mem[0:17B] into the cache and remove the mucnch containing mem[20B:37B] from the cache. Remember that increments of 1000B do not change the row address in the cache for a memory location.
%
iapMemory: subroutine;
saveReturn[Arlink];
cnt ← 17s, t←a0;
iapMemL1:
loopUntil[CNT=0&-1, .], t ← (Store←t)+1, DBuf← t;

cnt ← 10s;
t ← 20c;
noop;* for MicroD
t ← t + (1000c);

iapMemL2:
STORE ← t, DBuf ← t;
loopUntil[CNT=0&-1, iapMemL2], t ← t + (1000c);
returnUsing[Arlink];

* June 16, 1981 4:07 PM
%
iapFltTask
This subroutine initializes the fault task for the memory pipe and fault diagnostics. The fault task code examines makingFaults, an RM flag set by the diagnostics to determine what to do if there’s been a fault.
IF makingFaults is true, tpc[testTask]←@testTaskContinueLoc; otherwise, there’s been an error. The fault task uses the aMakingFaults Rbase.
%


iapFltTask: subroutine;
saveReturn[iapFltTskRtn];
t ← FaultInfo’[];* clear any waiting wakeups
call[setMcr],t←mcr.noSeWake;* set mcr for wakeups
call[getFaultTaskLoc];
subroutine;* link ← code loc from getFaultTaskLoc
t ← 17c;* the fault task is task 17
top level;
LdTPC ← t;
noop;* for microD
call[notifyTask];* t = task to notify;
noop;* wait to assure it has run
returnUsing[iapFltTskRtn];

getFaultTaskLoc: subroutine;
coreturn;
branch[faultTask];

set[xtask, 1];
top level;
faultTask:
RBASE ← rbase[aMakingFaults];
taskingOn;

apFltTaskL:
block;
(aMakingFaults)-1;* see if apMakeNfaults caused this fault
branch[apFltTask1, alu=0];

error;* AWAKENED WHEN aMakingFaults NOT valid !!!!

apFltTask1:* come here if apMakeNfaults
t ← not(FaultInfo’);* block won’t work until we do this
Q←t;
branch[apFltTaskL];* wait extra cycle before blocking

set[xtask, 0];
knowRbase[defaultRegion];

* June 17, 1981 8:49 AM
%
apMakeNFlts
Make a series of faults in the pipe. Enter with T = the number of faults to make. ENTER W/ MCR.noWake!!! Once the fault task wakes up because of a memory wakeup, it cannot go to sleep again without performing ←FaultInfo,
and THAT will reset nFaults which screws up the diagnostics.
%
mc[largerThanCacheC, 4000];
* this value should be larger than the cache
apMakeNFlts: subroutine;
saveReturnAndT[Arlink, AsubrScr];
rscr← t← 1c;
call[setBR], rscr2← t;* set BR to 1,,1 to cause faults on our refs

aMakingFaults ← t;* aMakingFaults ← 1, to notify fault task
*
that our faults are ok.

call[getAsubrScr];

t ← t - 1;* remove one ’cause we test at end of loop
cnt ← t;
apmakeNFltsL:
FETCH ← t;* this reference causes a fault
rscr ← MD;
t← t+ (largerThanCacheC);,
loopUntil[CNT=0&-1, apMakeNFltsL];

rscr←a0;
call[setBR], rscr2←a0;* reset BR to usual value
aMakingFaults ← a0;* disalow further faults
returnUsing[Arlink];

iapMap:
subroutine;
pushReturn[];* This emulator subroutine sets up the map so that pages w/ BRHI=1 are vacant. This makes is easy to guarantee that apMakeNFlts will cause faults

rscr2←a0, cnt← 17s;

iapMapL:
rscr←1c;
call[setBR];* rscr=brHi, rscr2=brLO
rscr←3c;* wp+dirty means vacant
call[writeMap];* leaves rscr2 as it is
loopUntil[CNT=0&-1, iapMapL], rscr2← (rscr2)+(largerThanCacheC);

returnP[];

* June 2, 1981 10:18 AM
%
loop controls, misc subroutines
%
mc[maxTestTaskC, 16];
iapTestTask: subroutine;
return, aTestTaskX ←a0;

apNextTestTask: subroutine;
saveReturn[Arlink];
RBASE ← rbase[aTestTaskX];
t ← aTestTaskX ← (aTestTaskX) + 1, RBASE ← rbase[defaultRegion];
noop;* for MicroD
rscr ← t - (maxTestTaskC);
returnAndBranch[Arlink, rscr];
apGetTestTask: subroutine;
RBASE ← rbase[aTestTaskX];
return, t ← aTestTaskX, RBASE ← rbase[defaultRegion];

mc[
maxNfaultsC, 7];* nFaults IN [0..maxNfaultsC)

iapNFlts: subroutine;
return, aNfaultsX ← a0;
apNextFltX: subroutine;
saveReturn[Arlink];
RBASE ← rbase[aNfaultsX];
t ← aNfaultsX ← (aNfaultsX)+1, RBASE ← rbase[defaultRegion];
noop;* for MicroD
rscr ← t - (maxNfaultsC);
returnAndBranch[Arlink, rscr];
apGetFltX: subroutine;
RBASE ← rbase[aNfaultsX];
return, t ← aNfaultsX, RBASE ← rbase[defaultRegion];

iapNFlts2:
subroutine;
return, aNfaultsX2 ← a0;
apNextFlt2: subroutine;
saveReturn[Arlink];
RBASE ← rbase[aNfaultsX2];
t ← aNfaultsX;
rscr ← t+1;
t ← aNfaultsX2 ← (aNfaultsX2)+1, RBASE ← rbase[defaultRegion];
rscr ← t - (rscr);
returnAndBranch[Arlink, rscr];

apGetFlt2:
subroutine;
RBASE ← rbase[aNfaultsX2];
return, t ← aNfaultsX2, RBASE ← rbase[defaultRegion];

* June 3, 1981 11:52 AM
mc[
maxSrnC, 20];* Asrn IN [1..20)
set[xtask, 1];
aSetAsrnForWrite: subroutine;
saveReturnAndT[Arlink, AsubrScr];
t← lshift[300,10]C;
TIOA←t, t←a0;

aSetAsrnL:
IOFetch←t;
rscr ← not(Config’);
rscr ← (rscr) and (config.Asrn);* isolate and rt justify current asrn value
call[getAsubrScr];
noop;* for MicroD
rscr ← rsh[rscr, config.AsrnShift];
(rscr) - t;
loopUntil[alu=0, aSetAsrnL], t←a0;* gets incremented before it gets used again

returnUsing[Arlink];

* June 2, 1981 10:19 AM
aIncAsrn: subroutine;
* cause Asrn to increment. Accomplish this
* by writing the map. The subroutine that writes the map also clobbers BR so this routine must regenerate BR as well.
t← lshift[300,10]C;
TIOA← t;
IOFetch← t;
RETURN;

iapSrn: subroutine;
t ← (r0)+1;
return, aSrnX ← t;
apNextSrn: subroutine;
saveReturn[Arlink];
RBASE ← rbase[aSrnX];
t ← aSrnX ← (aSrnX) + 1;
RBASE ← rbase[defaultRegion];
rscr ← t - (maxSrnC);
returnAndBranch[Arlink, rscr];
apGetSrn: subroutine;
RBASE ← rbase[aSrnX];
return, t ← aSrnX, RBASE ← rbase[defaultRegion];

apIncSrn: subroutine;* Increment an Srn value. wraparound to 2
t ← t+1;* when new srn>17B. Note: enter w/ T =
t-(20c);* current srn value
skpif[alu#0];
t ← 2c;
return;
apDecSrn: subroutine;* decrement an Srn value. wraparound to 17
t ← t-1;* when new srn=1. Note: enter w/ T =
Pd← t-1;* current srn value
skpif[alu#0];
t ← 17c;
return;


* August 27, 1978 7:51 PM

* apSaveT0Tpc
*
Save tpc[0] in apSavedT0Tpc so that a non emulator task can briefly
* "run" as the emulator (so it can perform map← operations).

* apRestoreT0Tpc
*
Restore tpc[0] that is stored in apSavedT0Tpc

* apSetTpc
*
t = task, rscr = location

apSaveT0Tpc: subroutine;
saveReturn[apSaveT0TpcRtn];
zeroHold[rscr2];
RdTpc ← r0;
t ← link;
apSavedT0Tpc ← t;* we’ve stashed tpc[0] into apSavedT0Tpc
call[resetHold];
returnUsing[apSaveT0TpcRtn];

apRestoreT0Tpc: subroutine;
saveReturn[apSaveT0TpcRtn];
noop;* for MicroD

RBASE ← rbase[apSavedT0Tpc];
t ← apSavedT0Tpc, RBASE ← rbase[defaultRegion];
rscr ← t;
call[apSetTpc], t ← r0;
noop;* for MicroD

returnUsing[apSaveT0TpcRtn];

apSetTpc: subroutine;* t = task number, rscr = IM location
saveReturnAndT[apSetTpcRtn, rscr2];
noop;* for MicroD

zeroHold[t];
t ← rscr2;
subroutine;
link ← rscr;
top level;
LdTpc ← t;
noop;* for MicroD
call[resetHold];

returnUsing[apSetTpcRtn];