GenTraps.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Edward Fiala March 5, 1986 10:49:41 am PST
This diagnostic tests the following machine functions (** means not tested; a few more tests are in GenTraps2):
1) LIP[ifuStatus] and SIP[ifuStatus].
2) KFC instruction.
3) RETK instruction (tested but needs thorough alpha test as per RET).
4) Registers legal and illegal in User mode.
5) Instructions legal and illegal in User mode.
6) Write addresses legal and illegal in User mode.
7) Verify that IFU stack overflow occurs when traps are enabled on DFC, SFC, SFCI, LFC, Xop1, Xop2, Xop3, Xop5, or KFC; on RBC, QBC, or BC that get bounds-check trap; on ADD that overflows; on LADD that gets NaN trap; on DUP that gets EU stack overflow; on user mode RADD that gets mode fault trap; on user mode WB that gets address check trap; on RB[0] that gets an EU page fault; or on an ifu page fault (ifu page fault tested in GenTraps2).
8) Verify that IFU stack overflow does not occur with 11 call stack entries on Jn, JB, JDB, JQB, JS, or RET; on RBC, QBC, or BC that do not trap.
9) Verify that EU stack overflow trap occurs when traps are enabled and an instruction would put S in [SLimit .. SLimit + 16) for several opcodes that push the stack and for AS[n], ASL[n], and RET[n] (tested for only one value of SLimit).
10) **Verify that EU stack overflow trap occurs when traps are enabled and an instruction would put S in [SLimit .. SLimit + 16) for several opcodes that pop the stack (Lizard won't allow this test).
11) Verify that an EU stack overflow trap does not occur when ASL[n] makes S equal to SLimit - 1 or SLimit + 16 and does occur when ASL[n] makes S equal to SLimit or SLimit + 15 for SLimit = 1, 2, 4, 8, 16, 32, 64, and 111. **Lizard gives "out of envelope" for ASL[32], so can't run the tests for 16, 32, 64, or 111.
12) Verify that EU stack overflow is lower priority than KFC, address check, bounds check, NaN, overflow, EU page fault, mode fault, and **ifu page fault traps.
13) Verify that EU stack overflow occurs with greater priority than Reschedule following a SIP which reenables interrupts (tested in GenTraps2).
14) **Verify that EU stack overflow occurs with greater priority than an ALU trap caused on the instruction following a SIP which reenables interrupts.
15) Verify that IFU page fault occurs in sequence when jumping, calling, returning, conditionally jumping (correctly or incorrectly predicted), or falling through into an undeclared page.
16) Verify that IFU page fault does not occur when the untaken path of a conditional jump or conditional trap lies in an undeclared page.
17) Verify that EU page fault occurs in sequence for a storage read, a storage write, CST, and SFCI; that machine state which would have been affected by the faulting instruction is not modified, and that euMAR contains the fault address. **EU page fault by IOS read and IOS write isn't tested.
18) Verify that mode fault prevails over bounds check, overflow, NaN, address check, and EU page fault traps.
19) Address check prevails over EU page fault trap.
20) A reschedule trap occurs when SIP[ifuStatus] turns it on if traps are enabled; a reschedule trap does not occur if traps are disabled; if reschedule was on, it does not occur if traps are enabled and reschedule turned off concurrently.

20) **EU write protect fault occurs in sequence for a storage write and the CST instruction, that machine state which would have been affected by the faulting instruction is not modified, and that euMAR contains the fault address. (Lizard has no way to simulate write protect faults.)
21) **Occurrence of Reschedule trap when Reschedule is issued by the CauseReschedule IO instruction isn't tested because it is not simulated.

