%
Page Numbers: Yes First Page: 1
Heading:
Ifu3c.mcMay 17, 1982 5:57 PM%
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Table of Contents
Organized by Occurence of subroutine in this Listing
SubroutineFunction
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
beginIfu3c:"main control", it calls the test subroutines
iReschedTest:test Ifu reschedule for defered, non-deferred operation
iRamPEtest:test ramPe exception conditions
ifuChaos:Test randomly constructed opCodes.
ifuBrkInsTestTest execution of opcodes sourced from BrkIns
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%
May 17, 1982 5:57 PM
Add comments.
June 21, 1981 1:21 PM
Fix ifuChaos to use POINTERS value saved by afterDispatch when checking Membase values
June 20, 1981 2:51 PM
Have to set Jump bit in ifum for RamPe stuff, too.
June 20, 1981 11:06 AM
Finally found an IFU hardware design bug that causes RamPE exception to be forgotten if ReschedPending is true and the opcode after the one w/ the bad parity has good parity. Fix in microcode is to keep the pause bit logically true. That prevents J from loading valid data after causing a ram pe.
June 18, 1981 1:53 PM
Add new section to iRamPEtest that actually executes ram pe jumps.
June 18, 1981 10:24 AM
Add a call to longWait in iRamPEtest to avoid notReady dispatch
May 20, 1981 3:04 PM
Construct this file out of ifu3.mc
May 19, 1981 4:50 PM
Begin adding iMiscEffects test (for RestoreStkP, IDFetch←, Fetch←ID, etc.)

...

