GenReg.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Edward Fiala February 7, 1986 2:59:57 pm PST
McCreight, January 7, 1986 3:52:02 pm PST
This diagnostic tests EU and IFU registers using LIP and SIP and (in a limited way) using LFC and RETN. It presumes that LIQB and RJEBJ have been thoroughly tested by GenLICJ. When successfully executed it halts at instruction 2162, cycle 4975, PC 4031055B.
DIRECTORY
--Basics USING [],
DragOpsCross USING [XopBase, TrapBase, TrapWidthBytes, bytesPerWord, TrapIndex, Word, ProcessorRegister, IFUStackIndex],
--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
GenReg: CEDAR PROGRAM
IMPORTS DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport
= BEGIN OPEN DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport;
Word: TYPE = DragOpsCross.Word;
ProcessorRegister: TYPE = DragOpsCross.ProcessorRegister;
IFUStackIndex: TYPE = DragOpsCross.IFUStackIndex;
ifuSLimit: CARDINAL = LOOPHOLE[ProcessorRegister.ifuSLimit, CARDINAL];
ifuEldestPC: CARDINAL = LOOPHOLE[ProcessorRegister.ifuEldestPC, CARDINAL];
ifuEldestL: CARDINAL = LOOPHOLE[ProcessorRegister.ifuEldestL, CARDINAL];
ifuYoungestPC: CARDINAL = LOOPHOLE[ProcessorRegister.ifuYoungestPC, CARDINAL];
ifuYoungestL: CARDINAL = LOOPHOLE[ProcessorRegister.ifuYoungestL, CARDINAL];
ifuStatus: CARDINAL = LOOPHOLE[ProcessorRegister.ifuStatus, CARDINAL];
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]];
};
GenRegWrite: PROC [reg: CARDINAL, val: LONG CARDINAL] ~ {
drLIQB[CardToWord[val]];
drSIP[reg];
};
GenRegRead: PROC [reg: CARDINAL, val: LONG CARDINAL] ~ {
rdOK: Label = GenLabel[];
drLIP[reg];
drLIQB[CardToWord[val]];
drRJEBJ[popSrc, belowSrcPop, UseLabel8B[rdOK]];
Pause[];
SetLabel[rdOK];
};
area: Area = GetCurrentArea[];
savePC: LONG CARDINAL;
start: Label = GenLabel[];
dummy: Label = GenLabel[];
initL: Label = GenLabel[];
enterEUSLTest: Label = GenLabel[];
enterIFUSLTest: Label = GenLabel[];
GenEUSL tests all EU registers except const0 using LIQB and SIP to consecutively write different values in all registers, then LIP, LIQB, and RJEB to read back and check all values. This test will catch addressing errors which cause the write of one register to wind up in another as well as storage failures. Register descriptions are in DragOpsCross.mesa. Skip over euJunk = 128 and 129; test euMar = 130 and euField = 131. euMar is a dumping place for memory addresses on address faults; it is (??) a regular register. euField is both a normal register and a collection of other logic to control the field unit; this test covers the register part of it; the other control logic can only be tested indirectly by noting whether or not the field unit performs correctly for values in euField.
GenEUSL: PROC = {
testVal: LONG CARDINAL;
SetLabel[enterEUSLTest];
testVal ← 8;
GenRegWrite[0, 1];
FOR I: CARDINAL IN [3..127] DO
GenRegWrite[I, testVal];
testVal ← IF testVal = 20000000000B THEN 1 ELSE testVal + testVal;
ENDLOOP;
FOR I: CARDINAL IN [130..131] DO
GenRegWrite[I, testVal];
testVal ← IF testVal = 20000000000B THEN 1 ELSE testVal + testVal;
ENDLOOP;
FOR I: CARDINAL IN [133..159] DO
GenRegWrite[I, testVal];
testVal ← IF testVal = 20000000000B THEN 1 ELSE testVal + testVal;
ENDLOOP;
Read and compare; must skip registers 1 and 2 which have been smashed by the various pushes during writing and reading.
testVal ← 8;
GenRegRead[0, 1];
FOR I: CARDINAL IN [3..127] DO
GenRegRead[I, testVal];
testVal ← IF testVal = 20000000000B THEN 1 ELSE testVal + testVal;
ENDLOOP;
FOR I: CARDINAL IN [130..131] DO
GenRegRead[I, testVal];
testVal ← IF testVal = 20000000000B THEN 1 ELSE testVal + testVal;
ENDLOOP;
FOR I: CARDINAL IN [133..159] DO
GenRegRead[I, testVal];
testVal ← IF testVal = 20000000000B THEN 1 ELSE testVal + testVal;
ENDLOOP;
Finally, go back and test registers 1 and 2.
drASL[4]; --S ← 5
GenRegWrite[1, 2];
GenRegWrite[2, 4];
GenRegRead[1, 2];
GenRegRead[2, 4];
drASL[255]; --S ← 0 again
Write with inverse values.
testVal ← 37777777767B;
GenRegWrite[0, 37777777776B];
FOR I: CARDINAL IN [3..127] DO
GenRegWrite[I, testVal];
testVal ← IF testVal = 17777777777B THEN 37777777776B ELSE testVal + testVal + 1;
ENDLOOP;
FOR I: CARDINAL IN [130..131] DO
GenRegWrite[I, testVal];
testVal ← IF testVal = 17777777777B THEN 37777777776B ELSE testVal + testVal + 1;
ENDLOOP;
FOR I: CARDINAL IN [133..159] DO
GenRegWrite[I, testVal];
testVal ← IF testVal = 17777777777B THEN 37777777776B ELSE testVal + testVal + 1;
ENDLOOP;
Read and compare, skipping registers 1 and 2 smashed by stack operations.
testVal ← 37777777767B;
GenRegRead[0, 37777777776B];
FOR I: CARDINAL IN [3..127] DO
GenRegRead[I, testVal];
testVal ← IF testVal = 17777777777B THEN 37777777776B ELSE testVal + testVal + 1;
ENDLOOP;
FOR I: CARDINAL IN [130..131] DO
GenRegRead[I, testVal];
testVal ← IF testVal = 17777777777B THEN 37777777776B ELSE testVal + testVal + 1;
ENDLOOP;
FOR I: CARDINAL IN [133..159] DO
GenRegRead[I, testVal];
testVal ← IF testVal = 17777777777B THEN 37777777776B ELSE testVal + testVal + 1;
ENDLOOP;
Finally, go back and test registers 1 and 2.
drASL[4]; --S ← 5
GenRegWrite[1, 37777777775B];
GenRegWrite[2, 37777777773B];
GenRegRead[1, 37777777775B];
GenRegRead[2, 37777777773B];
drASL[255]; --S ← 0 again
};
GenIFUSL tests all IFU registers except ifuXBus (untestable) and ifuStatus using LIQB and SIP to consecutively write different values in all registers, then LIP, LIQB, and RJEB to read back and check all values. The IFU stack is tested both when writing it with ifuEldestL/PC and when writing it with ifuYoungestL/PC and changing the stack depth with LFC/RETN. This test will catch addressing errors which cause the write of one register to wind up in another, and it checks the manipulation of the IFU stack and L register by LFC and RETN. The description of the funny IFU registers is in DragOpsCross.mesa.
Current values of L, S, and PC cannot be read; the stack covers only previous frames. In normal operation, ifuEldestL/PC are written on IFU stack underflow when previous frames are restored to the registers, and read on IFU or EU stack overflow to remove frames from the registers. One test below operates the IFU stack by reading and writing ifuEldestL/PC. Another test below writes the IFU stack by doing a LFC to push the stack, then using SIP on ifuYoungestL/PC; then it reads the stack back by doing RET and LIP to read values.
ifuXBus = base for IFU regs = 240 can't be tested.
ifuStatus = 241 is not tested here.
ifuSLimit = stack limit register = 242; 7-bit register. This register is written and read by GenIFUSL, but its function as a stack limit register is not tested.
IFUStackSize = 15.
ifuYoungestL = youngest L in IFU stack = 243.
ifuYoungestPC = youngest PC in IFU stack = 244.
ifuEldestL = eldest L in IFU stack = 245.
ifuEldestPC = eldest PC in IFU stack = 246 (read removes, write adds).
GenIFUSL: PROC = {
GenCallTest: PROC [dest: Label, lVal, rVal: CARDINAL] ~ {
drLFC[UseLabel16[dest]];
GenRegRead[ifuYoungestL, rVal];
drRETN[];
Pause[];
SetLabel[dest];
GenRegWrite[ifuYoungestL, lVal];
};
testPCVal, testLVal: LONG CARDINAL;
SetLabel[enterIFUSLTest];
Test with single 1-bit cycled left 1 position each time.
testPCVal ← 1;
testLVal ← 4;
GenRegWrite[ifuSLimit, 0];
FOR I: CARDINAL IN IFUStackIndex DO
GenRegWrite[ifuEldestPC, testPCVal];
testPCVal ← IF testPCVal = 20000000000B THEN 1 ELSE testPCVal + testPCVal;
GenRegWrite[ifuEldestL, testLVal];
testLVal ← IF testLVal = 100B THEN 1 ELSE testLVal + testLVal;
ENDLOOP;
GenRegRead[ifuSLimit, 0];
FOR I: CARDINAL IN IFUStackIndex DO
testLVal ← IF testLVal = 1 THEN 100B ELSE testLVal / 2;
GenRegRead[ifuEldestL, testLVal];
testPCVal ← IF testPCVal = 1 THEN 20000000000B ELSE testPCVal / 2;
GenRegRead[ifuEldestPC, testPCVal];
ENDLOOP;
Test with single 0-bit cycled left 1 position each time (i.e., inverse of first test).
testPCVal ← 37777777776B;
testLVal ← 173B;
GenRegWrite[ifuSLimit, 177B];
FOR I: CARDINAL IN IFUStackIndex DO
GenRegWrite[ifuEldestPC, testPCVal];
testPCVal ← IF testPCVal = 17777777777B THEN 37777777776B ELSE testPCVal + testPCVal + 1;
GenRegWrite[ifuEldestL, testLVal];
testLVal ← IF testLVal = 77B THEN 176B ELSE testLVal + testLVal + 1 - 200B;
ENDLOOP;
GenRegRead[ifuSLimit, 177B];
FOR I: CARDINAL IN IFUStackIndex DO
testLVal ← IF testLVal = 176B THEN 77B ELSE testLVal / 2 + 100B;
GenRegRead[ifuEldestL, testLVal];
testPCVal ← IF testPCVal = 37777777776B THEN 17777777777B ELSE testPCVal / 2 + 20000000000B;
GenRegRead[ifuEldestPC, testPCVal];
ENDLOOP;
Test the ifu stack with LFC and ifuYoungestL/PC used to push and to write, and ifuEldestL/PC used to read and pop.
testPCVal ← 200000B;
testLVal ← 1;
FOR I: CARDINAL IN IFUStackIndex DO
youngCall: Label = GenLabel[];
drLFC[UseLabel16[youngCall]];
SetLabel[youngCall];
GenRegWrite[ifuYoungestPC, testPCVal];
testPCVal ← IF testPCVal = 20000000000B THEN 1 ELSE testPCVal + testPCVal;
GenRegWrite[ifuYoungestL, testLVal];
testLVal ← IF testLVal = 100B THEN 1 ELSE testLVal + testLVal;
ENDLOOP;
testPCVal ← 200000B;
testLVal ← 1;
FOR I: CARDINAL IN IFUStackIndex DO
GenRegRead[ifuEldestL, testLVal];
testLVal ← IF testLVal = 100B THEN 1 ELSE testLVal + testLVal;
GenRegRead[ifuEldestPC, testPCVal];
testPCVal ← IF testPCVal = 20000000000B THEN 1 ELSE testPCVal + testPCVal;
ENDLOOP;
Test the ifu stack with LFC used to push and to write PC, ifuYoungestL to write, and RETN used to read and pop. This test will malfunction unless L and PC are correctly manipulated by LFC and RETN. Note that only 15 calls can be made here because, even though there are 16 levels in the ifu stack, only 15 are usable by call and return; if a 16th LFC is given, then its RETN results in a stack underflow trap.
{
Call1: Label = GenLabel[];
Call2: Label = GenLabel[];
Call3: Label = GenLabel[];
Call4: Label = GenLabel[];
Call5: Label = GenLabel[];
Call6: Label = GenLabel[];
Call7: Label = GenLabel[];
Call8: Label = GenLabel[];
Call9: Label = GenLabel[];
Call10: Label = GenLabel[];
Call11: Label = GenLabel[];
Call12: Label = GenLabel[];
Call13: Label = GenLabel[];
Call14: Label = GenLabel[];
Call15: Label = GenLabel[];
EndCallTest: Label = GenLabel[];
drLFC[UseLabel16[Call1]];
drJDB[UseLabel16[EndCallTest]];
SetLabel[Call1];
GenRegWrite[ifuYoungestL, 1];
GenCallTest[Call2, 2, 1];
GenCallTest[Call3, 3, 2];
GenCallTest[Call4, 4, 3];
GenCallTest[Call5, 5, 4];
GenCallTest[Call6, 6, 5];
GenCallTest[Call7, 7, 6];
GenCallTest[Call8, 8, 7];
GenCallTest[Call9, 9, 8];
GenCallTest[Call10, 10, 9];
GenCallTest[Call11, 11, 10];
GenCallTest[Call12, 12, 11];
GenCallTest[Call13, 13, 12];
GenCallTest[Call14, 14, 13];
GenCallTest[Call15, 15, 14];
GenRegRead[ifuYoungestL, 15];
drRETN[];
SetLabel[EndCallTest];
};
};
ProcedureEntry[dummy, 0];
ProcedureExit[0];
Opcodes 0 and 377B are intercepted by the simulator, but make them trap to dummy here anyway.
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 not necessary 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]; --When there is nothing on the stack, S should be at L-1
At this point, L = 1, S = 0.
GenEUSL[];
GenIFUSL[];
Halt[177777B]; --Terminate here at the end of the program
};
END.