%
Page Numbers: Yes First Page: 1
Heading:
eventCounters2.mcOctober 13, 1979 12:32 PM%
* INSERT[D1ALU.MC];
* TITLE[Ifu4];
* INSERT[PREAMBLE.MC];
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CONTENTS

TEST
DESCRIPTION
beginEventcounters1:Control subroutine that calls each test in this file
eventTrue:Test event counters A&B for True (always counting).
eventHold:Test event counters A&B for Hold
eventRef:Test event counters A&B for processor/ifu references
eventIfuJump:Test event counters A&B for various Ifu jumps
eventMiss:Test event counters A&B for Misses
eventFlushMunches:Flush munches [0..t]
eventEmuOrFT:Test event counters A&B for ability to count only EmuOrFT
zeroAndEnableCounter:zero specified counter and enable specified conditions
readCounterARead current value of counter A
readCounterBRead current value of counter B
eventArithcompute counter value given raw ←EventCnt* value.
getElapsedHi:Return current value of ctrElapsedHi
getElapsedLo:Return current value of ctrElapsedLo
getBeginCtrs:Push the values for beginCtrHi, beginCtrLo onto stack
initJunkForWakeups:Setup Junk task’s tpc
disableJunkTPC:Make junk wakeups cause midas breakpoint.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

%
October 13, 1979 12:32 PM
forgot to fix ctr.aTasksAll.
October 13, 1979 12:20 PM
Fix bug in definition of ctr.AtasksAll, fix omitted skpif s in event3EmuOrFt.
October 12, 1979 7:57 PM
Add some formatting in eventEmuOrFT.
October 12, 1979 7:46 PM
Fix bug in task16/17 stuff that failed to save link in T.
October 12, 1979 7:15 PM
Change constant name to ctr.tasksAll. Change eventEmuOrFT to accommodate my new & correct understanding that emuOrFT is the default (ie the bit value is zero) arrangement and setting the bit causes All tasks to be counted.
October 12, 1979 2:51 PM
Add eventEmuOrFT. Rename this file to be eventCountres2.mc
October 12, 1979 11:07 AM
Rename file to eventCounters1.mc
October 12, 1979 9:15 AM
Add code for eventMiss
October 11, 1979 6:24 PM
Add top level loop control to eventIfuJump -- had omitted it.
October 11, 1979 6:18 PM
Fix bug in eventIfuJump: called readEventB when needed eventA, computed expected number of jumps incorrectly (off by 1).
October 11, 1979 5:55 PM
Add code for IfuJumps (successful & not ready)
October 11, 1979 5:38 PM
fix eventBrefErrLo bug that failed to compute 3*(nIfuJumps+1) -- computed 3*nIfuJumps +1.
October 11, 1979 4:58 PM
Fix "value for PcF" bug in eventBrel.
October 11, 1979 2:23 PM
Fix a bug in eventHold, add code for Ref.
October 11, 1979 11:07 AM
Add eventHold, eventRef, eventIfuJump, eventMiss (stubs for Ref, IfuJump &Miss).
October 10, 1979 3:58 PM
Add ←EventCntB.
October 10, 1979 3:56 PM
Add readEventB, eventArith, modify eventTrue to test eventB.
October 9, 1979 5:02 PM
More fixes to zeroAndEnableCounter. Finishing implications of earlier change that more cleanly separated counterA from counterB; also remove incorrect loop control stuff in eventtrue.
October 9, 1979 12:58 PM
Fix handling of zeroANdEnableCounter -- discovered that disabling the counter then reading it doesn’t accomplish anything.
October 9, 1979 10:40 AM
Change error labels, fix handling of readCounterA.
October 1, 1979 2:38 PM
Fix stkp bug in zeroAndEnableCounter, fix bug in handldig link in initJunkForWakeups.
October 1, 1979 11:02 AM
Add getBeginCtrs, fix readCounterA to compute elapsed time, initialize task 2 so that junk wakeups don’t cause everything to screw up.
September 27, 1979 10:03 AM
Construct this file and the test for "true".
%

* September 27, 1979 10:04 AM
beginEventcounters2:
pushReturn[];
call[disableConditionalTask];
call[initJunkForWakeups];
call[eventTrue];* test counting all cycles.
call[eventHold];* test hold couting
call[eventRef];* test memory reference counting
call[eventIfuJump];* test ifu jump counting
call[eventMiss];* test memory reference miss counting
call[eventEmuOrFT];* test counting for emulator or faulttask, only
call[disableJunkTPC];
returnP[];
* October 13, 1979 12:32 PM

