%
Page Numbers: Yes First Page: 1
Heading:
MODEL 1: memrwC.mcFebruary 5, 1981 5:57 PM%
title[memrwC];
top level;
%
February 5, 1981 5:57 PM
Add toplevel decl to singleStep to satisfy micro.
September 19, 1979 6:23 PM
Move beginCTest to beginning of file, call disableConditionalTask from beginCtest, add table of contents, remove surplus code from cacheComprTest. Add lost mods that constructed and used ccColWrite (to save space & simplify the logic) -- changed cacheAddr and cacheCompr.
%
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TABLE OF CONTENTS, by order of Occurence
beginCtestControl subroutine that calls the tests in thi file
cPipeVA:Test the low 16 bits of the pipe
cBRrwTest:Test all the bits of the base registers
cacheAddr:Test the Cache A-Memory
cacheCompr:Test the cache comparators
ccColWrite:Subroutine to write Cache A.
cFlagsTest:Test cache flags memory
cacheAddrTest:Cache A addressing test
setCAAF:Set current cache location and cache flags to all ones
resadCurrentCFlags:Read "current" value of CFlags
readOldCflags:Read "old" value of CFlags
readCurrentCAmem:Read current Cache Amemory
readOldCAmem:Read "old" value of CacheA memory
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

* September 19, 1979 7:14 PM
beginCtest: top level;* FIRST TEST IN MEMRWC
pushReturn[];
call[disableConditionalTask];
call[cPipeVa];* test pivpe va
call[cBRrwTest];* test base registers
call[cacheAddr];
call[cacheCompr];
call[cFlagsTest];
call[cacheAddrTest];
returnP[];

* February 5, 1981 5:57 PM

set[xtask,1];
* NON EMULATOR!!!
set[sslocC,210]; mc[ssloc,sslocC];
singleStep:* INIT SINGLE STEP CODE
taskingon;
t←mcr.disBr;* turn off base registers, cache flags
t←t+(mcr.disCF);
loadmcr[t,t];
t←ssloc;
link ← t;
toplevel;
ldtpc ← r1;
notify[1];
noop;
noop;
branch[emulMem];
ssHere:
rbase ← 17s, at[sslocC];* init our rbase
breakpoint,t←r1;* begin single step. t controls blocking
* set t to zero when done
memAsel:
*
map ← r01;* ASEL=0, FF[0:1]=0. FF OK (emulator)
set[xtask, 0];
store←ID;* ASEL=0, FF[0:1]=1. FF OK
set[xtask, 1];
store ← t;* ASEL=0, FF[0:1]=2. FF OK
store ← r01;* ASEL=0, FF[0:1]=3. FF OK
memAsel1:
preFetch←r01;* ASEL=1, FF[0:1]=0. FF OK
set[xtask, 0];
fetch ← ID;* ASEL=1, FF[0:1]=1. FF OK
set[xtask, 1];
fetch ← t;* ASEL=1, FF[0:1]=2. FF OK
fetch ← r01;* ASEL=1, FF[0:1]=3. FF OK

memAsel2:
*
ioStore←t;* ASEL=2, FF[0:1]=2. FF OK (emulator)
ioStore←r01;* ASEL=2, FF[0:1]=3. FF OK

memAsel3:
set[xtask, 0];
dummyRef←r01;* ASEL=2, FF[0:1]=0. FF OK
Fetch←ID;* ASEL=2, FF[0:1]=1. FF OK
set[xtask, 1];
ioFetch←t;* ASEL=2, FF[0:1]=2. FF OK
ioFetch←r01;* ASEL=2, FF[0:1]=3. FF OK

