GenLICJ.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Edward Fiala February 7, 1986 1:35:30 pm PST
McCreight, January 7, 1986 3:48:37 pm PST
When it finishes without error, this diagnostic executes a Halt[177777B] at PC = 4034017B, instruction 2560, cycle 6804.
DIRECTORY
Basics USING [BITXOR],
DragOpsCross USING [XopBase, TrapBase, TrapWidthBytes, bytesPerWord, TrapIndex, Word],
--XopBase, TrapBase, TrapWidthBytes, Inst, wordsPerPage, bytesPerWord, charsPerWord, bitsPerByte, bitsPerCharacter, bitsPerWord, logWordsPerPage, logBitsPerByte, logBitsPerChar, logBytesPerWord, logCharsPerWord, logBitsPerWord, logBytesPerPage, PageCount, PageNumber, maxPagesInVM, SixBitIndex, FiveBitIndex, Word, TwoWords, FourBitIndex, Half, ThreeBitIndex, FourHalves, TwoHalves, Byte, ZerosByte, OnesByte, EightBytes, FourBytes, ByteIndex, BytesPerWord, TwoBytes, Comparison, ByteAddress, WordAddress, FieldDescriptor, TrapWidthWords, KernalLimit, TrapIndex, StackUnderflowTrap, IFUPageFaultTrap, ResetTrap, IFUStackOverflowTrap, EUStackOverflowTrap, RescheduleTrap, ALUCondOver, ALUCondBC, ALUCondIL, ALUCondDO, EUPageFault, EUWriteFault, AUFault, euStack, euJunk, euMAR, euField, euConstant, euAux, euBogus, euLast, ifuXBus, ifuStatus, ifuSLimit, ifuYoungestL, ifuYoungestPC, ifuEldestL, ifuEldestPC, ifuBogus, ifuL, ifuS, ifuPC, ifuLast, IFUStatusRec, IFUStackIndex, IFUStackSize, IFUOverflow, EUStackIndex, EUStackSize, EULocalIndex, EULocals, EUAuxIndex, EUAuxRegs, EUConstIndex, EUConstants, IOLocation, ioRescheduleRequest, ioResetRequest
DragOpsCrossUtils USING [CardToWord],
--BytePCToWordAddress, WordAddressToBytePC, IOOperandToCard, CardToIOOperand, FieldDescriptorToCard, CardToFieldDescriptor, StatusToWord, WordToStatus, BytesToWord, BytesToHalf, WordToBytes, HalfToBytes, HalvesToWord, WordToHalves, HighHalf, LowHalf, LeftHalf, RightHalf, SwapHalves, WordToInt, IntToWord, WordToCard, HalfToCard, ByteToCard, CardToWord, CardToHalf, CardToByte, DragAnd, DragOr, DragXor, DragNot, VanillaAdd, VanillaSub, AddDelta, HalfNot, HalfAnd, HalfOr, HalfXor, HalfShift, DoubleWordShiftLeft, SingleWordShiftLeft, SingleWordShiftRight, TrapIndexToBytePC, XopToBytePC
HandCoding, --Has opcode and register defs.
HandCodingPseudos, --GenLabel, GenLabelHere, SetLabel, Halt, Pause, MakeLabelGlobal, UseLabel8B, UseLabel16, UseLabel32, ProcedureEntry, ProcedureExit, EnableTraps, IndexedJump, SetupField, ExtractField, ShiftLeft, LoadProcessorReg, StoreProcessorReg, DisableTraps, CauseReschedule, CauseReset, GetSPLimit, SetSPLimit, GetL, SetL, GetYoungestPC, GetYoungestL, GetEldestPC, GetEldestL, SetYoungestPC, SetYoungestL, SetEldestPC, SetEldestL
HandCodingSupport; --Area, GetCurrentArea, ReserveData, SetOutputPC, GetProc, PutProc, ProcList, NewArea, GenWithArea, Gen1WithArea, ForceOut, GetOutputPC, WordAlign, OutputByte, OutputOneByte, OutputAlphaBeta, OutputAlphaBetaGammaDelta, OutputWord
GenLICJ: CEDAR PROGRAM
IMPORTS Basics, DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport
= BEGIN OPEN DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport;
Word: TYPE = DragOpsCross.Word;
All: PROC = {
The Xop trap locations assigned to each opcode are at at opcode*TrapWidthBytes + xopBase*bytesPerWord = 4,000,000B + 20B * opcode, and the trap location assigned to each trap are at TrapIndex*TrapWidthBytes + TrapBase*bytesPerWord = 4,002,000B + 20B * TrapIndex. The TrapIndex definitions are in DragOpsCross.
FillXop: PROC [inst: CARDINAL, dest: Label] = {
SetOutputPC[inst * DragOpsCross.TrapWidthBytes + DragOpsCross.XopBase * DragOpsCross.bytesPerWord];
drJDB[UseLabel16[dest]];
};
FillTrap: PROC [tx: DragOpsCross.TrapIndex, dest: Label] = {
SetOutputPC[LOOPHOLE[tx, CARDINAL] * DragOpsCross.TrapWidthBytes + DragOpsCross.TrapBase * DragOpsCross.bytesPerWord];
drJDB[UseLabel16[dest]];
};
area: Area = GetCurrentArea[];
oldPC: LONG CARDINAL;
start: Label = GenLabel[];
dummy: Label = GenLabel[];
const0OK: Label = GenLabel[];
enterLIQBTest: Label = GenLabel[];
enterLIDBTest: Label = GenLabel[];
enterLIBTest: Label = GenLabel[];
enterJEBTest: Label = GenLabel[];
This procedure generates tests on LIQB, RJEB, RJEBJ, RJNEB, and RJNEBJ for each of the 32 values of 2^n. Each subtest loads two values onto the evaluation stack and tests whether or not a true jump opcode jumps and a false jump opcode doesn't jump. The first jump of each test leaves both stack operands on the stack; the second jump pops the two arguments from the stack. Value combinations tested are as follows for a particular value w = 2^n:
 w w
 w 0
 0 w
 w' 0'
 0' w'
 w' w'.
Then LIDB is tested against LIQB for all 16 values of 2^n using RJEB; finally, LIB is tested against LIQB for all 8 values of 2^n.
Don't screw with these tests; code alignment is important to make sure that bypass paths are used or not used when expected. TestE1, TestE2, TestNE1, and TestNE2 must each produce exactly 4*n + 2 code bytes.
GenLI: PROC = {
TestE1 produces 10 code bytes.
TestE1: PROC [] ~ {
ok1: Label ← GenLabel[];
ok2: Label ← GenLabel[];
bad1: Label ← GenLabel[];
drRJEB[left: topSrc, right: belowSrc, dist: UseLabel8B[ok1]];
Pause[]; --Bug: [s] = [s-1] but RJEB didn't jump.
SetLabel[ok1];
a1 and a2 are still on the stack;
drRJNEB[left: popSrc, right: belowSrcPop, dist: UseLabel8B[bad1]];
drJB[UseLabel8A[ok2]];
SetLabel[bad1]; Pause[]; --Bug: [s] = [s-1] but RJNEB jumped.
a1 and a2 have been popped from the stack;
SetLabel[ok2];
};
TestE2 produces 14 code bytes. It is the same as TestE1 but uses RJEBJ and RJNEBJ instead of RJEB and RJNEB, and it uses RAND to move the one of the arguments to const1 so that the B bypass path can be tested.
TestE2: PROC [] ~ {
ok1: Label ← GenLabel[];
ok2: Label ← GenLabel[];
bad1: Label ← GenLabel[];
drJ1[]; --No-op to preserve alignment
drRAND[c: const1, a: topSrc, b: popSrc];
This one exercises the B bypass path
drRJEBJ[left: topSrc, right: const1, dist: UseLabel8B[ok1]];
Pause[]; --Bug: [s] = const1 but RJEBJ didn't jump.
SetLabel[ok1];
a1 and a2 are still on the stack;
drRJNEBJ[left: popSrc, right: const1, dist: UseLabel8B[bad1]];
drJB[UseLabel8A[ok2]];
SetLabel[bad1]; Pause[]; --Bug: [s] = const1 but RJNEB jumped.
a1 and a2 have been popped from the stack;
SetLabel[ok2];
};
TestNE produces 10 code bytes.
TestNE1: PROC [] ~ {
ok1: Label ← GenLabel[];
ok2: Label ← GenLabel[];
bad1: Label ← GenLabel[];
drRJNEB[left: topSrc, right: belowSrc, dist: UseLabel8B[ok1]];
Pause[]; --Bug: [s] # [s-1] but RJNEB didn't jump.
SetLabel[ok1];
a1 and a2 are still on the stack;
drRJEB[left: popSrc, right: belowSrcPop, dist: UseLabel8B[bad1]];
drJB[UseLabel8A[ok2]];
SetLabel[bad1]; Pause[]; --Bug: [s] # [s-1] but RJEB jumped.
a1 and a2 have been popped from the stack;
SetLabel[ok2];
};
TestNE2 produces 14 code bytes. It is the same as TestNE1 but uses RJNEBJ and RJEBJ instead of RJNEB and RJEB, and it uses RAND to move one of the arguments to const1 so that the B bypass path can be tested.
TestNE2: PROC [] ~ {
ok1: Label ← GenLabel[];
ok2: Label ← GenLabel[];
bad1: Label ← GenLabel[];
drJ1[]; --No-op to preserve word alignment
drRAND[c: const1, a: topSrc, b: popSrc];
drRJNEBJ[left: topSrc, right: const1, dist: UseLabel8B[ok1]];
Pause[]; --Bug: [s] # const1 but RJNEBJ didn't jump.
SetLabel[ok1];
a1 and a2 are still on the stack;
drRJEBJ[left: popSrc, right: const1, dist: UseLabel8B[bad1]];
drJB[UseLabel8A[ok2]];
SetLabel[bad1]; Pause[]; --Bug: [s] # const1 but RJEBJ jumped.
a1 and a2 have been popped from the stack;
SetLabel[ok2];
};
GenLIQBTest: PROC [value: LONG CARDINAL] = {
w: Word ← CardToWord[value];
nw ← ones complement of w.
nw: Word ← CardToWord[LOOPHOLE[- LOOPHOLE[value, INT] - 1, LONG CARDINAL]];
z: Word ← CardToWord[0];
nz: Word ← CardToWord[37777777777B];
Each LIQB opcode is 5 bytes and each TestXX procedure produces 10 bytes, so 20 total bytes or 5 words are produced for each test; this means that byte alignment of the first test is preserved for subsequent tests. To for sure exercise the EU's A bypass path, the first conditional jump must finish in the same word as the last byte of the preceding opcode. This is arranged by beginning on a word boundary and inserting three J1's before the first test.
drLIQB[w]; drLIQB[w]; TestE1[];
drLIQB[w]; drLIQB[z]; TestNE1[];
drLIQB[z]; drLIQB[w]; TestNE1[];
drLIQB[nw]; drLIQB[nz]; TestNE1[];
drLIQB[nz]; drLIQB[nw]; TestNE1[];
drLIQB[nw]; drLIQB[nw]; TestE1[];
The next group of tests are identical to the previous group but RJEBJ and RJNEBJ are used instead of RJEB and RJNEB, and the B bypass path is executed instead of the A bypass path by using RAND to move the top stack argument to const1; 24 bytes are produced for each test.
drLIQB[w]; drLIQB[w]; TestE2[];
drLIQB[w]; drLIQB[z]; TestNE2[];
drLIQB[z]; drLIQB[w]; TestNE2[];
drLIQB[nw]; drLIQB[nz]; TestNE2[];
drLIQB[nz]; drLIQB[nw]; TestNE2[];
drLIQB[nw]; drLIQB[nw]; TestE2[];
};
GenLIDBTest produces 18 code bytes.
GenLIDBTest: PROC [value: CARDINAL] = {
w: Word ← CardToWord[LONG[value]];
drLIDB[value]; drLIQB[w]; TestE1[];
};
GenLIBTest produces 15 code bytes.
GenLIBTest: PROC [value: CARDINAL] = {
drLIB[value]; drLIDB[value]; TestE1[];
};
Test JEBB and JNEBB on an 8-bit value.
GenJEBTest: PROC [value: CARDINAL] = {
ok1: Label ← GenLabel[];
ok2: Label ← GenLabel[];
ok3: Label ← GenLabel[];
ok4: Label ← GenLabel[];
bad: Label ← GenLabel[];
notValue: CARDINAL ← Basics.BITXOR[value, 377B];
drLIB[value];
drJEBB[value, UseLabel8B[ok1]];
Pause[]; --JEBB should have jumped but didn't
SetLabel[ok1];
drLIB[value];
drJNEBB[0, UseLabel8B[ok2]];
Pause[]; --JNEBB should have jumped but didn't
SetLabel[ok2];
drLIB[value];
drJEBB[0, UseLabel8B[bad]];
drLIB[value];
drJNEBB[value, UseLabel8B[bad]];
drLIB[notValue];
drJEBBJ[377B, UseLabel8B[bad]];
drLIB[notValue];
drJNEBBJ[notValue, UseLabel8B[bad]];
drLIB[notValue];
drJEBBJ[notValue, UseLabel8B[ok3]];
Pause[]; --JEBBJ should have jumped but didn't
SetLabel[ok3];
drLIB[notValue];
drJNEBBJ[377B, UseLabel8B[ok4]];
SetLabel[bad]; Pause[];
SetLabel[ok4];
};
val: LONG CARDINAL ← 1;
hval: CARDINAL ← 1;
bval: CARDINAL ← 1;
jval: CARDINAL ← 1;
WordAlign[area];
SetLabel[enterLIQBTest];
These 3 no-ops cause the last byte of the 2nd LIQB opcode for each test to appear in the first byte of a word, so that the conditional jump which follows appears in the same word and exercises the B bypass path.
drJ1[]; drJ1[]; drJ1[];
UNTIL val = 0 DO
GenLIQBTest[val];
val ← val + val;
ENDLOOP;
SetLabel[enterLIDBTest];
UNTIL hval = 0 DO
GenLIDBTest[hval];
hval ← hval + hval;
ENDLOOP;
SetLabel[enterLIBTest];
UNTIL bval = 400B DO
GenLIBTest[bval];
bval ← bval + bval;
ENDLOOP;
SetLabel[enterJEBTest];
UNTIL jval = 400B DO
GenJEBTest[jval];
jval ← jval + jval;
ENDLOOP;
};
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 anyway.
oldPC ← GetOutputPC[area];
FillTrap[ResetTrap, start];
FillXop[0, dummy];
FillXop[377B, dummy];
SetOutputPC[oldPC];
WordAlign[area];
SetLabel[start]; --Simulator execution begins here on a Reset.
drASL[255]; --When there is nothing on the stack, S should be at L-1
drLC0[];
drJEBB[0, UseLabel8B[const0OK]];
Pause[]; --const0 wrong
SetLabel[const0OK];
**Don't bum this instruction; code alignment is important here.**
drJDB[UseLabel16[enterLIQBTest]];
GenLI[];
Halt[177777B]; --Terminate here at the end of the program
};
END.