DIRECTORY
DebuggerDefs,
DragOpsCross USING [TrapBase, TrapWidthBytes, TrapIndex, XopBase],
--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, MapFault, AUFault, DynaBusTimeOut, DynaBusOtherFault, euStack, euJunk, euToKBus, euMAR, euField, euConstant, euAux, euBogus, euLast, ifuYoungestL, ifuYoungestPC, ifuEldestL, ifuEldestPC, ifuSLimit, ifuBogus, ifuL, ifuS, ifuPC, ifuLast, EURegs, EULegalRegs, IFURegs, IFULegalRegs, StackedStatusWord, IFUStackIndex, IFUStackSize, IFUOverflow, EUStackIndex, EUStackSize, EULocalIndex, EULocals, EUAuxIndex, EUAuxRegs, EUConstIndex, EUConstants, IOLocation, ioRescheduleRequest, ioResetRequest, IOOperand, PCmdFormat, PCmdByteSelect, PCmdClass, PCmdSpace, PCmdDirection
DragOpsCrossUtils USING [CardToWord],
--InstToBytes, InstToFormat, BytePCToWordAddress, WordAddressToBytePC, IOOperandToCard, CardToIOOperand, FieldDescriptorToCard, CardToFieldDescriptor, BytesToWord, BytesToHalf, WordToBytes, HalfToBytes, HalvesToWord, WordToHalves, HighHalf, LowHalf, LeftHalf, RightHalf, SwapHalves, WordToInt, IntToWord, WordToCard, HalfToCard, ByteToCard, CardToWord, CardToHalf, CardToByte, DragAnd, DragOr, DragXor, DragNot, VanillaAdd, VanillaSub, AddDelta, HalfNot, HalfAnd, HalfOr, HalfXor, HalfShift, DoubleWordShiftLeft, SingleWordShiftLeft, SingleWordShiftRight, XopToBytePC, TrapIndexToBytePC, FieldUnit
HandCoding, --Has opcode and register defs.
HandCodingPseudos, --Label, SetLabel, GenLabel, GenLabelHere, UseLabel8A, UseLabel8B, UseLabel16, UseLabel32, LReg, PReg, SReg, AddReg, SubReg, SetRegConst, MoveReg, MoveRegI, LRegI, IndexedJump, ProcedureEntry, ProcedureExit, SetupField, ExtractField, ShiftLeft, LoadProcessorReg, StoreProcessorReg, CauseReschedule, CauseReset, GetSPLimit, SetSPLimit, GetYoungestPC, GetYoungestStatus, GetEldestPC, GetEldestStatus, SetYoungestPC, SetYoungestStatus, SetEldestPC, SetEldestStatus, Pause, Halt
HandCodingSupport, --Area, GetProc, PutProc, ProcList, NewArea, GenWithArea, Gen1WithArea, ForceOut, GetCurrentArea, LoadArea, GetOutputPC, SetOutputPC, WordAlign, ReserveData, OutputByte, OutputOneByte, OutputAlphaBeta, OutputAlphaBetaGammaDelta, OutputWord
SoftcardPrivate USING [Car1PeriodicIntToDragon, CarVirtualMemAccessEU, CarVirtualMemAccessIFU, DragonMapAddr, SCBaseAddr];
GenDebugger:
CEDAR
PROGRAM
IMPORTS DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport
= BEGIN OPEN DebuggerDefs, DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport;
TrapWidthBytes: NAT = DragOpsCross.TrapWidthBytes;
All:
PROC = {
When debugDebugger = TRUE, the debugger's wait loop is not assembled and all the registers saved by GenDebugger are zeroed during reset; after this, it is possible to continue from Lizard's Pause[] or Halt[] stop into the Xop traps defined below for the purposes of debugging the GenDebugger module itself. When debugDebugger = FALSE, Lizard can still be used, but the program must terminate at Pause[] or Halt[].
debugDebugger: BOOLEAN = FALSE;
debuggerCacheClearAddr: LONG CARDINAL = (debuggerBasePC / bytesPerWord) + 10000B;
area: Area = GetCurrentArea[];
Start: Label = GenLabel[];
enterDebug: Label = GenLabel[];
enterReschedule: Label = GenLabel[];
A trap's location is TrapIndex*TrapWidthBytes + TrapBase*bytesPerWord =
1,002,000B + 20B * TrapIndex. TrapIndex definitions are in DragOpsCross.
FillTrap:
PROC [tx: DragOpsCross.TrapIndex, dest: Label] = {
SetOutputPC[LOOPHOLE[tx, CARDINAL] * TrapWidthBytes + DragOpsCross.TrapBase * bytesPerWord];
drJQB[UseLabel32[dest]];
};
Come here in Kernel mode with at least 1 IFU stack slot and 3 EU stack registers free and at lease 1 IFU stack slot in use; also, the PC in the most recent IFU stack slot must not be identical to the PC's in any earlier IFU stack slots. Entry by a Pause or Halt Xop normally ensures at least 1 IFU stack slot will be in use and unduplicated. The values in [S], [S+1], [S+2], and the next IFU stack slot are smashed here. Before entry here, the a, ab, or abcd argument of the Xop causing debugger entry (if any) has been stored in debugBase+debuggerAlphaBeta; [S] = reg0 holds the opcode number causing debugger entry; and L = the value of S at the onset of the trap + 1. The Pause (opcode 0) and Halt (opcode 377B) defined here as Xops can be used to enter the debugger only when the program is in Kernel mode. Otherwise, the program wishing to enter the debugger must define some other Xop trap like Pause[] but with Kernel entry via KFC prior to jumping here.
GenDebug:
PROC = {
readS: Label = GenLabel[];
setL: Label = GenLabel[];
noMoreFrames: Label = GenLabel[];
wait: Label = GenLabel[];
SetOutputPC[debuggerBasePC];
SetLabel[enterDebug];
drALS[0]; --L ← S equals the value of S at the onset of the entry Xop + 1.
drLIQB[CardToWord[debugBase]];
drWB[debuggerOpcode]; --Save opcode number
Put a table pointer retained through state save and restore below into reg0 = [S]
drLIQB[CardToWord[debugBase]];
Save registers. Register descriptions here are copied from DragOpsCross.mesa.
euStack (0), beginning of EU Stack
euJunk (128), the non-matching EU register (not saved)
euToKBus (129), send result on K bus to IFU (not saved)
euMAR (130), MemoryAddressRegister
euField (131), Field register
euConstant (132), Base of EU constant registers (12 regs)
euAux (144), Base of EU aux registers (16 regs)
euBogus (160), [euBogus..euLast] not legal (NA) (80 regs)
euLast (239), last possible EU reg (NA)
These IFU register addresses are noticed within the IFU. Destinations are changed to references to the "toKBus" register. Sources are changed so that ALURightSource (an EU control input) = kBus. Note that L, other status, S, and PC for the current frame are unreadable.
ifuYoungestL (240), youngest L & status in IFU stack
ifuYoungestPC (241), youngest PC in IFU stack
ifuEldestL (242), eldest L & status in IFU stack
ifuEldestPC (243), eldest PC in IFU stack (rd removes, wt adds)
ifuSLimit (244), stack limit register
drRADD[pushDst, const0, const0]; drSRIn[reg0, debuggerCarry];
Read, save, and clear the IFU stack.
GetYoungestPC[]; --Youngest PC into LR1
FOR reg:
CARDINAL
IN [0..IFUStackSize)
DO
moreFrames: Label ← GenLabel[];
GetEldestStatus[]; drSRIn[reg0, ifuRegBase + reg + reg];
GetEldestPC[]; --Recover the PC of the old frame
drRJNEBJ[topSrc, reg1, UseLabel8B[moreFrames]];
drSRIn[reg0, ifuRegBase + reg + reg + 1];
drLIB[reg]; drJDB[UseLabel16[noMoreFrames]];
SetLabel[moreFrames];
drSRIn[reg0, ifuRegBase + reg + reg + 1];
ENDLOOP;
drLIB[IFUStackSize]; --Shouldn't ever get here
SetLabel[noMoreFrames];
drSRIn[reg0, debuggerFrame]; --No. frames including the one created by Halt.
drDIS[]; --Pop the youngest PC off the stack.
Build a frame in which to access L and Status of this frame, which equals S+1 in the frame where the halt occurred. Return with the current value of L pushed onto the stack and with traps disabled.
drLFC[UseLabel16[readS]]; drSUBB[1]; drSRIn[reg0, debuggerS];
GetSPLimit[]; drSRIn[reg0, debuggerSLimit]; --ifuSLimit
The stack is saved by doing EUStackSize - 1 SRIn's, the first one saving the word immediately underneath reg0 (which contains debugBase); this word is saved in the table entry at EUStackSize - 2. During restoration, debugBase will be in reg0 and S will point at reg0; EUStackSize registers will be restored with LRIn[reg0, euRegBase+n]'s; the first word restored will be from the 0th table entry; the stack word containing debugBase is overwritten on the final load from the 127th table entry, after which the stack is popped once.
drAS[377B]; --Point S at the entry underneath debugBase
FOR reg:
CARDINAL
IN [0..EUStackSize - 1)
DO
drSRIn[reg0, euRegBase + EUStackSize - 2 - reg]; --Save the EU stack
ENDLOOP;
S now points at reg0 containing debugBase.
FOR reg:
CARDINAL
IN [131..160)
DO
--EU registers except stack
drLIP[reg]; drSRIn[reg0, euRegBase + reg];
ENDLOOP;
Now the state has been saved, and the IFU stack is empty. Loop here until the debugging software signals "resume". Then reload registers and return from the most recent call; if the debugging software has changed nothing, then the "resume" will restore state and continue.
drLIB[1]; drSRIn[reg0, debuggerProceed]; --Indicate "stopped"
SetLabel[wait];
IF
NOT debugDebugger
THEN {
Setup to clear Softcard cache.
drLIQB[CardToWord[debugBase + debuggerProceed + 10000B]];
drRB[0]; drDIS[]; --Clear cache
drLIQB[CardToWord[debugBase + debuggerProceed]];
drRB[0];
drRJNEBJ[popSrc, const0, UseLabel8B[wait]];
};
Set L = debuggerS + 1 by calling a procedure, changing caller's L within the procedure and returning. Then repush debugBase onto the stack.
drLRIn[reg0, debuggerS]; drADDB[1]; drLFC[UseLabel16[setL]]; drASL[377B];
drLIQB[CardToWord[debugBase]];
Restore the IFU stack from the saved state. The oldest frame was the first one saved, in location 0 of the table, so this must be the last frame reloaded.
drLRIn[reg0, debuggerFrame]; --reg1 ← last frame to reload;
FOR reg:
CARDINAL ← IFUStackSize - 1, reg - 1
DO
notYet: Label ← GenLabel[];
drLIB[reg]; drRJGB[popSrc, belowSrc, UseLabel8B[notYet]];
drLRIn[reg0, ifuRegBase + reg + reg + 1]; SetEldestPC[];
drLRIn[reg0, ifuRegBase + reg + reg]; SetEldestStatus[];
SetLabel[notYet];
IF reg = 0 THEN EXIT;
ENDLOOP;
drAS[377B];
drLRIn[reg0, debuggerSLimit]; SetSPLimit[];
drLRIn[reg0, debuggerCarry];
drLIQB[CardToWord[37777777777B]];
drRUADD[belowDst, popSrc, belowSrcPop]; --Reload Carry
drLRIn[reg0, euRegBase + 131]; drSIP[131]; --Reload euField
FOR reg:
CARDINAL
IN [133..160)
DO
--Reload constants except const0 and aux registers
drLRIn[reg0, euRegBase + reg]; drSIP[reg];
ENDLOOP;
Finish by reloading the EU stack. The first register reloaded from the 0th table entry is the one immediately above debugBase; the last register reloaded is the one containing debugBase. Then pop the stack on the return from the trap.
FOR reg:
CARDINAL
IN [0..EUStackSize)
DO
drLRIn[reg0, euRegBase + reg];
ENDLOOP;
Resume program at location after Xop with S restored.
drRET[377B];
Procedure to read the halting opcode's S = L for the calling context and to disable traps.
WordAlign[area];
SetLabel[readS];
GetYoungestStatus[]; drLIB[377B]; drAND[];
drDUP[]; SetYoungestStatus[]; drRETN[];
WordAlign[area];
SetLabel[setL];
SetYoungestStatus[]; drRETN[];
};
XPause[] = Pause[] but uses opcode 1 instead of 0.
XPause:
PROC = {
HandCodingSupport.OutputByte[HandCodingSupport.GetCurrentArea[], LOOPHOLE[1]];
};
GenReschedule:
PROC = {
SetLabel[enterReschedule]; --Jump here on Reschedule
drRUADD[pushDst, const0, const0]; --Save carry on the stack
drLIQB[CardToWord[40500h]];
drRSB[0];
drADDB[1]; --Increment location 40500h on each reschedule
drWB[0];
drLIQB[CardToWord[80000000h+(SoftcardPrivate.Car1PeriodicIntToDragon-SoftcardPrivate.SCBaseAddr)/2]]; --Clear periodic interrupt
drRSB[0];
drDIS[];
drRB[1];
drDIS[];
drLIQB[CardToWord[0FFFFFFFFh]];
drRUADD[topDst, popSrc, belowSrc]; -- Restore carry
drDIS[];
drRETN[];
};
GenReset is the last code module instantiated below, so it establishes the initial PC of the diagnostic whose code is loaded afterwards.
GenReset:
PROC = {
fixL: Label = GenLabel[];
loop1: Label = GenLabel[];
loop2: Label = GenLabel[];
WordAlign[area];
SetLabel[Start]; --Softcard comes here on Reset.
--drLIQB[CardToWord[debugBase]];
--drLC0[];
--drWSB[debuggerLoopCount];
IF withSoftCard
THEN {
drLIQB[CardToWord[80000000h+(SoftcardPrivate.DragonMapAddr-SoftcardPrivate.SCBaseAddr)/2]]; --Base of the map in R0
drLIQB[CardToWord[4000h]]; --loop count in R1
SetLabel[loop1];
drLIQB[CardToWord[8000h]]; --Page fault in R2
drLRn[reg0]; --Address in R3
drWB[0]; -- (R3)^ ← R2
drRADD[reg0, reg0, const1]; -- increment address
drSUBB[1]; -- decrements loop count
drRJNEBJ[topSrc, const0, UseLabel8B[loop1]];
drAS[376B]; --pop 2
Set the 1Meg to 2Meg portion of the VM to map the Physical memory
drLIQB[CardToWord[80000000h+100h+(SoftcardPrivate.DragonMapAddr-SoftcardPrivate.SCBaseAddr)/2]]; -- Map address of VM = 1Meg in R0
drLIQB[CardToWord[0h]]; -- Physical address in R1
drLIQB[CardToWord[100h]]; -- loop count in R2
SetLabel[loop2];
drLRn[reg1]; -- Physical address in R3
drLRn[reg0]; -- Address in R4
drWB[0]; -- (R4)^ ← R3
drRADD[reg0, reg0, const1]; -- increment address
drRADD[reg1, reg1, const1]; -- increment Physical address
drSUBB[1]; -- decrements loop count
drRJNEBJ[topSrc, const0 ,UseLabel8B[loop2]];
drAS[375B]; --pop 3
Set virtual acces for the IFU
drLIQB[CardToWord[80000000h+(SoftcardPrivate.CarVirtualMemAccessIFU-SoftcardPrivate.SCBaseAddr+2)/2]]; -- A read at this location set virtual access
drRB[0];
drDIS[];
Set virtual acces for the EU
drLIQB[CardToWord[80000000h+(SoftcardPrivate.CarVirtualMemAccessEU-SoftcardPrivate.SCBaseAddr+2)/2]]; -- A read at this location set virtual access
drRB[0];
drDIS[];
}
ELSE
IF debugDebugger
THEN {
Initialize all the registers so that Lizard will not complain about uninitialized registers; this code serves no other functional purpose.
FOR
I:
CARDINAL
IN [0..EUStackSize)
DO
drLC0[]; --Initialize the stack
ENDLOOP;
drSIP[130]; --euMAR
drSIP[131]; --euField
SetSPLimit[]; --ifuSLimit
FOR
I:
CARDINAL
IN [4..12+16)
DO
drSIP[132 + I]; --Initialize the constants (except 0 to 3) and aux regs
ENDLOOP;
};
drLIB[1]; drLFC[UseLabel16[fixL]];
drASL[377B]; --S ← 0
drJQB[CardToWord[userBasePC]];
WordAlign[area];
SetLabel[fixL];
SetYoungestStatus[];
spLimit is set with room for 17 overflow words (just in case). A stack overflow trap occurs when S is in [spLimit..spLimit + 16). Since most diagnostis never enables the trap, it is not necessary to execute the code here.
--drLIB[128-16-1];
--SetSPLimit[];
drRETN[]; --L ← 1 in caller's frame
SetOutputPC[userBasePC];
Begin the program with all registers containing 0, L=0, and S = 377B.
};
GenTest is a test program for the debugger itself.
--GenTest:
PROC = {
--drLFC[3];
--drLIB[33]; drLIB[133]; Pause[];
--drLFC[3];
--drLIB[44]; drLIB[144]; Pause[];
--drLFC[3];
--drLIB[55]; drLIB[155]; Pause[];
--drLFC[3];
--drLIB[66]; drLIB[166]; Pause[];
--Halt[177777B];
--};
Xops trap at word location XopBase + opcode*TrapWidthWords = a PC of XopBase*bytesPerWord + opcode * TrapWidthWords * bytesPerWord = 4,000,000B + 20B * opcode.
Pause (opcode 0) entry (Note: Lizard intercepts this, so only works on Softcard.).
SetOutputPC[0 * TrapWidthBytes + DragOpsCross.XopBase * bytesPerWord];
drLIQB[CardToWord[debugBase]];
drLIP[130]; drWSB[euRegBase + 130]; --euMAR
drLC0[]; --Opcode number of Pause[];
drJDB[UseLabel16[enterDebug]];
Halt (opcode 377B) entry (Note: Lizard intercepts this, so only works on Softcard.).
SetOutputPC[377B * TrapWidthBytes + DragOpsCross.XopBase * bytesPerWord];
AlphaBeta already on the stack.
drLIQB[CardToWord[debugBase]];
drLIP[130]; drPSB[euRegBase + 130]; --euMAR
drWB[debuggerAlphaBeta];
drLIB[377B]; --Opcode number of Halt[ab];
drJDB[UseLabel16[enterDebug]];
EU Fault entry. Note that if the client diagnostic wants to, it can overwrite this trap entry with a special trap for the event.
SetOutputPC[LOOPHOLE[DragOpsCross.TrapIndex.IOAccessFault, CARDINAL] * TrapWidthBytes + DragOpsCross.TrapBase * bytesPerWord];
drLIQB[CardToWord[debugBase]];
drLIP[130]; drWSB[euRegBase + 130];
drLIB[debugEntryEUFault];
drJDB[UseLabel16[enterDebug]];
IFU Fault entry. Note that if the client diagnostic wants to, it can overwrite this trap entry with a special trap for the event.
SetOutputPC[LOOPHOLE[DragOpsCross.TrapIndex.IFUPageFaultTrap, CARDINAL] * TrapWidthBytes + DragOpsCross.TrapBase * bytesPerWord];
drLIQB[CardToWord[debugBase]];
drLIP[130]; drWSB[euRegBase + 130];
drLIB[debugEntryIFUFault];
drJDB[UseLabel16[enterDebug]];
FillTrap[ResetTrap, Start];
FillTrap[RescheduleTrap, enterReschedule];
GenReschedule[];
GenDebug[];
GenReset[];
--GenTest[];
Fall through into first instruction of user's code in following module.
END.