*----------------------------------------------------------- Title[DMesaFaultsTestW.mc...June 27, 1985 10:48 AM...Willie-Sue]; *----------------------------------------------------------- % Mesa fault handler. If the fault was an emulator map fault or a stack error, and the emulator running at the time was Mesa, then calls the appropriate trap procedure in SD. For any other fault, halts at one of the following breakpoints: (In fault task, not having reset FaultInfo) ManyFaults More than one fault NotEmuFault Fault in non-emulator task NotMapFault Memory system fault other than map fault UnknownFault Fault of unknown origin (In emulator task, having reset FaultInfo) AEmuStackErr Stack error from Alto emulator AEmuMapFault Map fault from Alto emulator (In emulator task, the fault task never having been awakened) MesaMapFault Map fault caused by IFU reference MesaFGParity FG parity error MesaRamPE IFU decoding Ram parity error BogusMapFault IFU gave a map fault, but the page referenced by PCX is not vacant and shouldn't have faulted. In the case of faults passed to the emulator task, interesting information is left in R-registers, as follows: FltErrors NOT (Errors') FaultInfo NOT (Pipe2') FltEmuPC Emulator TPC at time of fault FaultVal DBuf -- value being stored if faulted on Store_ Note that this version of the fault task does NOT try to emulate an XM Alto. % *----------------------------------------------------------- * Fault Task *----------------------------------------------------------- Set[XTask, IP[FLT]]; Subroutine; FLTInitPC: T_ FLT, CoReturn; TopLevel; T_ A0, RBase_ RBase[FaultInfo]; TIOA_ T, Block; FaultTask: FltErrors_ NOT (Errors'); * Read this always FaultInfo_ NOT (Pipe2'); * Doesn't clear FaultInfo * Test for memory system fault T_ (FaultInfo) AND (fi.numfaults); PD_ T XOR (fi.numFaults); * See if we have all bits set; FltPointers_ Pointers, Branch[ChkStkErr, ALU=0]; * All ones => no fault * Memory system fault, see what kind PD_ (FaultInfo) AND (fi.numFaults); * All zeroes => one fault PD_ (FaultInfo) AND (fi.emuFault), Branch[ManyFaults, ALU#0]; PD_ (FltErrors) AND (pipe4.notMapTrouble), Branch[NotEmuFault, ALU=0]; Branch[NotMapFault, ALU#0]; * Emulator map fault. Clear it and pass fault to emulator. B_ FaultInfo', Branch[EmuFault]; * Not memory system fault, check for stack overflow or underflow ChkStkErr: PD_ (FltPointers) AND (300C); * 200 = stack overflow, 100 = stack underflow Branch[UnknownFault, ALU=0]; * Emulator map fault or stack error. * Save emulator's state and restart emulator at Fault0. EmuFault: FaultVal_ DBuf; RdTPC_ EMU; FltEmuPC_ NOT (Link); * TPC data is complemented Call[GetEmuFaultPC]; LdTPC_ T; Block, Branch[FaultTask]; * Fault conditions that we can't handle: MC[DiskFaulted, LShift[14, 10]]; ManyFaults: Branch[.], Breakpoint; * More than 1 fault NotEmuFault: branch[DiskFault], T_ 177520C; * T_ (FaultInfo) AND (7400C); * task# that faulted * PD_ T XOR (DiskFaulted); * branch[DiskFault, alu=0], T_ 177520C; * Branch[.], Breakpoint; * Not Emulator or Disk fault NotMapFault: Branch[.], Breakpoint; * Not map fault UnknownFault: Branch[.], Breakpoint; * Don't know what fault occurred DiskFault: membase_ IOBR; T_ 177520C; Fetch_ T; FaultVal_ Md; FltTemp_ A0; store_ T, DBuf_ FltTemp; * turn off the disk task!! TIOA_ FltTemp; KIOCB_ A0; B_ FaultInfo'; * restart the disk task Call[DSKInitPC]; LdTPC_ T; RdTPC_ EMU; FltEmuPC_ NOT (Link); * TPC data is complemented Call[GetDiskFaultPC]; LdTPC_ T; Block, Branch[FaultTask]; Set[XTask, IP[EMU]]; Subroutine; GetDiskFaultPC: T_ EMU, CoReturn; TopLevel; RBase_ RBase[FltPipe0]; FltTemp_ A0, Call[RestoreALUFM]; * In case faulted during BITBLT TrapParam _ A0; FaultMapVal _ 2C; branch[JoinFault]; *----------------------------------------------------------- * IFU faults for the Mesa instruction set *----------------------------------------------------------- Set[MesaTrapBase, Sub[300, LShift[MesaInsSet, 6]]]; Set[XTask, IP[EMU]]; DontKnowRBase; TopLevel; MesaFGparity: At[MesaTrapBase, 4], Branch[.], Breakpoint; :IfMEP; At[MesaTrapBase, 5], Branch[.], Breakpoint; At[MesaTrapBase, 6], Branch[.], Breakpoint; :EndIf; MesaRamPE: At[MesaTrapBase, 74], Branch[.], Breakpoint; :IfMEP; At[MesaTrapBase, 75], Branch[.], Breakpoint; At[MesaTrapBase, 76], Branch[.], Breakpoint; :EndIf; :If[AltoMode]; ********** Alto version ********** MesaMapFault: At[MesaTrapBase, 0], Branch[.], Breakpoint; :IfMEP; At[MesaTrapBase, 1], Branch[.], Breakpoint; At[MesaTrapBase, 2], Branch[.], Breakpoint; :EndIf; :Else; ******** PrincOps version ******** MesaMapFault: At[MesaTrapBase, 0], MemBase_ Code, Branch[MapFault1]; :IfMEP; At[MesaTrapBase, 1], Stack_ MD, MemBase_ Code, Branch[MapFault1]; At[MesaTrapBase, 2], StkP+1, MemBase_ Code, Branch[MapFault1]; :EndIf; * For the IFU to have given a map fault exception, some byte in [PCX..PCX+IL) * must lie on a vacant page. So simply reference those bytes, in the * expectation that a fault will occur and the fault task will * wrench control away from here. MapFault1: T_ NOT (PCX'); T_ T RSH 1; * PCX/2 = word address in code segment T_ (Fetch_ T)+1; Fetch_ T; T_ MD; * Wait for fault to occur BogusMapFault: Branch[.], Breakpoint; :EndIf; ********************************** *----------------------------------------------------------- * Emulator Task * The emulator is restarted here by the fault task after an emulator * map fault or stack error. *----------------------------------------------------------- Subroutine; GetEmuFaultPC: T_ EMU, CoReturn; TopLevel; RBase_ RBase[FltPipe0]; FltTemp_ A0, Call[RestoreALUFM]; * In case faulted from BITBLT TIOA_ FltTemp; * In case faulted from I/O operation :If[AltoMode]; ********** Alto version ********** * Which emulator was running at the time? T_ NOT (IFUMLH'); PD_ T AND (14000C); * Test InsSet (Alto=0, Mesa=2) PD_ (FltPointers) AND (300C), Branch[FaultFromMesa, ALU#0]; * Fault from Alto emulator. Branch[AEmuMapFault, ALU=0]; AEmuStackErr: Branch[.], Breakpoint; AEmuMapFault: Branch[.], Breakpoint; :Else; ******** PrincOps version ******** PD_ (FltPointers) AND (300C); :EndIf; ********************************** * Fault from Mesa emulator. * If we got a stack error or StkP is now out of bounds, must give a StackError * in preference to a PageFault, because otherwise page fault processing would trap * (in SaveState) at an inconvenient moment. ALU = stack overflow/underflow bits here. FaultFromMesa: T_ FltErrors, RBase_ RBase[RTemp1], Branch[.+2, ALU=0]; Branch[StackError]; * Fault caused by stack error SCall[CheckStkP]; Branch[StackError]; * StkP now out of bounds *----------------------------------------------------------- * Handle emulator map fault. *----------------------------------------------------------- * Must distinguish between page faults and WP faults. It is a WP fault if the * map entry is WP and not dirty (i.e., not vacant) and the reference was a Store. * T = FltErrors here. T_ T AND (Or[pipe4.wProtect!, pipe4.dirty!]C); RTemp0_ PRef; RTemp0_ (RTemp0) AND (pipe5.store'); T_ (RTemp0) OR T; * Bits are disjoint PD_ T#(Pipe4.wProtect); * ALU=0 iff WP=1, dirty=0, store'=0 RTemp0_ IfE[AltoMode, 0, qPageFault, sPageFault], Branch[.+2, ALU#0]; RTemp0_ IfE[AltoMode, 0, qWriteProtectFault, sWriteProtect]; T_ VAHi; :If[AltoMode]; ********** Alto version ********** OTPReg_ VALo; OTPReg_ RCY[T, OTPReg, 10]; * OTPReg_ virtual page of fault :Else; ******** PrincOps version ******** FaultParam0_ VALo; * FaultParam0, 1 _ VA of fault * The @#&%*!$ hardware returns ones in VAHi[0:3] !! JoinFault: FaultParam1_ T AND (7777C); :EndIf; ********************************** * Now have trap or fault code in RTemp0. * Must reset IFU to clear BrkByte in case a break was pending and a fault * occurred before it could be executed. T_ 50C; T_ T-1, IFUReset, Branch[., ALU#0]; :If[AltoMode]; ********** Alto version ********** T_ RTemp0, Branch[SavePCAndTrap]; * Trap via SD[T] :Else; ******** PrincOps version ******** T_ RTemp0, Branch[MesaFault]; * Fault onto PDA.queue[T] :EndIf; ********************************** *----------------------------------------------------------- StackError: * Generate stack error trap. * Enter: RBase[RTemp0] *----------------------------------------------------------- * Attempt to restore StkP to its initial state. But if initial state was also * out of bounds, reset StkP to maximum legal value, because otherwise the * subsequent trap XFER or the DST executed by the trap routine would suffer * a recursive stack error trap. * Note: in principle I should RestoreStkP only if XferFlags.xfInvalid=0; however, * I believe it's impossible to get a stack error while the context is invalid. RestoreStkP; T_ Add[sizeStack]C, SCall[CheckStkP]; StkP_ T; * Out of bounds, reset it T_ sStackError, Branch[SavePCTrapNRStkP]; *----------------------------------------------------------- CheckStkP: * Returns +1 if StkP is out of bounds, +2 normally. * Clobbers RTemp0 *----------------------------------------------------------- Subroutine; RTemp0_ TIOA&StkP; PD_ (RTemp0)-(Add[sizeStack, 1]C); Return[ALU<0]; *----------------------------------------------------------- * Unimplemented opcodes *----------------------------------------------------------- TopLevel; :If[AltoMode]; ********** Alto version ********** *----------------------------------------------------------- * StoreMDS[@LocalBase[L].pc]^ _ PC; * XFER[dst: FetchMDS[@SD[sUnimplemented]]^, src: L]; *----------------------------------------------------------- UnimplOpcodeTrap: T_ sUnimplemented, Branch[SavePCAndTrap]; :IfMEP; T_ sUnimplemented, Stack_ MD, Branch[SavePCAndTrap]; T_ sUnimplemented, StkP+1, Branch[SavePCAndTrap]; :EndIf; :Else; ******** PrincOps version ******** *----------------------------------------------------------- * Cedar extension to unimplemented opcode trapping. * Generalized for use in opcodes that are implemented partially by * microcode and partially by software. * Enter at OpcodeTrap for both main and misc opcodes: * T = trap parameter, if there is one * opTrap: POINTER = FetchMDS[@SD[p137B]]; * IF opTrap=NIL THEN TrapZero[sUnimplemented] * ELSE BEGIN * opcode: CARDINAL _ FetchCodeByte[savedPC]^; * IF opcode=MISC THEN opcode _ 400B + FetchCodeByte[savedPC+1]^; * handler: ControlLink = FetchMDS[opTrap+opcode]; * PC _ savedPC; SP _ savedSP; * IF ValidContext[] THEN StoreMDS[@LocalBase[LF].pc]^ _ PC; * XFER[dst: handler, src: LF, push: FALSE, trap: TRUE]; * StoreMDS[@LF.trapParam, trapParameter]; * END; *----------------------------------------------------------- * IFU dispatches here for undefined opcodes. UnimplOpcodeTrap: T_ A0, Branch[OpcodeTrap]; * Trap parameter = 0 :IfMEP; Stack_ MD, Branch[.-1]; StkP+1, Branch[.-2]; :EndIf; * Microcode branches here with T = trap parameter to cause a trap when the * opcode can't be handled by the microcode. OpcodeTrap: RBase_ RBase[RTemp0], Global; TrapParam_ T; RTemp0_ T_ A0, MemBase_ Code, Branch[OpTrap1]; * Loop back here for MISC opcode -- dispatch on alpha byte instead MiscTrap: RTemp0_ T_ (ID)-1, MemBase_ Code; * Know ID = IL = 2 here. * T = RTemp0 = 0 for main opcode, 1 for MISC opcode. OpTrap1: RTemp1_ T-(PCX')-1; * PC of byte to dispatch on T_ RSH[RTemp1, 1]; * T_ word address Fetch_ T, FlipMemBase; * Fetch the word; MemBase_ MDS T_ MD, RTemp1_ And[Add[SDLoc, 137], 177400]C, Branch[.+2, R even]; * Which byte? T_ LSH[T, 10]; * Odd, left-justify T_ RCY[RTemp0, T, 10]; * T_ opcode or 400B+alpha PD_ T XOR (Add[MOpMISC]C); * See if opcode is MISC RTemp1_ (RTemp1) OR (And[Add[SDLoc, 137], 377]C), Branch[MiscTrap, ALU=0]; * Now T = opTrapTable offset. Trap via control link in opTrapTable. * RTemp1 = @SD[137B]. Fetch_ RTemp1; * Fetch SD[137B] PD_ MD, RestoreStkP; T_ T+MD, Branch[NoOpTrapTbl, ALU=0]; Fetch_ T, XferFlags_ xf.trap; * Fetch control link of trap handler RTemp1_ NOT (PCX'), Call[SavePCInFrame]; DLink_ MD, MemBase_ MDS, Branch[Xfer]; * If SD[137]=0 then no opcode trap table is set up. * Trap via SD[sUnimplemented] in the traditional manner. NoOpTrapTbl: T_ sUnimplemented, Branch[SavePCAndTrap]; :EndIf; **********************************