%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
These constants define the way BMux inputs affect the counters when the processor performs "MOS←" FFs. IF b0=1 then the ifu instruction set gets loaded; otherwise, the counters load control information.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
m[EventCntA’, IFA[BSEL,ER[Multiple.B.sources],FF256[171]] B ];
m[
EventCntB’, IFA[BSEL,ER[Multiple.B.sources],FF256[174]] B ];
mc[
ctr.Aenable, b4];
set[
ashift, 5];

mc[
ctr.Atrue, lshift[0, ashift]];* A always counts
mc[
ctr.Ahold, lshift[1, ashift]];* A counts holds
mc[
ctr.AprocRef,, lshift[2, ashift]];* A counts proc references
mc[
ctr.AifuJump, lshift[3, ashift]];* A counts good good ifu jumps (not (hold or exception))
mc[
ctr.Amiss, lshift[4, ashift]];* A counts misses
mc[
ctr.AbpA, lshift[5, ashift]];* A counts back pannel events A, C, or E
mc[
ctr.AbpC, lshift[6, ashift]];
mc[
ctr.AbpE, lshift[7, ashift]];
mc[
ctr.AtasksAll, b11];

mc[
ctr.Benable, b5];
set[
Bshift, 1];

mc[
ctr.Btrue, lshift[0, bshift]];* B always counts
mc[
ctr.Bhold, lshift[1, bshift]];* B counts holds
mc[
ctr.BifuRef,, lshift[2, bshift]];* B counts ifu references
mc[
ctr.BifuNotReady, lshift[3, bshift]];* B counts not ready ifu jumps
mc[
ctr.Bmiss, lshift[4, bshift]];* B counts misses
mc[
ctr.BbpB, lshift[5, bshift]];* B counts back pannel events B, C, or D
mc[
ctr.BbpC, lshift[6, bshift]];
mc[
ctr.BbpD, lshift[7, bshift]];
mc[
ctr.BtasksAll, b15];



* October 8, 1979 6:20 PM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
eventTrue
This test checks that the event counters on the ifu board will work when the "TRUE" (always count) option is used. The basic idea is to zero the current count, initialize the counters and then loop for a fixed number of iterations. We should be able to predict closely how many cycles the event counters read. There are several complications:
1) The counters begin counting as soon as we enable them & there may be more than zero cycles between enabling the counters and beginning the fixed iterations.
2) We cannot read the counters instantaneously, so they will continue to tick, even as we prepare to read them.
3) If we use the wakeup task to update our count, an unpredictable number of wakeups -- and there fore unpredictable number of cycles -- may occur.
4) THEREFOR we insist the count be close, but not necessarily exact.

eventTrue: PROCEDURE =
BEGIN
FOR i IN [1..25] DO
-- test counter "A": zero& enable true, iterate "i" times then check results
ZeroAndEnableCounter[A, TRUE];

FOR j IN [0..i] DO ; -- fixed iterations to test counter A

[x,y] ← readClock[A];
IF x #0 THEN ERROR; -- no way the hi-order bits should be set
difference ← y - ourBestGuess;
IF difference > ourBestHedge THEN ERROR; -- not counting properly

-- test counter "B": zero& enable true, iterate "i" times then check results
ZeroAndEnableCounter[B,TRUE];

FOR j IN [0..i] DO ; -- fixed iterations to test counter B

[x,y] ← readClock[B];
IF x #0 THEN ERROR; -- no way the hi-order bits should be set
difference ← y - ourBestGuess;
IF difference > ourBestHedge THEN ERROR; -- not counting properly
ENDLOOP;
END;
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

* October 9, 1979 5:02 PM
eventTrue:
pushReturn[];
rscr2←100c;* we’ll try it a maximum of 25 times
eventTrueL:
t←ctr.Aenable;
t←t or (ctr.Atrue);
call[zeroAndEnableCounter], cnt←rscr2;
loopUntil[CNT=0&-1, .];
noop;
call[readCounterA];
call[getElapsedHi];* return w/ t = elapsed hi
skpif[ALU=0];
eventATrueErrHi:* shouldn’t have hi order bits non zero-- only looped 25 times max!
error;

* error unless nCycles< elapsedLo < nCycles+20B We’re using 20B as a slop factor.

t←(rscr2)+(20c);
call[getElapsedLo], rscr←t;
t←(t) - (rscr);* elapsed time - nCycles+overhead
skpif[ALU<0];
eventATrueErrBig:* guess it takes 10 cycles overhead to do everything.
error;* plus 10 should be greater then elapsed lo

call[getElapsedLo];
(rscr2)-t;
skpif[ALU<0];
eventATrueErrSmall:* elapsed lo is too small. It should be greater than the loop count.
error;* rscr2= loop count, t = elapsed lo

