<> <> <> <> DIRECTORY Basics USING [BYTE, RawBytes], MesaRuntimeInit USING [], PrincOps USING [ControlLink, ControlModule, Frame, FrameCodeBase, FrameHandle, GFT, GFTItem, GlobalFrameHandle, MainBodyIndex, NullControl, NullFrame, NullGlobalFrame, Port, PortHandle, PrefixHandle, sBoundsFault, sControlFault, SD, sDivideCheck, sError, sHardwareError, sPointerFault, sRestart, sStackError, sStart, sSwapTrap, StateVector, sUnbound, SVPointer, sWakeupError, sZeroDivisor, zAND, zDESCBS, zLDIV, zPORTI, zPORTO, zSFC], PrincOpsUtils USING [Codebase, Free, GetReturnFrame, GetReturnLink, MyLocalFrame, ReadOTP, SetReturnFrame, SetReturnLink], RuntimeError USING []; TrapsImpl: PROGRAM IMPORTS PrincOpsUtils EXPORTS MesaRuntimeInit, RuntimeError = BEGIN OPEN PrincOps; <> CodeBytesPtr: TYPE = LONG POINTER TO Basics.RawBytes; <> BoundsFault: PUBLIC ERROR = CODE; ControlFault: PUBLIC SIGNAL [source: ControlLink] 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; <<>> <> Start: PUBLIC PROC [cm: PrincOps.ControlModule] = { CM: PROGRAM _ LOOPHOLE[cm]; state: StateVector; state _ STATE; IF ~cm.multiple THEN { OPEN f: cm.frame; IF @f = NullGlobalFrame OR f.started THEN ERROR StartFault[CM]; StartCM[LOOPHOLE[f.global[0]], @f, @state]; IF ~f.started THEN {f.started _ TRUE; StartWithState[@f, @state]} ELSE IF state.stkptr ~= 0 THEN SIGNAL StartFault[CM]; } ELSE { StartCM[cm, NIL, NIL]; IF state.stkptr ~= 0 THEN SIGNAL StartFault[CM]; }; }; <> Restart: PUBLIC PROC [dest: GlobalFrameHandle] = { stops: BOOL; frame: FrameHandle; IF dest = NullGlobalFrame THEN ERROR StartFault[LOOPHOLE[dest, PROGRAM]]; IF ~dest.started THEN Start[[frame[dest]]]; stops _ PrincOpsUtils.Codebase[dest].header.info.stops; IF ~stops THEN ERROR StartFault[LOOPHOLE[dest, PROGRAM]]; IF (frame _ LOOPHOLE[dest.global[0]]) ~= NullFrame THEN { frame.returnlink _ PrincOpsUtils.GetReturnLink[]; PrincOpsUtils.SetReturnFrame[frame] } }; <> <<>> StartCM: PROC [cm: ControlModule, frame: GlobalFrameHandle, state: SVPointer] = { Call: PROC [ControlLink] = MACHINE CODE {zSFC}; SELECT TRUE FROM cm = NullControl => RETURN; cm.multiple => { 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; PrincOpsUtils.Free[cm.list]; }; cm.frame.started => RETURN; ENDCASE => { control: ControlModule _ LOOPHOLE[cm.frame.global[0]]; IF control ~= cm THEN StartCM[control, frame, state]; IF ~cm.frame.started THEN { cm.frame.started _ TRUE; IF frame ~= cm.frame THEN Call[MainBody[cm.frame]] ELSE StartWithState[frame, state]; }; }; }; StartWithState: PROC [frame: GlobalFrameHandle, state: PrincOps.SVPointer] = { s: StateVector _ state^; retFrame: FrameHandle _ PrincOpsUtils.GetReturnLink[].frame; s.dest _ MainBody[frame]; PrincOpsUtils.SetReturnLink[s.source _ retFrame.returnlink]; -- allows stack trace if RETURN WITH s faults. PrincOpsUtils.Free[retFrame]; RETURN WITH s }; <> BoundsFaultTrap: PROC = { frame: FrameHandle; state: RECORD [a: WORD, v: StateVector]; state.v _ STATE; state.v.dest _ ControlLink[frame[frame _ PrincOpsUtils.GetReturnFrame[]]]; BumpPC[frame, 1]; state.v.stkptr _ state.v.stkptr - 1; ERROR BoundsFault; -- pc is advanced on this trap <> }; CodeTrap: PROC = { dest: ControlLink; state: StateVector; frame: GlobalFrameHandle; state _ STATE; dest _ PrincOpsUtils.ReadOTP[]; state.dest _ PrincOpsUtils.GetReturnLink[]; DO IF dest.proc THEN {frame _ GetFrame[GFT[dest.gfi]]; EXIT}; IF NOT dest.indirect THEN {frame _ dest.frame.accesslink; EXIT}; dest _ dest.link^; ENDLOOP; IF ~frame.started THEN Start[[frame[frame]]]; frame.code.out _ FALSE; RETURN WITH state }; DivideCheckTrap: PROC = { frame: FrameHandle; state: RECORD [a: WORD, v: StateVector]; state.v _ STATE; state.v.dest _ ControlLink[frame[frame _ PrincOpsUtils.GetReturnFrame[]]]; BumpPC[frame, 1]; state.v.stkptr _ state.v.stkptr - 2; SIGNAL DivideCheck; -- pc is advanced on this trap RETURN WITH state.v }; HardwareErrorTrap: PROC = { state: RECORD [a, b: WORD, v: StateVector]; state.v _ STATE; ERROR HardwareError }; PointerFaultTrap: PROC = { frame: FrameHandle; state: RECORD [a: WORD, v: StateVector]; state.v _ STATE; state.v.dest _ ControlLink[frame[frame _ PrincOpsUtils.GetReturnFrame[]]]; BumpPC[frame, 1]; ERROR PointerFault; -- pc is advanced on this trap <> }; StackErrorTrap: PROC = { state: RECORD [a: WORD, v: StateVector]; foo: BOOL; state.v _ STATE; foo _ TRUE; -- The garbage with foo is so all the code for the next statement <> <> IF foo THEN ERROR StackError }; <> <<>> 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 = { sourceOp: Basics.BYTE; frame: FrameHandle; dest: ControlLink; state: StateVector; state _ STATE; dest _ PrincOpsUtils.ReadOTP[]; state.dest _ ControlLink[frame[frame _ PrincOpsUtils.GetReturnFrame[]]]; BumpPC[frame, OpcodeLengths[sourceOp _ GetCodeBytes[frame][frame.pc]]]; IF sourceOp = zSFC OR sourceOp = zPORTO THEN state.stkptr _ state.stkptr - 1; [] _ SIGNAL UnboundProcedure[dest]; RETURN WITH state }; WakeupErrorTrap: PROC = { state: RECORD [a, b: WORD, v: StateVector]; state.v _ STATE; ERROR WakeupError }; ZeroDivisorTrap: PROC = { frame: FrameHandle; state: RECORD [a: WORD, v: StateVector]; state.v _ STATE; state.v.dest _ ControlLink[frame[frame _ PrincOpsUtils.GetReturnFrame[]]]; state.v.stkptr _ state.v.stkptr - (IF GetCodeBytes[frame][frame.pc] = zLDIV THEN 2 ELSE 1); BumpPC[frame, 1]; SIGNAL ZeroDivisor; -- pc is advanced on this trap RETURN WITH state.v }; ControlFaultTrap: PROC = { errorStart, savedState: StateVector; sourceOp: Basics.BYTE; PORTI: PROC = MACHINE CODE {zPORTI}; p, q: PortHandle; sourceFrame, self: FrameHandle; source: ControlLink; savedState _ STATE; self _ PrincOpsUtils.MyLocalFrame[]; sourceFrame _ self.returnlink.frame; source _ PrincOpsUtils.ReadOTP[]; sourceOp _ GetCodeBytes[sourceFrame][sourceFrame.pc]; BumpPC[sourceFrame, OpcodeLengths[sourceOp]]; IF sourceOp = zPORTO THEN { savedState.stkptr _ savedState.stkptr - 1; p _ source.port; q _ p.dest.port; IF q = NIL THEN errorStart.stk[0] _ LOOPHOLE[LinkageFault] ELSE { q^ _ Port[links[NullFrame, [indirect[port[p]]]]]; errorStart.stk[0] _ LOOPHOLE[PortFault]; }; errorStart.stk[1] _ 0; -- message errorStart.instbyte _ 0; errorStart.stkptr _ 2; errorStart.source _ sourceFrame.returnlink; <> errorStart.dest _ LOOPHOLE[SD[sError]]; IF savedState.stkptr = 0 THEN RETURN WITH errorStart -- RESPONDING port ELSE { p.frame _ self; TRANSFER WITH errorStart; PORTI[]; p.frame _ sourceFrame; savedState.stk[savedState.stkptr + 1] _ LOOPHOLE[savedState.source _ ControlLink[indirect[port[p]]]]; savedState.stk[savedState.stkptr] _ LOOPHOLE[savedState.dest _ p.dest]; RETURN WITH savedState } } ELSE {-- not a port call IF sourceOp = zSFC THEN savedState.stkptr _ savedState.stkptr - 1; <> savedState.dest _ ControlLink[frame[sourceFrame]]; [] _ SIGNAL ControlFault[LOOPHOLE[sourceFrame]]; RETURN WITH savedState -- to press on } }; <> BumpPC: PROC [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 {zDESCBS, MainBodyIndex}; GetFrame: PROC [g: GFTItem] RETURNS [GlobalFrameHandle] = INLINE { And: PROC [g: GFTItem, mask: GFTItem] RETURNS [GlobalFrameHandle] = MACHINE CODE {zAND}; maskFrame: GFTItem = [ep[data: 37777B, epbias: 0]]; RETURN[And[g, maskFrame]] }; <> <<>> Initialize: PROC = { pSD: POINTER TO ARRAY NAT OF PROC ANY RETURNS ANY _ LOOPHOLE[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; }; Initialize[]; END.