%
Page Numbers: Yes First Page: 1
Heading:
DORADO: MemRWsApril 12, 1982 2:56 PM %
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
April 12, 1982 2:57 PM
Add sRefreshTest
March 17, 1982 10:21 AM
Move sMemMisc to memMisc, add special scope loop code for sdTest.
September 22, 1981 10:02 AM
Add noop to longFetch test to help placement problem.
May 19, 1981 11:23 AM
Change addressing test to take a parameter=value to background memory with.
Then change the test to run once w/ 0, once w/ 177777B.
February 6, 1981 10:34 AM
Change main r/w test to use prefetch.
September 19, 1979 10:39 PM
Cause sFlushTest, sMiscTest to do ←MD to wait for any activity to finish that should finish before manipulating the cache flags.
September 13, 1979 4:52 PM
Make beginStest into a subroutine that invokes all the other storage board tests.
September 7, 1979 6:23 PM
Change, again, the order of the tests so that the sDtest happens before the addressing test.
June 28, 1979 8:36 AM
Fix bug in svarpipe2resume -- resumes at wrong label -- change name to sVaPipeResume, too.
June 27, 1979 6:52 PM
Fix bug in sDbufMdTest (wrong sex on skip), make sLongFetch reset BRs when done.
June 27, 1979 11:46 AM
Fix placement problem with afterStest, iLongFetchMem.
June 27, 1979 11:23 AM
Add sLongFetchTest.
June 25, 1979 3:02 PM
Make each test in memRWs into a subroutine; add sMiscTest.
June 8, 1979 10:12 AM
Save and restore random number generator seed in sDataTest -- to aid patching the code.
April 18, 1979 3:18 PM
Change branch at end of sAddrTest to branch to sDtest rather than sChaosTest (this caused memA to skip the storage data test!).
April 18, 1979 9:36 AM
Remove conditionalTasks from Flush test because it reads CFlags and this leaves memory in state that can’t handle references from arbittrary task wakeups.
April 17, 1979 10:41 PM
Bracket the flush test w/ calls to enableConditionalTask, disableConditionalTask.
April 12, 1979 8:53 AM
Move the storage addressing test to be first in the sequence of storage tests.
April 11, 1979 3:47 PM
Added breakpoint at end of read/check loop so operator can tell when the diagnostic has made one complete pass over the memory storage.
January 16, 1979 3:55 PM
Invoke sRestoreMcrVictim at end of sFlushTest -- to allow entire cache to be used if it is enabled.
January 15, 1979 5:43 PM
fix sFlushTest to guarantee no hits in a column not selected by sMCRvictim
January 15, 1979 10:55 AM
more comments about patching, force microD to cause to instrs to occur sequentially in IM.
January 12, 1979 11:55 PM
comments that describe how to avoid conditional tasking during sDtest’s write loop
January 11, 1979 9:15 AM
add Flush← test, fix missing "sVa←t" in addressing test’s find error sections, add flush← to addressing test.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

title[memrwS];
top level;
* September 22, 1981 10:07 AM
beginStest:
pushReturn[];
checkMtest[memFlags.sBoard, doneStest];* skip everything if required
call[disableConditionalTask];* prevent task simulator from running
call[iSboard];* find out mem configuration, size, etc

call[sdTest];* data test
call[sAddrTest];* addressing test
call[sFlushTest];* flush← test
noop;* for placement
call[sChaosTest];* chaos (random operations) test
call[sRefreshTest];* see if refresh works ok
noop;* for placement
doneStest:
returnP[];* done
%
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
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
%

* May 19, 1981 11:20 AM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Storage Addressing Test

NOTE: The Addressing test has been rewritten so that it runs once backgrounding memory w/ 0. Then it runs again and backgrounds memory w/ 177777B. The test was changed to accommodate this new subroutine parameter (the background value). Otherwise, the algorithms are the same.

Background memory w/ 0 then write -1 into ascending addresses. Before the write,
check that the word that is about to be written is still zero. Suppose it is non zero.
Then there was an addressing error. Remember the address of the non zero word, background memory with zeros again and proceed writing -1s. This time, check the
previously clobbered address each time before writing the -1. This approach will catch the reference that clobbers the known location. The same algorithm can be applied for
descending addresses, mutatis mutandi, to finish a complete check of the addressing logic.