t←ctr.Benable;
t←t or (ctr.Btrue);
call[zeroAndEnableCounter], cnt←rscr2;
loopUntil[CNT=0&-1, .];
noop;
call[readCounterB];
call[getElapsedHi];* return w/ t = elapsed hi
skpif[ALU=0];
eventBTrueErrHi:* shouldn’t have hi order bits non zero-- only looped 25 times max!
error;

* error unless nCycles< elapsedLo < nCycles+20B We’re using 20B as a slop factor.

t←(rscr2)+(20c);
call[getElapsedLo], rscr←t;
t←(t) - (rscr);* elapsed time - nCycles+overhead
skpif[ALU<0];
eventBTrueErrBig:* guess it takes 10 cycles overhead to do everything.
error;* plus 10 should be greater then elapsed lo

call[getElapsedLo];
(rscr2)-t;
skpif[ALU<0];
eventBTrueErrSmall:* elapsed lo is too small. It should be greater than the loop count.
error;* rscr2= loop count, t = elapsed lo

rscr2←(rscr2)-1;
loopUntil[ALU<0, eventTrueL];
returnP[];
* October 11, 1979 12:19 PM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Count holds.
This program is complicated by the fact that we use memory references to count holds. Unfortunately, memory references may cause an unspecified number of holds if they cause storage references (since a refresh could occur or be occuring & thereby cause an unspecified number of holds). Therefore we will cause MDI holds on references to the cache, which occur for only one cycle.

iMem[];
-- initialize memory system for our use
FOR holds IN [1..100B] DO
-- test counter A
zeroAndEnableCounter[A, hold];
ignore ← Mem[0];
* force vm 0 into cache
FOR j IN [0..holds] DO
ignore ← (Mem[0] OR 0);-- force MDI hold
ENDLOOP;
[elapsedHi, elapsedLo] ← readCounterA[];
IF elapsedHi # 0 THEN ERROR;
-- never made more than 10d1B references!
IF elapsedLo # (j+1) THEN ERROR;
-- made exactly j+1 references

-- test counterB

zeroAndEnableCounter[B, hold];
ignore ← Mem[0];
* force vm 0 into cache
FOR j IN [0..holds] DO
ignore ← (Mem[0] OR 0);-- force MDI hold
ENDLOOP;
[elapsedHi, elapsedLo] ← readCounterB[];
IF elapsedHi # 0 THEN ERROR;
-- never made more than 10d1B references!
IF elapsedLo # (j+1) THEN ERROR;
-- made exactly j+1 references
ENDLOOP;
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

eventHold:
pushReturn[];
call[iMem];* initialize memory system
rscr2 ← 100c;* try 1-100B holds
t←a0;
Fetch←t;
eventHoldL:
rscr2←(rscr2)-1;
skpif[ALU>=0];
branch[eventHoldXit];

cnt←rscr2;
t←ctr.Aenable;
t←t or (ctr.Ahold);
call[zeroAndEnableCounter], rscr←Md;* init the counter, cause any leftover holds to occur.

t←a0;
Fetch←t;
loopUntil[cnt=0&-1, .-1], rscr ← (Md) or (rscr);* MDI hold

call[readCounterA];
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];
eventAHoldErrHi:* since we made only one hold per
error;* reference we should never get many holds


call[getElapsedLo], rscr←(rscr2)+1;
t # (rscr);* we should have exactly as many holds as
skpif[ALU=0];* references.
eventAHoldErrLo:* t = number of holds by the counters,
error;* rscr = number of holds we actually made

cnt←rscr2;
t←ctr.Benable;
t←t or (ctr.Bhold);
call[zeroAndEnableCounter], rscr←Md;* init the counter, cause any leftover holds to occur.

t←a0;
Fetch←t;
loopUntil[cnt=0&-1, .-1], rscr ← (Md) or (rscr);* MDI hold

call[readCounterB];
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];
eventBHoldErrHi:* since we made only one hold per
error;* reference we should never get many holds


call[getElapsedLo], rscr←(rscr2)+1;
t # (rscr);* we should have exactly as many holds as
skpif[ALU=0];* references.
eventBHoldErrLo:* t = number of holds by the counters,
error;* rscr = number of holds we actually made

branch[eventHoldL];

eventHoldXit:
returnP[];
* October 11, 1979 5:26 PM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
eventRef
Count references. CounterA counts processor references while CounterB counts Ifu references, so those must be tested differently.

initIfuCache[];
-- initialize ifumemory, memory system, etc.

-- test ability to count processor references.

FOR refs IN [1..100B] DO
zeroAndEnableCounter[A, procRefs];
FOR j IN [1..refs] DO
ignore ← mem[0];
ENDLOOP;

