%
Page Numbers: Yes First Page: 1
Heading:
ifuTestSubrs.mcMay 6, 1982 11:24 PM%
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Table of Contents
Organized by Occurrence of subroutine in this Listing
SubroutineFunction
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
initIfuCacheInit memory, IfuMemory and write opcodes into memory
iMemInitialize (main) memory system for Ifu
ifuOpcodesToMemConstruct various "programs" in "main" memory
appendHaltsWrite three halt opcodes into memory using address in CDbyteAddr.
getCDbyteAddrReturn t = "current cache byte address"
putCDbyteAddrSet "current cache byte address" with t
putNextByteWrite byte in T into cache at current addr, then increment the addr
putCDbyteWrite byte in rscr into memory byte addr in t
getCDbyteReturns the byte pointed to by T
getIUsingInstrSetReturns current value of iUsingInstrSet
setIUsingInstrSetSets value of iUsingInstrSet
fixByteAddrForInstrSetModify a byte address to accommodate the current instr. set
ResetIfuReset ifu, zero IfuTest, clear reschedPending
ifuGetInstrSetReturn the current value of ifu instruction set
ifuSetInstrSetSet the current value of the ifu instruction set.
initItestInitialize the test loop control
initTestCountInitialize the test opcode count
nextITestReturn ALU=0 ==> no more tests, t = memory byte addr of next test
getTestBoundsHIDEOUS IMPLEMENTATION DEPENDENT routine that returns the beginning and end byte address of the "current" IFU test (test indicated by iTestX).
getIfuNotReadyLocReturns t=not ready location for current instr set.
nextITestCountReturn ALU=0 ==> no more counts, t = current count
ifuTestLoopinfinite loop that invokes a particular (passed in T) ifu executin test
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%
May 6, 1982 11:24 PM
Add comments
September 17, 1979 6:37 PM
Remove reference to afterIfu3.mc
August 1, 1979 10:38 AM
Cause ifuSetInstrSet to set iUsingInstrSet.
July 3, 1979 12:02 AM
Add code to handle various exception conditions: Cause initIfuCache to clear exceptionsMask.
June 29, 1979 3:35 PM
Add slight performance enhancement to memory initialization loop in iMem, fix bug in FixByteAddrForInstrSet that prevented it from noticing that instruction set 2 accesses the bytes right to left.
June 28, 1979 11:45 AM
Call xGetConfig in iMem.
June 6, 1979 10:32 AM
Fix placement problems in getIfuNotReadyLoc.
June 5, 1979 11:46 AM
Add call to disableConditionalTask in iMem.
June 4, 1979 10:06 AM
Add getIfuNotReadyLoc.
May 30, 1979 10:44 AM
Add boiler plate to iMem to withstand effects of power-up sequence on Dorado.
May 4, 1979 10:09 AM
Add ←ID instructions to ifuTestLoop -- to suck data out of pipe in case of 3 byte instrs.
May 2, 1979 10:33 AM
Add calls to ifuGetInstrSet, ifuSetInstrSet to force microD to place them properly (they are Midas subroutines, only, for the moment).
May 1, 1979 5:01 PM
Add getIfuInstrSet, setIfuInstrSet.
April 27, 1979 4:54 PM
Fix bug in fixByteAddrForInstrSet.
April 26, 1979 5:04 PM
Create this file from ifu3.mc
%
* July 3, 1979 12:03 AM
%
initIfuCache
This code has four main functions:
It initializes the Dorado storage system
It backgrounds all IfuM with valid parity opcodes to a location that invokes error.
It writes opcodes into IfuM[21:30]
It writes a succession of byte codes into the cache
%
initIfuCache:
subroutine;
pushReturn[];
t ← a0;
exceptionsMask ← t;* disallow all exceptions but "notReady"
call[iMem], t ← t-t;* Use col 0 of cache exclusively.
call[ifuBackground];* write halts into all locations of the Ifu
call[initIfuMemory];* write our opcodes into special locations
call[ifuOpcodesToMem];* write various programs into memory
returnP[];