sAddrCheck: PROCEDURE=
BEGIN
zeroMem: PROCEDURE
BEGIN
FOR munch ← 0, munch ← munch+20B UNTIL maxMunch DO
FOR i IN [0..20B) DO
mem[munch+i] ← 0;-- microcode implementation will be fast!
ENDLOOP:
ENDLOOP:
END;
findErrUp: PROCEDURE [clobbered: VA] =
BEGIN
zeroMem[];
FOR i IN VA DO
IF mem[clobbered]#0 THEN SIGNAL ErrUp[i-1, clobbered];
mem[i] ← -1;
ENDLOOP:
SIGNAL IntermittentErrUp[clobbered];
END:
findErrDown: PROCEDURE [clobbered: VA] =
BEGIN
zeroMem[];
FOR i DECREASING IN VA DO
IF mem[clobbered] #0 THEN SIGNAL ErrDown[i+1, clobbered];
mem[i] ← -1;
ENDLOOP;
SIGNAL IntermittentErrDown[clobbered];
END;
-- this is the program
zeroMem[];
FOR i IN VA DO
IF mem[i] # 0 THEN FindErrUp[i];
mem[i] ← -1;
ENDLOOP;
zeroMem[];
FOR i DECREASING IN VA DO
IF mem[i] # 0 THEN FindErrDown[i];
mem[i] ← -1;
ENDLOOP;
END;
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

* May 19, 1981 1:00 PM
sAddrTest:
pushReturn[];
checkMtest[memFlags.sAddr, sAddrTestDone];
t←a0;* for MicroD
call[sDoAddressTest], t←a0;* address test w/ background = 0
t←a1;* for MicroD
call[sDoAddressTest], t←a1;* address test w/ background = 1
sAddrTestDone:
pReturnP[];

sDoAddressTest:* This address test backgrounds memory with the value we were passed in T. Keep that value on the stack.

pushReturnAndT[];
call[enableConditionalTask];
call[setMemory], t←stack;
call[iSvaCtrl];

sAddrUpL:
call[nextSva];
branch[sAddrLxit, alu=0], Sva ← t;

fetch ← t, t←stack;
rscr ← md;
(rscr) # t;* is memory same value as we stored there?
skpif[alu=0], t ← not(stack);
branch[sAddrUpFindErr];

branch[sAddrUpL], DBuf ← t, store ← Sva;

sAddrLxit:
noop;
call[setMemory], t←stack;
call[iSvaDownCtrl];

sAddrDownL:
call[nextSvaDown];
branch[sDoAddrTestDone, alu=0], sva ← t;

fetch ← t, t← stack;
rscr ← md;
(rscr)#t;* is memory same value as we stored there?
skpif[alu=0], t ← not(stack);
branch[sAddrDownFindErr];

branch[sAddrDownL], DBuf ←t, store ← Sva;

* May 19, 1981 11:19 AM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sAddrUpFindErr
REMEMBER: Stack contains the background value for this test.

This test tries to isolate the reference that clobbered the location (denote it the
target location) that was detected by the sAddrUpL loop. The test proceeds as before except that as it ascends memory it continually checks to see if the target location has been clobbered yet. Use Flush← to force the target munch out of the cache.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

sAddrUpFindErr:
call[saveMemAddr];* save addr of clobbered location
call[setMemory], t←stack;
call[fetchMemAddr];* returns w/ rscr = brHi, rscr2 = low 16
t ← rscr2;
call[setBR], rscr2 ← t-t;
fetch ← t, rscr3←t;
t←stack;
rscr2 ← md;
(rscr2)#t;
skpif[alu=0];* error implies setMemory didn’t work
sAddrUpErr1:
error;* rscr3 = low 16 bits of addr, rscr = hi 8 bits, rscr2 = MD value
saueFlush1:
Flush ← rscr3;* remove target munch from cache

