-- Traps.mesa (August 26, 1982 11:26 am by Levin) DIRECTORY Environment USING [Byte], Frame USING [Free, GetReturnFrame, GetReturnLink, MyLocalFrame, SetReturnFrame, SetReturnLink], Mopcodes USING [zDESCBS, zLDIV, zPORTI, zPORTO, zSFC], ProcessorFace USING [SetMP], PilotMP USING [cEarlyTrap, Code], PrincOps USING [ AV, AVHandle, ControlLink, ControlModule, Frame, FrameCodeBase, FrameHandle, GlobalFrameHandle, LargeReturnSlot, MainBodyIndex, NullControl, NullFrame, NullGlobalFrame, Port, PortHandle, PrefixHandle, StateVector, SVPointer], PrincOpsRuntime USING [GetFrame, GFT], Runtime USING [ValidateGlobalFrame], RuntimeInternal USING [Codebase], RuntimePrograms USING [], SDDefs USING [ sBoundsFault, sControlFault, SD, sDivideCheck, sError, sHardwareError, sPointerFault, sRestart, sSignal, sStackError, sStart, sSwapTrap, sUnbound, sWakeupError, sZeroDivisor], Trap USING [ReadOTP]; Traps: PROGRAM IMPORTS Frame, PrincOpsRuntime, ProcessorFace, RuntimeInternal, Trap, Runtime EXPORTS Runtime, RuntimePrograms = BEGIN ControlLink: TYPE = PrincOps.ControlLink; FrameHandle: TYPE = PrincOps.FrameHandle; GlobalFrameHandle: TYPE = PrincOps.GlobalFrameHandle; StateVector: TYPE = PrincOps.StateVector; AV: PrincOps.AVHandle = PrincOps.AV; LargeReturnSlot: CARDINAL = PrincOps.LargeReturnSlot; BoundsFault: PUBLIC ERROR = CODE; ControlFault: PUBLIC SIGNAL [source: FrameHandle] RETURNS [ControlLink] = CODE; DivideCheck: PUBLIC SAFE SIGNAL = CODE; HardwareError: PRIVATE ERROR = CODE; LinkageFault: PUBLIC ERROR = CODE; PointerFault: PUBLIC ERROR = CODE; PortFault: PUBLIC ERROR = CODE; StartFault: PUBLIC SIGNAL [dest: PROGRAM] = CODE; StackError: PUBLIC ERROR = CODE; UnboundProcedure: PUBLIC SIGNAL [dest: ControlLink] RETURNS [ControlLink] = CODE; WakeupError: ERROR = CODE; ZeroDivisor: PUBLIC SAFE SIGNAL = CODE; CodeBytesPtr: TYPE = LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte; -- Non-trap type procedures: BumpPC: PROCEDURE [f: FrameHandle, i: INTEGER] = INLINE {f.pc ← [f.pc + i]}; GetCodeBytes: PROC [frame: FrameHandle] RETURNS [CodeBytesPtr] = INLINE { RETURN[LOOPHOLE[frame.accesslink.code.longbase]]}; MainBody: PROC [GlobalFrameHandle] RETURNS [ControlLink] = MACHINE CODE BEGIN Mopcodes.zDESCBS, PrincOps.MainBodyIndex END; --RuntimePrograms.--Restart: PUBLIC PROC [dest: GlobalFrameHandle] = BEGIN stops: BOOLEAN; frame: FrameHandle; IF dest = PrincOps.NullGlobalFrame THEN ERROR StartFault[LOOPHOLE[dest, PROGRAM]]; IF ~dest.started THEN Start[[frame[dest]]]; stops ← LOOPHOLE[RuntimeInternal.Codebase[LOOPHOLE[dest, PROGRAM]], LONG PrincOps.PrefixHandle].header.info.stops; IF ~stops THEN ERROR StartFault[LOOPHOLE[dest, PROGRAM]]; IF (frame ← dest.global[0]) # PrincOps.NullFrame THEN BEGIN frame.returnlink ← Frame.GetReturnLink[]; Frame.SetReturnFrame[frame] END END; --RuntimePrograms.--Start: PUBLIC PROCEDURE [cm: PrincOps.ControlModule] = BEGIN CM: PROGRAM; FramesStarted: PROCEDURE RETURNS [BOOLEAN] = INLINE BEGIN OPEN PrincOpsRuntime; dest: ControlLink = LOOPHOLE[Runtime.ValidateGlobalFrame]; RETURN[GetFrame[GFT[dest.gfi]].started]; END; state: StateVector; state ← STATE; CM ← LOOPHOLE[cm]; IF ~cm.multiple THEN BEGIN OPEN f: cm.frame; IF @f = PrincOps.NullGlobalFrame OR f.started THEN ERROR StartFault[CM]; -- don't start trap module Frames early!! IF FramesStarted[] THEN Runtime.ValidateGlobalFrame[@f]; StartCM[f.global[0], @f, @state]; IF ~f.started THEN {f.started ← TRUE; StartWithState[@f, @state]; } ELSE IF state.stkptr # 0 THEN SIGNAL StartFault[CM]; END ELSE BEGIN StartCM[cm, NIL, NIL]; IF state.stkptr # 0 THEN SIGNAL StartFault[CM]; END; RETURN END; StartCM: PROCEDURE [ cm: PrincOps.ControlModule, frame: GlobalFrameHandle, state: PrincOps.SVPointer] = BEGIN Call: PROCEDURE [ControlLink] = MACHINE CODE BEGIN Mopcodes.zSFC END; SELECT TRUE FROM cm = PrincOps.NullControl => RETURN; cm.multiple => BEGIN length: CARDINAL; cm.multiple ← FALSE; IF (length ← cm.list.nModules) = 0 THEN RETURN; cm.list.nModules ← 0; FOR i: CARDINAL IN [0..length) DO StartCM[[frame[cm.list.frames[i]]], frame, state]; ENDLOOP; Frame.Free[cm.list]; END; cm.frame.started => RETURN; ENDCASE => BEGIN control: PrincOps.ControlModule ← cm.frame.global[0]; IF control # cm THEN StartCM[control, frame, state]; IF ~cm.frame.started THEN BEGIN cm.frame.started ← TRUE; IF frame # cm.frame THEN Call[MainBody[cm.frame]] ELSE StartWithState[frame, state]; END; END; RETURN END; StartWithState: PROC [frame: GlobalFrameHandle, state: PrincOps.SVPointer] = BEGIN s: StateVector ← state↑; retFrame: FrameHandle ← Frame.GetReturnLink[].frame; s.dest ← MainBody[frame]; Frame.SetReturnLink[s.source ← retFrame.returnlink]; -- allows stack trace if RETURN WITH s faults. Frame.Free[retFrame]; RETURN WITH s; END; -- Trap Handlers: BoundsFaultTrap: PROC = BEGIN frame: PrincOps.FrameHandle; state: RECORD [a: UNSPECIFIED, v: StateVector]; state.v ← STATE; state.v.dest ← ControlLink[frame[frame ← Frame.GetReturnFrame[]]]; BumpPC[frame, 1]; state.v.stkptr ← state.v.stkptr - 1; ERROR BoundsFault; -- pc is advanced on this trap -- RETURN WITH state.v END; CodeTrap: PROC = BEGIN OPEN PrincOpsRuntime; dest: ControlLink; state: StateVector; frame: GlobalFrameHandle; state ← STATE; dest ← Trap.ReadOTP[]; state.dest ← Frame.GetReturnLink[]; DO IF dest.proc THEN {frame ← GetFrame[GFT[dest.gfi]]; EXIT} ELSE IF dest.indirect THEN dest ← dest.link↑ ELSE {frame ← dest.frame.accesslink; EXIT}; -- frame ENDLOOP; IF ~frame.started THEN Start[[frame[frame]]]; frame.code.out ← FALSE; RETURN WITH state END; DivideCheckTrap: PROC = BEGIN frame: PrincOps.FrameHandle; state: RECORD [a: UNSPECIFIED, v: StateVector]; state.v ← STATE; state.v.dest ← ControlLink[frame[frame ← Frame.GetReturnFrame[]]]; BumpPC[frame, 1]; state.v.stkptr ← state.v.stkptr - 2; SIGNAL DivideCheck; -- pc is advanced on this trap RETURN WITH state.v END; HardwareErrorTrap: PROC = BEGIN state: RECORD [a, b: UNSPECIFIED, v: StateVector]; state.v ← STATE; ERROR HardwareError END; PointerFaultTrap: PROC = BEGIN frame: PrincOps.FrameHandle; state: RECORD [a: UNSPECIFIED, v: StateVector]; state.v ← STATE; state.v.dest ← ControlLink[frame[frame ← Frame.GetReturnFrame[]]]; BumpPC[frame, 1]; ERROR PointerFault; -- pc is advanced on this trap --RETURN WITH state.v END; StackErrorTrap: PROC = BEGIN state: RECORD [a: UNSPECIFIED, v: StateVector]; foo: BOOLEAN; state.v ← STATE; foo ← TRUE; -- The garbage with foo is so all the code for the next statement -- looks like it is in this procedure -- to the debugger (when it looks in the fine grain table) IF foo THEN ERROR StackError END; OpcodeLengths: PACKED ARRAY [0..255] OF [0..3] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 2, 2, 3, 0, 0, 0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 3, 3, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 3, 2, 3, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 0, 2, 2, 1, 0]; UnboundProcedureTrap: PROC = BEGIN sourceOp: Environment.Byte; frame: PrincOps.FrameHandle; dest: ControlLink; state: StateVector; state ← STATE; dest ← Trap.ReadOTP[]; state.dest ← ControlLink[frame[frame ← Frame.GetReturnFrame[]]]; BumpPC[frame, OpcodeLengths[sourceOp ← GetCodeBytes[frame][frame.pc]]]; IF sourceOp = Mopcodes.zSFC OR sourceOp = Mopcodes.zPORTO THEN state.stkptr ← state.stkptr - 1; [] ← SIGNAL UnboundProcedure[dest]; RETURN WITH state END; WakeupErrorTrap: PROC = BEGIN state: RECORD [a, b: UNSPECIFIED, v: StateVector]; state.v ← STATE; ERROR WakeupError END; ZeroDivisorTrap: PROC = BEGIN frame: PrincOps.FrameHandle; state: RECORD [a: UNSPECIFIED, v: StateVector]; state.v ← STATE; state.v.dest ← ControlLink[frame[frame ← Frame.GetReturnFrame[]]]; state.v.stkptr ← state.v.stkptr - (IF GetCodeBytes[frame][frame.pc] = Mopcodes.zLDIV THEN 2 ELSE 1); BumpPC[frame, 1]; SIGNAL ZeroDivisor; -- pc is advanced on this trap RETURN WITH state.v END; ControlFaultTrap: PROC = BEGIN errorStart, savedState: StateVector; sourceOp: Environment.Byte; PORTI: PROC = MACHINE CODE BEGIN Mopcodes.zPORTI END; p, q: PrincOps.PortHandle; sourceFrame, self: FrameHandle; source: ControlLink; savedState ← STATE; self ← Frame.MyLocalFrame[]; sourceFrame ← self.returnlink.frame; source ← Trap.ReadOTP[]; sourceOp ← GetCodeBytes[sourceFrame][sourceFrame.pc]; BumpPC[sourceFrame, OpcodeLengths[sourceOp]]; IF sourceOp = Mopcodes.zPORTO THEN BEGIN savedState.stkptr ← savedState.stkptr - 1; p ← source.port; q ← p.dest.port; IF q = NIL THEN errorStart.stk[0] ← LinkageFault ELSE BEGIN q↑ ← PrincOps.Port[links[PrincOps.NullFrame, [indirect[port[p]]]]]; errorStart.stk[0] ← PortFault END; errorStart.stk[1] ← 0; -- message errorStart.instbyte ← 0; errorStart.stkptr ← 2; errorStart.source ← sourceFrame.returnlink; -- lets UNWIND skip trapping frame errorStart.dest ← SDDefs.SD[SDDefs.sError]; IF savedState.stkptr = 0 THEN RETURN WITH errorStart -- RESPONDING port ELSE BEGIN p.frame ← self; TRANSFER WITH errorStart; PORTI[]; p.frame ← sourceFrame; savedState.stk[savedState.stkptr + 1] ← savedState.source ← ControlLink[indirect[port[p]]]; savedState.stk[savedState.stkptr] ← savedState.dest ← p.dest; RETURN WITH savedState END END ELSE -- not a port call BEGIN Punt: PROC [c: PilotMP.Code] = INLINE BEGIN ProcessorFace.SetMP[c]; DO ENDLOOP END; IF sourceOp = Mopcodes.zSFC THEN savedState.stkptr ← savedState.stkptr - 1; IF SDDefs.SD[SDDefs.sSignal] = 0 THEN Punt[PilotMP.cEarlyTrap]; -- avoid loop savedState.dest ← ControlLink[frame[sourceFrame]]; [] ← SIGNAL ControlFault[sourceFrame]; RETURN WITH savedState -- to press on END END; -- XFER break tracing implementation: -- The following code is thought not to work. Furthermore, we do not want it permanently resident. Thus it is retired, at least for now. -- continueTracing: BOOLEAN; -- ++RuntimeInternal.++StartTrace: PUBLIC PROC [ -- loc: POINTER, val: UNSPECIFIED, mask: WORD, equal: BOOLEAN] = -- BEGIN -- state: PrincOps.StateVector; -- lval: UNSPECIFIED; -- continueTracing ← TRUE; -- state ← STATE; -- state.dest ← Frame.GetReturnLink[]; -- SDDefs.SD[SDDefs.sXferTrap] ← state.source ← Frame.MyLocalFrame[]; -- ProcessInternal.DisableInterrupts[]; -- DO -- lval ← Inline.BITAND[loc↑, mask]; -- IF (IF equal THEN val = lval ELSE val # lval) THEN -- RuntimeInternal.WorryCallDebugger["TraceTrap"L]; -- IF ~continueTracing THEN { -- SDDefs.SD[SDDefs.sXferTrap] ← 0; -- ProcessInternal.EnableInterrupts[]; -- RETURN WITH state} -- ELSE { -- XferTrap.WriteXTS[skip1]; -- ProcessInternal.EnableInterrupts[]; -- TRANSFER WITH state}; -- ProcessInternal.DisableInterrupts[]; -- state ← STATE; -- XferTrap.WriteXTS[off]; -- state.dest ← Frame.GetReturnLink[]; -- state.source ← 0; -- ENDLOOP -- END; -- ++RuntimeInternal.++StopTrace: PUBLIC PROC = {continueTracing ← FALSE}; Initialize: PROC = -- (This code only needs to be initially resident.) BEGIN OPEN SDDefs; pSD: POINTER TO ARRAY [0..0) OF UNSPECIFIED ← SD; pSD[sBoundsFault] ← BoundsFaultTrap; pSD[sControlFault] ← ControlFaultTrap; pSD[sDivideCheck] ← DivideCheckTrap; pSD[sHardwareError] ← HardwareErrorTrap; pSD[sPointerFault] ← PointerFaultTrap; pSD[sRestart] ← Restart; pSD[sStackError] ← StackErrorTrap; pSD[sStart] ← Start; pSD[sSwapTrap] ← CodeTrap; pSD[sUnbound] ← UnboundProcedureTrap; pSD[sWakeupError] ← WakeupErrorTrap; pSD[sZeroDivisor] ← ZeroDivisorTrap; END; -- Main body Initialize[]; END. LOG (For earlier entries, please see version archived with Pilot 4.0.) April 10, 1980 5:16 PM Knutsen Made compatible with changed ResidentMemory procedure names; set mds in MemorySwap. April 29, 1980 9:38 PM Forrest Moved MemorySwap and callers to Traps, MiscDeviceCleanups to OISProcessorHeadD0. Rearrange and eliminate MONITOR. May 3, 1980 1:28 PM Forrest Mesa 6.0 (non-Dandelion) conversion June 23, 1980 5:46 PM McJones OISProcessorFace=>ProcessorFace; no longer disable interrupts when getting PrincOps trap parameters. September 2, 1980 1:56 PM Johnsson New XferTrap semantics. September 29, 1980 9:30 AM Johnsson all princops traps occur with state restored to beginning of instruction. October 3, 1980 1:54 PM Forrest Moved Unimplemented Trap to Processor Head. December 2, 1980 10:43 AM Knutsen Retired AllocTrap backstop allocator and its storage, replaced with bear trap. Fix return link in StartWithState. January 19, 1981 9:32 AM Knutsen Frame fault handler, FrameSize, Codebase, GetTableBase moved to FrameImpl. Retired StartTrace, StopTrace. February 5, 1981 6:01 PM Knutsen PrincOps fields changed names. August 26, 1982 11:26 am Levin Make BoundsFault and PointerFault be ERRORs.