GenTraps.mesa
Copyright © 1986, 1987 by Xerox Corporation. All rights reserved.
Edward Fiala March 5, 1986 10:49:41 am PST
McCreight February 16, 1987 10:56:29 am PST
Curry, September 11, 1986 2:40:33 pm PDT
Fiala November 7, 1986 6:44:21 pm PST Massive edits to fix program for the fact that Reschedule and address check are no longer implemented, for the fact that ifuStatus is no longer pushed on the EU stack on a trap, for the different way of enabling and disabling traps and entering user mode, for features which can now be tested with ← LizardLiverImpl.careful ← FALSE, and for the deimplementation of partial simulation for IOD, IODA, and ION.
Fiala April 3, 1987 4:21:46 pm PST Eliminate Reset, Halt, and Pause stuff
to run with GenDebugger. Add XPause[] error halt to enter user mode and disable traps before entering the debugger. Add drRAND[...const0] to make FSDB have a harmless argument.
Fiala April 10, 1987 1:26:22 pm PST Moved the test that EU page fault is higher priority than EU stack overflow from GenSLimit to GenEUPageFault for Softcard debugging, so that the GenSLimit test will not run into page fault incompatibilities with the Softcard.
Load with "quad -cx GenDebugger GenTraps" and do "← LizardLiverImpl.careful ← FALSE" before execution. When simulated correctly with withSoftCard = TRUE, it terminates with HALT[177777B] at PC 4043607B, cycle 4758, Inst 1588. This diagnostic will NOT run under Lizard if DebuggerDefs.withSoftCard = TRUE because Lizard traps user mode writes to addresses < KernalLimit.
It tests the following machine functions (** means not tested because of some problem with the Lizard simulation):
1) User mode enabling and trap enabling and disabling via ifuYoungestL and RET to caller (L and the IFU stack were tested in GenReg.mesa).
2) KFC instruction.
3) Registers legal and illegal in User mode.
4) Instructions legal and illegal in User mode.
5) 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 RB[0] that gets an EU page fault; or on an ifu page fault (ifu page fault tested in GenTraps2); on user mode RADD that gets mode fault trap.
6) Verify that IFU stack overflow does not occur with 11 call stack entries on Jn, JB, JDB, JQB, JSR, JSD, or RET; on RBC, QBC, or BC that do not trap.
7) 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).
8) 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.
9) 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.
10) Verify that EU stack overflow is lower priority than bounds check, NaN, overflow, EU page fault, and mode fault.
11) 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.
12) Verify that IFU page fault does not occur when the untaken path of a conditional jump or conditional trap lies in an undeclared page.
13) 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.
14) Verify that mode fault prevails over bounds check, overflow, NaN, and EU page fault traps.