* April 6, 1982 9:57 AM
iMem: subroutine;* Enter w/ t IN[0..3] ==> use one column
pushreturnAndT[];* of cache (t specifies the column).
RBASE ← rbase[MemoryOK];
t ← MemoryOK, RBASE ← rbase[defaultRegion];
branch[iMemXit, ALU#0];* only do this once
* Background storage so that mem[va] = va for first 65 K memory.

call[disableConditionalTask];
call[xGetConfig];* set up to handle current configuration.
call[xGetMapICs];* determine size of map
t ← FaultInfo’[];* clear any wairting faults
call[clearCacheFlags];* nothing in the cache
call[presetMap];* start up the map
t ← 200c;* use the error corrector
call[setTestSyn];
call[clearCacheFlags];* nothing in the map (setting Tsyn changed cache)
t ← 37C;* init ifu’s membase
call[setMbase];
rscr ← t-t;
call[setBR], rscr2 ← t-t;* Use zero in Ifu’s base register

MEMBX←0s;* We’ll use membase zero, and zero it, too.
call[setMbase], t ← t-t;
rscr← t-t;
call[setBR], rscr2 ← t-t;

(stack) - (4c);* see if we’re supposed to use only one col
skpif[ALU<0];* of the cahce
branch[iMemSetMcr], t ← r0;
t ← lsh[stack, 13];* sigh. we can’t fit memdefs, so
t ← t or (b2);* use numbers. should be mcr.useMcrV
iMemSetMcr:
t ← t or (b14);* should be mcr.noSEwake;
stack+1 ← t;* remember it for a while
call[setMCR], t ← t or (b15);* should be mcr.noWake
t ← rscr ← A0;
iMemWriteL:* tight loop that writes all of storage
PreFetch ← rscr;* Prefetch is uninteresting first time thru.
cnt ← 17s;
loopUntil[CNT=0&-1, .], t ← (STORE←t)+1, DBuf←t;* write current munch
loopUntil[ALU=0, iMemWriteL], rscr ← t + (40C);* increment prefetch pointer

t ← rscr ← 100000C;* do it again, just to make sure we flush
iMemWriteL2:* the cache. Otherwise, there may still
Prefetch ← rscr;* be storage with bad parity.
cnt ← 17s;
loopUntil[CNT=0&-1, .], t ← (STORE←t)+1, DBuf←t;
loopUntil[ALU=0, iMemWriteL2], rscr ← t + (40c);
t ← 1c;* remember that we’ve done all this;
MemoryOK ← t;

B ← FaultInfo’[];
call[setMCR], t ← stack&-1;* set MCR for default value.

iMemXit:
pReturnP[];
* May 6, 1982 11:25 PM
%
ifuOpcodesToMem -- write opcodes into cache: FOR INSTRUCTION SETS 2, 3
This initialization works ONLY for instruction sets two and three -- those insrtuction sets take data from the right half FIRST, then the left half of the word. PutNextByte ALWAYS works left to right.
word 0 byte 0(test0MemByteLocC)begins one byte jump .
word 30
byte 60(test1MemByteLocC)begins two byte jump .
word 50
byte 120(test2MemByteLocC)begins (two byte) jump .+2, jump .-2
word 100
byte 200(test3MemByteLocC)a small program whose opcodes cross word boundaries.
word 200
byte 400(---------)fastTest code (not appropriate to "default" tests.
%

ifuOpcodesToMem: subroutine;
pushReturn[];
call[setIUsingInstrSet], t ← 3c;
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Background all storagte with "identity".
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
t ← cm1;
cnt ← t;
t ← t-t;
loopUntil[cnt=0&-1, .], t ← (store←t)+1, DBuf ← t;
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Write one-byte "jump ." into
LOCATION 0, followed by "halts".
Logical:
(jump. fastHalt) (fastHalt fastHalt) (fastHalt fastHalt) (fastHalt <undefinedByte>)
Physical:
(fastHalt jump.) (fastHalt fastHalt) (fastHalt fastHalt) (fastHalt <undefinedByte>)
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
iic3:* write jump0 into the first 40B bytes in the cache
* At word 0, byte 0

call[putCDbyteAddr], t←test0MemByteLocC;* begin writing at location zero

call[putNextByte], t ← jump0;
call[putNextByte], t ← fastHalt;
call[appendHalts];* try to keep ifu from deep-ending

%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Write two-byte "jump ." into word
LOCATION 30, followed by "halts".
Logical:
(jump+ 0) (fastHalt fastHalt) (fastHalt fastHalt) (fastHalt fastHalt)
Physical:
(0 jump+) (fastHalt fastHalt) (fastHalt fastHalt) (fastHalt fastHalt)
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

iic4:* place a two byte jump . into cache.
* at word location 30

t←test1MemByteLocC;
call[putCDbyteAddr];* initialize the byte address

call[putNextByte], t ← jumpL2;* put the offset (=0)
call[putNextByte], t ← r0;* put the opcode (=2byte jump)
call[appendHalts];* try to keep ifu from deep-ending

%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

At word
LOCATION 50, byte LOCATION 120 (test2MemByteLocC):
Logical:
(jumpL2 2) (jumpML2- -2)(fastHalt fastHalt) (fastHalt fastHalt) (fastHalt fastHalt)
Physical:
(2 jumpL2) (-2 jumpML2)(fastHalt fastHalt) (fastHalt fastHalt) (fastHalt fastHalt)
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

iic5:* place an infinite loop into the cache: jump .+2, jump .-2, where opcode len=2.
t ← test2MemByteLocC;
call[putCDbyteAddr];

call[putNextByte], t ← jumpL2;
call[putNextByte], t ← 2c;
call[putNextByte], t ← jumpML2;
call[putNextByte], t ← cm2;* now jump .-2

call[appendHalts];* try to keep ifu from deep-ending

iic6:
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
At
word LOCATION 100, byte location 200 (test3MemByteLocC):
Logical:
(op1 op2)(A op3)(A B)(jumpML2 6)(fastHalt fastHalt)(fastHalt fastHalt)(fastHalt fastHalt)
Physical (extracting right to left from memory):
(op2 op1)(op3 A1=2)(B2=32 A2=31)(-6 jumpML2)(fastHalt fastHalt)(fastHalt fastHalt)(fastHalt fastHalt)
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

t ← test3MemByteLocC;
call[putCDbyteAddr];
noop;* for placement
call[putNextByte], t ←opNoop ;* cross word boundary on 2 byte instr.
call[putNextByte], t ← opNoopL2;
call[putNextByte], t ← 2c;
call[putNextByte], t ← opNoopL3;* cross word boundary on 3 byte instr.
call[putNextByte], t ← 31c;
call[putNextByte], t ← 32c;
call[putNextByte], t ← JumpML2;
call[putNextByte], t ← (add[not[6],1]C);* offset for jumpML2 is -6
call[appendHalts];* try to keep ifu from deep-ending
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

At word
LOCATION 200, byte location 400:
Logical:
(fastExit fastFetch) (fastStore fast1) (fastFetch fastStore) (fastJfail toHalt) (fastJ top3) (fastHalt fastJ)(-11d fastHalt) <six fastHalts>
Physical (extracting right to left from memory):
(fastFetch fastExit) (fast1 fastStore) (fastStore fastFetch) (toHalt fastJfail) (top3 fastJ) (fastMJ fastHalt)(fastHalt -11d) <six fastHalts>
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

iic7:
t ← (lshift[200,1]C);* begin at word 200
call[putCDbyteAddr];
noop;* for placement
call[putNextByte], t ← fastExit;
call[putNextByte], t ← fastFetch;
call[putNextByte], t ← fastStore;
call[putNextByte], t ← fast1;
call[putNextByte], t ← fastFetch;
call[putNextByte], t ← fastStore;
call[putNextByte], t ← fastJfail;
call[putNextByte], t ← 10c;
call[putNextByte], t ← fastJ;
call[putNextByte], t ← 3c;
call[putNextByte], t ← fastHalt;
call[putNextByte], t ← fastMJ;
noop;* for placement.
call[putNextByte], t ← (add[not[13],1]C);
call[putNextByte], t ← fastHalt;* -11d = -13B = not(13B)+1
call[putNextByte], t ← fastHalt;* try to keep ifu from deep-ending
call[appendHalts];
call[appendHalts];
t ← 100c;
call[longWait];* assure that the ifu’s mem refs won’t miss

returnP[];

appendHalts: subroutine;
pushReturn[];
call[putNextByte], t ← fastHalt;
call[putNextByte], t ← fastHalt;
call[putNextByte], t ← fastHalt;
returnP[];

* April 26, 1979 9:00 AM
%
These subroutines support writing opcodes into the cache. Note that several of them use and increment the "current" byte address in the cache:

getCDbyteAddrreturns t = "current" cache byte address
setCDbyteAddrt = new value for "current" cache byte address

putNextBytet = byte. place t into "current" cache byte location, increment current addr
putCDbytet = byte address, rscr = value. Put rscr into indicated byte address
getCDbytet = byte address, Returns T = byte at that byte location
setIUsingInstrSett = instr set number. set iUsingInstrSet
getIUsingInstrSetReturns t = current instruciton set number
fixByteAddrForInstrSett = byte address, returns t = byte address modified to reference a byte for the current instruction set. Don’t clobber rscr!
%

getCDbyteAddr: subroutine;
RBASE ← rbase[currentCDbyte];
t ← currentCDbyte, RBASE←rbase[defaultRegion];
return;
putCDbyteAddr: subroutine;
RBASE ← rbase[currentCDbyte];
currentCDbyte ← t, RBASE ← rbase[defaultRegion];
return;
putNextByte: subroutine;* enter w/ t = byte to put in "current"
noop, global;
pushReturnAndT[];* location in cache. Increment the
t ← stack;* current address after writing the byte

rscr ← t;* save the byte to write
call[getCDbyteAddr];
call[putCDbyte];* write it

call[getCDbyteAddr];* increment the current address
call[putCDbyteAddr], t ← t+1;
pReturnP[];

putCDbyte: subroutine;* t = byte address, rscr = byte value
pushReturn[];* use stack, clobber rscr, t.
call[fixByteAddrForInstrSet];* modify byte address if required
stack+1 ← t;* save it on the stack
t ← stack;
t and (1c);* see if odd byte
branch[putCDbyteOdd, ALU#0];
*
put it into left side
t ← t rsh 1;* fetch the current 16bit value
FETCH ← t;
t ← MD;

rscr ← lsh[rscr, 10];* position the byte to the left side
t ← t and (377C);* keep the current right side of memory
rscr ← t or (rscr);* Rscr = the new 16 bit value.

t ← (stack) rsh 1;* retrieve memory byte pointer
STORE ← t, DBuf ← rscr;
branch[putCDxit];

putCDbyteOdd:* odd byte address ==> right half of word
t ← t rsh 1;* fetch the current 16bit value
FETCH ← t;
t ← MD;

rscr ← (rscr) and (377c);* isolate the bits on the right side
t ← t and (177400C);* keep the current left side
rscr ← (rscr) or t;* Rscr = the new 16 bit value.

t ← (stack) rsh 1;* retrieve memory byte pointer
STORE ← t, DBuf ← rscr;
putCDxit:
pReturnP[];

getCDbyte:* enter w/ t = byte address
pushReturn[];
call[fixByteAddrForInstrSet];* modify byte address if required
rscr ← t;
branch[getCDodd, r odd], rscr ← (rscr) rsh 1;
FETCH ← rscr;
t ← MD;
t ← rsh[t, 10];
getCDbyteRtn:
returnP[];

getCDodd:
FETCH ← t;
t ← MD;
branch[getCDbyteRtn], t ← t and (377C);

* June 29, 1979 3:35 PM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
When we use instruction set 2 or 3, the ifu fetches bytes in the inverse order. Ie., Loc 0 implies the right byte of word 0 and loc 1 implies the left byte of word 0. This terrible hack accommodates the Alto’s Mesa implementation which addresses bytes in this way.
For the duration, all instruction sets invert the bytes.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
setIUsingInstrSet: subroutine;
return, iUsingInstrSet ← t;
getIUsingInstrSet:
RBASE ← rbase[iUsingInstrSet];
return, t ← iUsingInstrSet, RBASE ← rbase[defaultRegion];
fixByteAddrForInstrSet:
pushReturnAndT[];

call[getIUsingInstrSet];
t-(2c);* invert the order of the bytes if we
skpif[ALU>=0];* are using instr set 3 or 4.
branch[fbaifiRtn], t ← (stack&-1);* rtn w/ t = original input, adjust stack

branch[fbaifiOdd, R ODD], t ← (stack&-1);* put byte addr back into t, adjust stack
branch[fbaifiRtn], t ← t + 1;* it is an even byte address
fbaifiOdd:* address is odd, IN instructionSet2 or 3.
t ← t and (177776C);* remove low order bit
fbaifiRtn:
returnP[];
* August 1, 1979 10:40 AM
%
ResetIfu
Reset the Ifu by performing two IfuReset functions separated by a longWait of 100B cycles.
%
resetIfu: subroutine;
pushReturn[];
t ← t-t;
ifuTest←t;
IfuReset[];
noReschedule[];
call[longWait], t ← 100c;
ifuReset[];
returnP[];

* May 2, 1979 10:32 AM
top level;
call[ifuGetInstrSet];* These two subroutine calls force microD
call[ifuSetInstrSet];* to place the subroutine entry pts properly.
noop;
ifuGetInstrSet: subroutine;
t← not(IFUMLH’);
return, t ← ldf[t, ifu.InstrSetSize, ifu.GetInstrSetShift];

ifuSetInstrSet: subroutine;
t ← t and (ifu.InstrSetMask);
iUsingInstrSet ← t;
t ← lsh[t, ifu.SetInstrSetShift];
t ← t or (100000C);
return, MOS ← t;

* April 24, 1979 8:12 AM
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
test iteration control:
initItest
initTestCount
nextTest

getTestBounds
nextTestCount
These subroutines cause the main ifu diagnostic to iterate a fixed number of times for each test, then to change to the next test.
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
initItest: subroutine;
t←cm1;
return, iTestX←t;
initITestCount:
t ← cm1;
return, iTestCountX←t;

nextITest: subroutine;* RTN: ALU#0 ==> more tests to do;
pushReturn[];* T = memory byte location of current test.
RBASE ← rbase[iTestX];
t ← iTestX ← (iTestX)+1, RBASE ← rbase[defaultRegion];
t # (lastTestC);
branch[nextITestXDone, ALU=0];
Bdispatch ← t;
branch[testMemTable];
set[testMemTbl, 1140];
testMemTable:
branch[nextITest2], t ← test0MemByteLocC,at[testMemTbl,0];
branch[nextITest2], t ← test1MemByteLocC,at[testMemTbl,1];
branch[nextITest2], t ← test2MemByteLocC,at[testMemTbl,2];
branch[nextITest2], t ← test3MemByteLocC,at[testMemTbl,3];
nextITest2:
iCurrentTestLoc ← t;
rscr ← 1c;
nextITestXit:
returnPandBranch[rscr];
nextITestXDone:
branch[nextITestXit], rscr ← t-t;
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
getTestBounds
HIDEOUS DEPENDENCY:
THIS CODE PRESUMES TO KNOW THE LENGTH OF THE PROGRAMS WRITTEN IN MEMRY
RETURNS RSCR = beginning of the current test program in memory (byte location)
RSCR2 = end of current test program in memory (byte location)
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
getTestBounds:
pushReturn[];
RBASE ← rbase[iTestX];
t←iTestX, RBASE ← rbase[defaultRegion];
BDispatch←t;
branch[testMemTable2];
set[
testMemTbl2, 1150];
testMemTable2:* this table sets RSCR = lower bound
branch[gtbl0], rscr ← test0MemByteLocC,at[testMemTbl2,0];
branch[gtbl1], rscr ← test1MemByteLocC,at[testMemTbl2,1];
branch[gtbl2], rscr ← test2MemByteLocC,at[testMemTbl2,2];
branch[gtbl3], rscr ← test3MemByteLocC,at[testMemTbl2,3];

*
This code sets RSCR2 = the upper bound
gtbl0: branch[gtblRtn], rscr2 ← rscr;
gtbl1: branch[gtblRtn], rscr2 ← rscr;
gtbl2: rscr2 ← rscr;
branch[gtblRtn], rscr2 ← (rscr2) + (2c);
gtbl3: rscr2 ← rscr;
rscr2 ← (rscr2) + (6c);

gtblRtn:
returnP[];
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
nextTestCount
This subroutine determines if the current test has executed enough times to go on to the next test. ALU#0 means there are more ifuJumps to come.
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
nextITestCount: subroutine;
pushReturn[];
RBASE ← rbase[iTestCountX];
t ← iCurrentTestLoc;
rscr2 ← t;
t ← iTestCountX ← (iTestCountX)+1, RBASE ← rbase[defaultRegion];
t # (lastTestCountC);
skpif[ALU#0], rscr ← 1c;
rscr ← t-t;
t ← rscr2;
returnPandBranch[rscr];
* June 6, 1979 10:32 AM
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
getIfuNotReadyLoc
Returns T = absolute IM location for the not-Ready dispatch for the current instruction set.Clobber T.
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
getIfuNotReadyLoc:
pushReturn[];
call[ifuGetInstrSet];* return instr set number in t

PD←t, stkp+1;* instruction set 0?
branch[getReady’Ret, ALU=0], stack ← 334C;

t # (1c);* instruction set 1?
skpif[ALU#0];
branch[getReady’Ret], stack ← 234c;

t # (2c);* instruction set 2?
skpif[ALU#0];
branch[getReady’Ret], stack ← 134c;* it’s instr set 2
stack ← 34c;* default = instr set 3
getReady’Ret:
t ← stack&-1;
returnP[];
* May 4, 1979 10:07 AM
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ifuTestLoop
This code implements an infinite loop associated with one of the various ifu execution tests. If all goes well, control will pass from the location of the IfuJump to after Dispatch to the location that perfroms the ifuJump (again). In the event a random transfer of control occurs, the place in IM where control passes must be patched to the location "ifuTestL" which will reset PcF. Note that we suck 4 IDs from Ifu -- to free pipe in case of 3 byte instructions w/ encoded constant, packed alpha, etc.
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ifuTestLoop:
top level;
t ← t-1;* enter w/ t = index of ifu test
iTestX ← t;
call[initIfuCache];
call[setIUsingInstrSet], t ← 3c;
call[nextItest];
skpif[ALU#0];
ifuTestLErr:* entered with a bad value in T
error;
stack+1 ← t;* remember the byte location in the stack.
ifuTestL:
call[resetIfu];
PcF ← stack;
call[setIfuTestLRet];
ifuTestLRet:
A←ID;
A←ID;
A←ID;
IfuJump[0], A←ID;

setIfuTestLRet:
pushReturn[];
call[sitlr2];
t ← link;
klink ← t;
returnP[];
sitlr2:
coreturn;
branch[ifuTestLRet];