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 = { debugDebugger: BOOLEAN = FALSE; debuggerCacheClearAddr: LONG CARDINAL = (debuggerBasePC / bytesPerWord) + 10000B; area: Area = GetCurrentArea[]; Start: Label = GenLabel[]; enterDebug: Label = GenLabel[]; enterReschedule: Label = GenLabel[]; FillTrap: PROC [tx: DragOpsCross.TrapIndex, dest: Label] = { SetOutputPC[LOOPHOLE[tx, CARDINAL] * TrapWidthBytes + DragOpsCross.TrapBase * bytesPerWord]; drJQB[UseLabel32[dest]]; }; 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 drLIQB[CardToWord[debugBase]]; drRADD[pushDst, const0, const0]; drSRIn[reg0, debuggerCarry]; 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. drLFC[UseLabel16[readS]]; drSUBB[1]; drSRIn[reg0, debuggerS]; GetSPLimit[]; drSRIn[reg0, debuggerSLimit]; --ifuSLimit 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; FOR reg: CARDINAL IN [131..160) DO --EU registers except stack drLIP[reg]; drSRIn[reg0, euRegBase + reg]; ENDLOOP; drLIB[1]; drSRIn[reg0, debuggerProceed]; --Indicate "stopped" SetLabel[wait]; IF NOT debugDebugger THEN { drLIQB[CardToWord[debugBase + debuggerProceed + 10000B]]; drRB[0]; drDIS[]; --Clear cache drLIQB[CardToWord[debugBase + debuggerProceed]]; drRB[0]; drRJNEBJ[popSrc, const0, UseLabel8B[wait]]; }; drLRIn[reg0, debuggerS]; drADDB[1]; drLFC[UseLabel16[setL]]; drASL[377B]; drLIQB[CardToWord[debugBase]]; 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; FOR reg: CARDINAL IN [0..EUStackSize) DO drLRIn[reg0, euRegBase + reg]; ENDLOOP; drRET[377B]; WordAlign[area]; SetLabel[readS]; GetYoungestStatus[]; drLIB[377B]; drAND[]; drDUP[]; SetYoungestStatus[]; drRETN[]; WordAlign[area]; SetLabel[setL]; SetYoungestStatus[]; drRETN[]; }; 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: 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 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 drLIQB[CardToWord[80000000h+(SoftcardPrivate.CarVirtualMemAccessIFU-SoftcardPrivate.SCBaseAddr+2)/2]]; -- A read at this location set virtual access drRB[0]; drDIS[]; drLIQB[CardToWord[80000000h+(SoftcardPrivate.CarVirtualMemAccessEU-SoftcardPrivate.SCBaseAddr+2)/2]]; -- A read at this location set virtual access drRB[0]; drDIS[]; } ELSE IF debugDebugger THEN { 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[]; --drLIB[128-16-1]; --SetSPLimit[]; drRETN[]; --L _ 1 in caller's frame SetOutputPC[userBasePC]; }; --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]; --}; SetOutputPC[0 * TrapWidthBytes + DragOpsCross.XopBase * bytesPerWord]; drLIQB[CardToWord[debugBase]]; drLIP[130]; drWSB[euRegBase + 130]; --euMAR drLC0[]; --Opcode number of Pause[]; drJDB[UseLabel16[enterDebug]]; SetOutputPC[377B * TrapWidthBytes + DragOpsCross.XopBase * bytesPerWord]; drLIQB[CardToWord[debugBase]]; drLIP[130]; drPSB[euRegBase + 130]; --euMAR drWB[debuggerAlphaBeta]; drLIB[377B]; --Opcode number of Halt[ab]; drJDB[UseLabel16[enterDebug]]; SetOutputPC[LOOPHOLE[DragOpsCross.TrapIndex.IOAccessFault, CARDINAL] * TrapWidthBytes + DragOpsCross.TrapBase * bytesPerWord]; drLIQB[CardToWord[debugBase]]; drLIP[130]; drWSB[euRegBase + 130]; drLIB[debugEntryEUFault]; drJDB[UseLabel16[enterDebug]]; 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[]; }; END. ΦGenDebugger.mesa Copyright c 1987 by Xerox Corporation. All rights reserved. Edward Fiala May 5, 1987 1:24:20 pm PDT. Removed init for constants 1 to 3 (Lizard didn't catch this problem). Renamed the boolean that controls assembly of code to debug this module itself debugDebugger. Copied in edits from Christophe Cuenod as follows: Added GenReschedule and debugger trap entries for IOAccessFault and IFUPageFaultTrap for Softcard. Initialize VM map just after reset so that: 0 to 1 MByte => Fault 1 to 2 MByte => Mapped into the 1 MByte of real memory 2 to 64 MByte => Fault Increment a counter on reschedule and return. Enter the debugger on IOAccessFault and IFUPageFaultTrap. Used the withSoftCard BOOLEAN appropriately on Cuenod's code. withSoftCard must now be TRUE for the Softcard and FALSE for Lizard. This module implements the Pause (opcode 0) and Halt (opcode 377B) Xops and the Reset trap; together these provide a debugging interface to the Softcard for other diagnostics. Another diagnostic GenFoo is then run from the Softcard with "quad -cx GenDebugger GenFoo". The code here saves the IFU/EU state, stores 1 in debuggerProceed, waits for debuggerProceed to be made zero, restores state from the table, and resumes the program by returning from the Xop. Pause and Halt as defined here only work when executed in Kernel mode. A diagnostic that wants to use similar facilities from User mode must define another Xop which first enters Kernel mode using a KFC trap and then jumps here to debuggerBasePC. Note that the euJunk and euToKBus registers are not saved or restored; also, [S], [S+1], [S+2], and the next IFU stack frame are smashed at entry to the debugger. However, the saved state in the table can be modified prior to resuming; and the values put in smashed table locations [S], [S+1], and [S+2] will be restored. The Dragon has opcode and other traps in the word range [1,000,000B..1,002,400B) or the PC range [4,000,000B..4,012,000B). When running simulated under Lizard, there are no particular limits on addressing, but running on the Softcard, all memory addresses are mapped into [0B..1,000,000B); i.e., the memory address bits higher than 777,777B are discarded. 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[]. A trap's location is TrapIndex*TrapWidthBytes + TrapBase*bytesPerWord = 1,002,000B + 20B * TrapIndex. TrapIndex definitions are in DragOpsCross. 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. Put a table pointer retained through state save and restore below into reg0 = [S] 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 Read, save, and clear the IFU 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. 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. S now points at reg0 containing debugBase. 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. Setup to clear Softcard cache. Set L = debuggerS + 1 by calling a procedure, changing caller's L within the procedure and returning. Then repush debugBase onto the stack. 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. 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. Resume program at location after Xop with S restored. Procedure to read the halting opcode's S = L for the calling context and to disable traps. XPause[] = Pause[] but uses opcode 1 instead of 0. GenReset is the last code module instantiated below, so it establishes the initial PC of the diagnostic whose code is loaded afterwards. Set the 1Meg to 2Meg portion of the VM to map the Physical memory Set virtual acces for the IFU Set virtual acces for the EU Initialize all the registers so that Lizard will not complain about uninitialized registers; this code serves no other functional purpose. 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. Begin the program with all registers containing 0, L=0, and S = 377B. GenTest is a test program for the debugger itself. 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.). Halt (opcode 377B) entry (Note: Lizard intercepts this, so only works on Softcard.). AlphaBeta already on the stack. EU Fault entry. Note that if the client diagnostic wants to, it can overwrite this trap entry with a special trap for the event. IFU Fault entry. Note that if the client diagnostic wants to, it can overwrite this trap entry with a special trap for the event. Fall through into first instruction of user's code in following module. Κβ˜codešœ™Kšœ Οmœ1™J˜šžœžœžœ˜Jšœ™Jšœ9˜9JšœŸ ˜ Jšœ0˜0J˜Jšœ+˜+J˜—J˜JšœŒ™ŒJšœI˜IJ˜J˜Jšœ›™›JšœŸ˜<šžœžœž˜0K˜K˜9Kšœ8˜8Kšœ8˜8K˜Jšžœ žœžœ˜Jšžœ˜—J˜ J˜Jšœ+˜+Jšœ˜Jšœ!˜!Jšœ)Ÿ˜7Jšœ,Ÿ˜<š žœžœžœ žœŸ2˜VKšœ*˜*Jšžœ˜—Jšœμ™μšžœžœžœž˜(Kšœ˜Jšžœ˜—Jšœ5™5Jšœ ˜ J˜JšœZ™ZJ˜J˜J˜*J˜'J˜J˜J˜J˜J˜—K˜Kšœ2™2š œžœ˜KšœAžœ˜NJ˜—K˜š  œžœ˜JšœŸ˜5Jšœ#Ÿ˜