DIRECTORY
DragOpsCross USING [Word, XopBase, TrapBase, TrapWidthBytes, bytesPerWord, TrapIndex],
--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
GenCall:
CEDAR
PROGRAM
IMPORTS DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport
= BEGIN OPEN DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport;
Word: TYPE = DragOpsCross.Word;
All:
PROC = {
All traps enter kernel mode, disable traps, and push the old ifuStatus onto the EU stack. Disabling affects only Reschedule, EU stack overflow, and IFU stack overflow.
When traps are enabled, any opcode causing S to wind up in the range [SLimit..SLimit+16) causes an EU stack overflow trap; this detects both underflows and overflows, though underflow can only happen due to a programming error.
Xops and KFC 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[];
oldPC: LONG CARDINAL;
start: Label = GenLabel[];
dummy: Label = GenLabel[];
enterDFCRETTest: Label = GenLabel[];
enterLFCTest: Label = GenLabel[];
Exercise every bit position of the PC address and every bit position of the alpha byte of RET. The test procedures do something entirely non-sensical, but the purpose of the diagnostic is served.
GenDFCRETTest:
PROC [] ~ {
Produce a small procedure consisting of an instruction which counts [S] before a DFC and before RET so that the passage of control through all the procedures can be verified by checking the value in [S] at the end. The change in L at procedure entry by ALS offsets the change in S at procedure exit by RET so that RET[alpha] can be tested for all values of alpha without changing [S].
DoDFC:
PROC [destPC:
LONG
CARDINAL, nArgs:
CARDINAL] ~ {
alsArg: CARDINAL = (1 - nArgs) MOD 400B;
retArg: CARDINAL = (nArgs - 1) MOD 400B;
drALS[alsArg]; --ALS[1 - nargs] => set L nArgs below S
drADDB[200B];
drDFC[CardToWord[destPC]];
drADDB[1];
RET does S ← L + alpha; return.
drRET[retArg]; --RET[nResults - 1] => set S nArgs above L
SetOutputPC[destPC];
};
enterDFCRETTestPC: LONG CARDINAL = 4000B;
endDFCRETTestPC: LONG CARDINAL = 6000B;
okDFCRET: Label = GenLabel[];
endDFCRETTest: Label = GenLabel[];
drJQB[UseLabel32[enterDFCRETTest]];
SetOutputPC[enterDFCRETTestPC];
SetLabel[enterDFCRETTest];
Exercise every bit position of the PC address.
Must avoid the vector for Xops and Traps between byte positions 4000000B and 4004000B; must avoid the locations occupied by the other tests in the diagnostic.
drLIB[0]; --Counter used to verify that the calls and returns have occurred.
drDFC[CardToWord[400100B]];
drLIQB[CardToWord[3416B]];
drRJEB[popSrc, belowSrcPop, UseLabel8B[okDFCRET]]; Pause[]; SetLabel[okDFCRET];
drJQB[UseLabel32[endDFCRETTest]];
SetOutputPC[400100B];
DoDFC[ 1000200B, 1B]; --[s] = 200B after the DFC, 3416B after the RETN
DoDFC[ 2000400B, 2B]; --[s] = 400B after the DFC, 3415B after the RETN
DoDFC[ 4010000B, 4B]; --[s] = 600B after the DFC, 3414B after the RETN
DoDFC[ 10002000B, 10B]; --[s] = 1000B after the DFC, 3413B after the RETN
DoDFC[ 20004001B, 20B]; --[s] = 1200B after the DFC, 3412B after the RETN
DoDFC[ 40001002B, 40B]; --[s] = 1400B after the DFC, 3411B after the RETN
DoDFC[ 100020004B, 100B]; --[s] = 1600B after the DFC, 3410B after the RETN
DoDFC[ 200040010B, 177B]; --[s] = 2000B after the DFC, 3407B after the RETN
DoDFC[ 400100020B, 3B]; --[s] = 2200B after the DFC, 3406B after the RETN
DoDFC[ 1000000000B, 5B]; --[s] = 2400B after the DFC, 3405B after the RETN
DoDFC[ 2000000000B, 6B]; --[s] = 2600B after the DFC, 3404B after the RETN
DoDFC[ 4000000000B, 7B]; --[s] = 3000B after the DFC, 3403B after the RETN
DoDFC[10000000000B, 11B]; --[s] = 3200B after the DFC, 3402B after the RETN
DoDFC[20000200040B, 0B]; --[s] = 3400B after the DFC, 3401B after the RETN
drRETN[];
SetOutputPC[endDFCRETTestPC];
SetLabel[endDFCRETTest];
};
GenLFCTest:
PROC [] ~ {
Produce a procedure which counts [S] before and after an LFC and exits with a RETN, and which modifies the PC to point at the procedure called by the LFC. Page creation zeroes unused bytes, so a trap will happen if a wild jump or non-jump occurs.
DoLFC:
PROC [destDisp:
CARDINAL] ~ {
oldPC: LONG CARDINAL;
drADDB[200B];
oldPC ← GetOutputPC[area];
drLFC[destDisp];
drADDB[1];
drRETN[];
SetOutputPC[oldPC + destDisp + (IF destDisp >= 100000B THEN -200000B ELSE 0)];
};
oldPC: LONG CARDINAL;
endLFCTestPC: LONG CARDINAL = 7000B;
okLFC: Label = GenLabel[];
endLFCTest: Label = GenLabel[];
SetLabel[enterLFCTest];
Exercise every bit position of the PC displacement.
drLIB[0]; --Counter used to verify that the calls and returns have occurred.
oldPC ← GetOutputPC[area];
drLFC[40000B];
drLIQB[CardToWord[2613B]];
drRJEB[popSrc, belowSrcPop, UseLabel8B[okLFC]]; Pause[]; SetLabel[okLFC];
drJQB[UseLabel32[endLFCTest]];
SetOutputPC[oldPC + 40000B];
DoLFC[ 20001B]; --[s] = 200B after the LFC, 2613B after the RETN
DoLFC[ 10002B]; --[s] = 400B after the LFC, 2612B after the RETN
DoLFC[ 4004B]; --[s] = 600B after the LFC, 2611B after the RETN
DoLFC[ 2010B]; --[s] = 1000B after the LFC, 2610B after the RETN
DoLFC[ 1000B]; --[s] = 1200B after the LFC, 2607B after the RETN
DoLFC[ 400B]; --[s] = 1400B after the LFC, 2606B after the RETN
DoLFC[ 200B]; --[s] = 1600B after the LFC, 2605B after the RETN
DoLFC[ 100B]; --[s] = 2000B after the LFC, 2604B after the RETN
DoLFC[ 40B]; --[s] = 2200B after the LFC, 2603B after the RETN
DoLFC[ 20B]; --[s] = 2400B after the LFC, 2602B after the RETN
DoLFC[100400B]; --[s] = 2600B after the LFC, 2601B after the RETN
drRETN[];
SetOutputPC[endLFCTestPC];
SetLabel[endLFCTest];
};
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. These calls to FillXop and FillTrap initialize the trap locations with JDB[trap procedure].
oldPC ← GetOutputPC[area];
FillXop[0, dummy]; --opcode 0 = Pause[]
FillXop[377B, dummy]; --opcode 377B = Halt[xxx]
FillTrap[ResetTrap, start];
SetOutputPC[oldPC];
WordAlign[area];
Simulator execution begins here on a Reset.
SetLabel[start];
Initialize L to 1 and S to 0; initialize aux8 to 0 meaning no traps expected; initialize const4 to 6 for trap routines.
--drLFC[UseLabel16[initL]];
--drASL[255];
--drROR[aux8, const0, const0];
--drLIB[6];
--drROR[const4, popSrc, topSrc];
GenDFCRETTest[];
GenLFCTest[];
Halt[177777B]; --Terminate here at the end of the program
END.