call[iSvaCtrl];
sAddrUpFindL:
call[nextSva];
branch[sAddrUpNoFind, alu=0], sVA ← t;

noop;
call[restoreBrHi];* we clobbered it to check clobbered mem location
t ← not(stack);* perform next reference before we check for clobbered data
store ← Sva, DBuf ← t;

call[fetchMemAddr];* returns rscr= brhi, rscr2 = low 16 bits of va
t ← rscr2;
call[setBR], rscr2 ← t-t;
fetch ← t, rscr3←t;* save low 16 bits of addr in rscr3
t ← md;
(t)#(stack);
skpif[alu=0];* error => last reference clobbered the location at
sAddrUpErr2:
error;* rscr,,rscr3. bad bits are in rscr2. Last reference at sVaHi,,sVaX
saufeFlush2:
Flush ← rscr3;* remove target munch from cache

branch[sAddrUpFindL];

sAddrUpNoFind:
error;* intermittent error;
* May 19, 1981 11:18 AM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sAddrDownFindErr
REMEMBER: Stack contains the background value for this test.

This test tries to isolate the reference that clobbered the location (denote it the
target location) that was detected by the sAddrDownL loop. The test proceeds as before except that as it descends memory it continually checks to see if the target location has been clobbered yet. Use Flush← to force the target munch out of the cache.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

sAddrDownFindErr:

call[saveMemAddr];* save address of clobbered location
call[setMemory], t← stack;
call[fetchMemAddr];* return w/ rscr = brhi, rscr2 = low 16 bits
t ← rscr2;
call[setBR], rscr2 ← t-t;* make sure target word is zero
fetch ← t, rscr3←t;
t ← md;
(t)#(stack);
skpif[alu=0];* failure implies setMemory didn’t work
sAddrDownErr1:
error;* rscr = brHI, rscr3 = low 16 bits of va, rscr2 = md
sadfeFlush1:
Flush ← rscr3;* remove target munch from cache

call[iSvaDownCtrl];
sAddrDownFindL:
rscr2 ← Sva;
call[nextSvaDown];
branch[sAddrDownNoFind, alu=0], sVA ← t;

noop;
call[restoreBrHi];* we clobbered it to check clobbered mem location
t ← not(stack);
store←sva, DBuf ← t;

call[fetchMemAddr];* returns w/ rscr = brhi, rscr2 = low a6 bits
t ← rscr2;
call[setBR], rscr2 ← t-t;
fetch ← t, rscr3←t;
t ← md;
(t)#(stack);
skpif[alu=0];
sAddrDownErr2:
error;* ref at sVaHi,,sVaX clobbered rscr,,rscr3

sadfeFlush2:
Flush ← rscr3;* remove target munch from cachebranch[sAddrDownFindL];

sAddrDownNoFind:
error;* intermittent error;
sDoAddrTestDone:
call[disableConditionalTask];
pReturnP[];

* February 6, 1981 10:52 AM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Storage Data Test
FOR patX IN PatX DO
FOR va IN VA DO
mem[va] ← getPattern[patX, va];
ENDLOOP:
FOR munch IN [MunchVa] DO
FOR i IN [0..17] DO
va ← munch+va;
got ← mem[va];
expect ← getPattern[patX, va];
IF ~sChkNoErrs[] THEN
-- sChkNoErrs turns OFF checking
T ← expect xor got;
IF T # 0 THEN SIGNAL memErr[va, expect, got];
ENDLOOP;
-- check the pipe after we’ve read the entire munch
IF ~ sChkNoErrs[] THEN
-- sChkNoErrs turns OFF checking
IF aChkPipeFlt[] THEN
BEGIN;
myPipe4 ← PIPE4[];
num1Bits ← Count1Bits[myPipe4.syndrome];
IF num1Bits = 1 THEN SIGNAL checkBitFailure[myPipe4];
IF myPipe4.syndrome = 0 AND (num1Bits AND 1) = 0) THEN
SIGNAL doubleError[myPipe4];
synWdX ← myPipe4.syndromeWdX;
IF (synWdX=3) OR (synWdX=5) OR (synWdX=6) THEN
SIGNAL singleError[myPipe4];
SIGNAL unknownError[myPipe2];
END;
ENLOOP;
ENDLOOP;
%
%
sNoErrsOn() is a midas subroutine that will cause the sdTest to avoid ALL error checking
sNoErrsOff() is a midas subroutine that reenables sdTest error checking
sdNoDataErrs is the location of the branch that skips error checking within the data check of sdTest. Patch out this branch to allow data checking and to disalow pipe checking when sNoErrsOn is in effect. Notice the note below.
sdNoPipeErrs is the location of a branch that skips error checking of the pipe within the read loop of the sdTest. Patch out this branch to allow pipe error checking when sNoErrsON is in effect. Notice the note above.
sdOffCTask is the location of a call to enable conditional task that occurs just before the write loop portion of sdTest. Patch out this call to disallow the memory task simulator’s memory references during the sdTest. Notice the note below.
sdOnCtask is the location of a noop that may be patched into a call on the enableConditionalTask subroutine to cause the memory task simulator to run during the checking portion of the sdTest. Notice the note above.
sVaTryNextPat is the location of the branch that causes the diagnostic to write a new pattern into memory after the current pattern has been checked. Patch this location to into a branch[sdBeginCheck] to force the diagnostic into an infinite loop that always checks the current pattern.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

