DIRECTORY
--Basics USING [],
DragOpsCross USING [XopBase, TrapBase, TrapWidthBytes, bytesPerWord, TrapIndex, Word, ProcessorRegister, IFUStackIndex],
--Word, wordsPerPage, bytesPerWord, charsPerWord, bitsPerByte, bitsPerCharacter, bitsPerWord, bytesPerPage, logWordsPerPage, logBitsPerByte, logBitsPerChar, logBytesPerWord, logCharsPerWord, logBitsPerWord, logBytesPerPage, PageCount, PageNumber, maxPagesInVM, SixBitIndex, FiveBitIndex, TwoWords, FourBitIndex, Half, ThreeBitIndex, FourHalves, TwoHalves, Byte, ZerosByte, OnesByte, EightBytes, FourBytes, ByteIndex, BytesPerWord, TwoBytes, Comparison, ByteAddress, WordAddress, FieldDescriptor, RegIndex, PadByte, Lit8, Op4, Op8, JDist8, Inst, OIFormat, OQBformat, LRformat, QRformat, ShortRegQR, OBformat, LRBformat, RRformat, ODBformat, LRRBformat, RJBformat, ShortRegRJB, JBBformat, TrapWidthWords, TrapWidthBytes, XopBase, TrapBase, KernalLimit, TrapIndex, StackUnderflowTrap, IFUPageFaultTrap, ResetTrap, IFUStackOverflowTrap, EUStackOverflowTrap, RescheduleTrap, ALUCondFalse, ALUCondEZ, ALUCondLZ, ALUCondLE, ALUCondSpare, ALUCondNE, ALUCondGE, ALUCondGZ, ALUCondOver, ALUCondBC, ALUCondIL, ALUCondDO, ALUCondNotOver, ALUCondNB, ALUCondNI, ModeFault, MemAccessFault, IOAccessFault, EUPageFault, EUWriteFault, AUFault, euStack, euJunk, euToKBus, euMAR, euField, euConstant, euAux, euBogus, euLast, ifuYoungestL, ifuYoungestPC, ifuEldestL, ifuEldestPC, ifuSLimit, ifuBogus, ifuL, ifuS, ifuPC, ifuLast, EURegs, EULegalRegs, IFURegs, IFULegalRegs, StackedStatusWord, IFUStackIndex, IFUStackSize, IFUOverflow, EUStackIndex, EUStackSize, EULocalIndex, EULocals, EUAuxIndex, EUAuxRegs, EUConstIndex, EUConstants, IOLocation, ioRescheduleRequest, ioResetRequest, IOOperand, PCmdFormat, PCmdByteSelect, PCmdClass, PCmdSpace, PCmdDirection
DragOpsCrossUtils USING [CardToWord],
--InstToBytes, InstToFormat, BytePCToWordAddress, WordAddressToBytePC, IOOperandToCard, CardToIOOperand, FieldDescriptorToCard, CardToFieldDescriptor, 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, XopToBytePC, TrapIndexToBytePC, FieldUnit
HandCoding, --Has opcode and register defs.
HandCodingPseudos, --Label, SetLabel, GenLabel, GenLabelHere, UseLabel8A, UseLabel8B, UseLabel16, UseLabel32, LReg, PReg, SReg, AddReg, SubReg, SetRegConst, MoveReg, MoveRegI, LRegI, IndexedJump, ProcedureEntry, ProcedureExit, SetupField, ExtractField, ShiftLeft, LoadProcessorReg, StoreProcessorReg, CauseReschedule, CauseReset, GetSPLimit, SetSPLimit, GetYoungestPC, GetYoungestStatus, GetEldestPC, GetEldestStatus, SetYoungestPC, SetYoungestStatus, SetEldestPC, SetEldestStatus, Pause, Halt
HandCodingSupport; --Area, GetProc, PutProc, ProcList, NewArea, GenWithArea, Gen1WithArea, ForceOut, GetCurrentArea, LoadArea, GetOutputPC, SetOutputPC, WordAlign, ReserveData, 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];
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]];
};
Note that the write of the StackedStatusWord does not mask the upper fields in the word; not needed because userMode=FALSE and trapsEnabled=FALSE.
GenRegWrite:
PROC [reg:
CARDINAL, val:
LONG
CARDINAL] ~ {
IF reg = ifuYoungestL THEN { drLIB[val]; SetYoungestStatus[]; }
ELSE { drLIQB[CardToWord[val]]; drSIP[reg]};
};
GenRegRead:
PROC [reg:
CARDINAL, val:
LONG
CARDINAL] ~ {
rdOK: Label = GenLabel[];
IF reg = ifuYoungestL THEN { GetYoungestStatus[]; drLIB[377B]; drAND[]; }
ELSE IF reg = ifuEldestL THEN { GetEldestStatus[]; drLIB[377B]; drAND[]; }
ELSE drLIP[reg];
drLIQB[CardToWord[val]];
drRJEBJ[popSrc, belowSrcPop, UseLabel8B[rdOK]];
Pause[];
SetLabel[rdOK];
};
SetYoungestL: PROC = {
GetYoungestStatus[];
drLIQB[CardToWord[37777777400B]]; drAND[]; drOR[];
SetYoungestStatus[];
};
--area: Area = GetCurrentArea[];
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;
Const0, 1, 2, and 3 are read-only.
FOR I:
CARDINAL
IN [136..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;
Const0 = 132. const0, 1, 2, and 3 are read-only.
FOR I:
CARDINAL
IN [136..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;
Const0 = 132. const0, 1, 2, and 3 are read-only.
FOR I:
CARDINAL
IN [136..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;
Const0 = 132. const0, 1, 2, and 3 are read-only.
FOR I:
CARDINAL
IN [136..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) 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. 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. 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.
ifuXBus = base for IFU regs, can't be tested.
ifuSLimit = stack limit register, 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 (user mode and traps enabled not tested).
ifuYoungestPC = youngest PC in IFU stack.
ifuEldestL = eldest L in IFU stack (user mode and traps enabled not tested).
ifuEldestPC = eldest PC in IFU stack (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];
};
};
Begin at PC = userBasePC = 1010000B * 4, L = 1, S = 0 as established in GenDebugger.
GenEUSL[];
GenIFUSL[];
Halt[177777B]; --Terminate here at the end of the program
END.