memAselNotOK:
store←r01, t←1c;* ASEL=0, FF not OK
fetch←r01, t←1c;* ASEL=1, FF not OK
t←t;* test to see if we should block
skpif[alu#0];
tsk1quit:
goto[.],block;
branch[memAsel];

* EMULATOR ASEL CHECKOUT COMES HERE
set[xtask,0];
emulMem:
map ← r01;* ASEL=0, FF[0:1]=0. FF OK
Flush←r01;* ASEL=2, FF[0:1]=0. FF OK
branch[emulMem];
afterSingleStep:

* September 13, 1979 4:37 PM
%
CHECK PIPE VA BITS!!!

First disable base registers and init cnt to allow 20B iterations.
Then perform a dummyRef once for every bit on marMux (1, 2, 4, 10, etc). Note that the value stored with dummyRef is kept in rscr, the value read from pipe1 is kept in rscr2. This code need not be single stepped.
%

cpipeVA:
pushReturn[];
checkMtest[memFlags.cPipeVA, cPipeVaDone];
cnt ← 17s;* loop control: once for each bit
rscr ← r1;* RSCR begins w/ 1
T←mcr.disBr;
T←T+(mcr.disCf);
t ← t OR (mcr.noRef);
call[setMCR];* DISABLE BASE REGISTERS

cpipeVAl:
dummyRef ← rscr;* RSCR goes to pipe
noop;
t←pipe1;
rscr2←t;* rscr2 gets pipeVA
t←t#(rscr);* t ← pipeVA xor RSCR
skpif[alu=0];
cPipeVAerr:* t = bad bits, rscr = value we wrote into
ERROR;* pipe, rscr2 = value from pipe

loopuntil[cnt=0&-1, cPipeVAl], rscr←(rscr)+(rscr);* shift left test value by one

cPipeVaDone:
returnP[];

* March 17, 1978 8:32 AM
%
CHECK BASE REGISTER BITS

FOR BR IN [0..31] DO
-- once for every base register
FOR brhi ← 1,brhi+brhi UNTIL brhi = BrHiEndC DO-- once for each bit
FOR brlo ← 1, brlo+brlo UNTIL brlo = 0 DO-- once for each bit
writeBR[br, brhi, brlo];
IF pipe1 # brlo THEN ERROR;
if pipe0.va # brhi THEN ERROR;
ENDLOOP; ENDLOOP;
ENDLOOP;
%

cBRrwTest:
pushReturn[];
checkMtest[memFlags.cBR, cBRdone];
Q ←r0;* Q = base register being tested
t←(37c);
cnt ← t;* cnt controls Q-loop
t←rscr ← r1;* rscr = brHI
rscr2 ← t;* rscr2 = brLO
t←mcr.disCf;
t ← t OR (mcr.noRef);
call[setMCR];* reenable base registers
brL:
noop;
call[setMbase],t←q;
noop;
brWriteHiL:* come here from incrementing brHi=rscr
branch[brWriteLoL];* instruction for placement
brWriteLoL:* come here from incrementing brLo=rscr2
branch[brl2];
brl2:
CALL[setBR];* rscr =>brhi, rscr2 => brlo
dummyref ← r0;* force pipe entry
noop;
t ← pipe1;* pipe1 = VA[8:23] = low 16 bits
t ← t #(rscr2);
skpif[alu=0];
cbrLow16ER:* rscr2=value written into BrLo, t=bad bits
error;* q = current base register being tested

t←pipe0;
t←t and(CABitsInPipe0Mask);
t←t#(rscr);
skpif[alu=0];* rscr = value written into brhi. t = bad
cbrHi8ER:* bits that came back.
error;* q = current base register being tested

brLoopCtrl:
t←(rscr2)+(rscr2);* increment and check brlo
loopuntil[alu=0, brWriteLoL],rscr2 ← t;

rscr2 ← r1;* reset brlo, increment and check brhi
t←(rscr)+(rscr);
t#(BrHiEndC);
loopuntil[alu=0,brWriteHiL],rscr←t;

rscr ← r1;* reset brhi, increment and check BR
t←(r1)+(q);
loopuntil[cnt=0&-1, brL],q←t;

cBRdone:
returnP[];

%
Test the cache address memory.

Proceed as follows:
For each pattern, write the entire cache address memory with known values. Then for each row and for each column write the memory again and check to see that the correct entry appeared in the pipe.
Load MCR as follows:
dPipeVa←Vic, FDmiss, useMcrV, DisCF, DisHOLD
mcrVec: ARRAY [0..3] OF [
[FDmiss, useMcrV, McrV:0, DisCF, DisHold],
[FDmiss, useMcrV, McrV:1, DisCF, DisHold],
[FDmiss, useMcrV, McrV:2, DisCF, DisHold],
[FDmiss, useMcrV, McrV:3, DisCF, DisHold]
];
FOR pat IN Npats DO
FOR row IN Row DO
FOR col IN Column DO
checkPattern ← getCPattern[pat,row,col];
va←0;
va.cacheBits ← row;
-- select current row

LOADMCR[mcrVec[col] OR noRef];
setBrCacheABits[checkPatternj];
DBuf←0,STORE←va;
ENDLOOP;
ENDLOOP;
FOR row IN Row DO
FOR col IN Column DO
LOADMCR[mcrVec[col] OR dPipeVa←Vic OR noRef];
otherPattern ← NOT[getCPattern[pat,row,col]];
setBrCacheABits[otherPattern];

-- now perform the check
va←0; va.cacheBits ← row;
DBuf←0,STORE←va;
NOOP;
--?????

pipe0 ← PIPE0[]; pipe1 ← PIPE1[];
vaBits ← getCaBitsFromPipe[];
pat ← not(OtherPattern);
pat ← pat AND (CABitsMaskC);
IF pipe1.cacheBits # row THEN ERROR;
ENDLOOP;
ENDLOOP:-- end of row check loop
ENDLOOP:-- end of pattern loop
%

* September 19, 1979 7:03 PM
INIT cache address code and data

cacheAddr:
pushReturn[];
checkMtest[memFlags.cAmem, caTestDone];
call[initCPatterns];* initialize pattern loop control

caPatternL:
call[nextCPattern];* THIS IS MAIN, OUTER LOOP
branch[caTestDone,alu=0];
noop;* for placement

caRowInit:
call[initRowCtrl];* initialize row loop control
caRowL:
call[nextRow];* incremnt row value. rtn’d in T
branch[noRow,alu=0];* nextRow sets up this test
Q ← t;* save current row in Q
call[initColCtrl];* initialize column loop control
caColL:
call[nextCol];* increment column value. rtn’d in T
branch[noColumn,alu=0];* nextCol sets up this test
col ← T;* save current col in col
call[ccColWrite], t←a0;* write current cache entry
branch[caColL];

noColumn:
branch[caRowL];

noRow:


* March 13, 1978 9:11 AM
TEST THE CACHE DATA: we’re inside several layers of loop

cAmemTest:
call[initRowCtrl];* initialize row loop control

caRowTestL:
call[nextRow];* incremnt row value. rtn’d in T
branch[noRowTest,alu=0];* nextRow sets up this test
Q ← t;* save current row in Q
call[initColCtrl];* initialize column loop control
caColTestL:
call[nextCol];* increment column value. rtn’d in T
branch[noColumnTest,alu=0];* nextCol sets up this test
col ← T;* save current col in col
t←(mcr.dPipeVa);
t ← t OR (mcr.noRef);
call[mcrForCol];* set up mcr for current column
call[setBrCacheABits], t←r0;* use 0: dPipeVa causes data to be or’d.

call[vaForRow], t ← q;
va ← t;
DBuf←r0,STORE ← t;* TEST proper cache entry

call[getCPattern];* test 15 bit pattern
t ← t and (CABitsMaskC);* isolate exactly the bits we believe in
call[getPipeCacheABits],rscr2←t;* against pipe info. rscr2 is preserved!
rscr ← t;* remember pipe hi 15 bits
%*------------------------------------------------------------------------------
membase+va = the address we referenced. The value in va selects the cache row, and the value in membase is the value used to test cacheA. Q=current row, col = current column (both in the cache).
%*------------------------------------------------------------------------------
t←t#(rscr2);* see if any bits are different
skpif[alu=0];* t=bad bits, rscr = hi 15 bits from pipe,
caBadVaBits:* rscr2=expected pattern (rscr, rscr2 right
error;* justified). Q=current row, col=current column

call[chkPipeRow],t←q;* check "row" bits of PIPE1
skpif[alu=0];
caBadRow:* Q=current row. For some reason we didn’t
error;* read the row in the pipe we wanted

branch[caColTestL];

noColumnTest:
branch[caRowTestL];

noRowTest:
branch[caPatternL];

caTestDone: noop;
returnP[];

* September 30, 1978 6:24 PM
%
TEST CACHE COMPARATORS
FOR br IN [0..31] DO
SETMEMBASE[br];
FOR pat IN Npats DO
FOR row IN Row DO
FOR col IN Col DO
-- check comparators using data from each column in this row
FOR otherCol IN Col DO-- init current row
pattern ← getCPattern[pat, col, row];
IF col # otherCol THEN pattern ← NOT[pattern];
va ← 0;
va.cacheBits ← row;
setBrCacheABits[pattern];
setMcrForCol[otherCol, noRef];
DBuf←0,STORE←va;
ENDLOOP;
-- set up to generate test reference
pattern ← getCPattern[pat, col, row];
va ← 0;
va.cacheBits ← row;
setBrCacheABits[pattern];
set mcr appropriately;
DBuf←0, STORE←va;
noop?;
-- test the results of the reference
pipe5 ← pipe5[];
IF pipe5.col # col THEN ERROR;
ENDLOOP;
-- column loop
ENDLOOP;-- row loop
ENDLOOP;-- pattern loop
ENDLOOP;-- base registers loop
%
* December 7, 1977 4:31 PM
%
INITIALIZE THE CODE THAT TESTS THE CACHE COMPARATORS
Use same loop control subroutines as the cache address test code
%
cacheCompr:
pushReturn[];
checkMtest[memFlags.cComprs, ccTestDone];
call[initBrs];* initialize base registers loop
ccBrL:
* THIS IS MAIN, OUTER LOOP
call[nextBr];
skpif[alu#0];
branch[ccTestDone];
noop;
call[setMbase];* change membase
call[initCPatterns];* initialize pattern loop control

ccPatternL:
call[nextCPattern];
skpif[alu#0];
branch[ccNoPats];
noop;* for placement

ccRowInit:
call[initRowCtrl];* initialize row loop control
ccRowL:
call[nextRow];* incremnt row value. rtn’d in T
branch[ccNoRow,alu=0];* nextRow sets up this test
Q ← t;* save current row in Q

* September 19, 1979 7:03 PM
TEST THE CACHE COMPARATORS: we’re inside several layers of loop

cacheComprTest:
call[initColCtrl];* initialize column loop control
ccColL:
call[initCol2Ctrl];
ccCol2L:* this loop inits the backgound values
call[nextCol2];* (background = NOT(pattern)
branch[ccNoCol2,alu=0];* nextCol sets up this test
col ← T;* save current col in col
call[ccColWrite],t←a1;* write current col,row w/ not(current pattern)
branch[ccCol2L];

ccNoCol2:
call[nextCol];
branch[ccNoCol,alu=0];
col ← t;
%
now that the current row has been properly backgrounded by the "col2" loop, force a known value into this row in the current column, then reference that value and see if the comparators find it.
%
call[ccColWrite], t←a0;* write current col,row w/ current pattern

t←(mcr.disCF);* set mcr to disable cache faults,
t←t+(mcr.noRefHold);* disable hold
t ← t+(mcr.noWake);
call[setMcr];
call[getCPattern];* knows about Q, currnet pat
call[setBrCacheABits];* getCPattern returned value in T

call[vaForRow], t ← q;
va ← t;
DBuf←r0,STORE ← t;* TEST proper cache entry

%*------------------------------------------------------------------------------
membase+va = the address we referenced. The value in va selects the cache row, and the value in membase is the value used to test the comparators. Q=current row, col = current column (both in the cache). Only one column contains the value implicit in the current membase. A hit in a different column means that the comparators failed.
%*------------------------------------------------------------------------------
noop;
rscr ← pipe5[];
call[chkPipe5col],t←col;* see if matched proper column
skpif[alu=0];
ccBadCol:* T=bad bits, rscr=pipe5, col=column
error;* expected

branch[ccColL];

ccNoCol:
%
Add code here to make sure that misses occur when then should
%
branch[ccRowL];

ccNoRow:
branch[ccPatternL];
ccNoPats:
branch[ccBrL];
ccTestDone:
returnP[];
* September 19, 1979 6:57 PM
ccColWrite:% Write current (col) column with current pattern in the row specified by Q. We xor (rscr) with the current pattern. This produces the current pattern when rescr=0 an, the complement of the current pattern when rscr=-1, and (probably) a bug otherwise.
%
pushReturnAndT[];
t←mcr.fdMiss;
t←t OR (mcr.noRef);
call[mcrForCol];* set up mcr for current column, other flags are defaulted by mcrForCol

call[getCPattern];* knows about Q, SHC, current pattern
call[setBrCacheAbits], t←(stack&-1)#t;* get CPattern retukrned value in T

call[vaForRow], t←q;
DBuf←r0, Store←t;* write proper cache entry
returnP[];

* November 30, 1977 10:04 AM
%
TEST CACHE FLAGS: TREAT THEM LIKE A MEMORY

For each column and row entry in the cache, test all the possible cache flag values. The enigmatic method for reading and writing the cache flags reflects the fact that the flags weren’t designed to be read and written like a memory.
Basically, write the cache flags as follows:
Turn on fdMiss, disHold, enable the flags and the base registers. Use useMcrV to select the current column. PRESUME the cflags value has been left shifted by four to allign it with the proper position in the cache.
Let va = vaForRow[row] - flagsValue, and write the low 16 bits of the current base register with va. Now write the value as follows:
dummyREF ← flagsValue;
CFLAGS ← flagsValue;
To read the flags, the current contents of the A memory must be known and there must not be two hits in the cach when the reference occurs:
Disable hold, enable the flags, use UseMcrv to force a different column for the victim. Perform,
dummyREF ← va; pipe5 ← pipe5[];
where the pipe5[] occurs in the next instruction and va[0:14] are known to be in the A memory of the cache. Check that col = the column that should have matched and not the column that was chosen as victim.
FOR flagsV ← 0, flagsV+20B UNTIL 1000B DO -- generate vals properly positioned
FOR row IN Row DO
useFlags ← flagsV;
FOR col IN Col DO
-- first, initialize the current row so that subsequent efforts to read the cache flags that have been written will not result in two hits in the cache
setBr[0];
va ← vaForRow[row];
setMcrForCol[fdMiss, disHold, col2];
va ← va+1000B;
DBuf←0,STORE←va;
setMcrForCol[fdMiss, disHold, useMcrv, mcrv=col2];
-- now write a different flags pattern into the current column so that each column of the row will have a different value, a value not same as the one being tested
setBr[va-useFlags];
dummyRef ← useFlags;
CFLAGS ← useFlags;
useFlags ← useFlags+minFlagVal;
IF useFlags > maxFlags THEN useFlags ← minFlagVal;
ENDLOOP;

-- now check it

useFlags ← flagsV;
FOR col IN Col DO
setMcr[disHold, useMcrv, mcrv:~col];
va ← vaForRow[row] + col *1000B;
setBR[va];
dummyRef ← 0;
pipe5 ← pipe5;
IF pipe5.col#col THEN ERROR;
fval ← pipe5 AND cFlagsMask;
IF (fval # useFlags) # 0 THEN ERROR;
useFlags ← useFlags+minFlagVal;
IF useFlags > maxFlags THEN useFlags ← minFlagVal;
ENDLOOP;
-- end col loop
ENDLOOP;-- end row loop
ENDLOOP;-- end flagsV loop
%
* March 14, 1978 11:16 AM* INIT cache flags read/write test
cFlagsTest:* read and write cache flags
pushReturn[];
checkMtest[memFlags.cFlags, cfTestDone];
call[setMbase],t←r0;* MEMBASE ← 0
call[initFlagsCtrl];
cfL:* MAIN outer LOOP
call[nextCFlag];
branch[cfTestDone,alu=0];
flagsV ← t;
call[initRowCtrl];

cfRowL:* top of row loop
call[getCflag];* restore flagsV since cfColReadL
flagsV ← t;* clobbers it
call[nextRow];* check for next row
skpif[alu#0];
branch[cfl];* try next set of flags
q←t;* keep row in Q

cfColInitL:* top of column loop
call[initColCtrl];
cfColWL:* top of row write loop
call[nextCol];
branch[cfBeginCheck, alu=0],col←t;
rscr ← col;
call[cVaForCrowCol], t ← q;* get unique va for this row/col
va ← t;
call[setCAmem];* va = addr, col = column
rscr ← flagsv;
call[setCFlags], t ← va;* set the flags for this col/row
call[incFlagsV];* get unique flags for each column
branch[cfColWL];

cfBeginCheck:
call[initColCtrl];* init column loop control
call[getCflag];* reset flagsV to current value
flagsV ← t;

cfColReadL:* top of column read/check loop
call[nextCol];
skpif[alu#0], col←t;
branch[cfRowL];* no more cols, try next row

rscr ← col;
call[cVaForCrowCol], t ← q;* get unique va for this row/col
va ← t;* save the va
rscr2 ← col;
call[readCflags], rscr ← t;* returns w/ pipe5 in T

%*------------------------------------------------------------------------------
membase+va = the address we referenced. The value in va selects the cache row, and the value in membase gets us to the correct column in the row (because the cache row has been written with unique addresses for each column). Q=current row, col = current column (both in the cache). FlagsV contains the value we wrote into the cache flags for the current row and column.
%*------------------------------------------------------------------------------
rscr ← t;
call[chkPipe5Col], t ← col;* expects rscr = pipe5, t = col
skpif[alu=0];* bad column. bad bits in T, pipe5 in rscr
cfBadCol:
error;* expected val in col

call[chkCflags],t←flagsV;* check for proper cflags in rscr
skpif[alu=0];* t = bad bits, flagsV = expected bits,
cfBadFlags:
error;* rscr = pipe5

call[incFlagsV];* adjust for unique flagsV for each col
branch[cfColReadL];

incFlagsV: subroutine;
FlagsV ← (FlagsV) + (cflags.beingLoaded);* better be least signf. bit!
FlagsV ← (FlagsV) AND (cflags.mask);
skpif[alu#0];
FlagsV ← (cflags.beingLoaded);
return;
top level;
cfTestDone:
returnP[];

* February 21, 1978 6:53 PM
%
Cache Addressing Test
This test checks that the addressing mechanism (as opposed to the bits that hold cache address values) works. The algorithm works as follows:
Zero the amemory and the cache
Ascend thru the amemory and cach flags: check that the current value is zero and then set it to -1. If the current value is not zero, an earlier store clobbered this entry. In this case perform the "find UP" check test.
Zero the amemory and the cache flags
Descend thru the amemory and cache flags: check that the current value is zero and then set it to -1. If the current value is not zero, an earlier store clobbered this entry. In this case perform the "findDOWN" check test
Otherwise, the addressing works.

Find UP: zero the amemory and the cache flags.
Ascend thru the amemory and cache flags: before setting the current location to -1 check that the earlier clobbered location is still zero. If it is not zero, the previous store clobbered that location.
FindDown: same as findUP except descend thru the amemory and cache flags
ZeroCacheAndFlags[];
FOR row IN Row DO
FOR col IN Col DO
IF cache[row,col] #0 THEN findErrUp[row,col];
IF cacheFlags[row,col] #0 THEN findErrUP[row, col];
cache[row,col] ← -1;
cacheFlags[row,col] ← -1;
ENDLOOP;
ENDLOOP:
zeroCacheAndFlags[];
FOR Row DESCENDING IN Row DO
FOR col IN Col DO
IF cache[row,col] #0 THEN findErrUp[row,col];
IF cacheFlags[row,col] #0 THEN findErrUP[row, col];
cache[row,col] ← -1;
cacheFlags[row,col] ← -1;
ENDLOOP;
ENDLOOP:

-- These are subroutines used in the "addressing test" shown above.
findErrUp: PROCEDURE[r: Row, c: Col] =
BEGIN
zeroCacheAndFlags[];
FOR row IN Row DO
FOR col IN Col DO
IF cache[r,c] #0 THEN Signal CacheAddrUp[r,c, row-1, col-1];
IF cacheFlags[r,c] #0 THEN Signal CacheAddrUp[r,c,row-1, col-1];
cache[row,col] ← -1;
cacheFlags[row,col ← -1;
ENDLOOP:
ENDLOOP:
END:
findErrDown: PROCEDURE[r: Row, c: Col] =
BEGIN
zeroCacheAndFlags[];
FOR row DESCENDING IN Row DO
FOR col IN Col DO
IF cache[r,c] #0 THEN Signal CacheAddrUp[r,c, row-1, col-1];
IF cacheFlags[r,c] #0 THEN Signal CacheAddrUp[r,c,row-1, col-1];
cache[row,col] ← -1;
cacheFlags[row,col ← -1;
ENDLOOP:
ENDLOOP:
END:
%

* March 14, 1978 11:17 AM
cacheAddrTest:
pushReturn[];
checkMtest[memFlags.cAddr, catDone];
call[zeroCacheAndFlags];
call[initRowCtrl];

catRowUpL:
call[nextRow];* see if done going up
skpif[alu#0];
branch[catUpXit];* time to descend thru addresses
q ← t;* KEEP ROW IN Q

call[initColCtrl];
catColUpL:
call[nextCol];* check if done w/ cols
skpif[alu#0];
branch[catRowUpL];* try next row

col ← t;
call[readCurrentCflags];
skpif[alu=0];
branch[catFindUpF];* flags were clobbered
call[readCurrentCAmem];
skpif[alu=0];
branch[catFindUpAd];* amem clobbered

call[setCAAF];* set amem and flags to -1
branch[catColUpL];

catUpXit:* ascending stores did not causes a detectable addressing error. Try the same approach w/ descending addresses.
call[zeroCacheAndFlags];
call[initRowDown];

catRowDownL:
call[nextRowDown];
skpif[alu#0];
branch[catDone];
q←t;* KEEP ROW IN Q

call[initColCtrl];
catColDownL:
call[nextCol];
skpif[alu#0];
branch[catRowDownL];
col ← t;

col ← t;
call[readCurrentCflags];
skpif[alu=0];
branch[catFindDownF];* flags were clobbered
call[readCurrentCAmem];
skpif[alu=0];
branch[catFindDownAd];* amem clobbered

call[setCAAF];* set amem and flags to -1

branch[catRowDownL];

* December 13, 1978 9:57 AM

set[
catPackShift, 3];* left shift the row value this much to make room for the column (all in a "packed" va).

catFindDownF:
catFindDownAD:
va ← q;* PACK row,,col INTO VA
t ← col;
va ← lsh[va, catPackShift];
va ← (va) OR t;

call[zeroCacheAndFlags];
call[initRowDown];

catRowFindDL:
call[nextRowDown];
skpif[alu#0];
branch[catDone];
q←t;* KEEP ROW IN Q

call[initColCtrl];
catColFindDL:
call[nextCol];
skpif[alu#0];
branch[catRowFindDL];
col ← t;
%*------------------------------------------------------------------------------
These two errors indicate that
the last time we wrote the cache A memory or the flags there was an addressing error. Unfortunately this means the reader must determine what the address was "last time". Q = current row and col = current column. Subtract one from the column number to determine the last address. If the column number goes negative, then the last column was 3 and the last row was current row +1 (this loop scans "down" the possible cache addresses). The packed va, contained in "va" may be decoded as follows: The 3 least significant bits are the column number of the address that got clobbered and the remaining bits are the row number. Hence, if va = 132, the clobbered address is row 13 column 2.
%*------------------------------------------------------------------------------
call[readOldCflags];
skpif[alu=0];
catDownCFerr:* q=current row, col = current column,
*
va = packed, old, clobbered row,column
error;* flags were clobbered

call[readOldCAmem];
skpif[alu=0];
catDownAmemErr:* q=current row, col = current column,
*
va = packed, old, clobbered row,column
error;* amem clobbered

call[setCAAF];* set amem and flags to -1

branch[catRowFindDL];

* December 13, 1978
catFindUpF:
catFindUpAD:
va ← q;* PACK row,,col INTO VA
t ← col;
va ← lsh[va, catPackShift];
va ← (va) OR t;* VA = row,,col of clobbered location.

call[zeroCacheAndFlags];
call[initRowCtrl];

catRowFindUpL:
call[nextRow];
skpif[alu#0];
branch[catDone];
q←t;* KEEP ROW IN Q

call[initColCtrl];
catColFindUpL:
call[nextCol];
skpif[alu#0];
branch[catRowFindUpL];
col ← t;

%*------------------------------------------------------------------------------
These two errors indicate that
the last time we wrote the cache A memory or the flags there was an addressing error. Unfortunately this means the reader must determine what the address was "last time". Q = current row and col = current column. Subtract one from the column number to determine the last address. If the column number goes negative, then the last column was 3 and the last row was current row -1 (this loop scans "up" the possible cache addresses). The packed va, contained in "va" may be decoded as follows: The 3 least significant bits are the column number of the address that got clobbered and the remaining bits are the row number. Hence, if va = 132, the clobbered address is row 13 column 2.
%*------------------------------------------------------------------------------
call[readOldCflags];
skpif[alu=0];
catUpCFerr:* q=current row, col = current column,
*
va = packed, old, clobbered row,column
error;* flags were clobbered

call[readOldCAmem];
skpif[alu=0];
catUpAddrErr:* q=current row, col = current column,
*
va = packed, old, clobbered row,column
error;* amem clobbered

call[setCAAF];* set amem and flags to -1

branch[catRowFindUpL];

* December 5, 1978 12:18 PM
setCAAF: subroutine;* set current cache location and cache flags to all ones
pushReturn[];
t ← q;
call[vaForRow];
rscr ← t;
t ← col;
rscr2 ← t;
t ← rscr;
rscr ← cm1;
call[putCAmem];* t = va, rscr = brHi15, rscr2 = col
t ← q;
call[vaForRow];
rscr ← t;
t ← col;
rscr2 ← t;
t ← rscr;
rscr ← (cflags.mask);
call[putCFmem];* t = va, rscr = flags, rscr2 = col
returnP[];

readCurrentCFlags: subroutine;
pushReturn[];
t ← q;
call[vaForRow];
rscr ← t;
rscr2 ← col;
call[readCflags];* rscr = va, rscr2 = col
t ← t AND (cflags.mask);* isolate flags from other pipe5 stuff
returnPAndBranch[t];
readOldCflags: subroutine;
pushReturn[];
t ← rsh[va, catPackShift];;
call[vaForRow];
rscr ← t;
t ← (va) AND (3c);* isolate col
call[readCflags], rscr2 ← t;* rscr = va, rscr2 = col
t ← t AND (cflags.mask);* isolate flags from other pipe5 stuff
returnPAndBranch[t];
readCurrentCAmem: subroutine;* the cache address memory requires destructive read. Therefore, read the memory w/ the value we expect to find!
pushReturn[];
t ← (mcr.dPipeVa);
t ← t OR (mcr.noRef);
call[mcrForCol];
call[setBrCacheABits], t ← r0;
call[vaForRow], t ← q;
rscr2 ← t;* save va since shortMemWait clobbers t
DBuf ← r0, STORE ← t;* TAG bits now screwed
shortMemWait[rscr];
call[getPipeCacheABits];* does not clobber rscr2
rscr ← t;* save hi 15 bits of va in rscr
t ← rscr2;* restore va
DBuf ← r0, STORE ← t;* fix TAG bits
shortMemWait[rscr2];
t ← rscr;
returnPAndBranch[t];
readOldCAmem: subroutine;* the cache address memory requires destructive read. Therefore, read the memory w/ the value we expect to find!
pushReturn[];
t ← q;
rscr ← va;* SWAP "va state"
va ← lsh[t, catPackShift];
t ← (col) AND (3c);
va ← (va) OR t;* va = packed copy of "current" state
t ← (rscr) AND (3c);
col ← t;
t ← rsh[rscr, catPackShift];
q ← t;* now, q = old row, col = old col

t ← (mcr.dPipeVa);
t ← t OR (mcr.noRef);
call[mcrForCol];
call[setBrCacheABits], t ← r0;
call[vaForRow], t ← q;
rscr2 ← t;* save va since shortMemWait clobbers t
DBuf ← r0, STORE ← t;* TAG bits now screwed
shortMemWait[rscr];
call[getPipeCacheABits];* does not clobber rscr2
rscr ← t;* save hi 15 bits of va in rscr
t ← rscr2;* restore va
DBuf ← r0, STORE ← t;* fix TAG bits
shortMemWait[rscr2];

t ← q;
noop;
t ← lsh[t, catPackShift];
t ← t OR (col);
rscr2 ← t;* rscr2 = original value of packed va

t ← (va) and (3c);
col ← t;* "current" col restored
va ← rsh[va, catPackShift];
q ← va;* "current" row restored
t ← rscr2;
va ← rscr2;* "old" packed va restored
t ← rscr;* return w/ Amem in T
returnPAndBranch[t];
CATdone: noop;
returnP[];