**Note to myself: RETK executed with traps enabled which causes EU stack overflow to become true is outside the envelope, but RET which causes EU stack overflow to become true traps.
When simulated correctly it terminates with HALT[177777B] at PC 4016556B, cycle 5506, Inst 1881.
DIRECTORY
Basics USING [DoubleShiftLeft],
DragOpsCross USING [Word, ProcessorRegister, XopBase, TrapBase, TrapWidthBytes, bytesPerWord, TrapIndex, Inst, KernalLimit],
--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, IntToWord, CardToByte],
--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
GenTraps: CEDAR PROGRAM
IMPORTS Basics, DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport
= BEGIN OPEN DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport;
Word: TYPE = DragOpsCross.Word;
ProcessorRegister: TYPE = DragOpsCross.ProcessorRegister;
ifuSLimit = 7-bit stack limit register. Any opcode which causes the stack pointer to enter the region [SLimit..SLimit+16) will be trapped to the EU stack overflow location.
ifuSLimit: CARDINAL = LOOPHOLE[ProcessorRegister.ifuSLimit, CARDINAL];
IFUStackSize = 15. LIP[ifuEldestPC] removes and SIP[ifuEldestPC] adds to the call stack.
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];
euMAR: CARDINAL = LOOPHOLE[ProcessorRegister.euMAR, CARDINAL];
KernelLimit: LONG CARDINAL = DragOpsCross.KernalLimit;
In this diagnostic, the auxiliary registers are called aux0 .. aux15; the locals reg0 .. reg15; and the constants const0 .. const11. Global register usage is as follows:
aux8 contains a code indicating the trap expected (0 if none).
const4 contains the constant 6 for trap routines.
aux0: AuxRegSpec = [aux[0]];
aux1: AuxRegSpec = [aux[1]];
aux2: AuxRegSpec = [aux[2]];
aux3: AuxRegSpec = [aux[3]];
aux4: AuxRegSpec = [aux[4]];
aux5: AuxRegSpec = [aux[5]];
aux6: AuxRegSpec = [aux[6]];
aux14: AuxRegSpec = [aux[14]];
aux15: AuxRegSpec = [aux[15]];
const5: ConstSpec = [const[5]];
const6: ConstSpec = [const[6]];
const7: ConstSpec = [const[7]];
const8: ConstSpec = [const[8]];
const9: ConstSpec = [const[9]];
const10: ConstSpec = [const[10]];
const11: ConstSpec = [const[11]];
All: PROC = {
area: Area = GetCurrentArea[];
oldPC: LONG CARDINAL;
start: Label = GenLabel[];
dummy: Label = GenLabel[];
initL: Label = GenLabel[];
These labels are for trap procedures.
IFUStackOverflow: Label = GenLabel[];
AddressCheck: Label = GenLabel[];
Overflow: Label = GenLabel[];
BoundsCheck: Label = GenLabel[];
LispNaN: Label = GenLabel[];
UserModeViolation: Label = GenLabel[];
EUPageFlt: Label = GenLabel[];
EUPageFaultBad: Label = GenLabel[];
EUWPFlt: Label = GenLabel[];
EUWPFaultBad: Label = GenLabel[];
IFUPageFault: Label = GenLabel[];
IFUPageFaultBad: Label = GenLabel[];
IFUPageFaultPC: LONG CARDINAL = 300000000B;
EUPageFaultAddress: LONG CARDINAL = IFUPageFaultPC/4;
EUStackOverflow: Label = GenLabel[];
EUStkOvfBad: Label = GenLabel[];
Reschedule: Label = GenLabel[];
RescheduleBad: Label = GenLabel[];
KFCTrap: Label = GenLabel[];
KFCBad: Label = GenLabel[];
Xop1Trap: Label = GenLabel[];
Xop1Bad: Label = GenLabel[];
Xop2Trap: Label = GenLabel[];
Xop2Bug: Label = GenLabel[];
Xop3Trap: Label = GenLabel[];
Xop3Bug: Label = GenLabel[];
Xop5Trap: Label = GenLabel[];
Xop5Bug: Label = GenLabel[];
enterIFUStatusTest: Label = GenLabel[];
enterIFUStackOverflowTest: Label = GenLabel[];
enterSLimitTest: Label = GenLabel[];
enterRescheduleTest: Label = GenLabel[];
enterIFUPageFaultTest: Label = GenLabel[];
enterEUPageFaultTest: Label = GenLabel[];
enterModeFaultPriorityTest: Label = GenLabel[];
enterAddressCheckPriorityTest: Label = GenLabel[];
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, the IFU stack allows 11 normal calls but converts the 12th call into an IFU stack overflow trap; when traps are disabled, all 15 levels of the IFU stack are usable. Note, however, that when a trap or KFC is the 12th call, it will complete and disable traps without causing an IFU stack overflow trap. There is no IFU stack underflow trap; the first location in the IFU stack must be made to contain a return link to an appropriate trap procedure (or use the trick of causing a page fault).
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]];
};
16 bytes between consecutive trap instructions is insufficient for StandardTrap, so the trap instruction must be filled separately with FillTrap[TrapName, dest]. aux8 has previously been loaded with a code for the trap presently expected (or 0 if none), and an opcode which is supposed to trap is followed by enough Pause[] opcodes to fill out 6 bytes (i.e., enough for a 5-byte trapping opcode and a 1-byte Pause[] after it); then if no trap occurs, the first Pause[] after the opcode will stop simulation; or if the wrong trap occurs, the mismatch on aux8 will cause Pause[] to occur. Otherwise, the trap procedure will return to the 6th byte after the location that trapped.
StandardTrap: PROC [dest: Label, code: CARDINAL] = {
TrapUnexpected: Label = GenLabel[];
SetLabel[dest];
drALS[0]; --ALS[1 - nargs], where nargs includes 1 for IFUstatus
drLIB[code];
drRJNEB[popSrc, aux8, UseLabel8B[TrapUnexpected]];
Advance return PC by 6
GetYoungestPC[]; drRVADD[topDst, const4, topSrc]; SetYoungestPC[];
drRETK[377B]; --RETK[nResults - 1]
SetLabel[TrapUnexpected]; Pause[];
};
Write 0 into storage at the address addr.
WriteAtAddress: PROC [addr: LONG CARDINAL] ~ {
Make the location addr known to Lizard.
oldPC: LONG CARDINAL = GetOutputPC[area];
bytePC: LONG CARDINAL ← Basics.DoubleShiftLeft[[lc[addr]], 2].lc;
SetOutputPC[bytePC]; --pc is a byte address
OutputWord[area, IntToWord[-1], FALSE];
SetOutputPC[oldPC];
drLC0[]; drLIQB[CardToWord[addr]]; drWB[0];
};
Write 0 into storage at the address addr which should cause an Address Check trap.
WriteTrapAtAddress: PROC [addr: LONG CARDINAL] ~ {
WriteAtAddress[addr];
Pause[]; Pause[]; Pause[]; Pause[];
};
The status register has 3 two bit fields. When written, the MSB of each field controls whether the LSB of the field is to be preserved (1) or changed(0). When read, the preserve bit will always be false for userModeKeep and trapsEnabledKeep, so that writing the word back restores the state, and always true for rescheduleKeep.
pad0  (0: 0..15): [0..65535] ← 0,
pad1  (0:16..25): [0..1023] ← 0,
userModeKeep (0:26..26): BOOL ← FALSE,
userMode  (0:27..27): BOOL ← FALSE,
trapsEnabledKeep (0:28..28): BOOL ← FALSE,
trapsEnabled (0:29..29): BOOL ← FALSE,
rescheduleKeep (0:30..30): BOOL ← FALSE,
reschedule  (0:31..31): BOOL ← FALSE
User mode can be enabled either by using SIP[IFUStatus] or RETK to change IFUStatus. In user mode, the following actions are illegal:
1) Any write of a constant or aux0 to aux7 causes a mode fault trap.
2) Any memory write to an address < 100000000B (= KernelLimit) causes an address check trap.
3) All SIPs, RETK, and LIP[IFUEldestPC] (an active operation) cause a mode fault trap.
4) IOS, IOL, and ION pass a device number in Beta for which the low-order bit is 0 (PRead) or 1 (PWrite) and for which the next two low-order bits serve both as a device number and for user mode checking purposes as follows:
 Beta[4B] = 1 means "kernel mode required"; the IO operation will get
  a ModeFault trap if it is executed in user mode.
 Beta[2B] = 1 means "address check"; the instruction will cause an
  AddressCheck trap on a Kernel address.
