-- MMInterrupt.mesa  Edited by Sandman on May 23, 1979  11:51 AM
-- Forrest on July 15, 1980  4:47 PM

DIRECTORY
  ControlDefs USING [StateVector],
  ImageDefs USING [AbortMesa],
  InlineDefs USING [BcplLongNumber],
  KeyDefs USING [KeyBits, Keys, updown],
  Mopcodes USING [zBRK, zEXCH, zKFCB],
  OsStaticDefs USING [OsStatics],
  MMInit,
  ProcessDefs USING [Priority],
  ProcessOps USING [FirstStateVector],
  SDDefs USING [sInterrupt];

MMInterrupt: MONITOR []IMPORTS ImageDefs EXPORTS MMInit SHARES OsStaticDefs =
BEGIN

wakeup: PUBLIC CONDITION;

GetDebugger: PROCEDURE =
  MACHINE CODE BEGIN Mopcodes.zKFCB, SDDefs.sInterrupt END;

HardwareTime: TYPE = InlineDefs.BcplLongNumber;
TimeData: POINTER TO TimeDataRecord = LOOPHOLE[572B];
TimeDataRecord: TYPE = MACHINE DEPENDENT RECORD [
  timeOfDay, milliSeconds, timeBase: HardwareTime];

CheckInterrupt: PUBLIC ENTRY PROCEDURE =
  BEGIN
  clockSecond: POINTER TO HardwareTime ← OsStaticDefs.OsStatics.ClockSecond;
  keys: POINTER TO KeyDefs.KeyBits ← KeyDefs.Keys;
  interruptState: KeyDefs.updown ← up;
  SV: POINTER TO ARRAY ProcessDefs.Priority OF ControlDefs.StateVector =
    LOOPHOLE[ProcessOps.FirstStateVector↑];
  RealTimeClock: POINTER TO CARDINAL = LOOPHOLE[430B];
  timeData: POINTER TO TimeDataRecord ← TimeData;

  DO ENABLE ABORTED => CONTINUE;
  WAIT wakeup;
  IF RealTimeClock↑-timeData.timeBase.highbits > clockSecond.highbits THEN
    BEGIN
    HT: PROCEDURE [LONG CARDINAL] RETURNS [HardwareTime] =
      MACHINE CODE BEGIN Mopcodes.zEXCH END;
    LC: PROCEDURE [HardwareTime] RETURNS [LONG CARDINAL] =
      MACHINE CODE BEGIN Mopcodes.zEXCH END;
    timeData.timeOfDay ← HT[LC[timeData.timeOfDay]+1];
    timeData.milliSeconds ← HT[LC[timeData.milliSeconds]+1000];
    timeData.timeBase ← HT[LC[timeData.timeBase]+LC[clockSecond↑]];
    END;
  -- The following code checks for Shft-Swat, the swat interrupt keys.
  IF keys.LeftShift = down AND keys.Spare3 = down THEN ImageDefs.AbortMesa[];
  IF keys.Ctrl = down AND (keys.Spare3 = down OR keys.FR5 = down) THEN
    BEGIN
    IF interruptState = up THEN
      BEGIN
      interruptState ← down;
      FOR pp: ProcessDefs.Priority IN [0..6) DO
	SV[pp].instbyte ← Mopcodes.zBRK;
	WAIT wakeup;
	IF SV[pp].instbyte = 0 THEN EXIT ELSE SV[pp].instbyte ← 0;
	REPEAT FINISHED => GetDebugger[];
	ENDLOOP;
      END;
    END
  ELSE interruptState ← up;
  ENDLOOP;
  END;

END.