Fix bug in ifuBrkInsTest -- failing to load BrkIns from left half of Bmux.
August 1, 1979 3:24 PM
Invert order of BrkIns←, Pcf←.
August 1, 1979 11:11 AM
Rearrange parts of IfuBrkInsTest for easier scope looping.
August 1, 1979 10:45 AM
Add noop to ifuBrkInsTest to accommodate placement problems.
August 1, 1979 10:36 AM
Fix omitted initialization of ifu memory in ifuBrkInsTest, missking skip instr, set instrset in ifu.
August 1, 1979 9:28 AM
Add the ifuBrkInsTest, add misc. comments.
July 3, 1979 2:27 AM
fix stack underflow error in resched test.
July 3, 1979 2:21 AM
Fix bug in iReschedTest -- clobbered the value that we load PcF with.
July 3, 1979 2:08 AM
Add noops for placement purposes. -- apparently setIUsingInstrSet causes some problems.
July 3, 1979 1:55 AM
Fix resched test, further, to handle the fact that reschedules don’t occur after one IfuJump but after several.
July 3, 1979 12:37 AM
Cause iRamPEtest to enable the ramPE exception condition.
June 29, 1979 5:02 PM
Fix ifuChaos’ ID checking to preserve ID in a register rather than xoring it with the expected value.
June 29, 1979 11:54 AM
Cause ifuChaos to reset memBase and memBX inside the ifuChaosL; check ;Rbase immediately after the IfuJump (in ifuChaos), since afterDispatch leaves POINTERS in a very fragile place (stk+1).
June 29, 1979 10:53 AM
Add missing "coreturn" at sicR2 (inside setIfuChaosRet).
June 24, 1979 6:40 PM
Change ifuChaos to use getIfuMBase, getIfuRBase for checking.
June 19, 1979 9:53 AM
Fix stack bug in iRamtest.
June 18, 1979 9:24 AM
Fix functional bugs in iRamPEtest (check for resched loc, reset rbase, membase, call setUsingInsrSet.
June 18, 1979 9:01 AM
Fix stack bugs in iRamPEtest.
June 17, 1979 4:30 PM
Add iRamPEtest.
June 6, 1979 10:30 AM
Chaos placement errors.
June 5, 1979 11:40 AM
Add calls to enableConditionalTask
June 1, 1979 6:16 PM
Fix ifuChaos errors.

...

May 13, 1979 5:12 PM
Add ifuChaose.

...
March 1, 1979 7:17 PM
Add reschedule test.

...
%

*

beginIfu3c:
pushReturn[];

call[iReschedTest];
call[iRamPEtest];
call[ifuChaos];
call[ifuBrkInsTest];
endIfu3c:
returnP[];
* September 18, 1979 11:11 AM
%
RESCHED Test
This test checks that the ifu delays a normal resched by one successful ifuJump and that the reschedNow FF causes an immediate resched.
resetIfu[];
SetPcf[];
Set resched.
DO
Perform an Ifu Jump
If dispatchLocation=resched OR dispatchLocation=Unknown THEN ERROR
If dispatchLocation=notReady THEN LOOP;
EXIT;
ENDLOOP;
Perform an IfuJump
IF dispatchLocation#resched THEN ERROR
Set reschedNow
Perform an IfuJump
If dispatchLocation#resched THEN ERROR;
NoResched[];
IfuReset[];
%
iReschedTest: subroutine;
pushReturn[];
call[initIfuCache];
call[enableConditionalTask];
call[resetIfu];
call[setIUsingInstrSet], t ← 3c;
noop;* for placement.

t ← exceptions.Resched3;* this test accepts reschedule exceptions
exceptionsMask ← t;

t ← 2c;
iTestX ← t;* So that checkPcX will work on test 2

t ← Test2MemByteLocC;* vanilla program (test 2)
PcF ← t;
call[getIReschedCont1];
t ← link;
reschedule[];
klink ← t;
iReschedL:
IfuJump[0];
iReschedCont1:* AfterDispatch leaves rscr= dispatch loc
(rscr) # (is3reschedLocC);
skpif[ALU#0];
iReschedErr1a:* resched dispatch occured immediately
error;* after first ifuJump

(rscr) # (opAt15);
skpif[ALU#0];
branch[iResched2];* got one successful ifuJump. try again.
(rscr) #(is3notReadyLocC);
skpif[ALU#0];* not ready only reasonable thing left.
branch[iReschedL];* try again.
iReschedErr1b:* unknown dispatch. wasn’t (resched,
error;* notReady, expected opcode).

iResched2:
call[getIReschedCont2];
t ← link;
klink ← t;
cnt ← 2s;* should get resched after small number
iReschedL2:* of "normal" ifu dispatches.
IfuJump[0];
iReschedCont2:
t ← rscr;* save rscr on stack, then
call[checkPcX], stack+1 ← t;* see if PcX indicates we’re in correct
branch[iReschedBad, ALU#0], t ← stack&-1;* "program."

rscr ← t;* Either we’ve come from not ready,
(rscr) # (is3notReadyLocC);* a "normal" opcode, or a reschedule
skpif[ALU#0];
branch[iReschedL2];* not ready yet. try again.

(rscr) # (is3reschedLocC);* perhaps we’ve had a reschedule
skpif[ALU#0];
branch[iResched3Init];* finally got the reschedule we wanted.

loopUntil[CNT=0&-1, iReschedL2];* Small number of "normal" dispatches ok.
iReschedErr2a:* Eventually should get resched dispatch.
error;* Only got normal opcode dispatches.

iReschedBad:* According to PcX, the last IfuJump
error;* executed an opcode NOT a part of the test program. T = return link for dispatch

* Normal, delayed resched worked.
* March 2, 1979 9:05 AM

* Test reschedNow

iResched3Init:
noReschedule[];* begin by clearing out the old one
call[resetIfu];

ff256[103];* do reschedNow, setPcf and then IfuJump.
t ← 100c;
PcF ← t;
call[getIReschedCont3];
t ← link;
klink ← t;
IResched3:
IfuJump[0];
iReschedCont3:
(rscr) # (is3reschedLocC);
skpif[ALU#0];
branch[iReschedTestDone];
(rscr) # (is3NotReadyLocC);
skpif[ALU#0];
branch[iResched3];* try as long as its not ready
iReschedErr3a:* after reschedNow we should get ONLY
error;* resched dispatch, not ready or
* unexpected machine errors.

iReschedTestDone:
call[disableConditionalTask];
noReschedule[];
call[resetIfu];
exceptionsMask← a0;
returnP[];
* March 2, 1979 5:20 PM
getIReschedCont1:
coreturn;
branch[iReschedCont1];
getIReschedCont2:
coreturn;
branch[iReschedCont2];
getIReschedCont3:
coreturn;
branch[iReschedCont3];
* June 20, 1981 2:50 PM
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
iRamPeTest
Test the ramPE exception logic.

The first test generates real ram PEs and checks that the IFU actually dispatches the processor to the IFU ramPE location. It does this by setting the non-pe bits in the IFUM to all 0s or all 1s. Then it selects one of the three PE bits to have the WRONG value. When the processor executes an IFUJump, the IFU should dispatch the microcode to the appropriate ram pe location. USE reschedNow to guarantee that we don’t go off to some arbitrary location if the ram pe logic fails. Ie., We set reschedNow and when the IFUJump occurs, the processor will end up at the resched location UNLESS there is a ram PE.

The second test employs reschedNow to force the IFU to dispatch the processor to a known location, regardless of the IM target address in the IfuM. This way many different bit patterns in IfuM can be tested, without having to dedicate code in IM for ifu entrypoints for all possible IFAD (IM target address, as stored in the Ram) values.
iRamPEtest: PROCEDURE =
BEGIN
FOR pat IN PatX DO
lh ← getPat[patX];
rh ← getPat[patX] AND (not ifu.PEmask);
call[setRPEJret];
FOR iAddr IN iAddrX DO
putIfuWd[iAddr, lh, rh];--- write patterh w/ good parity
reschedNow[];
-- force immediate reschedule
putCDbyte[0, iAddr];
-- write opcode into memory
setInstrSet[iAddr];
PcFG ← 0;
IfuJump[];
RPEcont:
IF wentTo # Resched THEN ERROR;
ENDLOOP;
-- try next address in IfuM w/ the current pattern
ENDLOOP;-- try a new pattern
END;
setRPEJret: PROCEDURE =
BEGIN
t ← @RPEcont0;
klink←t;
RETURN;
RPEcont0:
goto[RPEcont];
END;
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

iRamPEtest: pushReturn[];
call[initIfuCache];
call[disableConditionalTask];
set[wantExceptionsRPE, OR[exceptions.RamPe3!, exceptions.RamPe2!, exceptions.RamPe1!, exceptions.RamPe0!]];
t ← (and[wantExceptionsRPE,177400]C);
t ← t or (and[wantExceptionsRPE, 377]C);
exceptionsMask ← t;
call[resetIfu];

call[iIAddr], stkp+1;* we’ll keep iAddr on stack;

%
This test checks the PE bits in IFUM. When ReschedPending is true the IFU hardware has a bug that allows it to forget ram parity errors if the opcode in the pipe following the one with the parity error has good parity. Consequently we force the Pause and Jump bits to be logically true (0). This way we guarantee that J will not fill up and that guarantees that the IFU will not forget the ram parity error. (When ReschedPending is true InstrAddrLd is true. This causes the IFU to reevaluate which exception dispatch it should generate. The ram parity error gets loaded into M during one cycle. Then, when J fills up with an instruction with valid parity, SawRamParityErr goes away and the exception dispatch changes from RamPE to Reschedule! Ugh. That was a hard two days.

The practical consequence of this is that when we background the IFUM w/ all ones, iDoRamPe will zero the Pause bit so we can use our reschedule trick. That means we must set PE2 appropriately for all ones except for the pause bit; ie., we must set pe2 to 1 unless we want to check that bit itself. The reschedule trick guarantees that we don’t start executing some random IM location if the Ram PE logic fails -- we go to the reschedule location instead.
%
iRamPeL:
call[nextIaddr];
branch[iRamPeLXit, ALU=0], stack←t;

rscr← 4c;* ramPE is 3 bit field. test PE0 bit
rscr2← a0;* IFUM has all zeros
iRamPeL0:* testing PE0 bit
call[iDoRamPE], t← stack;

rscr← 5c;* ramPE is 3 bit field. test PE0 bit
rscr2← a1;* IFUM has all ones
call[iDoRamPE], t← stack;

rscr← 2c;* ramPE is 3 bit field. test PE1 bit
rscr2← a0;* IFUM has all zeros
iRamPeL1:* testing PE1 bit
call[iDoRamPE], t← stack;

rscr← 3c;* ramPE is 3 bit field. test PE1 bit
rscr2← a1;* IFUM has all ones
call[iDoRamPE], t← stack;

rscr← 1c;* ramPE is 3 bit field. test PE2 bit
rscr2← a0;* IFUM has all zeros
iRamPeL2:* testing PE2 bit
call[iDoRamPE], t← stack;

rscr← 1c;* ramPE is 3 bit field. test PE2 bit
rscr2← a1;* IFUM has all ones
call[iDoRamPE], t← stack;

branch[iRamPeL];
iRamPeLXit:
stkp-1;* decrement stack where we kept iAddr


set[wantExceptionsResched, OR[exceptions.Resched3!, exceptions.Resched2!, exceptions.Resched1!, exceptions.Resched0!]];
t ← (and[wantExceptionsResched,177400]C);
t ← t or (and[wantExceptionsResched, 377]C);
exceptionsMask ← t;
call[resetIfu];

call[iPat16];
iRamPePatL:
call[nextPat16];
skpif[ALU#0];
branch[iRamPeXit];

noop;* for placement
call[getPat16], stkp+1;
call[getPat16], stack&+1 ← t;
stack&+1← t and (NOT[ifu.peMask!]C);* push stack again, keep iAddr at top
call[setIRamPeJret];

call[iIAddr];
iRamPeAddrL:
call[nextIaddr];
branch[iRamPeAddrXit, ALU=0];
stack←t;* TOS = iaddr, TOS-1 = rh, TOS-2 = LH
call[resetIfu];
t ← (stack) or (mos.ifuCmmd);* set instruction set from current address
mos ← t;

*Set reschedNow and write current pattern into new IfuM location

ff256[103], stkp-2;* terrible hack to get reschedNow
t ← stack&+1;
rscr ← t;
t ← stack&+1;
rscr2 ← t;
mc[
ifu.notTypeMask, not[or[b10!,b11!]]];
rscr2← (rscr2)AND (ifu.notTypeMask);* keep Pause and Jump logically true.
call[putIfuWd], t ← stack;* rscr = lh, rscr2 = rh, t = address

*call setIUsingInstrSet so that putting bytes in memory works properly, then load "byte 0" with current opcode (ifum address).

t ← ldf[stack, 2, 10];* isolate "instruction set bits
call[setIUsingInstrSet];
t ← stack;* make memByte[0] point to current ifu
call[putCDbyte], rscr← A0;* address
iRamPEsetPcF:
PcF ← r0;* now begin ifu at location 0
call[longWait], t←30c;* a few noops for pipe to fill
IfuJump[0];
iRamPeCont:
memBase ← 0s;
RBASE ← rbase[defaultRegion];
t ← (rscr) and (dispatchLocBaseMask);
t # (reschedBaseLocC);
skpif[ALU=0];
iRamPEDispatchErr:* we should go to resched only. Any other
error;* dispatch is an error. We went to "rscr".

branch[iRamPeAddrL];* move stack down (below address), try next address

iRamPeAddrXit:* try next pattern
branch[iRamPePatL], stkp-3;* pop stack since pattern loop pushes it.

iRamPeXit:
t ← a0;
exceptionsMask ← t;
call[enableConditionalTask];
returnP[];

setIRamPeJret:
pushReturn[];
call[sirpe2];
t ← link;
klink ← t;
returnP[];
sirpe2:
coreturn;
branch[iRamPeCont];

* June 20, 1981 2:36 PM
% iDoRamPE
This subroutine executes an IfuJump that SHOULD get a ramPE.

Enter: rscr=bits for ifuRam PE field in IfuMemory
rscr2= background value for IFUM word
t= IFUM address we will test
Always write IFUM so that the pause bit is logically true (0)
%
iDoRamPE: subroutine;
pushReturn[];
stack+1← t;* SAVE: stack+1=ifuM address
rscr3← rscr;* rscr3= bits for IFUM PE field
rscr4← rscr2;* rscr4= background value for IFUM word
call[resetIfu];
t ← (stack) or (mos.ifuCmmd);* set instruction set from current address
mos ← t;

*Set reschedNow and write current pattern into new IfuM location
ff256[103];* terrible hack to get reschedNow

rscr←rscr4;
call[putIfuLH], t←stack;

t← DpF[rscr3, 3, ifu.pe2Shift];* position bits for pe
rscr4← (rscr4) AND (NOT[ifu.peMask!]C);
rscr← (rscr4) OR (t);
rscr← (rscr) and (ifu.notTypeMask);* mask-out to make pause, jump true
call[putIfuRH], t←stack;

*call setIUsingInstrSet so that putting bytes in memory works properly, then load "byte 0" with current opcode (ifum address).

t ← ldf[stack, 2, 10];* isolate "instruction set bits
call[setIUsingInstrSet];
t ← stack;* make memByte[0] point to current ifu
rscr← t;* address
call[putCDbyte], t← a0;

PcF ← r0;* now begin ifu at location 0
call[longWait], t←30c;* a few noops for pipe to fill
branch[iSetDoRamPEcont];
iDoRamPEJ:
IfuJump[0];
iDoRamPeCont:
memBase ← 0s;
RBASE ← rbase[defaultRegion];
t ← (rscr) and (dispatchLocBaseMask);
t # (ramPeBaseLocC);
skpif[ALU=0];
iDoRamPEDispatchErr:* we should go to ramPe only. Any other
error;* dispatch is an error. We went to "rscr".
* "stack" contains IFUM address that failed to generate ram pe.
* rscr3 contains background value for IFUM word
* rscr4 contains bits for ifuRam PE field in IfuMemory. Expect that these bits are set
* such that only one of the three bytes in the memory should generate a parity error.
* Eg., if rscr4=40000C then one of the bits associated w/ ifu.pe0 is bad
* IF rscr4= 3 one of the bits w/ ifu.pe0 is bad (the background value of IFUM is adjusted
* so that all non-PE bits in IFUM have same value and the test changes the PE bits.

pReturnP[];

iSetDoRamPEcont: top level;
call[iDoRamPeSetup];
klink←link, branch[iDoRamPEJ];
iDoRamPeSetup: subroutine;
coreturn;
branch[iDoRamPECont];
* May 13, 1979 4:11 PM
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ifuChaos
Test generates and executes randomly constructed opcodes from randomly chosen memory locations. The test uses two phases. The first phase involves writing the randomly generated opcode into IFUM and writing the value of Alpha and Beta into storage. The second phase of the test involves executing and checking the opcode.
The first phase uses random numbers to choose these characteristics of the opcode:
Location of the opcode in storage
Location of the instruction in IFUM
The following characteristics of the instruction:
NX or none
Packed alpha or not
Sign extension or not
Instruction length
Instruction type
IM destination address
RBase and MemBase
The test always computes proper parity.
The test always uses the same IM target address
The first phases leaves a record of how it constructed the opcode for use by the second phase.
The second (checking) phase assures validity of the following:
IM target address (as well as it can)
PcX
←ID sequence
RBase
Mbase
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* February 1, 1980 8:04 PM
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ifuChaos: PROCEDURE =
BEGIN-- Main Loop
FOR testX IN ChaosTestRange DO-- execute a bunch of tests
opCodeRecord ← makeIfuOpcodeRecord[];
ifuChaosPhase1[opCodeRecord];
-- initialize everything for an opcode
setIfuPc[opCodeRecord.ifuPc];
ifuChaosPhase2[opCodeRecord];
-- execute and test the opcode
ENDLOOP;
END;
ifuChaosPhase1: PROCEDURE RETURNS [rec: ifuOpcodeRecord] =
BEGIN-- Initialization Code

putCDbyte[rec.ifuPc, rec.ifuOpcode];
-- write the opcode, alpha and beta into
putCDbyte[rec.ifuPc+1, rec.ifuAlpha];
-- storage.
putCDbyte[rec.ifuPc+2, rec.ifuBeta];

resetIfu[];
putIfuWd[rec.ifuOpcode, rec.instrHi, rec.instrLow];
-- write opcode into IfuMem
resetIfu[];

END;
ifuChaosPhase2: PROCEDURE [rec: ifuOpcodeRecord] =
BEGIN-- Checking Code
setIfuReturnLink[@phase2Return];
count ← 25;

phase2Loop:
IfuJump[];
phase2Return:
IF (count = 0) THEN SIGNAL TooManyNotReadies[];
IF (cameFrom # opAt15) THEN BEGIN
IF (cameFrom # notReady) THEN
SIGNAL BadDispatchLoc[cameFrom];
END;
ELSE BEGIN
count ← count-1;
goto[phase2Loop];
END;
END;
-- We get here when the test believes the opcode had dispatched correctly.
memBaseAndRbase ← POINTERS[];
-- machine instruction rtns memBase,,Rbase
expectMemBaseAndRbase ← getExpectedMemAndRbase[];
IF getPcX[] # (rec.ifuPc) THEN SIGNAL badPcX[];
IF memBaseAndRbase # expectMemBaseAndRbase THEN
SIGNAL badPointers[memBaseAndRbase, expectMemBaseAndRbase];
FOR i ← 1, i+1 UNTIL i=6 DO
expectVal ← getExpectedID[rec];
IF ifuDataCount # (expectedIfuDataCount[]) THEN SIGNAL BadIfuDataCount;
IF expectVal # (gotValue ← getID[]) THEN SIGNAL BadID[i, expectVal, gotVal];
ENDLOOP;
END;
%*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* June 21, 1981 1:20 PM
ifuChaos: subroutine;
pushReturn[];
call[initIfuChaosX];

ifuChaosL:* main, outer loop
call[nextIfuChaosX];
skpif[ALU#0];
branch[afterIfuChaos];
noop;* for placement

memBase ← 0s;* undo the effects of any previous
memBX ← 0s;* ifuJump.

call[makeIfuOpcodeRecord];
call[ifuChaosPhase1];* initialize the Ifu memory, storage.

ifuChaosSetPc:
call[enableConditionalTask];
call[getIfuPc];
PcF ← t;
t ← 25C;
cnt ← t;* this controls number of "not readies" before an error
call[setIfuChaosRet];* set KLINK

ifuChaosPhase2Cont:
IfuJump[];

ifuChaosPhase2Ret:
(rscr) # (opAt15);
skpif[ALU#0];
branch[ifuChaosPhase2Chk];
noop;* for placement
call[getIfuNotReadyLoc];
t # (rscr);
skpif[ALU=0];
ifuChaosDispatchErr:
error;* went to unexpected dispatch location.

loopUntil[CNT=0&-1, ifuChaosPhase2Cont];

ifuChaosPhase2Chk:
stkp+1;* get the value of POINTERS that
call[getIfuRbase], rscr ← stack;* afterDispatch has saved.
rscr ← (rscr) and (17C);* isolate rbase from POINTERS
t # (rscr);* NOTE: stack= value of POINTERS saved by
skpif[ALU=0];* afterdispatch. Don’t forget to decrement stkp!
ifuChaosRBaseErr:* t = expected rbase, rscr = real rbase
error;

call[getIfuPc];
rscr ← not(PcX’);
(rscr) # t;
skpif[ALU=0];
ifuChaosPcXErr:* rscr = PcX, t = expected value for PcX
error;

* check MemBase
call[getIfuMbase];
rscr ← stack&-1;* scarf POINTERS and decrement StkP. See above.
rscr ← ldf[rscr, 5, 10];* isolate membase from POINTERS
t # (rscr);
skpif[ALU=0];
ifuChaosMBaseErr:* t = expected rbase, rscr = real rbase
error;

RBASE ← rbase[defaultRegion];* Heretofor we’ve avoided depending upon
call[setMBase], t ← r0;* these values.

cnt ← 6s;
ifuChaosIDL:
noop;
call[getExpectedID];
rscr ← ID;
PD ← (rscr) # t;
skpif[ALU=0];* t = expected ID, rscr = actual ID
ifuChaosIDErr:* (7-CNT) = number of IDs performed
error;* ifuChaosOpcode = the opcode
loopUntil[CNT=0&-1, ifuChaosIDL];* ifuChaosPc = memory location

branch[ifuChaosL];

afterIfuChaos:
call[disableConditionalTask];
returnP[];
setIfuChaosRet:
pushReturn[];
call[sicR2];
t ← link;
klink ← t;
returnP[];
sicR2:
coreturn;
branch[ifuChaosPhase2Ret];

* September 18, 1979 11:13 AM
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ifuBrkInsTest
Test the BrkIns register as it would be used for implementing breakpoints:
Load BrkIns
Set PcFG
Execute an IfuJump
If BrkIns is working properly, we’ll execute the opcode loaded in BrkIns, otherwise we’ll execute the opcode pointed to by PcFG.
%*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ifuBrkInsTest:
pushReturn[];
call[initIfuCache];
call[enableConditionalTask];
noop;* for placement.
call[resetIfu];
call[setIUsingInstrSet], t ← 3c;
call[ifuSetInstrSet], t ← 3c;
call[putCDbyteAddr], t ← A0;* we’ll set PcFG to zero
noop;* for placement.
call[appendHalts];
call[appendHalts];* lots of halt opcodes which we should never execute!
call[setIfuBrkInsRet1];
ifuBrkInsScopeL:
ifuReset;
t ← 40c;
cnt ← t;
loopUntil[CNT=0&-1, .];
ifuReset;
call[justReturn];* for patching into call[scopeTrigger],
t← (r0)+1, taskingOff;* if it’s needed.
PcF ← t;
t ← lshift[opNoop!, 10]C;* BrkIns loads from left half of Bmux
BrkIns ← t;
taskingOn;
cnt ← 17s;
ifuBrkInsL1:
IfuJump[0];

ifuBrkInsCont1:
(rscr) # (is3NotReadyLocC);
branch[ifuBrkInsChk, ALU#0];
noop;* for placement
loopUntil[CNT=0&-1, ifuBrkInsL1];* got not ready. try again
ifuBrkInsNotReadyErr1:* always went to not ready
error;* this should not have happened
ifuBrkInsChk:
(rscr) # (opAt15);* see if we went where we expected
skpif[ALU=0];
ifuBrkInsJmpErr1:* expected to execute opNoop which would
error;* have taken us to opAt15


* now try it again, except flush the munch from the cache
Flush ← 0s;
call[justReturn];* for patching into call[scopeTrigger],
t ← lshift[opNoop!, 10]C;* it’s needed. Remember, BrkIns loads from
taskingOff;* left half of Bmux
PcF ← r0;
BrkIns ← t;
taskingOn;
t ← 100c;
cnt ← t;
call[setIfuBrkInsRet2];
loopUntil[CNT=0&-1, .];* now wait right here for a long while
IfuJump[0];
ifuBrkInsCont2:
(rscr) # (opAt15);* should have gone directly to opAt15
skpif[ALU=0];
ifuBrkInstJumpErr2:
error;* went to "rscr" rather than opAt15

call[disableConditionalTask];
returnP[];

setIfuBrkInsRet1:
pushReturn[];
call[setIfuBrkIns1];
t ← link;
klink ← t;
returnP[];
setIfuBrkIns1:
coreturn;
branch[ifuBrkInsCont1];

setIfuBrkInsRet2:
pushReturn[];
call[setIfuBrkIns2];
t ← link;
klink ← t;
returnP[];
setIfuBrkIns2:
coreturn;
branch[ifuBrkInsCont2];

top level;