Traps.mesa
last edited by Levin on March 11, 1983 4:43 pm
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;
CMLOOPHOLE[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 UNSPECIFIEDSD;
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.