[elapsedHi, elapsedLo] ← readCounterA[];
IF elapsedHi #0 THEN ERROR;
-- shouldn’t be greater than 101B !!
IF elapsedLo # (refs+1) THEN ERROR;
-- made exactly refs+1 references

-- test abilit;y to count processor references

KLINK ← @eventRefCont;
-- set up return link after IfuJump
zeroAndEnableCounter[B, ifuRefs];
FOR j IN [1..refs] DO
resetIfu[];
PcFG ← locationOfPauseOpcode;
THROUGH [1..10] DO;
-- wait 10 cycles for ifud to be ready
IfuJump[0];
eventRefCont:
IF cameFrom # opAt15 THEN ERROR;-- didn’t ifuJump to right place
ENDLOOP;

[elapsedHi, elapsedLo] ← ReadCounterB[];
IF elapsedHi #0 THEN ERROR;
-- shouldn’t be greater than 101B*3 !!
IF elapsedLo # (3*(refs+1)) THEN ERROR; -- we assume the ifu made 3 references to fill F, G, and HJ.

ENDLOOP;
-- loop for next "refs" value.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
eventRef:
pushReturn[];
call[initIfuCache];
rscr2←100C;
q←rscr2;* keep number of iterations in Q !!
eventRefL:
t←(q);
t←t-1;
PD ← q←t;
skpif[ALU>=0];
branch[eventRefXit];

t←ctr.Aenable;
call[zeroAndEnableCounter], t←t or (ctr.AprocRef);

t←q;
cnt←t;
loopUntil[cnt=0&-1, .], Fetch←t;* make cnt references

call[readCounterA];
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];
eventARefErrHi:* made max 101B references! elapsedHi
error;* is too big (t=elapsedHi)

call[getElapsedLo];
rscr←(q)+1;
t # (rscr);* procRefs should be rscr. counter said
skpif[ALU=0];* there were t references.
eventArefErrLo:
error;

t←ctr.Benable;
call[zeroAndEnableCounter], t←t or (ctr.BifuRef);

t←q;
cnt←t;

call[setEventBRefKlink];
t← 3c;
call[ifuSetInstrSet];
rscr ← opPause;
call[putCDbyte], t←a0;* place a pause opcode at byte location 0
call[resetIfu];
eventBrefL:* top of local loop for ifu jumps
t←a0;
PcF←t;
t←10c;
loopUntil[ALU=0, .], t←t-1;
ifuJump[0];

eventBrefCont:
(rscr) # (opAt15);* see if we went to correct ifu dispatch
skpif[ALU=0];
eventBrefErrLoc:* ifu should have dispatched us to opAt15.
error;* instead we went to absolute location rscr.

loopUntil[CNT=0&-1, eventBrefL];* execute req’d number of ifuJumps

call[readCounterB];* did right number of ifu refs happen?
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];* shouldn’t have a big number. we only
eventBrefErrHi:* made maximum of 101B ifujumps. !!
error;

t←q;
t←t+t;
call[getElapsedLo], rscr←t+(q);* get rscr ← 3* (numIfuJumps+1), t=ctrLo
rscr ← (rscr)+(3C);
t#(rscr);
skpif[ALU=0];
eventBrefErrLo:* expected num Ifu references = rscr,
error;* counters counted number in t

branch[eventRefL];
eventRefXit:
returnP[];

setEventBRefKlink:
pushReturn[];
call[getEventBRefKlink];
t←link;
klink←t;
returnP[];
getEventBRefKlink:
coreturn;
branch[eventBrefCont];
top level;
* October 11, 1979 6:25 PM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
eventIfuJump
Test the counter’s ability to count successful and unsuccessful Ifu jumps. this code is patterned after the code that checks ifuReferences. see above.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
eventIfuJump:
pushReturn[];
call[initIfuCache];
rscr2←100C;
q←rscr2;* keep number of iterations in Q !!
eventIfuJumpL:* top level loop control
t←q;
t←t-1;
PD←(q←t);
skpif[ALU>=0];
branch[eventIfuJumpXit];

t←ctr.Aenable;
call[zeroAndEnableCounter], t←t or (ctr.AifuJump);

t←q;
cnt←t;

call[setEventAIfuJumpKlink];
t← 3c;
call[ifuSetInstrSet];
rscr ← opPause;
call[putCDbyte], t←a0;* place a pause opcode at byte location 0
call[resetIfu];
eventAIfuJumpL:* top of local loop for ifu jumps
t←a0;
PcF←t;
rscr←10c;
loopUntil[ALU=0, .], rscr←(rscr)-1;* wait to assure successful
ifuJump[0];* ifu jump dispatch