sDtest:
pushReturn[];
checkMtest[memFlags.sRW, sdTestDone];

sdOffCTask: * Comment-OUT this instruction to avoid conditional tasking during
call[enableConditionalTask];* the sdTest write loop.

call[iSPatCtrl];
sDpatL:
call[nextSPat];* top of pattern loop
skpif[alu#0];
branch[sDtestDone];
noop;

call[saveRandState];
call[iSmunchCtrl];
sVaWMunchL:* top of write loop; get here once/munch.
call[nextSmunch];
skpif[alu#0], Sva ← t;
branch[sVaWxit];* no more vas. Now Read it

t← t+(20C);
rscr← (PreFetch← t)-t;* speed-up the test; rscr←0
cnt← 17s;
sVaWL:* For this munch: mem[Sva]←curPattern
noop;* for placement.
call[getSPat], t ← Sva;
loopuntil[cnt=0&-1, sVaWL], DBuf ← t, Sva←(Store ← Sva)+1;
branch[sVaWMunchL];
sVaWxit:

* February 6, 1981 10:51 AM

sdOnCTask: * Patch this location into a call on
call[justReturn];* enableConditionalTask, if desired.
sdBeginCheck:
call[iSmunchCtrl];
call[restoreRandState];
B ← FaultInfo’[];
sVaRmunchL:
call[nextSmunch];* top of munch loop
skpif[alu#0], Sva ← t;
sVaTryNextPat:
branch[sDpatL], breakpoint;

t←t+(20C);
rscr← (PreFetch← t)-t;* speed-up the test; rscr←0
cnt ← 17s;* inner loop to zero current munch
sVaRL:* top of word read/check loop
FETCH ← sva;
call[getSPat], t ← Sva;
sExpected ← t;* copy current pattern into sExpected
rscr2 ← MD;* (avoid bypass)

call[sChkNoErrs];
skpif[ALU=0];
sdNoDataErrs: * Patch out this branch to allow data error checking during sdTest when
branch[svaRresume];* sNoErrsOn is in effect.

t ← sExpected;* retrieve sExpected into t
t ← t # (rscr2);* t ← cur t xor md
skpif[alu=0];* error => bad data from memory. Sva = addr
svaRErr:* sExpected = expected value
error;* t = bad bits, rscr2 = MD
svaRresume:
noop;* placement for microD
loopuntil[cnt=0&-1, svaRL], sva ← (sva) +1;
* now check pipe 2
noop;* placement for microD
call[sChkNoErrs];
skpif[ALU=0];
sdNoPipeErrs: * Patch out this branch to allow pipe error checking in sdTest when
branch[sVaRmunchL];* sNoErrsOn is in effect.
noop;

call[aChkPipeFlt];
skpif[alu#0];
branch[sVaRmunchL];* no errors; try next munch

* Pipe checking code on next page.
* June 28, 1979 8:38 AM

%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
nFaults#7 This means that a check bit failed or there was a double error or there’s some unknown thing occurring. "Strang thing" = not check error and not double error.
NOTE: sva points to one beyond the "current" munch since we incremented it at the same time we performed the loop control test. First we decrement Sva.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sva ← (sva)-1;* now sva points to last word in current munch
call[xGetPipe4];
rscr2 ← t;
cnt ← 7s;* count the number of ’1’ bits in syndrome.
t ← t-t;
sVaNsynBitsL:
skpif[r even], rscr2;
t ← t+1;
rscr2 ← rsh[rscr2, 1];
loopUntil[cnt=0&-1, sVaNsynBitsL];

t-(1c);
skpif[ALU#0], rscr ← t;* move num1Bits into rscr for even/odd check
sVaChkBitErr:* num1Bits ==>check bit error. See midas for
error;* PERRS 20, PVA 20, etc
noop;* for placement
call[xGetPipe4];

skpif[r even], rscr;* double errs only w/ even parity
branch[sVaChkSingleErr];
rscr ← (t) AND (pipe4.syndrome);* check for nonzero syndrome
skpif[alu#0];
branch[sVaChkSingleErr];
sVaDblErr:* syndrome # 0 and syndrome parity even
error;* means there was a double error

sVaChkSingleErr:

t ← t AND (pipe4.syndromeWdX);* put encoded word index in t
noop;
t ← rsh[t, pipe4.syndromeWdXShift];
t-(3c);* corresponds to word zero
skpif[ALU#0];
branch[sVaSingleErr];* error in word zero of quadword
t - (5c);* corresponds to word one
skpif[ALU#0];
branch[sVaSingleErr];* error in word one of quadword
t - (6c);* corresponds to word two
skpif[ALU#0];
branch[sVaSingleErr];* error in word two of quadword
t - (7c);* corresponds to word three
skpif[ALU=0];
branch[sVaUnknown];
sVaSingleErr:* double error. see PVA 20, PERRS 20
error;* using midas. t = encoded word index

sVaUnknown:* diagnostic is confused. Use Midas to
error;* examine the pipe to see what happened.
sVaPipeResume:
branch[sVaRmunchL];
sDtestDone:
call[disableConditionalTask];
returnP[];

*
April 17, 1979 10:41 PM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Flush←
Test the Flush← function of the memory system. Read the cache to determine if Flush← really worked. The test forces the memory system to use only one column during the checking phase; this makes it easier to determine what is happening. This test disables conditional tasking because it reads CFLAGS.
For each column:
Set CacheA to all zeros (works on all columns)
Set All CFLAGS to vacant (works on all columns)
Zero the memory (works on current column, only)
For each munch (works on current column, only)
Dirty the munch
Flush that va
Read the cache for the appropriate row to make sure the munch is vacant
Reread the munch to assure the dirty data is really there
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sFlushTest:
pushReturn[];
checkMtest[memFlags.sFlush, afterSflush];
call[disableConditionalTask];
call[initCol2Ctrl];* we use "col2" because some of the cache
* manipulating subroutines we call clobber "col".
sFlushColL:* top of the column loop
call[nextCol2];
skpif[ALU#0];
branch[sFlushColXit];
T←MD;* force Hold, if required.

call[ZeroCacheAndFlags];* set cacheA to all zeros(including CFLAGS)
call[clearCacheFlags];* set all cache to vacant

call[getCol2];
sMCRvictim ← t;
call[sUseDefaultMcr];* use current column of cache, only.

call[zeroMemory];* background the memory w/ zeros

call[iSmunchCtrl];
sFlushMunchL:* top of munch write loop
call[nextSmunch];
skpif[ALU#0], sVa ← t;
branch[sFlushMunchXit];
noop;* for placement

*
readCflags, which we call below, clobbers Mcr, so we must reset Mcr each time thru the loop.
t←cm1;
STORE←sVa, DBuf ← t;* fetch current munch (storage access), dirty it
B←MD;* wait for memory system if required
Flush←sVa;* FLUSH it!

t ← 100c;
call[longWait];* wait for memory system if required
rscr ← sVa;* rscr ← sVa, rscr2 ← column
call[getCol2];
call[readCflags], rscr2 ← t;* read the cflags

t ← t and (pipe5.flagsMask);
rscr ← t # (cflags.vacant);* only the vacant bit should be set
skpif[ALU=0];
sFlushErr1:* the munchd at sVa didn’t flush!
error;* t = cflags, rscr = bad bits in cflags

call[sUseDefaultMcr];* use current column of cache, only.
FETCH ← sVa;* make sure our dirty munch is really
t ← MD;* in storage.
sExpected ← cm1;
t # (sExpected);
skpif[ALU=0];
sFlushErr2:* the flush didn’t cause our dirty
error;* munch to go to storage. t = md,
* sExpected = value we expected

branch[sFlushMunchL];

sFlushMunchXit:
branch[sFlushColL];
sFlushColXit:
afterSflush:
call[disableConditionalTask];
call[sRestoreMcrVictim];
returnP[];

* April 12, 1982 2:53 PM
%
sRefreshTest

This test writs a pattern into memory and then waits a while before checking it. The goal is to determine if memory refresh works proberly. Strictly speaking there are two memories that must be refreshed, the map and the storge. Hopefully failures of the map refresh logic will cause a map parity error.
%
sRefreshTest:
pushReturn[];
call[setMemory], t←a0;* write all of memory with 0, wait
call[longWait], t←a1;* about 65000 cycles and then check it
call[refreshCheckMemory], t←a0;

call[setMemory], t←a1;* write all of memory with all ones, wait
call[longWait], t←a1;* about 65000 cycles and then check it
call[refreshCheckMemory], t←a1;
returnP[];

refreshCheckMemory:
pushReturnAndT[];
call[iSmunchCtrl];
refreshL:
call[nextSmunch];
skpif[alu#0], Sva← t;
branch[refreshXit];

t←t+(20C);
PreFetch←t;
cnt← 17s;
Sva← (Fetch← Sva)+1;
refreshCkL:
(Md)#(stack);
skpif[ALU=0], Sva← (Fetch← Sva)+1;
refreshErr:
error;* expected (stack) got (Md). Suspect a refresh problem. Sva-1 is the address that failed.
loopUntil[CNT=0&-1, refreshCkL];

refreshXit:
pReturnP[];
* March 17, 1982 11:47 AM
%
sdScopeLoop
This code supports placing the diagnostic in a scope loop after an error has been detected by sdTest. Read carefully the requirements and directions for this scope loop.

There are two cases: the error was detected at svaRerr or somewhere else. The svaRerr situation is easy: there’s been some sort of data bit failure and to run the scope loop all you have to do is to type,
sdScopeLoop;p
to Midas. Other error situations imply that there was trouble indicated
by nFaults, check bit errors, etc. This means you must examine to see if the error occured in Pipe 0 (the munch last examined by the diagnostic) or in some other Pipe (meaning the error occured during the storage transport due to the prefetch at sVaTryNextPat+2). Examine the data using the ROW display of Midas. Preferably you will find the bad word, eyeball the pattern to decide what the value should be and proceed as follows:

1. Set SVA to the address of the bad word
2. Set sExpected with the value it should be
3. type sdScopeLoop;p to midas

If you really aren’t sure what the proper value or offending word really is, you must experiment. The loop below will write the location at sva with the value of sExpected. Note: Flush← MUST work for this scope loop to work.
%
sdScopeLoop: top level;
t← sExpected;*save sExpected, sVa before we set MCR
stack+1←t;
t←sva;
stack+1←t;

t← OR[mcr.disHold!, mcr.noWake!]C;
call[setMCR];

t←stack&-1;* restore sVa, sExpected
sVa← t;
t← stack&-1;
sExpected←t;

rscr3← 60c;* wait value
sdSL:
call[longWait], t← rscr3;
rscr←a0;
TIOA← rscr, rscr←a1;* scope trigger if you wish
TIOA← rscr;
t← sva;
Store←t, DBuf← sExpected;
call[longWait], t← rscr3;
Flush← sva, branch[sdSL];