All:
PROC = {
Xops trap at opcode*TrapWidthBytes + xopBase*bytesPerWord = 4,000,000B + 20B * opcode.
FillXop:
PROC [inst:
CARDINAL, dest: Label] = {
SetOutputPC[inst * DragOpsCross.TrapWidthBytes + DragOpsCross.XopBase * DragOpsCross.bytesPerWord];
drJDB[UseLabel16[dest]];
};
A trap's location is TrapIndex*TrapWidthBytes + TrapBase*bytesPerWord =
4,002,000B + 20B * TrapIndex. TrapIndex definitions are in DragOpsCross.
FillTrap:
PROC [tx: DragOpsCross.TrapIndex, dest: Label] = {
SetOutputPC[LOOPHOLE[tx, CARDINAL] * DragOpsCross.TrapWidthBytes + DragOpsCross.TrapBase * DragOpsCross.bytesPerWord];
drJDB[UseLabel16[dest]];
};
area: Area = GetCurrentArea[];
savePC: LONG CARDINAL;
start: Label = GenLabel[];
dummy: Label = GenLabel[];
initL: Label = GenLabel[];
enterXopTest: Label = GenLabel[];
enterALTest: Label = GenLabel[];
enterASTest: Label = GenLabel[];
enterDISTest: Label = GenLabel[];
enterASLTest: Label = GenLabel[];
enterALSTest: Label = GenLabel[];
Generate a trap entry and stubs for all Xop's except 0 and 377B which will do Pause[] if the Xop is executed other than in the context of the test for it and which will remove the Alpha, AlphaBeta, or AlphaBetaGammaDelta argument from the stack if the xop is executed in the context of the test.
GenXop:
PROC [] ~ {
Xop5Trap: Label = GenLabel[];
abgdPushed: Label = GenLabel[];
GenXop1Trap:
PROC [I:
CARDINAL] ~ {
notBeingTested: Label = GenLabel[];
SetOutputPC[(I * TrapWidthBytes) + (XopBase * bytesPerWord)];
Push the number of the opcode being tested (or 0 if none); this is kept in aux13.
drLIB[I];
drRJNEB[popSrc, aux13, UseLabel8B[notBeingTested]];
drLIDB[12345B]; --Return value indicating trap routine was executed
drRETN[]; --Return without changing S
SetLabel[notBeingTested];
Pause[]; --Unexpected occurrence of Xop trap for opcode I
};
GenXop1Test:
PROC [I:
CARDINAL] ~ {
xop1OK: Label = GenLabel[];
drLIB[I];
drRAND[c: aux13, a: topSrc, b: popSrc]; --aux13 ← xop opcode
OutputByte[area, CardToByte[I]];
drLIDB[12345B];
drRJEBJ[popSrc, belowSrcPop, UseLabel8B[xop1OK]];
Pause[];
SetLabel[xop1OK];
};
GenXop2Trap:
PROC [I:
CARDINAL] ~ {
problem: Label = GenLabel[];
SetOutputPC[(I * TrapWidthBytes) + (XopBase * bytesPerWord)];
Compare the opcode number for this trap entry point with the opcode number of the Xop now being tested in aux 13.
drLIB[I];
drRJNEB[popSrc, aux13, UseLabel8B[problem]]; --Being tested?
drLIB[Basics.BITXOR[I, 377B]];
drRJNEB[popSrc, belowSrcPop, UseLabel8B[problem]]; --Alpha pushed?
drLIDB[23456B]; --Return value indicating trap routine was executed
drRETN[]; --Return without changing S
SetLabel[problem];
Pause[]; --Unexpected occurrence of Xop trap for opcode I
};
GenXop2Test:
PROC [I:
CARDINAL] ~ {
xop2OK: Label = GenLabel[];
drLIB[I];
drRAND[c: aux13, a: topSrc, b: popSrc]; --aux13 ← xop opcode
OutputAlphaBeta[area, (I * 400B) + Basics.BITXOR[I, 377B]];
drLIDB[23456B];
drRJEBJ[popSrc, belowSrcPop, UseLabel8B[xop2OK]];
Pause[];
SetLabel[xop2OK];
};
GenXop3Trap:
PROC [I:
CARDINAL] ~ {
problem: Label = GenLabel[];
SetOutputPC[(I * TrapWidthBytes) + (XopBase * bytesPerWord)];
Compare the opcode number for this trap entry point with the opcode number of the Xop now being tested in aux 13.
drLIB[I];
drRJNEB[popSrc, aux13, UseLabel8B[problem]]; --Trap expected?
drLIDB[177400B + I];
drRJNEB[popSrc, belowSrcPop, UseLabel8B[problem]]; --AlphaBeta pushed?
drLIDB[34567B]; --Return value indicating trap routine was executed
drRETN[]; --Return without changing S
SetLabel[problem];
Pause[]; --Unexpected occurrence of Xop trap for opcode I
};
GenXop3Test:
PROC [I:
CARDINAL] ~ {
xop3OK: Label = GenLabel[];
drLIB[I];
drRAND[c: aux13, a: topSrc, b: popSrc]; --aux13 ← xop opcode
OutputByte[area, CardToByte[I]]; --Should take Xop trap
OutputAlphaBeta[area, 177400B + I];
drLIDB[34567B];
drRJEBJ[popSrc, belowSrcPop, UseLabel8B[xop3OK]];
Pause[];
SetLabel[xop3OK];
};
GenXop5Trap:
PROC [I:
CARDINAL] ~ {
notBeingTested: Label = GenLabel[];
SetOutputPC[(I * TrapWidthBytes) + (XopBase * bytesPerWord)];
Compare the opcode number for this trap entry point with the opcode number of the Xop now being tested in aux13.
drLIB[I];
drRJNEB[popSrc, aux13, UseLabel8B[notBeingTested]];
drLIQB[CardToWord[37777777400B + LONG[I]]];
drJDB[UseLabel16[Xop5Trap]];
SetLabel[notBeingTested];
Pause[]; --Unexpected occurrence of Xop trap for opcode I
};
GenXop5Test:
PROC [I:
CARDINAL] ~ {
xop5OK: Label = GenLabel[];
drLIB[I];
drRAND[c: aux13, a: topSrc, b: popSrc]; --aux13 ← xop opcode
OutputByte[area, CardToByte[I]];
OutputWord[area, CardToWord[37777777400B + LONG[I]]]; --Should take Xop trap
drLIDB[45670B];
drRJEBJ[popSrc, belowSrcPop, UseLabel8B[xop5OK]];
Pause[];
SetLabel[xop5OK];
};
Generate stubs for Xop trap procedures which don't fit in 16 locations.
SetLabel[Xop5Trap]; --Did Xop push AlphaBetaGammaDelta correctly?
drRJEBJ[popSrc, belowSrcPop, UseLabel8B[abgdPushed]];
Pause[]; --Xop did not push AlphaBetaGammaDelta correctly.
SetLabel[abgdPushed];
drLIDB[45670B];
drRETN[]; --Return without changing S
Generate a trap entry sequence for every Xop except 0 (Pause) and 377B (Halt).
savePC ← GetOutputPC[area];
FOR I: CARDINAL IN [1..17B] DO GenXop1Trap[I]; ENDLOOP; --length = 1 Xops
FOR I: CARDINAL IN [30B..37B] DO GenXop1Trap[I]; ENDLOOP; --length = 1 Xops
FOR I: CARDINAL IN [40B..60B] DO GenXop5Trap[I]; ENDLOOP; --length = 5 Xops
FOR I: CARDINAL IN [63B..65B] DO GenXop5Trap[I]; ENDLOOP; --length = 5 Xops
FOR I: CARDINAL IN [70B..77B] DO GenXop5Trap[I]; ENDLOOP; --length = 5 Xops
GenXop1Trap[112B]; --112B length = 1 Xop
FOR I: CARDINAL IN [117B..123B] DO GenXop1Trap[I]; ENDLOOP; --length = 1 Xops
GenXop1Trap[125B]; --125B length = 1 Xop
FOR I: CARDINAL IN [130B..137B] DO GenXop1Trap[I]; ENDLOOP; --length = 1 Xops
GenXop2Trap[215B]; --215B length = 2 Xop
GenXop2Trap[223B]; --223B length = 2 Xop
FOR I: CARDINAL IN [234B..236B] DO GenXop2Trap[I]; ENDLOOP; --length = 2 Xops
GenXop3Trap[311B]; --311B length = 3 Xop (undefined behavior)
GenXop3Trap[313B]; --313B length = 3 Xop (undefined behavior)
GenXop3Trap[323B]; --323B length = 3 Xop
GenXop3Trap[337B]; --337B length = 3 Xop (undefined behavior)
GenXop3Trap[340B]; --340B length = 3 Xop (undefined behavior)
GenXop3Trap[344B]; --344B length = 3 Xop (undefined behavior)
GenXop3Trap[350B]; --350B length = 3 Xop (undefined behavior)
GenXop3Trap[354B]; --354B length = 3 Xop (undefined behavior)
FOR I: CARDINAL IN [364B..367B] DO GenXop3Trap[I]; ENDLOOP; --length = 3 Xops
FOR I: CARDINAL IN [374B..376B] DO GenXop3Trap[I]; ENDLOOP; --length = 3 Xops
SetOutputPC[savePC];
Generate a test for every Xop except 0 (Pause) and 377B (Halt). Note that 311B, 313B, 337B, 340B, 344B, 350B, and 354B are undefined, but not XOP's.
SetLabel[enterXopTest];
FOR I: CARDINAL IN [1..17B] DO GenXop1Test[I]; ENDLOOP; --length = 1 Xops
FOR I: CARDINAL IN [30B..37B] DO GenXop1Test[I]; ENDLOOP; --length = 1 Xops
FOR I: CARDINAL IN [40B..60B] DO GenXop5Test[I]; ENDLOOP; --length = 5 Xops
FOR I: CARDINAL IN [63B..65B] DO GenXop5Test[I]; ENDLOOP; --length = 5 Xops
FOR I: CARDINAL IN [70B..77B] DO GenXop5Test[I]; ENDLOOP; --length = 5 Xops
GenXop1Test[112B]; --112B length = 1 Xop
FOR I: CARDINAL IN [117B..123B] DO GenXop1Test[I]; ENDLOOP; --length = 1 Xops
GenXop1Test[125B]; --125B length = 1 Xop
FOR I: CARDINAL IN [130B..137B] DO GenXop1Test[I]; ENDLOOP; --length = 1 Xops
GenXop2Test[215B]; --215B length = 2 Xop
GenXop2Test[223B]; --223B length = 2 Xop
FOR I: CARDINAL IN [234B..236B] DO GenXop2Test[I]; ENDLOOP; --length = 2 Xops
GenXop3Test[323B]; --323B length = 3 Xop
FOR I: CARDINAL IN [364B..367B] DO GenXop3Test[I]; ENDLOOP; --length = 3 Xops
FOR I: CARDINAL IN [374B..376B] DO GenXop3Test[I]; ENDLOOP; --length = 3 Xops
};
Test AL (L ← L + Alpha mod 128). If the test completes successfully, L is restored to its original value. The current values of L cannot be read; this can only be done indirectly by calling a procedure, which saves L in ifuYoungestL, readable by LIP.
GenAL:
PROC [] ~ {
TestAL:
PROC [originalL, alpha:
CARDINAL] ~ {
pushL: Label = GenLabel[];
lOK: Label = GenLabel[];
alExit: Label = GenLabel[];
newL: CARDINAL = Basics.BITAND[originalL + alpha, 177B];
drAL[alpha];
drLFC[UseLabel16[pushL]];
drJDB[UseLabel16[alExit]];
SetLabel[pushL];
drLIP[ifuYoungestL];
drJEBBJ[newL, UseLabel8B[lOK]];
Pause[]; --L was wrong
SetLabel[lOK];
drRETN[];
SetLabel[alExit];
};
Initially, L = 1 and S = 0 here.
SetLabel[enterALTest];
TestAL[1, 127]; --L ← 0
TestAL[0, 1]; --L ← 1
TestAL[1, 2]; --L ← 3
TestAL[3, 4]; --L ← 7
TestAL[7, 8]; --L ← 15
TestAL[15, 16]; --L ← 31
TestAL[31, 32]; --L ← 63
TestAL[63, 64]; --L ← 127
TestAL[127, 128]; --L ← 127
TestAL[127, 0]; --L ← 127
TestAL[127, 64]; --L ← 63
TestAL[63, 32]; --L ← 95
TestAL[95, 16]; --L ← 111
TestAL[111, 8]; --L ← 119
TestAL[119, 4]; --L ← 123
TestAL[123, 2]; --L ← 125
TestAL[125, 1]; --L ← 126
drAL[3]; --L ← 1
};
Test ALS (L ← S+Alpha mod 128). If the test completes successfully, [L, S] is restored to [1, 0]. AS is assumed to work. Current values of L or S cannot be read; this can only be done indirectly by calling a procedure, which saves L in ifuYoungestL, readable by LIP.
GenALS:
PROC [] ~ {
TestALS:
PROC [originalS, alpha:
CARDINAL] ~ {
pushL: Label = GenLabel[];
lOK: Label = GenLabel[];
alsExit: Label = GenLabel[];
newL: CARDINAL ← Basics.BITAND[originalS + alpha, 177B];
drALS[alpha]; --L ← newL
drLFC[UseLabel16[pushL]]; --push L (= S) on the IFU stack for checking
drJDB[UseLabel16[alsExit]];
SetLabel[pushL];
drLIP[ifuYoungestL];
drJEBBJ[newL, UseLabel8B[lOK]];
Pause[]; --L was wrong, so S was wrong.
SetLabel[lOK];
drRETN[];
SetLabel[alsExit];
};
Initially, [L, S] = [1, 0] here.
SetLabel[enterALSTest];
Do every bit with no carry generation.
TestALS[0, 1]; --[L, S] ← [1, 0]
TestALS[0, 2]; --[L, S] ← [2, 0]
TestALS[0, 4]; --[L, S] ← [4, 0]
TestALS[0, 8]; --[L, S] ← [8, 0]
TestALS[0, 16]; --[L, S] ← [16, 0]
TestALS[0, 32]; --[L, S] ← [32, 0]
TestALS[0, 64]; --[L, S] ← [64, 0]
TestALS[0, 128]; --[L, S] ← [0, 0]
Now cause carry generation in each bit; (but AS has not yet been tested and might fail).
drAS[127]; --[L, S] ← [0, 127]
TestALS[127, 0]; --[L, S] ← [127, 127]
TestALS[127, 128]; --[L, S] ← [127, 127]
TestALS[127, 64]; --[L, S] ← [63, 127]
TestALS[127, 32]; --[L, S] ← [31, 127]
TestALS[127, 16]; --[L, S] ← [15, 127]
TestALS[127, 8]; --[L, S] ← [7, 127]
TestALS[127, 4]; --[L, S] ← [3, 127]
TestALS[127, 2]; --[L, S] ← [1, 127]
TestALS[127, 1]; --[L, S] ← [0, 127]
drAS[1]; --[L, S] ← [0, 0]
drALS[1]; --[L, S] ← [1, 0] restores original value
};
Test AS (S ← S + Alpha mod 128); ALS 0 is assumed to work. If the test completes successfully, L and S are restored to their original values. Current values of L or S cannot be read; this can only be done indirectly by calling a procedure, which saves L in ifuYoungestL, readable by LIP.
GenAS:
PROC [] ~ {
TestAS:
PROC [originalS, alpha:
CARDINAL] ~ {
pushL: Label = GenLabel[];
sOK: Label = GenLabel[];
asExit: Label = GenLabel[];
newS: CARDINAL = Basics.BITAND[originalS + alpha, 177B];
drAS[alpha];
drALS[0]; --L ← S
drLFC[UseLabel16[pushL]];
drJDB[UseLabel16[asExit]];
SetLabel[pushL];
drLIP[ifuYoungestL];
drJEBBJ[newS, UseLabel8B[sOK]];
Pause[]; --L was wrong, so S was wrong.
SetLabel[sOK];
drRETN[];
SetLabel[asExit];
};
Initially, [L, S] = [1, 0] here.
SetLabel[enterASTest];
TestAS[0, 1]; --[L, S] ← [1, 1]
TestAS[1, 2]; --[L, S] ← [3, 3]
TestAS[3, 4]; --[L, S] ← [7, 7]
TestAS[7, 8]; --[L, S] ← [15, 15]
TestAS[15, 16]; --[L, S] ← [31, 31]
TestAS[31, 32]; --[L, S] ← [63, 63]
TestAS[63, 64]; --[L, S] ← [127, 127]
TestAS[127, 128]; --[L, S] ← [127, 127]
TestAS[127, 0]; --[L, S] ← [127, 127]
TestAS[127, 64]; --[L, S] ← [63, 63]
TestAS[63, 32]; --[L, S] ← [95, 95]
TestAS[95, 16]; --[L, S] ← [111, 111]
TestAS[111, 8]; --[L, S] ← [119, 119]
TestAS[119, 4]; --[L, S] ← [123, 123]
TestAS[123, 2]; --[L, S] ← [125, 125]
TestAS[125, 1]; --[L, S] ← [126, 126]
drAS[2]; --[L, S] ← [126, 0]
drALS[1]; --[L, S] ← [1, 0] restores original value
};
Test DIS (S ← S - 1 mod 128). If the test completes successfully, L and S are restored to their original values. Current values of L or S cannot be read; this can only be done indirectly by calling a procedure, which saves L in ifuYoungestL, readable by LIP.
GenDIS:
PROC [] ~ {
TestDIS:
PROC [originalS:
CARDINAL]
RETURNS [newS:
CARDINAL] ~ {
pushL: Label = GenLabel[];
sOK: Label = GenLabel[];
disExit: Label = GenLabel[];
newS ← Basics.BITAND[originalS - 1, 177B];
drDIS[];
drALS[0]; --L ← S
drLFC[UseLabel16[pushL]];
drJDB[UseLabel16[disExit]];
SetLabel[pushL];
drLIP[ifuYoungestL];
drJEBBJ[newS, UseLabel8B[sOK]];
Pause[]; --L was wrong, so S was wrong.
SetLabel[sOK];
drRETN[];
SetLabel[disExit];
};
Initially, [L, S] = [1, 0] here.
SetLabel[enterDISTest];
{
curS: CARDINAL ← 0;
128 iterations restores original value of S.
FOR I:
CARDINAL
IN [0..128)
DO
curS ← TestDIS[curS];
ENDLOOP;
drALS[1]; --[L, S] ← [1, 0].
};
};
Test ASL (S ← L+Alpha mod 128; stack overflow not checked). If the test completes successfully, [L, S] is restored to [1, 0]. Current values of L or S cannot be read; this can only be done indirectly by calling a procedure, which saves L in ifuYoungestL, readable by LIP.
GenASL:
PROC [] ~ {
TestASL:
PROC [originalL, alpha:
CARDINAL] ~ {
pushL: Label = GenLabel[];
sOK: Label = GenLabel[];
aslExit: Label = GenLabel[];
newS: CARDINAL ← Basics.BITAND[originalL + alpha, 177B];
drASL[alpha]; --S ← newS
drALS[0]; --L ← S + 0
drLFC[UseLabel16[pushL]]; --push L (= S) on the IFU stack for checking
drJDB[UseLabel16[aslExit]];
SetLabel[pushL];
drLIP[ifuYoungestL];
drJEBBJ[newS, UseLabel8B[sOK]];
Pause[]; --L was wrong, so S was wrong.
SetLabel[sOK];
drRETN[];
SetLabel[aslExit];
};
Initially, [L, S] = [1, 0] here.
SetLabel[enterASLTest];
Do carry in low-order bit and propagate all the way across.
TestASL[1, 127]; --[L, S] ← [0, 0]
Do every bit with no carry generation.
TestASL[0, 1]; --[L, S] ← [1, 1]
TestASL[1, 2]; --[L, S] ← [3, 3]
TestASL[3, 4]; --[L, S] ← [7, 7]
TestASL[7, 8]; --[L, S] ← [15, 15]
TestASL[15, 16]; --[L, S] ← [31, 31]
TestASL[31, 32]; --[L, S] ← [63, 63]
TestASL[63, 64]; --[L, S] ← [127, 127]
TestASL[127, 0]; --[L, S] ← [127, 127]
Now cause carry generation in each bit.
TestASL[127, 64]; --[L, S] ← [63, 63]
TestASL[63, 32]; --[L, S] ← [95, 95]
TestASL[95, 16]; --[L, S] ← [111, 111]
TestASL[111, 8]; --[L, S] ← [119, 119]
TestASL[119, 4]; --[L, S] ← [123, 123]
TestASL[123, 2]; --[L, S] ← [125, 125]
TestASL[125, 1]; --[L, S] ← [126, 126]
drAS[2]; --[L, S] ← [126, 0]
drALS[1]; --[L, S] ← [1, 0] restores original value
};
WordAlign[area];
SetLabel[dummy];
Pause[]; Pause[]; Pause[]; Pause[]; Pause[]; Halt[123B];
Opcodes 0 and 377B are intercepted by the simulator, but make them trap to dummy here anway.
savePC ← GetOutputPC[area];
FillTrap[ResetTrap, start];
FillXop[0, dummy];
FillXop[377B, dummy];
SetOutputPC[savePC];
ProcedureEntry[initL, 0];
drLIB[1];
SetYoungestL[]; -- L ← 1 on return
spLimit is set with room for 17 overflow words (just in case). A stack overflow trap occurs when S is in [spLimit..spLimit + 16). Since this diagnostic program never enables the trap, it is unnecessary to execute the code here.
--drLIB[128-16-1];
--SetSPLimit[];
ProcedureExit[0];
WordAlign[area];
SetLabel[start]; --Simulator execution begins here on a Reset.
drLFC[UseLabel16[initL]]; --We use this method to initialize L to 1
drASL[255]; --and S to 0.
drJDB[UseLabel16[enterXopTest]];
GenXop[];
GenAL[];
GenALS[];
GenAS[];
GenDIS[];
GenASL[];
Halt[177777B]; --Terminate here at the end of the program