eventAIfuJumpCont:
(rscr) # (opAt15);* see if we went to correct ifu dispatch
skpif[ALU=0];
eventAIfuJumpErrLoc:* should have dispatched to opAt15.
error;* instead we went to absolute location rscr.

loopUntil[CNT=0&-1, eventAIfuJumpL];* execute req’d number of ifuJumps

call[readCounterA];* did right number of ifu jumps happen?
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];* shouldn’t have a big number. we only
eventAIfuJumpErrHi:* made maximum of 101B ifujumps. !!
error;

rscr←q;
call[getElapsedLo], rscr←(rscr)+1;* get rscr ← nIfuJumps (all successful)
t#(rscr);
skpif[ALU=0];
eventAIfuJumpErrLo:* expected num Ifu jumps = rscr,
error;* counters counted number in t

t←ctr.Benable;
call[zeroAndEnableCounter], t←t or (ctr.BifuNotReady);

t←q;
cnt←t;

call[setEventBIfuReady’Klink];
t← 3c;
call[ifuSetInstrSet];
rscr ← opPause;
call[putCDbyte], t←a0;* place a pause opcode at byte location 0
call[resetIfu];
eventBIfuReady’L:* top of local loop for ifu jumps
t←a0;
PcF←t;
noop;* must wait once cycle after ifujump
ifuJump[0];

eventBIfuReady’Cont:
(rscr) # (is3notReadyLocC);* see if we went to correct ifu dispatch
skpif[ALU=0];
eventBIfuReady’ErrLoc:* should have dispatched to notReady.
error;* instead we went to absolute location rscr.

loopUntil[CNT=0&-1, eventBIfuReady’L];* execute req’d number of ifuJumps

call[readCounterB];* did right number of ifu jumps happen?
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];* shouldn’t have a big number. we only
eventBIfuReady’ErrHi:* made maximum of 101B ifujumps. !!
error;

rscr←q;
call[getElapsedLo], rscr←(rscr)+1;* get rscr ← nIfuJumps (all not ready)
t#(rscr);
skpif[ALU=0];
eventBIfuReady’ErrLo:* expected num Ifu jumps = rscr,
error;* counters counted number in t

branch[eventIfuJumpL];
eventIfuJumpXit:
returnP[];





setEventAIfuJumpKlink:* init Klink for ifuJump counter test
pushReturn[];
call[getEventAIfuJumpKlink];
t←link;
klink←t;
returnP[];
getEventAIfuJumpKlink:
coreturn;
branch[eventAIfuJumpCont];
top level;
returnP[];

setEventBIfuReady’Klink:
* init Klink for ifu notReady counter test
pushReturn[];
call[getEventBIfuReady’Klink];
t←link;
klink←t;
returnP[];
getEventBIfuReady’Klink:
coreturn;
branch[eventBIfuReady’Cont];
top level;
returnP[];
* October 12, 1979 2:49 PM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
eventMiss
Count memory misses. This code flushes a collection of virtual addresses, then references them. The first reference to each flushed munch should cause a miss.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
eventMiss:
pushReturn[];
call[iMem];* initialize memory system
rscr2 ← 20c;* try 1-20B misses
t←a0;
Fetch←t;
eventMissL:
rscr2←(rscr2)-1;
skpif[ALU>=0];
branch[eventMissXit];

t←rscr2;
call[eventFlushMunches];
cnt←rscr2;
t←ctr.Aenable;
call[zeroAndEnableCounter], t←t or (ctr.Amiss);

rscr←rscr2;
t←a0;

cnt←17s;
loopUntil[CNT=0&-1, .], t← (Fetch←t)+1;* fetch words in the munch
rscr←(rscr)-1;* this is the munch loop control
loopWhile[ALU>=0, .-3];* fetch next munch, if more to go

call[readCounterA];
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];
eventAMissErrHi:* since we made only one miss per
error;* reference we should never get many misss


call[getElapsedLo], rscr←(rscr2)+1;
t # (rscr);* we should have exactly as many misss as
skpif[ALU=0];* references.
eventAMissErrLo:* t = number of misss by the counters,
error;* rscr = number of misss we actually made

call[eventFlushMunches], t←rscr2;
cnt←rscr2;
t←ctr.Benable;
call[zeroAndEnableCounter], t←t or (ctr.Bmiss);

rscr←rscr2;
t←a0;

cnt←17s;
loopUntil[CNT=0&-1, .], t← (Fetch←t)+1;* fetch words in the munch
rscr←(rscr)-1;* this is the munch loop control
loopWhile[ALU>=0, .-3];* fetch next munch if more to go