15) **User mode and trap enabling and disabling via ifuEldestL aren't tested (don't need testing?).
16) **Memory access faults aren't tested, such as user mode WB into the Kernel (former Address Check tests were commented out because of architecture change); references to addresses >= 2^30 aren't tested (Lizard limitation).
17) **IFU page fault priority over EU stack overflow is not tested (see GenTraps2).
18) **IO Access faults on IOD, IODA, and ION aren't tested.
19) **Verify that EU stack overflow occurs with greater priority than an ALU trap caused on the instruction following a SIP which reenables interrupts.
20) **Verify that EU stack overflow occurs with greater priority than Reschedule following a SIP which reenables interrupts (tested in GenTraps2).
21) **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 doesn't simulate write protect faults.)
22) **Reschedule trap isn't tested because it is not simulated.
DIRECTORY
Basics USING [DoubleShiftLeft],
DebuggerDefs,
DragOpsCross USING [ProcessorRegister, XopBase, TrapBase, TrapWidthBytes, TrapIndex, Inst],
--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, FieldDescriptorToCard, IntToWord, CardToByte],
--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
GenTraps: CEDAR PROGRAM
IMPORTS Basics, DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport
= BEGIN OPEN DebuggerDefs, DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport;
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];
euMAR: CARDINAL = LOOPHOLE[ProcessorRegister.euMAR, CARDINAL];
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]];
aux13: AuxRegSpec = [aux[13]];
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[];
These labels are for trap procedures.
IFUStackOverflow: 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[];
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[];
ErrorXop1Trap: Label = GenLabel[];
AlreadyInKernel: Label = GenLabel[];
TurnOnTraps: Label = GenLabel[];
TurnOffTraps: Label = GenLabel[];
TurnOnUserMode: Label = GenLabel[];
enterIFUStatusTest: Label = GenLabel[];
enterIFUStackOverflowTest: Label = GenLabel[];
enterSLimitTest: Label = GenLabel[];
enterIFUPageFaultTest: Label = GenLabel[];
enterEUPageFaultTest: Label = GenLabel[];
enterModeFaultPriorityTest: Label = GenLabel[];
Lizard only permits addresses >= DragOpsCross.KernelLimit = 100000000B to be written in user mode; the Softcard only permits addresses in [1,000,000B..2,000,000B) to be referenced.
userMemAddr: LONG CARDINAL = IF withSoftCard THEN 1770000B ELSE 100000000B;
kernelMemAddr: LONG CARDINAL = IF withSoftCard THEN 17760000B ELSE 77777777B;
All traps enter kernel mode and disable traps; 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 * 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 * bytesPerWord];
drJDB[UseLabel16[dest]];
};
Procedures to enable and disable traps in the caller's context; must be in Kernel mode.
EnableTraps: PROC [] = { drDFC[UseLabel32[TurnOnTraps]]; };
DisableTraps: PROC [] = { drDFC[UseLabel32[TurnOffTraps]]; };
EnterUser: PROC [] = { drDFC[UseLabel32[TurnOnUserMode]]; };
Indicate KFC trap expected by loading 12 into aux8
EnterKernel: PROC [] = { drLIB[12]; drROR[aux8, popSrc, topSrc]; drKFC[]; drROR[aux8, const0, const0]; };
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 XPause[] opcodes to fill out 6 bytes (i.e., enough for a 5-byte trapping opcode and a 1-byte XPause[] after it); then if no trap occurs, the first XPause[] after the opcode will stop simulation; or if the wrong trap occurs, the mismatch on aux8 will cause XPause[] 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];
drLIB[code];
drRJNEB[popSrc, aux8, UseLabel8B[TrapUnexpected]];
Advance return PC by 6
GetYoungestPC[]; drRVADD[topDst, const4, topSrc]; SetYoungestPC[];
drRETN[];
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];
XPause[]; XPause[]; XPause[]; XPause[];
};
StackedStatusWord: TYPE = MACHINE DEPENDENT RECORD [
version (0:00..07): [0..255] ← 0,
pad (0:08..13) [0..63] ← 0,
userMode (0:14..14) BOOL ← FALSE (True = kernel mode),
trapsEnabled (0:15..15): BOOL ← FALSE,
pad (1:00..07) [0..255] ← 0,
lBase (1:08..15) [0..255] ← 0 ];
User mode can be enabled by changing the user mode bit in the stacked status word and then doing a RET. In user mode, the following actions are illegal:
1) Any write of a constant or aux0 to aux7 causes a mode fault trap.
2) All SIPs, and LIP[IFUEldestPC] (an active operation) cause a mode fault trap.
3) IODA, IOD, 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 [] ~ {
UCall1: Label = GenLabel[];
UCall2: Label = GenLabel[];
UJump1: Label = GenLabel[];
JQBNop0: Label = GenLabel[];
JSDNop0: Label = GenLabel[];
BeginUserTest: Label = GenLabel[];
CheckTrapEnable: Label = GenLabel[];
CheckTrapDisable: Label = GenLabel[];
CheckUserMode: Label = GenLabel[];
BadEnable: 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[userMemAddr]]; drROR[aux0, topSrc, popSrc];
drJDB[UseLabel16[BeginUserTest]]; --inst 50
SetLabel[CheckTrapEnable];
GetYoungestStatus[]; drLIQB[CardToWord[200000B]]; drOR[];
drDUP[]; SetYoungestStatus[]; --Set trapsEnabled
drLIP[ifuYoungestL]; drRJNEB[popSrc, belowSrcPop, UseLabel8B[BadEnable]];
drRETN[];
SetLabel[BadEnable]; XPause[];
SetLabel[CheckTrapDisable];
GetYoungestStatus[]; drLIQB[CardToWord[37777577777B]]; drAND[];
drDUP[]; SetYoungestStatus[]; --Set trapsEnabled
drLIP[ifuYoungestL]; drRJNEB[popSrc, belowSrcPop, UseLabel8B[BadEnable]];
drRETN[];
SetLabel[CheckUserMode];
GetYoungestStatus[]; drLIQB[CardToWord[400000B]]; drOR[];
drDUP[]; SetYoungestStatus[]; --Set trapsEnabled
drLIP[ifuYoungestL]; drRJNEB[popSrc, belowSrcPop, UseLabel8B[BadEnable]];
drRETN[];
SetLabel[BeginUserTest];
Check trap enabling and disabling and user mode enabling (must call a subroutine).
drLFC[UseLabel16[CheckTrapEnable]];
drLFC[UseLabel16[CheckTrapDisable]];
drLFC[UseLabel16[CheckUserMode]];
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
drASL[377B]; --0 pushes on the EU stack, 1 call on the IFU stack
WriteAtAddress[userMemAddr];
***FIXES NEEDED HERE. IODA[2B] does [S] ← PRead[0 + [S], BetaZ].
--drLIQB[CardToWord[userMemAddr]]; drIODA[2B];
drASL[377B]; --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];
drADDQB[CardToWord[0]];
drSUBQB[CardToWord[0]];
drRXOR[topDst, topSrc, topSrc];
drRAND[topDst, topSrc, const0]; --Zero [S]
drFSDB[FieldDescriptorToCard[[mask: 6, shift: 20]]]; --1 push
drRFU[pushDst, topSrc, topSrc]; --2 pushes
drSHDL[FieldDescriptorToCard[[mask: 32, shift: 0]]]; --1 push
drSHL[FieldDescriptorToCard[[mask: 0, shift: 32]]]; --1 push
drSHR[FieldDescriptorToCard[[mask: 16, shift: 16]]]; --1 push
drJ1[];
drJ2[]; XPause[];
drJ3[]; XPause[]; XPause[];
drJ5[]; XPause[]; XPause[]; XPause[]; XPause[];
drJDB[3];
drJQB[UseLabel32[JQBNop0]]; SetLabel[JQBNop0];
drLIQB[UseLabel32[JSDNop0]]; drJSD[]; SetLabel[JSDNop0];
drEXDIS[]; --0 pushes
drLIDB[0]; --1 push
drASL[377B]; --0 pushes, 0 locals (S ← 0B, L = 1B)
drAL[0];
drLIQB[CardToWord[userMemAddr]]; --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[userMemAddr - 1]]; --2 pushes
drRBC[topDst, topSrc, belowSrc]; --won't trap
drQBC[topAtop, belowSrc]; --won't trap
drDIS[]; drLIQB[CardToWord[userMemAddr + 1]];
drBC[]; --1 push
drDUP[]; --2 pushes
drLC0[]; drRX[]; drDIS[]; --1 push
drQRX[pushAtop, const0]; drDIS[];
drLGF[0]; drDIS[]; --(aux0 was initialized to userMemAddr above)
drRAI[reg1, aux0, 0];
drDUP[]; drRB[0]; drDIS[];
drRRI[reg1, reg13, 0]; --(reg0 .. reg15 were set to userMemAddr above)
drRRX[reg1, reg13, const0];
drRSB[0]; drDIS[];
drWAI[reg1, aux0, 0];
drWRI[reg1, reg13, 0];
drLC0[]; drWSB[0]; --Still have 1 push
IF NOT withSoftCard THEN { drLIB[1]; drLC0[]; drCST[0]; };
drASL[377B]; --0 pushes
drLIB[1]; drJSR[];
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]];
EnterKernel[]; --KFC trap returns in Kernel mode with traps disabled.
EnterUser[]; --Enter user mode and enable traps
drLIQB[CardToWord[userMemAddr]]; --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]; XPause[]; XPause[]; XPause[];
drROR[aux1, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[aux2, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[aux3, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[aux4, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[aux5, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[aux6, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[aux7, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const0, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const1, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const2, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const3, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const4, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const5, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const6, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const7, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const8, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const9, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const10, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const11, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
Execute all instructions illegal in user mode.
Representative SIP instructions.
drSIP[0]; XPause[]; XPause[]; XPause[]; XPause[];
drSIP[242]; XPause[]; XPause[]; XPause[]; XPause[];
drSIP[246]; XPause[]; XPause[]; XPause[]; XPause[];
LIP[IFUEldestPC] is illegal in user mode because it modifies the call stack.
drLIP[ifuEldestPC]; XPause[]; XPause[]; XPause[]; XPause[];
drDIS[]; --16 locals, 1 push, 2 calls on the IFU stack
IOD, ION, and IODA are legal or illegal in user mode according to the device which is selected.
--drIOD[4B]; XPause[]; XPause[]; XPause[];
--drION[4B]; XPause[]; XPause[]; XPause[];
--drIODA[4B]; XPause[]; XPause[]; XPause[];
Now try a write reference to a Kernel page, which should trap.
--WriteTrapAtAddress[kernelMemAddr];
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
EnterKernel[]; --Use KFC to enter kernel mode and return with traps disabled.
FOR I: CARDINAL IN [0..0] 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[];
JSDNop1: Label = GenLabel[];
exitIFUStackOverflowTest: Label = GenLabel[];
eleventhCall: Label = GenLabel[];
drJB[UseLabel8A[enterIFUStackOverflowTest]];
SetLabel[UCall3];
XPause[]; --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
EnableTraps[];
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[4]; --11 calls
XPause[];
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[]; XPause[];
drJ3[]; XPause[]; XPause[];
drJ5[]; XPause[]; XPause[]; XPause[]; XPause[];
drJB[2];
drJDB[3];
drJQB[UseLabel32[JQBNop1]]; XPause[]; SetLabel[JQBNop1];
drLIQB[UseLabel32[JSDNop1]]; drJSD[]; XPause[]; SetLabel[JSDNop1];
drLIB[1]; drJSR[];
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 XPause[]'s after the call.
drLFC[3]; XPause[]; XPause[]; XPause[];
drDFC[UseLabel32[UCall3]]; XPause[];
drLIQB[UseLabel32[UCall3]]; drSFC[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
1, 2, 3, and 5-byte Xops should cause IFU stack overflow trap
OutputByte[area, CardToByte[1B]];
XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
OutputAlphaBeta[area, (234B * 400B) + 123B];
XPause[]; XPause[]; XPause[]; XPause[];
OutputByte[area, CardToByte[364B]]; OutputAlphaBeta[area, 234B];
XPause[]; XPause[]; XPause[];
OutputByte[area, CardToByte[40B]]; OutputWord[area, CardToWord[345B]];
XPause[];
drKFC[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
RBC, QBC, or BC should cause IFU stack overflow when they trap.
drLIB[1]; drLIB[2];
drQBC[pushAtop, belowSrc]; XPause[]; XPause[]; XPause[]; XPause[];
drRBC[pushDst, topSrc, belowSrc]; XPause[]; XPause[]; XPause[];
drEXDIS[]; drLIB[1];
drBC[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
NaN trap causing stack overflow should get IFU stack overflow trap.
drLIQB[CardToWord[10000000000B]]; drDUP[];
drLADD[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
ADD that Overflows should get IFU stack overflow trap.
drADD[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
EU page fault.
drLIQB[CardToWord[EUPageFaultAddress]];
drROR[aux9, topSrc, topSrc];
drRB[0]; XPause[]; XPause[]; XPause[]; XPause[];
Push that gets EU stack overflow
drASL[17B]; --L = 1, S = 20B
drLIB[21B]; drSIP[ifuSLimit];
drDUP[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
drDIS[]; drLIB[160B]; drSIP[ifuSLimit];
drROR[aux8, const0, const0]; --Indicate no traps expected
GetEldestPC[]; --Clear 1 call to enter user mode
EnterUser[];
drLFC[UseLabel16[eleventhCall]]; --11 calls again
Return here reducing call stack depth by 1 so KFC can get out of user mode.
drJDB[UseLabel16[exitIFUStackOverflowTest]]; --10 calls
SetLabel[eleventhCall];
drLIB[1]; drROR[aux8, topSrc, popSrc]; --Indicate IFU stack overflow expected
User mode RADD that gets mode fault.
drRADD[const1, const0, const0]; XPause[]; XPause[]; XPause[];
User mode store that gets address check
--****drLC0[]; drWB[0]; XPause[]; XPause[]; XPause[]; XPause[];
drROR[aux8, const0, const0]; --Indicate no traps expected
drRET[377B]; --returns from 11th call and trims stack
SetLabel[exitIFUStackOverflowTest];
EnterKernel[];
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 and aux15 must contain 9 (the code for EU stack overflow trap expected); 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, aux15, aux15];
drASL[SL]; XPause[]; XPause[]; XPause[]; XPause[]; --SLimit
drASL[SL + 15]; XPause[]; XPause[]; XPause[]; XPause[]; --SLimit + 15
drROR[aux8, const0, const0];
drASL[SL + 16]; --SLimit + 16
drASL[SL - 1]; --SLimit - 1
drASL[0]; --SLimit
};
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], and RET[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
EnableTraps[];
drLIB[13B]; drSIP[ifuSLimit];
drLIQB[CardToWord[userMemAddr]]; drSRn[reg0]; --Memory address for LRIn below
drLC0[]; --S = 11B
drLIB[9]; drROR[aux8, topSrc, topSrc]; --aux8 ← EU stk ovf trap expected
drROR[aux15, topSrc, popSrc]; --aux15 ← EU stk ovf trap expected for SLimitTests below
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]; XPause[];
Should get EU stack overflow trap on these typical instructions
drDUP[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
drLRn[reg2]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
drQADD[pushA0, const0]; XPause[]; XPause[]; XPause[]; XPause[];
drRADD[pushDst, const0, const0]; XPause[]; XPause[]; XPause[];
drLRIn[reg0, 0]; XPause[]; XPause[]; XPause[]; XPause[];
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]; XPause[]; XPause[]; XPause[]; XPause[];
drASL[11B + I]; XPause[]; XPause[]; XPause[]; XPause[];
drRET[11B + I]; XPause[]; XPause[]; XPause[]; XPause[];
ENDLOOP;
Now check for popping that puts S in the restricted range.
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
drSRn[reg15]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
drQAND[topAtop, popSrc]; XPause[]; XPause[]; XPause[]; XPause[];
drRAND[belowDst, topSrc, popSrc]; XPause[]; XPause[]; XPause[];
drSRIn[reg0, 0]; XPause[]; XPause[]; XPause[]; XPause[];
drDIS[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
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];
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.
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]; XPause[]; XPause[]; XPause[]; XPause[];
drRBC[pushDst, topSrc, belowSrc]; XPause[]; XPause[]; XPause[];
NaN should prevail; this is a particularly rough test because RLADD 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[]; --S = 20B (1 less than SLimit)
drRLADD[pushDst, topSrc, belowSrc]; XPause[]; XPause[]; XPause[];
drDIS[]; drLIB[5]; drROR[aux8, topSrc, popSrc]; --Overflow prevails
drDUP[]; --S = 20B (1 less than SLimit)
drRADD[pushDst, topSrc, belowSrc]; XPause[]; XPause[]; XPause[];
****Address check isn't implemented any more.
--drAS[376B]; EnterUser[]; drDUP[];
--drLIB[4]; drROR[aux8, topSrc, popSrc];
--drLC0[]; drWB[0]; XPause[]; XPause[]; XPause[]; XPause[];
****Used to test that Reschedule won out over EUStackOverflow here.
Test that ModeFault prevails over EUStackOVerflow when writing an illegal register occurs at the same time as popping into the restricted range.
drASL[377B]; --S = 0, L = 1 (won't trap)
drLIB[160B]; drSIP[ifuSLimit]; --S in [160B..177B] will trap
drLIB[8]; drROR[aux8, topSrc, topSrc]; --Indicate ModeFault expected
EnterUser[];
drRADD[const1, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
EnterKernel[]; --Enter Kernel mode and disable traps
drASL[17B]; --L = 1, S = 20B, traps disabled, Kernel mode, 0 calls on the stack
};
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
EnableTraps[];
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, IODA read, and IODA 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
EnableTraps[];
drLIB[2]; drROR[aux8, popSrc, topSrc]; --EU page fault expected
Verify that EU stack overflow is lower priority than EU page fault.
drLIB[21B]; drSIP[ifuSLimit];
drASL[16B]; --S = 17B
drLIQB[CardToWord[EUPageFaultAddress]];
drROR[aux9, topSrc, topSrc];
drRB[0]; XPause[]; XPause[]; XPause[]; XPause[];
drASL[377B]; --L = 1, S = 0
drLIQB[CardToWord[EUPageFaultAddress]];
drRB[0]; XPause[]; XPause[]; XPause[]; XPause[];
drRJEBJ[topSrc, aux9, UseLabel8B[OKState]]; --Make sure RB[0] didn't smash [S]
SetLabel[BadState]; XPause[];
SetLabel[OKState];
drLIB[123B]; drROR[aux10, popSrc, topSrc];
S ← S - 1 if the popSrc isn't a no-op.
drRRX[aux10, popSrc, const0]; XPause[]; XPause[]; XPause[];
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]; XPause[]; XPause[]; XPause[]; XPause[];
drLIDB[123456B];
drRJNEB[popSrc, belowSrcPop, UseLabel8B[BadState]];
drRJNEB[topSrc, aux9, UseLabel8B[BadState]];
IF NOT withSoftCard THEN {
drLIDB[111111B]; --new value
drLIDB[122222B]; --old value
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.
drCST[0]; XPause[]; XPause[]; XPause[]; XPause[];
};
drLIDB[122222B]; drRJNEB[popSrc, belowSrcPop, UseLabel8B[BadState]];
drDIS[];
drSFCI[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
drRJNEB[topSrc, aux9, UseLabel8B[BadState]];
Lizard doesn't trap the IODA opcode for page faults.
[S] ← PRead[AlphaZ + [S], BetaZ] with address check.
--drIODA[2B]; XPause[]; XPause[]; XPause[];
--drRJNEB[popSrc, aux9, UseLabel8B[BadState]];
--drLIB[123B]; drROR[pushDst, aux9, const0];
PWrite[AlphaZ + [S], BetaZ with address check, [S-1]]; S ← S-2.
--drIODA[3B];
--drRJNEB[popSrc, aux9, UseLabel8B[BadState]];
--drJNEBB[123B, UseLabel8B[BadState]];
};
Verify that ModeFault prevails over 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
EnterUser[];
drLIQB[CardToWord[10000000000B]]; drDUP[];
Modefault prevails over NaN.
drRLADD[const2, belowSrc, topSrc]; XPause[]; XPause[]; XPause[];
Modefault prevails over overflow.
drRADD[const2, belowSrc, topSrc]; XPause[]; XPause[]; XPause[];
Modefault prevails over bounds check.
drRBC[const2, belowSrc, popSrc]; XPause[]; XPause[]; XPause[];
drDIS[];
drLC0[]; drLIQB[CardToWord[EUPageFaultAddress]];
Modefault prevails over EU page fault.
drRRX[const2, popSrc, belowSrcPop]; XPause[]; XPause[]; XPause[];
EnterKernel[]; --Indicate KFC trap expected
Return here in Kernel mode
};
XPause[] = Pause[] but uses opcode 2 instead of 0.
XPause: PROC = {
HandCodingSupport.OutputByte[HandCodingSupport.GetCurrentArea[], LOOPHOLE[2]];
};
spLimit is set with room for 17 overflow words (just in case).
drLIB[128-16-1];
SetSPLimit[];
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[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]; --aux 15, inst. 33
Initialize all the locals for one frame
FOR I: CARDINAL IN [0..15) DO drLC0[]; ENDLOOP;
Next instruction is the 49th. All of these work except that in GenIFUStackOverflow ModeFault trap takes priority over IFUStackOverflow, a Lizard bug.
GenIFUStatus[];
GenIFUStackOverflow[];
GenSLimit[];
GenIFUPageFault[];
GenEUPageFault[];
GenModeFaultPriority[];
Halt[177777B]; --Terminate here at the end of the program
StandardTrap[IFUStackOverflow, 1]; --priority 2
EU page fault trap has code 2
EU write protect fault trap has code 3
StandardTrap[Overflow, 5];
StandardTrap[BoundsCheck, 6];
StandardTrap[LispNaN, 7];
StandardTrap[UserModeViolation, 8];
StandardTrap[EUStackOverflow, 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];
drLIB[2]; drRJNEB[popSrc, aux8, UseLabel8B[EUPageFaultBad]];
All of the EU page fault tests use the address EUPageFaultAddress in aux9.
drLIP[euMAR];
drRJNEB[popSrc, aux9, UseLabel8B[EUPageFaultBad]];
GetYoungestPC[]; drRVADD[topDst, topSrc, const4]; SetYoungestPC[];
drRETN[];
SetLabel[EUPageFaultBad]; Pause[];
SetLabel[EUWPFlt];
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[];
drRETN[];
SetLabel[EUWPFaultBad]; Pause[];
SetLabel[IFUPageFault];
1 arg = return PC
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]];
SetYoungestPC[];
drRETN[];
SetLabel[IFUPageFaultBad]; Pause[];
****Does Reschedule-waiting have to be cleared here?
SetLabel[Reschedule]; --Arg is the return PC
drLIB[11]; drRJNEB[popSrc, aux8, UseLabel8B[RescheduleBad]];
SetYoungestPC[];
drRETN[];
SetLabel[RescheduleBad]; Pause[];
KFC is used to get back into Kernel mode with traps disabled after testing in User mode
SetLabel[KFCTrap];
drLIB[12]; drRJNEB[popSrc, aux8, UseLabel8B[KFCBad]];
drLIP[ifuYoungestL]; drLIB[377B]; drAND[]; drSIP[ifuYoungestL];
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]; XPause[];
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]; XPause[];
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]; XPause[];
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]; XPause[];
XPause[] (opcode 2) is used instead of Pause[] (opcode 0) to enter the debugger from user mode. This is done by first executing KFC to enter monitor mode and then doing Pause[].
SetLabel[ErrorXop1Trap];
drLIQB[CardToWord[600000B]]; GetYoungestStatus[]; drAND[];
drJEBB[0, UseLabel8B[AlreadyInKernel]];
EnterKernel[];
SetLabel[AlreadyInKernel];
drLIQB[CardToWord[debugBase]];
drLIP[130]; drWSB[euRegBase + 130]; --euMAR
drLIB[2]; --Opcode number of XPause[];
drJQB[CardToWord[debuggerBasePC]];
SetLabel[TurnOnTraps]; --Call here with EnableTraps[]
drLIB[377B]; GetYoungestStatus[]; drAND[]; --Preserve L
drLIQB[CardToWord[200000B]]; drOR[]; SetYoungestStatus[]; --Set trapsEnabled
drRETN[];
SetLabel[TurnOffTraps]; --Call here with DisableTraps[]
drLIB[377B]; GetYoungestStatus[]; drAND[]; --Preserve L, clear trapsEnabled and User
SetYoungestStatus[]; --Set trapsEnabled
drRETN[];
SetLabel[TurnOnUserMode]; --Call here with EnterUser[]
drLIB[377B]; GetYoungestStatus[]; drAND[]; --Preserve L
Set trapsEnabled and user mode
drLIQB[CardToWord[600000B]]; drOR[]; SetYoungestStatus[];
drRETN[];
These calls to FillXop and FillTrap initialize the trap locations with JDB[trap procedure].
FillXop[LOOPHOLE[DragOpsCross.Inst.dKFC, CARDINAL], KFCTrap];
FillXop[1B, Xop1Trap];
FillXop[234B, Xop2Trap];
FillXop[364B, Xop3Trap];
FillXop[40B, Xop5Trap];
FillXop[2B, ErrorXop1Trap];
FillTrap[IFUStackOverflowTrap, IFUStackOverflow];
FillTrap[EUPageFault, EUPageFlt];
FillTrap[EUWriteFault, EUWPFlt];
FillTrap[ALUCondOver, Overflow];
FillTrap[ALUCondBC, BoundsCheck];
FillTrap[ALUCondIL, LispNaN];
FillTrap[ModeFault, UserModeViolation];
FillTrap[EUStackOverflowTrap, EUStackOverflow];
FillTrap[IFUPageFaultTrap, IFUPageFault];
FillTrap[RescheduleTrap, Reschedule];
};
END.