-- 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.