call[readCounterB];
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];
eventBMissErrHi:* since we made only one miss per
error;* reference we should never get many misss


call[getElapsedLo], rscr←(rscr2)+1;
t # (rscr);* we should have exactly as many misss as
skpif[ALU=0];* references.
eventBMissErrLo:* t = number of misss by the counters,
error;* rscr = number of misss we actually made

branch[eventMissL];

eventMissXit:
returnP[];


* October 12, 1979 10:17 AM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
eventFlushMunches
Flush munches [0..t].
Clobber cnt, t, rscr
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

eventFlushMunches:
subroutine;
cnt←t, t←a0;
rscr←20c;
loopUntil[CNT=0&-1, .], t← (Flush←t)+(rscr);
return;
top level;
* October 12, 1979 7:22 PM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
eventEmuOrFT
Make sure the event counters will count only EmuOrFT events. This code is a copy of the eventHold code, suitably modified.
Sequence of tests:
Task executingTasks enabledCounter activityLabel Prefix
0allcounteventEmuOrFT
17allcountevent2EmuOrFT
16emuOrFtno countingevent3EmuOrFT
16allcountevent4EmuOrFT

%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
eventEmuOrFT:
pushReturn[];
call[iMem];* initialize memory system
rscr2 ← 100c;* try 1-100B holds
t←a0;
Fetch←t;
eventEmuOrFTL:
rscr2←(rscr2)-1;
skpif[ALU>=0];
branch[eventEmuOrFTXit];

cnt←rscr2;
t←ctr.Aenable;
t←t or (ctr.Ahold);
t←t or (ctr.AtasksAll);
call[zeroAndEnableCounter], rscr←Md;* init the counter, cause any leftover holds to occur.

t←a0;
Fetch←t;
loopUntil[cnt=0&-1, .-1], rscr ← (Md) or (rscr);* MDI hold

call[readCounterA];
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];
eventAEmuOrFTErrHi:* since we made only one hold per
error;* reference we should never get many holds


call[getElapsedLo], rscr←(rscr2)+1;
t # (rscr);* we should have exactly as many holds as
skpif[ALU=0];* references.
eventAEmuOrFTErrLo:* t = number of holds by the counters,
error;* rscr = number of holds we actually made

cnt←rscr2;
t←ctr.Benable;
t←t or (ctr.Bhold);
t←t or (ctr.BtasksAll);
call[zeroAndEnableCounter], rscr←Md;* init the counter, cause any leftover holds to occur.

t←a0;
Fetch←t;
loopUntil[cnt=0&-1, .-1], rscr ← (Md) or (rscr);* MDI hold

call[readCounterB];
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];
eventBEmuOrFTErrHi:* since we made only one hold per
error;* reference we should never get many holds


call[getElapsedLo], rscr←(rscr2)+1;
t # (rscr);* we should have exactly as many holds as
skpif[ALU=0];* references.
eventBEmuOrFTErrLo:* t = number of holds by the counters,
error;* rscr = number of holds we actually made
* October 12, 1979 7:58 PM
event2EmuOrFT:
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Now we do the same thing, except that we make the references in Task 17.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

cnt←rscr2;
t←ctr.Aenable;
t←t or (ctr.Ahold);
t←t or (ctr.AtasksAll);
call[zeroAndEnableCounter], rscr←Md;* init the counter, cause any leftover holds to occur.

call[runEventTask17];

call[readCounterA];* run task 17 memory references.
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];
event2AEmuOrFTErrHi:* since we made only one hold per
error;* reference we should never get many holds


call[getElapsedLo], rscr←(rscr2)+1;
t # (rscr);* we should have exactly as many holds as
skpif[ALU=0];* references.
event2AEmuOrFTErrLo:* t = number of holds by the counters,
error;* rscr = number of holds we actually made

cnt←rscr2;
t←ctr.Benable;
t←t or (ctr.Bhold);
t←t or (ctr.BtasksAll);
call[zeroAndEnableCounter], rscr←Md;* init the counter, cause any leftover holds to occur.

call[runEventTask17];* run task 17 memory references.

call[readCounterB];
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];
event2BEmuOrFTErrHi:* since we made only one hold per
error;* reference we should never get many holds


call[getElapsedLo], rscr←(rscr2)+1;
t # (rscr);
skpif[ALU=0];
event2BEmuOrFTErrLo:* t = number of holds by the counters,
error;* rscr = number of holds we actually made
* October 12, 1979 7:58 PM
event3EmuOrFT:

%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Now we do the same thing, except that we make the references in Task 16.
This means the counters should
NOT count when we fail to set ctr.tasksAll.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