Once in user mode, kernel mode can be reentered only by executing a KFC or trapping.
GenIFUStatus: PROC [] ~ {
Bad0: Label = GenLabel[];
userOK0: Label = GenLabel[];
UCall1: Label = GenLabel[];
UCall2: Label = GenLabel[];
UJump1: Label = GenLabel[];
JQBNop0: Label = GenLabel[];
SetLabel[enterIFUStatusTest];
Initialize aux0 here before entering user mode because it cannot be written in user mode and must point at a valid memory address when the LGF opcode is tested in user mode.
drLIQB[CardToWord[KernelLimit]]; drROR[aux0, topSrc, popSrc];
Enter user mode with SIP[IFUStatus] and use LIP[IFUStatus] to check result.
drLIB[20B + 10B + 2B]; --User mode + trapsEnabledKeep + rescheduleKeep
drSIP[ifuStatus];
drLIP[ifuStatus];
Test ifuStatus read back against user mode + rescheduleKeep.
drJEBBJ[20B+2B, UseLabel8B[userOK0]]; SetLabel[Bad0]; Pause[]; SetLabel[userOK0];
Reference all registers that can legally be read and written in user mode.
drROR[aux9, aux0, aux1];
drROR[aux9, aux2, aux3];
drROR[aux10, aux4, aux5];
drROR[aux11, aux6, aux7];
drROR[aux12, aux8, aux9];
drROR[aux13, aux10, aux11];
drROR[aux14, aux12, aux13];
drROR[aux15, aux14, aux14];
drROR[aux15, aux15, aux15];
drROR[pushDst, const0, const1]; --1st push
drROR[topDst, const2, const3];
drROR[pushDst, const4, const5]; --2nd push
drROR[belowDst, const6, const7];
drROR[topDst, const8, const9];
drROR[topDst, const10, const11];
drLIP[0]; --3rd push
drLIP[127]; --4th push
drLIP[159]; --5th push
The call stack must be at least 1 deep for the ifu LIP operations to yield defined values.
drLFC[3];
drLIP[ifuYoungestL]; --6th push
drLIP[ifuYoungestPC]; --7th push
drLIP[ifuEldestL]; --8th push
drLIP[ifuSLimit]; --9th push
drLIP[ifuStatus]; --10th push
drASL[377B]; --0 pushes on the EU stack, 1 call on the IFU stack
Now do memory writes at addresses which are legal (>= 100000000B) in user mode.
WriteAtAddress[ KernelLimit];
WriteAtAddress[ 200000000B];
WriteAtAddress[ 400000000B];
WriteAtAddress[ 1000000000B];
WriteAtAddress[ 2000000000B];
WriteAtAddress[ 4000000000B];
Lizard can't handle the next two.
--WriteAtAddress[10000000000B];
--WriteAtAddress[20000000000B];
IOS[2B] does [S] ← PRead[0 + [S], BetaZ].
drLIQB[CardToWord[KernelLimit]]; drIOS[2B];
drLIQB[CardToWord[ 200000000B]]; drIOS[2B];
drLIQB[CardToWord[ 400000000B]]; drIOS[2B];
drLIQB[CardToWord[ 1000000000B]]; drIOS[2B];
drLIQB[CardToWord[ 2000000000B]]; drIOS[2B];
drLIQB[CardToWord[ 4000000000B]]; drIOS[2B];
Lizard can't handle the next two.
--drLIQB[CardToWord[10000000000B]]; drIOS[2B];
--drLIQB[CardToWord[20000000000B]]; drIOS[2B];
drAS[372B]; --0 pushes again
Now execute all instructions legal in user mode (LRn, SRn, LRIn, SRIn, and LCn each treated as a single instruction).
drLC0[]; drDUP[]; drADD[]; --1st push = reg0
drLC1[]; --2 pushes
drLIDB[0]; drLIQB[CardToWord[0]]; --4 pushes
drLRn[reg11]; --5 pushes
drQADD[topAtop, const0];
drRADD[belowDst, topSrc, belowSrcPop]; --4 pushes
drSUB[]; --3 pushes
drQSUB[topAtop, const0];
drRSUB[belowDst, popSrc, belowSrc]; --2 pushes
drQLADD[topAtop, const0];
drRLADD[belowDst, popSrc, const0]; --1 push
drQLSUB[topAtop, const0]; --1 push
drRLSUB[pushDst, popSrc, const0];
drRUADD[belowDst, const0, popSrc]; --0 pushes
drRUSUB[pushDst, const0, const0]; --1 push
drRVADD[pushDst, const0, topSrc]; --2 pushes
drRVSUB[topDst, topSrc, const0];
drAND[]; --1 push
drQAND[pushAtop, const0]; --2 pushes
drRAND[topDst, topSrc, topSrc];
drOR[]; --1 push
drQOR[pushAtop, const0]; --2 pushes
drADDB[0];
drSUBB[0];
drADDDB[0];
drSUBDB[0];
drRXOR[topDst, topSrc, topSrc];
drFSDB[444]; --1 push
drRFU[pushDst, topSrc, topSrc]; --2 pushes
drSHD[333]; --1 push
drSHL[111]; --1 push
drSHR[222]; --1 push
drJ1[];
drJ2[]; Pause[];
drJ3[]; Pause[]; Pause[];
drJ5[]; Pause[]; Pause[]; Pause[]; Pause[];
drJDB[3];
drJQB[UseLabel32[JQBNop0]]; SetLabel[JQBNop0];
drEXDIS[]; --0 pushes
drLIDB[0]; --1 push
drASL[377B]; --0 pushes, 0 locals (S ← 0B, L = 1B)
drAL[0];
drLIQB[CardToWord[KernelLimit]]; --legal address already used, 1 push
FOR I: CARDINAL IN [0..17) DO drDUP[]; ENDLOOP;
drSRn[reg0]; --Now have L = 1B, S = 21B (= 16 locals, 1 push)
drLRIn[reg0, 0]; drSRIn[reg0, 0];
drDUP[]; drJEBB[0, 3];
drDUP[]; drJNEBB[0, 3];
drDUP[]; drJNEBBJ[0, 3];
drRJEB[topSrc, topSrc, 3];
drRJEBJ[topSrc, topSrc, 3];
drRJGB[topSrc, topSrc, 3];
drRJGBJ[topSrc, topSrc, 3];
drRJLB[topSrc, topSrc, 3];
drRJLBJ[topSrc, topSrc, 3];
drRJGEB[topSrc, topSrc, 3];
drRJGEBJ[topSrc, topSrc, 3];
drRJLEB[topSrc, topSrc, 3];
drRJLEBJ[topSrc, topSrc, 3];
drRJNEB[topSrc, topSrc, 3];
drRJNEBJ[topSrc, topSrc, 3]; --Still have 1 push (L = 1B, S = 21B)
drLIQB[CardToWord[KernelLimit - 1]]; --2 pushes
drRBC[topDst, topSrc, belowSrc]; --won't trap
drQBC[topAtop, belowSrc]; --won't trap
drDIS[]; drLIQB[CardToWord[KernelLimit + 1]];
drBC[]; --1 push
drDUP[]; --2 pushes
drLC0[]; drRX[]; drDIS[]; --1 push
drQRX[pushAtop, const0]; drDIS[];
drLGF[0]; drDIS[]; --(aux0 was initialized to KernelLimit above)
drRAI[reg1, aux0, 0];
drDUP[]; drRB[0]; drDIS[];
drRRI[reg1, reg13, 0]; --(reg0 .. reg15 were set to KernelLimit above)
drRRX[reg1, reg13, const0];
drRSB[0]; drDIS[];
drWAI[reg1, aux0, 0];
drWRI[reg1, reg13, 0];
drLC0[]; drWSB[0]; --Still have 1 push
drLIB[1]; drLC0[]; drCST[0]; drAS[374B]; --0 pushes
drLIB[1]; drJS[];
drDFC[UseLabel32[UCall1]];
drLFC[UseLabel16[UCall2]];
drLIB[13]; drROR[aux8, topSrc, popSrc]; --Indicate XOP1 trap expected
OutputByte[area, CardToByte[1B]];
drLIB[14]; drROR[aux8, topSrc, popSrc]; --Indicate XOP2 trap expected
OutputAlphaBeta[area, (234B * 400B) + 123B];
drLIB[15]; drROR[aux8, topSrc, popSrc]; --Indicate XOP3 trap expected
OutputByte[area, CardToByte[364B]]; OutputAlphaBeta[area, 234B];
drLIB[16]; drROR[aux8, topSrc, popSrc]; --Indicate XOP5 trap expected
OutputByte[area, CardToByte[40B]]; OutputWord[area, CardToWord[345B]];
drLIB[12]; drROR[aux8, topSrc, popSrc]; --Indicate KFC trap expected
drKFC[];
Return from KFC trap in Kernel mode with traps disabled.
drROR[aux8, const0, const0]; --Indicate no traps expected
drLIB[20B + 4B + 2B]; --User mode + trapsEnabled + rescheduleKeep
drSIP[ifuStatus];
drLIQB[CardToWord[KernelLimit]]; --1 push
drLIQB[UseLabel32[UCall1]]; --2 pushes
drPSB[0]; --1 push
drAS[1]; --2 pushes
drSFC[]; --1 push
drSFCI[];
drJB[UseLabel8A[UJump1]];
SetLabel[UCall1];
drRETN[];
SetLabel[UCall2];
drALS[377B]; --L ← S-1
drRET[1B]; --S ← L+1
SetLabel[UJump1];
drASL[17B]; --16 local registers, 0 EU pushes, 1 call on the IFU stack
Reference all registers illegal in user mode.
drLIB[8]; --1 push
drROR[aux8, topSrc, topSrc]; --Indicate mode fault trap expected (aux8 = 8)
aux0 to aux7 and const0 to const11 are read-only in user mode.
drROR[aux0, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[aux1, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[aux2, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[aux3, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[aux4, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[aux5, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[aux6, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[aux7, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[const0, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[const1, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[const2, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[const3, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[const4, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[const5, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[const6, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[const7, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[const8, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[const9, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[const10, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
drROR[const11, popSrc, topSrc]; Pause[]; Pause[]; Pause[];
Execute all instructions illegal in user mode.
Representative SIP instructions.
drSIP[0]; Pause[]; Pause[]; Pause[]; Pause[];
drSIP[242]; Pause[]; Pause[]; Pause[]; Pause[];
drSIP[246]; Pause[]; Pause[]; Pause[]; Pause[];
LIP[IFUEldestPC] is illegal in user mode because it modifies the call stack.
drLIP[ifuEldestPC]; Pause[]; Pause[]; Pause[]; Pause[];
RETK is illegal in user mode
drLIB[20B + 10B + 2]; drLFC[4];
Pause[]; --RETK returned in user mode
drRETK[377B]; Pause[]; Pause[]; Pause[]; Pause[];
drDIS[]; --16 locals, 1 push, 2 calls on the IFU stack
IOL, ION, and IOS take an AlphaBeta argument for which the low bits are specially interpreted as well as being part of the device identifier:
1xx => Kernel mode required
01x => address check
x0 => read
x1 => write
Determine whether or not these operations get a ModeFault trap in user mode.
drIOL[4B]; Pause[]; Pause[]; Pause[]; --[S+1] ← PRead[AlphaZ, BetaZ]; S ← S+1.
drION[4B]; Pause[]; Pause[]; Pause[]; --[S+1] ← PRead[AlphaZ, BetaZ].
drIOS[4B]; Pause[]; Pause[]; Pause[]; --[S] ← PRead[AlphaZ + [S], BetaZ].
These 3 do an Address Check and write as well as checking for kernel mode; the ModeFault trap should prevail over the AddressCheck trap.
drIOL[177777B]; Pause[]; Pause[]; Pause[]; --PWrite[AlphaZ, BetaZ, [S]]; S ← S-1.
drION[177777B]; Pause[]; Pause[]; Pause[]; --PWrite[AlphaZ, BetaZ, [S]].
drIOS[177777B]; Pause[]; Pause[]; Pause[]; --PWrite[AlphaZ + [S], BetaZ, [S-1]]; S ← S-2.
drLIB[4];
drROR[aux8, popSrc, topSrc]; --Indicate Address Check trap expected
IOL and ION have an 8-bit Kernel address which always causes address check in user mode, but IOS may have a user address.
drIOL[2B]; Pause[]; Pause[]; Pause[]; --[S+1] ← PRead[AlphaZ, BetaZ]; S ← S+1.
drION[2B]; Pause[]; Pause[]; Pause[]; --[S+1] ← PRead[AlphaZ, BetaZ].
drLC0[]; drIOS[2B]; Pause[]; Pause[]; Pause[]; --[S] ← PRead[AlphaZ + [S], BetaZ].
drLIB[377B]; drIOS[2B]; Pause[]; Pause[]; Pause[];
drLIDB[177400B]; drIOS[2B]; Pause[]; Pause[]; Pause[];
drLIQB[CardToWord[400000B]]; drIOS[2B]; Pause[]; Pause[]; Pause[];
drLIQB[CardToWord[7000000B]]; drIOS[2B]; Pause[]; Pause[]; Pause[];
drLIQB[CardToWord[70000000B]]; drIOS[2B]; Pause[]; Pause[]; Pause[];
drLIQB[CardToWord[37777777B]]; drIOS[2B]; Pause[]; Pause[]; Pause[];
drASL[17B]; --16 locals, 0 pushes, 2 calls on IFU stack
Now try write references to addresses less than KernelLimit = 100000000B, which should cause an Address Check trap.
WriteTrapAtAddress[ 377B];
WriteTrapAtAddress[ 400B];
WriteTrapAtAddress[ 7000B];
WriteTrapAtAddress[ 70000B];
WriteTrapAtAddress[ 700000B];
WriteTrapAtAddress[ 3000000B];
4000000B will conflict with program
WriteTrapAtAddress[ 5000000B];
WriteTrapAtAddress[70000000B];
WriteTrapAtAddress[77777777B];
Remove the 2 calls from the stack
drASL[17B]; --16 locals, 0 pushes on the EU stack, 2 calls on the IFU stack, user mode
drLIB[12]; drROR[aux8, popSrc, topSrc]; --Indicate KFC trap expected
drKFC[];
Return here in Kernel mode with traps disabled.
drROR[aux8, const0, const0]; --Indicate no traps expected
FOR I: CARDINAL IN [0..1] DO GetEldestPC[]; ENDLOOP;
};
Test conditions which should and should not cause IFU stack overflow trap. Begin here in Kernel mode with traps disabled, and 0 IFU call stack entries.
GenIFUStackOverflow: PROC [] ~ {
UCall3: Label = GenLabel[];
JQBNop1: Label = GenLabel[];
exitIFUStackOverflowTest: Label = GenLabel[];
eleventhCall: Label = GenLabel[];
drJB[UseLabel8A[enterIFUStackOverflowTest]];
SetLabel[UCall3];
Pause[]; --DFC, SFC, or SFCI trap was expected but didn't.
SetLabel[enterIFUStackOverflowTest];
drASL[377B]; --0 locals, 0 pushes on the EU stack, 0 calls on the IFU stack
drLIB[40B + 4B + 2B];
drSIP[ifuStatus]; --UserModeKeep + TrapsEnabled + RescheduleKeep
Now in Kernel mode with traps enabled.
drLFC[3]; --1 calls
drLFC[3]; --2 calls
drLFC[3]; --3 calls
drLFC[3]; --4 calls
drLFC[3]; --5 calls
drLFC[3]; --6 calls
drLFC[3]; --7 calls
drLFC[3]; --8 calls
drLFC[3]; --9 calls
drLFC[3]; --10 calls
drLFC[UseLabel16[eleventhCall]]; --11 calls
Return here reducing call stack depth by 1 so KFC can get out of user mode.
drJDB[UseLabel16[exitIFUStackOverflowTest]]; --10 calls
SetLabel[eleventhCall];
The following opcodes should not cause IFU stack overflow trap
drLIB[40B + 4B + 2B];
drSIP[ifuStatus]; --UserModeKeep + TrapsEnabled + RescheduleKeep
Now in Kernel mode with traps enabled and 11 calls on the stack; the following opcodes shouldn't cause IFU stack overflow trap.
drJ1[];
drJ2[]; Pause[];
drJ3[]; Pause[]; Pause[];
drJ5[]; Pause[]; Pause[]; Pause[]; Pause[];
drJB[2];
drJDB[3];
drJQB[UseLabel32[JQBNop1]]; SetLabel[JQBNop1];
drLIB[1]; drJS[];
RBC, QBC, and BC should not cause IFU stack overflow when they don't trap.
drLIB[2]; drLIB[1]; drQBC[pushAtop, belowSrc]; drDIS[];
drRBC[pushDst, reg1, reg0]; drDIS[];
drEXDIS[]; drLIB[2]; drBC[];
drLIB[1]; drROR[aux8, popSrc, topSrc]; --Indicate IFU stack overflow expected
Each of the following instructions does a 12th call which should go through the IFU stack overflow trap and skip the Pause[]'s after the call.
drLFC[3]; Pause[]; Pause[]; Pause[];
drDFC[UseLabel32[UCall3]]; Pause[];
drLIQB[UseLabel32[UCall3]]; drSFC[]; Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
1, 2, 3, and 5-byte Xops should cause IFU stack overflow trap
OutputByte[area, CardToByte[1B]];
Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
OutputAlphaBeta[area, (234B * 400B) + 123B];
Pause[]; Pause[]; Pause[]; Pause[];
OutputByte[area, CardToByte[364B]]; OutputAlphaBeta[area, 234B];
Pause[]; Pause[]; Pause[];
OutputByte[area, CardToByte[40B]]; OutputWord[area, CardToWord[345B]];
Pause[];
drKFC[]; Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
RBC, QBC, or BC should cause IFU stack overflow when they trap.
drLIB[1]; drLIB[2];
drQBC[pushAtop, belowSrc]; Pause[]; Pause[]; Pause[]; Pause[];
drRBC[pushDst, topSrc, belowSrc]; Pause[]; Pause[]; Pause[];
drEXDIS[]; drLIB[1];
drBC[]; Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
NaN trap causing stack overflow should get IFU stack overflow trap.
drLIQB[CardToWord[10000000000B]]; drDUP[];
drLADD[]; Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
ADD that Overflows should get IFU stack overflow trap.
drADD[]; Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
EU page fault.
drLIQB[CardToWord[EUPageFaultAddress]];
drRB[0]; Pause[]; Pause[]; Pause[]; Pause[];
Push that gets EU stack overflow
drASL[17B]; --L = 1, S = 20B
drLIB[21B]; drSIP[ifuSLimit];
drDUP[]; Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
drDIS[]; drLIB[160B]; drSIP[ifuSLimit];
User mode RADD that gets mode fault.
drLIB[20B + 4B + 2B]; drSIP[ifuStatus]; --User + TrapEnable + RescheduleKeep
drRADD[const1, const0, const0]; Pause[]; Pause[]; Pause[];
User mode store that gets address check
drLC0[]; drWB[0]; Pause[]; Pause[]; Pause[]; Pause[];
drROR[aux8, const0, const0]; --Indicate no traps expected
drRET[377B]; --returns from 11th call and trims stack
SetLabel[exitIFUStackOverflowTest];
drLIB[12]; drROR[aux8, popSrc, topSrc]; --Indicate KFC trap expected
drKFC[];
Remove the 10 calls from the stack and cleanup
FOR I: CARDINAL IN [0..9] DO GetEldestPC[]; ENDLOOP;
drASL[17B]; --L = 1, S = 20B, traps enabled, Kernel mode, 0 calls on the stack
};
GenSLimit: PROC [] ~ {
S = L = 0 here; SL is the value of SLimit to be tested for ASL[SL-1], ASL[SL + 16], ASL[SL], and ASL[SL + 15]. Note that S is left equal to 0. SLimitTest executes about 15 instructions.
SLimitTest: PROC [SL: CARDINAL] ~ {
drLIB[SL]; drSIP[ifuSLimit];
drROR[aux8, const1, const1];
drASL[SL]; Pause[]; Pause[]; Pause[]; Pause[]; --SLimit
drASL[SL + 15]; Pause[]; Pause[]; Pause[]; Pause[]; --SLimit + 15
drROR[aux8, const0, const0];
drASL[SL + 16]; --SLimit + 16
drASL[SL - 1]; --SLimit - 1
drASL[0]; --SLimit
};
ReschedRet: Label = GenLabel[];
For one value of SLimit, verify that EU stack overflow trap occurs when traps are enabled and an instruction would put S in [SLimit .. SLimit + 16) for several opcodes that push and pop the stack and for AS[n], ASL[n], RET[n], and RETK[n]. Also verify that the trap occurs when S is already in the restricted range when traps are reenabled.
SetLabel[enterSLimitTest];
drASL[7B]; --L = 1, S = 10B, traps enabled, Kernel mode, 0 calls on the stack
drLIB[4B + 2B]; drSIP[ifuStatus]; --TrapsEnabled + RescheduleKeep
drLIB[13B]; drSIP[ifuSLimit];
drLIB[9]; drROR[const1, popSrc, topSrc]; --const1 ← EU stk ovf code
drROR[aux8, const1, const1]; --Indicate EU stack overflow trap expected
drLIQB[CardToWord[KernelLimit]]; drSRn[reg0]; --Memory address for LRIn below
drLC0[]; --S = 11B
drDUP[]; --S = 12B
Create one call stack entry so that RET below has a defined return; perhaps this is not strictly necessary because these instructions trap, but Lizard is picky.
drLFC[4]; Pause[];
Should get EU stack overflow trap on these typical instructions
drDUP[]; Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
drLRn[reg2]; Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
drQADD[pushA0, const0]; Pause[]; Pause[]; Pause[]; Pause[];
drRADD[pushDst, const0, const0]; Pause[]; Pause[]; Pause[];
drLRIn[reg0, 0]; Pause[]; Pause[]; Pause[]; Pause[];
Lizard gave a "VERY suspicious S adjustment" crash for alpha >= 40B in this test, so I changed the code to have fewer locals.
FOR I: CARDINAL IN [1..16] DO
drAS[I]; Pause[]; Pause[]; Pause[]; Pause[];
drASL[11B + I]; Pause[]; Pause[]; Pause[]; Pause[];
drRET[11B + I]; Pause[]; Pause[]; Pause[]; Pause[];
ENDLOOP;
drASL[377B]; --S = 0, L = 1 (won't trap)
drLIB[160B]; drSIP[ifuSLimit]; --S in [160B..177B] will trap
drLIP[ifuEldestPC]; drDIS[]; --clear the call stack
Now check for popping that puts S in the restricted range. **Russ added a check to Lizard which makes it "outside of defined envelope" to back S into EU overflow, so I had to comment out these checks.
--drSRn[reg15]; Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
--drQAND[topAtop, popSrc]; Pause[]; Pause[]; Pause[]; Pause[];
--drRAND[belowDst, topSrc, popSrc]; Pause[]; Pause[]; Pause[];
--drSRIn[reg0, 0]; Pause[]; Pause[]; Pause[]; Pause[];
--drDIS[]; Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
For SLimit = 4B, 10B, 20B, 1B, 40B, 100B, 2B, and 157B verify that an EU stack overflow trap does not occur when ASL[n] makes S equal to SLimit - 1 or SLimit + 16 and does occur when ASL[n] makes S equal to SLimit or SLimit + 15.
drROR[aux8, const0, const0]; --Indicate no trap expected
drAL[377B]; --L ← 0
L = 0, S = 0, 0 call stack entries, SLimit = 160B, no trap expected. Since S is left 0 by SLimitTest, none of the args to SLimitTest may be in [161B..0B].
SLimitTest[4B];
SLimitTest[10B];
**Lizard won't allow the 20B, 40B, 100B, or 157B tests (out of envelope if alpha >= 40B)
--SLimitTest[20B];
SLimitTest[1B];
drASL[377B];
--SLimitTest[40B];
--SLimitTest[100B];
SLimitTest[2B];
--SLimitTest[157B];
Verify that EU stack overflow is lower priority than all other traps. EU stack overflow can happen at the onset of another trap as a result of pushing ifuStatus onto the EU stack.
drLIB[21B]; drSIP[ifuSLimit];
drAL[1B]; --L = 1 again
drASL[15B]; --S = 16B
drLIB[6]; drROR[aux8, topSrc, popSrc]; --Bounds check should prevail
drLIB[1]; drLIB[2]; --S = 20B (1 less than SLimit)
drQBC[pushAtop, belowSrc]; Pause[]; Pause[]; Pause[]; Pause[];
drRBC[pushDst, topSrc, belowSrc]; Pause[]; Pause[]; Pause[];
NaN should prevail over EU stack overflow; this is a particularly rough test because the LADD would have decremented S if it hadn't trapped and because Overflow is happening as well as NaN.
drAS[376B]; drLIB[7]; drROR[aux8, topSrc, popSrc]; --NaN prevails
drLIQB[CardToWord[10000000000B]]; drDUP[];
drLADD[]; Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
drDIS[]; drLIB[5]; drROR[aux8, topSrc, popSrc]; --Overflow prevails
drDUP[];
drADD[]; Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
drDIS[]; drLIB[2]; drROR[aux8, topSrc, popSrc]; --EU page fault prevails
drLIQB[CardToWord[EUPageFaultAddress]];
drRB[0]; Pause[]; Pause[]; Pause[]; Pause[];
drDIS[]; drLIB[2B]; drSIP[ifuStatus]; --RescheduleKeep (= disable traps)
drLIQB[UseLabel32[ReschedRet]]; --Label for reschedule trap return
drLIB[11]; drROR[aux8, topSrc, popSrc]; --Reschedule should prevail
drLIB[4B + 1B]; --S = SLimit now
drSIP[ifuStatus]; --TrapEnable + Reschedule
Reschedule should happen here, and saving ifuStatus at the onset of the trap will make S = SLimit again, but Reschedule should prevail anyway.
Pause[];
Reschedule trap returns here with Reschedule-waiting bit in ifuStatus turned off.
SetLabel[ReschedRet];
drDIS[];
drLIB[20B + 4B + 2B]; drSIP[ifuStatus]; --User + TrapEnable + RescheduleKeep
drLIB[8]; drROR[aux8, topSrc, topSrc]; --Mode fault prevails
drRADD[const1, const0, const0]; Pause[]; Pause[]; Pause[];
drDIS[]; drLIB[4]; drROR[aux8, topSrc, popSrc]; --Address check prevails
drLC0[]; drWB[0]; Pause[]; Pause[]; Pause[]; Pause[];
drDIS[]; drLIB[12]; drROR[aux8, topSrc, topSrc]; --KFC should prevail
drKFC[];
Return here in Kernel mode with traps disabled.
drROR[aux8, const0, const0]; --No trap expected
drLIB[160B]; drSIP[ifuSLimit];
drASL[17B]; --L = 1, S = 20B, traps enabled, Kernel mode, 0 calls on the stack
};
Verify the occurrence of Reschedule trap when Reschedule is requested by this processor.
GenReschedule: PROC [] ~ {
RescheduleOK: Label = GenLabel[];
SetLabel[enterRescheduleTest];
drASL[17B]; --L = 1, S = 20B, 0 calls on the stack
drLIQB[UseLabel32[RescheduleOK]]; --Reschedule trap will send control here
drLIB[11]; drROR[aux8, popSrc, topSrc]; --Reschedule trap expected
When the condition (TrapsEnabled & Reschedule) = TRUE as a result of SIP or RETK, Reschedule should take immediately.
drLIB[40B + 4B + 1B]; --User mode keep + TrapEnable + Reschedule
drSIP[ifuStatus];
Pause[];
Return here after Reschedule has occurred.
SetLabel[RescheduleOK];
drROR[aux8, const0, const0]; --No traps expected
drLIB[40B + 1B]; --User mode keep + Reschedule (= traps disabled)
drSIP[ifuStatus]; --Shouldn't trap
User mode keep + Traps enabled (shouldn't trap); turns off Reschedule.
drLIB[40B + 4B]; drSIP[ifuStatus];
CauseReschedule issues the IO command which sends Reschedule to all processors, but this action isn't simulated by Lizard.
--CauseReschedule[];
No-ops while waiting for Reschedule
--drJ1[]; drJ1[]; drJ1[]; drJ1[]; drJ1[];
--Pause[];
};
Verify that IFU page fault occurs in sequence when jumping, calling, returning, conditionally jumping (correctly or incorrectly predicted), or falling through into an undeclared page.
GenIFUPageFault: PROC [] ~ {
oldPC: LONG CARDINAL;
LFCFaultOK: Label = GenLabel[];
RETNFaultOK: Label = GenLabel[];
CJumpFOK0: Label = GenLabel[];
CJumpFOK1: Label = GenLabel[];
FallThruOK: Label = GenLabel[];
endIFUPFTest: Label = GenLabel[];
nearFaultPagePC0: LONG CARDINAL = 277777600B;
nearFaultPagePC1: LONG CARDINAL = 310007600B;
IFUPageFaultPC1: LONG CARDINAL = 310010000B;
nearFaultPagePC2: LONG CARDINAL = 320007775B; --Must be page boundary - 3
SetLabel[enterIFUPageFaultTest];
drASL[377B]; --L = 1, S = 0
drLIB[4B + 2B]; drSIP[ifuStatus]; --TrapsEnabled + RescheduleKeep
drLIQB[CardToWord[nearFaultPagePC0]]; --location to which page fault trap returns
drLIB[10]; drROR[aux8, popSrc, topSrc]; --IFU page fault expected
drJQB[CardToWord[IFUPageFaultPC]]; --Will cause IFU page fault
oldPC ← GetOutputPC[area];
SetOutputPC[nearFaultPagePC0];
drLIQB[UseLabel32[LFCFaultOK]];
drLFC[IFUPageFaultPC - GetOutputPC[area]]; --IFU page fault next
SetLabel[LFCFaultOK];
drLIQB[CardToWord[IFUPageFaultPC]];
SetYoungestPC[];
drLIQB[UseLabel32[RETNFaultOK]];
drRETN[]; --Will cause IFU page fault
SetLabel[RETNFaultOK];
drLIQB[UseLabel32[CJumpFOK0]];
drRJEB[const0, const0, IFUPageFaultPC - GetOutputPC[area]]; --IFU page fault next
SetLabel[CJumpFOK0];
drLIQB[UseLabel32[CJumpFOK1]];
drRJEBJ[const0, const0, IFUPageFaultPC - GetOutputPC[area]]; --IFU page fault next
SetLabel[CJumpFOK1];
drLIQB[UseLabel32[FallThruOK]];
drJB[IFUPageFaultPC - GetOutputPC[area] - 1];
SetOutputPC[IFUPageFaultPC - 1];
drJ1[]; --Next instruction causes IFU page fault
SetOutputPC[nearFaultPagePC1];
SetLabel[FallThruOK];
Verify that IFU page fault does not occur when the untaken path of a conditional jump or conditional trap lies in an undeclared page.
drROR[aux8, const0, const0]; --Indicate no traps expected
predicted non-jump; jump would fault; doesn't jump; test that no fault occurs.
drRJNEB[const0, const0, IFUPageFaultPC1 - GetOutputPC[area]];
predicted jump; jump would fault; doesn't jump; test that no fault occurs.
drRJNEBJ[const0, const0, IFUPageFaultPC1 - GetOutputPC[area]];
drJB[IFUPageFaultPC1 - GetOutputPC[area] - 3]; SetOutputPC[IFUPageFaultPC1 - 3];
predicted non-jump; fall-through would fault; jumps; test that no fault occurs.
drRJEB[const0, const0, 370B];
SetOutputPC[IFUPageFaultPC1 - 3 - 10B];
drJQB[CardToWord[nearFaultPagePC2]]; SetOutputPC[nearFaultPagePC2];
predicted jump; fall-through would fault; jumps; test that no fault occurs.
drRJEBJ[const0, const0, 370B];
SetOutputPC[nearFaultPagePC2 - 10B];
drJQB[CardToWord[oldPC]];
SetOutputPC[oldPC];
**Should test EU stack overflow coincident with IFU page fault.
};
Verify that EU page fault occurs in sequence and that machine state which would have been affected by the faulting instruction is not modified on storage read, storage write, CST read-write, SFCI read, IOS read, and IOS write; verify that euMAR contains the fault address. No current instructions which are storage writes modify any EU registers; only S is modified, so verify that on a storage write S is not changed; reads modify both S and some destination register.
GenEUPageFault: PROC [] ~ {
OKState: Label = GenLabel[];
BadState: Label = GenLabel[];
SetLabel[enterEUPageFaultTest];
drASL[377B]; --L = 1, S = 0
drLIB[4B + 2B]; drSIP[ifuStatus]; --TrapsEnabled + RescheduleKeep
drLIQB[CardToWord[EUPageFaultAddress]];
drROR[aux9, topSrc, topSrc];
drLIB[2]; drROR[aux8, popSrc, topSrc]; --EU page fault expected
drRB[0]; Pause[]; Pause[]; Pause[]; Pause[];
drRJEBJ[topSrc, aux9, UseLabel8B[OKState]];
SetLabel[BadState]; Pause[];
SetLabel[OKState];
drLIB[123B]; drROR[aux10, popSrc, topSrc];
S ← S - 1 if the popSrc isn't a no-op.
drRRX[aux10, popSrc, const0]; Pause[]; Pause[]; Pause[];
Make sure value in aux10 isn't overwritten during the fault.
drLIB[123B]; drRJNEB[popSrc, aux10, UseLabel8B[BadState]];
Make sure S didn't change during the fault.
drRJNEB[topSrc, aux9, UseLabel8B[BadState]];
drLIDB[123456B];
drWSB[0]; Pause[]; Pause[]; Pause[]; Pause[];
drLIDB[123456B];
drRJNEB[popSrc, belowSrcPop, UseLabel8B[BadState]];
drRJNEB[topSrc, aux9, UseLabel8B[BadState]];
drLIDB[111111B]; --new value
drLIDB[122222B]; --old value
drCST[0]; Pause[]; Pause[]; Pause[]; Pause[];
It is a "don't care" whether or not CST smashes the value in [S+1] on a page fault because that value will be overwritten by the page fault trap procedure?
drLIDB[122222B]; drRJNEB[popSrc, belowSrcPop, UseLabel8B[BadState]];
drDIS[];
drSFCI[]; Pause[]; Pause[]; Pause[]; Pause[]; Pause[];
drRJNEB[topSrc, aux9, UseLabel8B[BadState]];
Lizard doesn't trap the IOS opcode for page faults.
[S] ← PRead[AlphaZ + [S], BetaZ] with address check.
--drIOS[2B];
-- Pause[]; Pause[]; Pause[];
--drRJNEB[popSrc, aux9, UseLabel8B[BadState]];
--drLIB[123B];
--drROR[pushDst, aux9, const0];
PWrite[AlphaZ + [S], BetaZ with address check, [S-1]]; S ← S-2.
--drIOS[3B];
--drRJNEB[popSrc, aux9, UseLabel8B[BadState]];
--drJNEBB[123B, UseLabel8B[BadState]];
};
Verify that ModeFault prevails over address check, bounds check, overflow, NaN, and EU page fault.
GenModeFaultPriority: PROC [] ~ {
SetLabel[enterModeFaultPriorityTest];
drASL[377B]; --L = 1, S = 0
drLIB[8]; drROR[aux8, topSrc, popSrc]; --code for ModeFault trap
drLIB[20B + 4B + 2B]; drSIP[ifuStatus]; --User mode + TrapsEnabled + RescheduleKeep
drLIQB[CardToWord[10000000000B]]; drDUP[];
Modefault prevails over NaN.
drRLADD[const2, belowSrc, topSrc]; Pause[]; Pause[]; Pause[];
Modefault prevails over overflow.
drRADD[const2, belowSrc, topSrc]; Pause[]; Pause[]; Pause[];
Modefault prevails over bounds check.
drRBC[const2, belowSrc, popSrc]; Pause[]; Pause[]; Pause[];
drDIS[];
drLC0[]; drLIQB[CardToWord[EUPageFaultAddress]];
Modefault prevails over EU page fault.
drRRX[const2, popSrc, belowSrcPop]; Pause[]; Pause[]; Pause[];
Modefault prevails over address check. These can only happen concurrently when an IO instruction is executed which specifies "kernel mode required" (4B) + "address check" (2B) + "write" (1B).
drLC0[]; drIOS[7B]; Pause[]; Pause[]; Pause[];
drLIB[12]; drROR[aux8, topSrc, popSrc]; --Indicate KFC trap expected
drKFC[];
Return here in Kernel mode
drROR[aux8, const0, const0]; --No traps expected
};
Verify that address check prevails over EU page fault.
GenAddressCheckPriority: PROC [] ~ {
SetLabel[enterAddressCheckPriorityTest];
drASL[377B]; --L = 1, S = 0
drLIB[20B + 4B + 2B]; drSIP[ifuStatus]; --UserMode + TrapsEnabled + RescheduleKeep
drLIB[4]; drROR[aux8, topSrc, popSrc]; --Indicate address check expected
drLC0[]; drLIQB[CardToWord[EUPageFaultAddress]];
drWB[0]; Pause[]; Pause[]; Pause[]; Pause[];
drLIB[12]; drROR[aux8, topSrc, popSrc]; --Indicate KFC trap expected
drKFC[];
drROR[aux8, const0, const0]; --Indicate no traps expected
};
SetLabel[dummy];
Pause[]; Pause[]; Pause[]; Pause[]; Pause[]; Halt[123B];
StandardTrap[IFUStackOverflow, 1]; --priority 2
EU page fault trap has code 2
EU write protect fault trap has code 3
StandardTrap[AddressCheck, 4];
StandardTrap[Overflow, 5];
StandardTrap[BoundsCheck, 6];
StandardTrap[LispNaN, 7];
StandardTrap[UserModeViolation, 8];
EU stack overflow has code 9
IFU page fault trap has code 10
Reschedule trap has code 11
KFC trap has code 12
1-byte Xop (opcode = 1B) has code 13
2-byte Xop (opcode 234B, alpha = 123B) has code 14
3-byte Xop (opcode 364B, alphabeta = 234B) has code 15
5-byte Xop (opcode 40B, alphabetagammadelta = 345B) has code 16
SetLabel[EUPageFlt];
drALS[0]; --1 - nargs; nargs = 1 for ifuStatus
drLIB[2]; drRJNEB[popSrc, aux8, UseLabel8B[EUPageFaultBad]];
All of the EU page fault tests use the address EUPageFaultAddress.
drLIQB[CardToWord[EUPageFaultAddress]];
drLIP[euMAR];
drRJNEB[popSrc, belowSrcPop, UseLabel8B[EUPageFaultBad]];
GetYoungestPC[]; drRVADD[topDst, topSrc, const4]; SetYoungestPC[];
drRETK[377B]; --nResults -1; nResults = 0
SetLabel[EUPageFaultBad]; Pause[];
SetLabel[EUWPFlt];
drALS[0]; --1 - nargs; nargs = 1 for ifuStatus
drLIB[3]; drRJNEB[popSrc, aux8, UseLabel8B[EUWPFaultBad]];
All of the EU page fault tests use the address EUPageFaultAddress.
drLIQB[CardToWord[EUPageFaultAddress]];
drLIP[euMAR];
drRJNEB[popSrc, belowSrcPop, UseLabel8B[EUWPFaultBad]];
GetYoungestPC[]; drRVADD[topDst, topSrc, const4]; SetYoungestPC[];
drRETK[377B]; --nResults -1; nResults = 0
SetLabel[EUWPFaultBad]; Pause[];
SetLabel[EUStackOverflow];
drALS[0]; --1 - nargs; nargs = 1 for ifuStatus
drLIB[9]; drRJNEB[popSrc, aux8, UseLabel8B[EUStkOvfBad]];
GetYoungestPC[]; drRVADD[topDst, topSrc, const4]; SetYoungestPC[];
drRETK[377B]; --nResults -1; nResults = 0
SetLabel[EUStkOvfBad]; Pause[];
SetLabel[IFUPageFault];
drALS[377B]; --1 - nargs; nargs = 2 (return PC and ifuStatus)
drLIB[10]; drRJNEB[popSrc, aux8, UseLabel8B[IFUPageFaultBad]];
GetYoungestPC[];
All of the IFU page fault tests try to execute an instruction at IFUPageFaultPC.
drLIQB[CardToWord[IFUPageFaultPC]];
drRJNEB[popSrc, belowSrcPop, UseLabel8B[IFUPageFaultBad]];
drLRn[reg0]; SetYoungestPC[];
drEXDIS[];
drRETK[377B]; --nResults -1; nResults = 0
SetLabel[IFUPageFaultBad]; Pause[];
SetLabel[Reschedule];
drALS[377B]; --1 - nargs; nargs = 2 (return PC and ifuStatus)
drLIB[11]; drRJNEB[popSrc, aux8, UseLabel8B[RescheduleBad]];
drLIB[74B]; drAND[]; --Clear RescheduleKeep and Reschedule in saved ifuStatus
drLRn[reg0]; SetYoungestPC[];
drEXDIS[];
drRETK[377B]; --nResults -1; nResults = 0
SetLabel[RescheduleBad]; Pause[];
KFC is used to get back into Kernel mode after testing in User mode
SetLabel[KFCTrap];
drLIB[12]; drRJNEB[popSrc, aux8, UseLabel8B[KFCBad]];
drDIS[]; --Discard the IFU status
drLIP[ifuStatus];
Jump if in user mode or traps disabled
drJNEBB[2B, UseLabel8B[KFCBad]];
drRETN[]; --Return to caller remaining in Kernel mode with traps disabled.
SetLabel[KFCBad]; Pause[];
SetLabel[Xop1Trap];
drLIB[13]; drRJNEB[popSrc, aux8, UseLabel8B[Xop1Bad]];
drRETN[]; --Return to caller remaining in Kernel mode.
SetLabel[Xop1Bad]; Pause[];
SetLabel[Xop2Trap];
drLIB[14]; drRJNEB[popSrc, aux8, UseLabel8B[Xop2Bug]];
drJNEBB[123B, UseLabel8B[Xop2Bug]]; --Discard the pushed Alpha
drRETN[]; --Return to caller remaining in Kernel mode.
SetLabel[Xop2Bug]; Pause[];
SetLabel[Xop3Trap];
drLIB[15]; drRJNEB[popSrc, aux8, UseLabel8B[Xop3Bug]];
drJNEBB[234B, UseLabel8B[Xop3Bug]]; --Discard the pushed AlphaBeta
drRETN[]; --Return to caller remaining in Kernel mode.
SetLabel[Xop3Bug]; Pause[];
SetLabel[Xop5Trap];
drLIB[16]; drRJNEB[popSrc, aux8, UseLabel8B[Xop5Bug]];
drJNEBB[345B, UseLabel8B[Xop5Bug]]; --Discard the pushed AlphaBetaGammaDelta
drRETN[]; --Return to caller remaining in Kernel mode.
SetLabel[Xop5Bug]; Pause[];
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]
FillXop[LOOPHOLE[DragOpsCross.Inst.dKFC, CARDINAL], KFCTrap];
FillXop[1B, Xop1Trap];
FillXop[234B, Xop2Trap];
FillXop[364B, Xop3Trap];
FillXop[40B, Xop5Trap];
FillTrap[ResetTrap, start];
FillTrap[IFUStackOverflowTrap, IFUStackOverflow];
FillTrap[EUPageFault, EUPageFlt];
FillTrap[EUWriteFault, EUWPFlt];
FillTrap[AddressCheckFault, AddressCheck];
FillTrap[ALUCondOver, Overflow];
FillTrap[ALUCondBC, BoundsCheck];
FillTrap[ALUCondIL, LispNaN];
FillTrap[ModeFault, UserModeViolation];
FillTrap[EUStackOverflowTrap, EUStackOverflow];
FillTrap[IFUPageFaultTrap, IFUPageFault];
FillTrap[RescheduleTrap, Reschedule];
SetOutputPC[oldPC];
ProcedureEntry[initL, 0];
drLIB[1];
SetYoungestL[]; -- L ← 1 on return
spLimit is set with room for 17 overflow words (just in case).
drLIB[128-16-1];
SetSPLimit[];
ProcedureExit[0];
WordAlign[area];
Simulator execution begins here on a Reset.
SetLabel[start];
drLFC[UseLabel16[initL]]; --Initialize L to 1
drASL[255]; --and S = 0.
drROR[aux8, const0, const0]; --Initialize aux8 to 0, meaning no traps expected.
drLIB[6];
drROR[const4, popSrc, topSrc]; --Initialize const4 to 6 for the trap routines.
Now initialize the other constants and auxiliary registers to 1 so that they can be read during the user mode test without confusing the simulators.
drLIB[1];
drROR[const1, topSrc, topSrc];
drROR[const2, topSrc, topSrc];
drROR[const3, topSrc, topSrc];
drROR[const5, topSrc, topSrc];
drROR[const6, topSrc, topSrc];
drROR[const7, topSrc, topSrc];
drROR[const8, topSrc, topSrc];
drROR[const9, topSrc, topSrc];
drROR[const10, topSrc, topSrc];
drROR[const11, topSrc, topSrc];
drROR[aux1, topSrc, topSrc];
drROR[aux2, topSrc, topSrc];
drROR[aux3, topSrc, topSrc];
drROR[aux4, topSrc, topSrc];
drROR[aux5, topSrc, topSrc];
drROR[aux6, topSrc, topSrc];
drROR[aux7, topSrc, topSrc];
To avoid undefined values, write the 3 registers which will be read by LIP in user mode.
drLC0[]; drSIP[0];
drLC0[]; drSIP[127];
drLC0[]; drSIP[159];
Initialize all the locals for one frame
FOR I: CARDINAL IN [0..15) DO drLC0[]; ENDLOOP;
GenIFUStatus[];
GenIFUStackOverflow[];
GenSLimit[];
GenReschedule[];
GenIFUPageFault[];
GenEUPageFault[];
GenModeFaultPriority[];
GenAddressCheckPriority[];
Halt[177777B]; --Terminate here at the end of the program
};
END.