cnt←rscr2;
t←ctr.Aenable;
t←t or (ctr.Ahold);
call[zeroAndEnableCounter], rscr←Md;* init the counter, cause any leftover holds to occur.

call[runEventTask16];

call[readCounterA];* run task 17 memory references.
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];
event3AEmuOrFTErrHi:* since we made only one hold per
error;* reference we should never get many holds


call[getElapsedLo];
skpif[ALU=0];
event3AEmuOrFTErrLo:* t = number of holds by the counters,
error;* remember we disabled tasks other than EmuOrFT

cnt←rscr2;
t←ctr.Benable;
t←t or (ctr.Bhold);
call[zeroAndEnableCounter], rscr←Md;* init the counter, cause any leftover holds to occur.

call[runEventTask16];* run task 17 memory references.

call[readCounterB];
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];
event3BEmuOrFTErrHi:* since we made only one hold per
error;* reference we should never get many holds


call[getElapsedLo];
skpif[ALU=0];
event3BEmuOrFTErrLo:* t = number of refs by the counters,
error;* remember we disabled tasks other than EmuOrFT

* October 12, 1979 7:58 PM
event4EmuOrFT:

%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Enable normal counting (for ALL tasks) and make sure that non-emulator references get counted properly.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

cnt←rscr2;
t←ctr.Aenable;
t←t or (ctr.Ahold);
t←t or (ctr.AtasksAll);
call[zeroAndEnableCounter], rscr←Md;* init the counter, cause any leftover holds to occur.

call[runEventTask16];

call[readCounterA];* run task 17 memory references.
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];
event4AEmuOrFTErrHi:* since we made only one hold per
error;* reference we should never get many holds


call[getElapsedLo], rscr←(rscr2)+1;
t # (rscr);* we should have exactly as many holds as
skpif[ALU=0];* references.
event4AEmuOrFTErrLo:* t = number of holds by the counters,
error;* rscr = number of holds we actually made

cnt←rscr2;
t←ctr.Benable;
t←t or (ctr.Bhold);
t←t or (ctr.BtasksAll);
call[zeroAndEnableCounter], rscr←Md;* init the counter, cause any leftover holds to occur.

call[runEventTask16];* run task 17 memory references.

call[readCounterB];
call[getElapsedHi];
t←t;* for placement.
skpif[ALU=0];
event4BEmuOrFTErrHi:* since we made only one hold per
error;* reference we should never get many holds


call[getElapsedLo], rscr←(rscr2)+1;
t # (rscr);* we should have exactly as many holds as
skpif[ALU=0];* references.
event4BEmuOrFTErrLo:* t = number of holds by the counters,
error;* rscr = number of holds we actually made

branch[eventEmuOrFTL];

eventEmuOrFTXit:
returnP[];
* October 12, 1979 7:45 PM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Task code
This code supports the use of task 17 and task16 for the eventEmuOrFT test.
runEventTask17:Initialize tpc for task 17 and run it.
getEventTask17Run:return in T the absolute location of the 1st instruction for task 17
eventTask17Run:Actual task 16 code that executes.
runEventTask16:Initialize tpc for task 16 and run it.
getEventTask16Run:return in T the absolute location of the 1st instruction for task 16
eventTask16Run:Actual task 16 code that executes.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
runEventTask17: subroutine;
pushReturn;
call[getEventTask17Run];
subroutine;
link←t;
top level;
LdTpc←17c;
notify[17];
returnP[];

getEventTask17Run:
pushReturn[];
call[get2EventTask17Run];
t←link;
returnP[];

get2EventTask17Run:
coreturn;
eventTask17Run:* This code must appear immediately following the coreturn in get2EventTask17Run !!!
RBASE ← rbase[defaultRegion];
MemBase←0s;
t←a0;
Fetch←t;
loopUntil[cnt=0&-1, .-1], rscr ← (Md) or (rscr);* MDI hold
set[xtask, 1];
block;
goto[.], breakpoint;
set[xtask, 0];

runEventTask16: subroutine;
pushReturn;
call[getEventTask16Run];
subroutine;
link←t;
top level;
LdTpc←16c;
notify[16];
returnP[];

getEventTask16Run:
pushReturn[];
call[get2EventTask16Run];
t←link;
returnP[];

get2EventTask16Run:
coreturn;
eventTask16Run:* This code must appear immediately following the coreturn in get2EventTask16Run !!!
RBASE ← rbase[defaultRegion];
MemBase←0s;
t←a0;
Fetch←t;
loopUntil[cnt=0&-1, .-1], rscr ← (Md) or (rscr);* MDI hold
set[xtask, 1];
block;
goto[.], breakpoint;
set[xtask, 0];
* October 10, 1979 3:45 PM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1. Enable the counter condition
2. Read and save the current value (negate it so future reads work properly)
ZeroAndEnableCounter: PROCEDURE[counter, enable] =
BEGIN
mosValue ← [talkToCounters, counterBit];
mos ← mosValue;

beginLo ← readCounter[counter];
-- hwre returns not(currentValue)
IF (-beginLo+1) <0 THEN ctrFlag←-1 ELSE ctrFlag←0;
beginLo ← beginLo+1;
-- compute "-currentValue"
beginHi←0;
ctrLo ← beginLo; ctrHi ← beginHi;

END;

ENTER:
t = entire MOS value, including counter enable bits
EXIT:
ctrLo, ctrHi, ctrBeginLo, ctrBeginHi, ctrFlag set to appropriate values
CLOBBER:
t, rscr, various "ctr" registers
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
zeroAndEnableCounter:
noop, global;
pushReturn[];* t = entire MOS value, including the counter bit
mos ← t, ctrFlag←a1;* enable current condition
t and (ctr.Aenable);* decide which counter we are using
skpif[ALU=0], rscr←1c;
skip, t←(rscr)+(EventCntA’);* we’re using EventCntA
t←(rscr)+(EventCntB’);* we’re using EventCntB

* ctrFlag default initialized to -1
ctrLo←t;* external bmux sources are complemented.
skpif[ALU>=0], ctrBeginLo←t;
ctrFlag ← a0;* ctrFlag gets fixed to zero
ctrHi←A0;
ctrBeginHi←A0;
returnP[];
* October 10, 1979 3:45 PM

%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Read the current value of event counterA or counterB. ctrFlag is negative if the last value of EventCntA that we noticed was negative.
CLOBBER:
t, lastEventA, ctrHi, ctrLo, ctrElapsedHi, ctrElapsedLo, ctrFlag
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
readCounterA:
pushReturn[];
taskingOff, PD←ctrFlag;
*
t←(ctrLo)-(EventCntA’)-1, branch[.+3, alu>=0];* get low part of result
t←(EventCntA’);
call[eventArith], lastEventA←(t);
returnP[];

readCounterB:

pushReturn[];
taskingOff, PD←ctrFlag;
*
t←(ctrLo)-(EventCntB’)-1, branch[.+3, alu>=0];* get low part of result
t←(EventCntB’);
call[eventArith], lastEventB←(t);
returnP[];


eventArith: subroutine;
t←(ctrLo)-(t);
t←(t)-1, branch[.+3, alu>=0];* get low part of result
taskingOn, branch[.+3, ALU<0];* low part overflow iff ctrFlag<0 and ctrLo>=0
ctrHi←(ctrHi)+1, skip;
taskingOn;
ctrLo←t;* remember to save new ctrLo!
ctrElapsedLo←t;* remember to save new ctrLo!

skpif[ALU>=0], ctrFlag←a0;
ctrFlag←a1;* update ctrFlag iff ctrLo is in 2nd cycle
t←ctrHi;
return, ctrElapsedHi←t;
* October 9, 1979 5:48 PM

getElapsedHi: subroutine;
RBASE ← rbase[ctrElapsedHi];
return, t←ctrElapsedHi, RBASE ← rbase[defaultRegion];

getElapsedLo: subroutine;
RBASE ← rbase[ctrElapsedLo];
return, t←ctrElapsedLo, RBASE ← rbase[defaultRegion];

getBeginCtrs: subroutine;
RBASE ← rbase[ctrBeginHi];
t←ctrBeginHi;
stack+1←t;
t←ctrBeginLo;
stack+1←t;
return, RBASE ← rbase[defaultRegion];
* October 1, 1979 2:33 PM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Initialize the junk wakeup’s tpc. when we test the counters we enable the junk wakeup.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
initJunkForWakeups:
pushReturn[];
call[getJWtpc];* get junk wakeup’s initialization tpc
taskingOff;* into link
LdTpc←2c;
taskingOn;
returnP[];

getJWtpc:* this subroutine sets up link to point to junkInit
subroutine;
coreturn;
top level;
set[xtask,1];
junkInit:* this is the code for the junk task
t←a0;
junkWakeupL:* top of junk loop
t←t+1;
call[justReturn];* waste a few cycles.
branch[junkWakeupL], block;
set[xtask,0];

* October 1, 1979 2:42 PM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Disable the junk wakeup’s tpc. Further notifies of the junk task will cause control to go to IMX 7777, where we believe there is a midas breakpoint.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
disableJunkTPC:
pushReturn[];
t←a1;* use IMX 7777 for task 2 for now on.
taskingOff;

subroutine;
link←t;
top level;
ldtpc←2c;

taskingOn;
returnP[];