-- InitialPack.Mesa  Edited by:
  -- Evans on May 19, 1980  4:33 PM
  -- Bruce on October 7, 1980  1:29 PM
  -- Sandman on July 30, 1980  9:49 AM
  -- Johnsson on July 15, 1980  2:54 PM
  -- Mark on August 20, 1980  8:32 PM

DIRECTORY
  BP USING [BBHandle, BytePC, Conditionalize, FindBB, ResetBBs],
  Commands USING [Go, WriteError],
  Cursor USING [Set],
  DebugFormat USING [BBHandle, Foo],
  DebugOps USING [
    BBHandle, Display, Foo, GFHandle, InvalidateFileCache, Numeric, ReadCodeByte,
    ShortCopyREAD, ShortCopyWRITE, ShortREAD, UserAborted],
  DI USING [ValFormat],
  DLoadState USING [Init],
  DOutput USING [Char, Decimal, EOL, Line, Octal, Text],
  DPsb USING [ResetCache],
  Drum USING [FlushCodeSegmentCache, FlushCoreCache, Initialize],
  DSyms USING [Clean, FreeItems, Prune],
  Dump USING [Num, ResetPrinters, UserText, XferFrame, XferName],
  Event USING [AddNotifier, Item, Masks, Notifier, Notify],
  Frames USING [FlushFrameCache, Invalid],
  Gf USING [FrameGfi],
  Init USING [
    CheckMemory, CoreSwap, CoreSwapMessages, LoadStateReason, usermessage, WriteHerald],
  Lf USING [Display, GF, Handle, PC, Validate],
  Lookup USING [Signal, StateCtx],
  MachineDefs USING [BYTE, FHandle, GFHandle, ProcDesc],
  Mopcodes USING [zBRK],
  Pc USING [EvalStackEmpty, ResetCache],
  PrincOps USING [BYTE, BytePC, SignalDesc, StateVector, SVPointer],
  SDDefs USING [SD, sSignal],
  Source USING [ResetFrames],
  State USING [GetGS, GSHandle, Msg],
  Storage USING [FreeString],
  Symbols USING [ISEIndex, ISENull, RecordSENull],
  SymbolTable USING [Missing],
  TajoMisc USING [SetState],
  UserInput USING [ResetUserAbort];

InitialPack: PROGRAM
  IMPORTS BP, Commands, Cursor, DebugOps, DOutput, DPsb, Drum, DSyms,
    Dump, Event, Frames, Gf, Init, Lf, DLoadState, Lookup, Pc,
    Source, State, Storage, SymbolTable, TajoMisc, UserInput
  EXPORTS BP, Dump, Init =
  BEGIN OPEN Event, Init, MachineDefs, PrincOps;
  
  Debug: PUBLIC SIGNAL = CODE;
  UCS: PUBLIC SIGNAL = CODE;
  MapLog: PUBLIC SIGNAL = CODE;

  bootLoaded: PUBLIC BOOLEAN ← FALSE;

  data: State.GSHandle;

  event: Event.Item ← [eventMask: Event.Masks[newFiles], eventProc: Notify];

  warning: PUBLIC CoreSwapMessages;

  RestartMsg: PUBLIC PROC =
    BEGIN OPEN DOutput;
    SELECT data.restartMsg FROM
      none => RETURN;
      interrupt => Line["*** interrupt ***"L];
      punt => Line["*** Fatal System Error (Punt) ***"L];
      bootloaded => Line["*** Debugger Bootloaded ***"L];
      invalid => Line["*** Invalid Swap Reason - Context Invalid ***"L];
      maplog => Line["*** Processing VM Map ***"L];
      ENDCASE;
    data.restartMsg ← none;
    END;

  SaveSignallerGF: PROCEDURE =
    BEGIN
    pd: MachineDefs.ProcDesc ← 
      DebugOps.ShortREAD[@SDDefs.SD[SDDefs.sSignal]];
    data.sigGF ← Gf.FrameGfi[pd.gfi];
    RETURN;
    END;
  
  BreakInstToState: PROCEDURE [sp: SVPointer, b: MachineDefs.BYTE] =
    BEGIN OPEN MachineDefs;
    state: StateVector;
    DebugOps.ShortCopyREAD[
      from: sp, to: @state, nwords: SIZE[StateVector]];
    state.instbyte ← b;
    DebugOps.ShortCopyWRITE[
      to: sp, from: @state, nwords: SIZE[StateVector]];
    RETURN
    END;
  
  CodeByteFromState: PROCEDURE [state: PrincOps.SVPointer]
    RETURNS [MachineDefs.BYTE] =
    BEGIN
    f: MachineDefs.FHandle = DebugOps.ShortREAD[@state.dest];
    RETURN[DebugOps.ReadCodeByte[Lf.GF[f],Lf.PC[f]]]
    END;

  Validate: PUBLIC PROC [sv: PrincOps.SVPointer] RETURNS [BOOLEAN] =
    BEGIN
    RETURN[sv # NIL AND CodeByteFromState[sv] = Mopcodes.zBRK]
    END;

  Break: PUBLIC PROCEDURE =
    BEGIN OPEN MachineDefs;
    -- breakpoint interpreter
    sp: SVPointer = data.StatePtr;
    f: FHandle ← DebugOps.ShortREAD[@sp.dest];
    gframe: GFHandle ← DebugOps.ShortREAD[@f.accesslink];
    bp: DebugOps.BBHandle;
    IF ~Lf.Validate[f] THEN
      BEGIN
      DOutput.Text["Breakpoint"L];
      Commands.Go[];
      RETURN
      END;
    data.breakFrame ← f;
    IF (bp ← BP.FindBB[gframe, Lf.PC[f]]) = NIL THEN
      DOutput.Text["Breakpoint not found!"L]
    ELSE {
      DOutput.EOL[];
      BreakInstToState[sp, bp.inst];
      WriteBreakHerald[f,bp]};
    Commands.Go[bp];
    RETURN
    END;
  
  WriteBreakHerald: PROCEDURE [f: FHandle, b: DebugOps.BBHandle] =
    BEGIN OPEN DOutput;
    BreakNum: PROC = BEGIN Text[" #"L]; Decimal[b.num] END;
    IF b.bt.ex = octal THEN
      BEGIN
      Text["Octal-break"L]; BreakNum[]; Text[" in frame: "L];
      Octal[Lf.GF[f]]; Text[", byte-pc: "L]; Octal[b.pc];
      EOL[]
      END
    ELSE
      BEGIN
      Text[IF b.bt.bt = break THEN "Break"L ELSE "Trace"L];
      BreakNum[];
      Text[SELECT b.bt.ex FROM
	entry => " at entry to "L,
	exit => " at exit from "L,
	ENDCASE => " in "L];
      Lf.Display[f];
      IF b.condition # NIL AND DebugOps.Numeric[b.condition] THEN
	BEGIN
	s: STRING ← b.condition;
	BP.Conditionalize[b,s];
	Storage.FreeString[s];
	END;
      END;
    SELECT TRUE FROM
      Pc.EvalStackEmpty[] => NULL;
      b.bt.ex = entry AND b.symbolsAvailable => NULL;
      b.bt.ex = exit => NULL;
      ENDCASE => {EOL[]; Line[" Eval-Stack not empty!"L]};
    RETURN
    END;
  
  UCSHandler: PUBLIC PROCEDURE = {DOutput.Text["*** uncaught SIGNAL "L]; Commands.Go[]};
  
  Msg: PROCEDURE = INLINE
    BEGIN
    vf: DI.ValFormat = [none[]];
    DOutput.Text[" msg = "L];
    Dump.Num[DebugOps.ShortREAD[@data.StatePtr.stk[0]], vf];
    RETURN
    END;

  PreDeclared: PROCEDURE [u: UNSPECIFIED] RETURNS [BOOLEAN] =
    BEGIN
    Sigs: ARRAY [0..3) OF INTEGER = [-1,3,5];
    Names: ARRAY [0..3) OF STRING = ["ERROR"L, "UNWIND"L, "ABORTED"L];
    FOR i: CARDINAL IN [0..3) DO
      IF Sigs[i] = u THEN {DOutput.Text[Names[i]]; RETURN[TRUE]};
      ENDLOOP;
    RETURN[FALSE];
    END;

  PrintUCS: PUBLIC PROCEDURE =
    BEGIN
    signal: PrincOps.SignalDesc ← data.signal;
    isei: Symbols.ISEIndex ← Symbols.ISENull;
    IF PreDeclared[signal] THEN RETURN;
    isei ← Lookup.Signal[signal];
    Dump.XferName[signal, isei];
    SignalCtxFromState[signal, data.StatePtr ! SymbolTable.Missing => {Msg[]; CONTINUE}];
    Dump.XferFrame[signal];
    RETURN;
    END;

  SignalCtxFromState: PUBLIC PROC [
      cl: PrincOps.SignalDesc, sv: PrincOps.SVPointer] =
    BEGIN
    f: DebugOps.Foo ← Lookup.StateCtx[Lookup.Signal[cl], sv, in, 1];
    IF f = NIL THEN ERROR SymbolTable.Missing[NIL];
    IF f.tsei = Symbols.RecordSENull THEN RETURN;
    f.xfer ← FALSE;
    DebugOps.Display[f, TRUE ! Frames.Invalid => {
      DOutput.Char[' ]; DOutput.Octal[f]; Commands.WriteError[nGframe,FALSE]; CONTINUE}];
    END;

  NewLoadState: PUBLIC PROCEDURE [why: LoadStateReason] =
    BEGIN 
    DLoadState.Init[];
    data.initBCD ← TRUE;
    SELECT why FROM
      debug => SIGNAL Debug;
      ucs => SIGNAL UCS;
      maplog => SIGNAL MapLog;
      ENDCASE => ERROR;
    END;

  CoreSwapMsg: PUBLIC PROC [msg: CoreSwapMessages] =
    BEGIN
    IF msg = none THEN RETURN;
    DOutput.Text[SELECT msg FROM
      cantSwap => "Core image not healthy, can't swap"L,
      evalstack => "Eval-Stack not empty!"L,
      interrupt => "*** interrupt ***"L,
      maplog => "*** Processing VM Map ***"L,
      ENDCASE => ERROR];
    END;

  usermessage: PUBLIC STRING ← NIL;

  GetUserMessage: PUBLIC PROCEDURE =
    BEGIN OPEN MachineDefs;
    s: StateVector;
    DebugOps.ShortCopyREAD[
      from: data.StatePtr, to: @s, nwords: SIZE[StateVector]];
    Init.usermessage ← IF s.stkptr = 1 THEN s.stk[0] ELSE NIL;
    s.stkptr ← 0;
    DebugOps.ShortCopyWRITE[
      from: @s, to: data.StatePtr, nwords: SIZE[StateVector]];
    RETURN
    END;

--  type: Cursor.Type = Cursor.UniqueType[];

  FlushCaches: PUBLIC Event.Notifier =
    BEGIN
--    toilet: Cursor.Object ← [
--      info: [type,8,8],
--      array: [36B, 42B, 102B, 702B, 102B, 102B, 102B, 7702B, 70042B,
--	120142B, 114602B, 103002B, 60004B, 14004B, 3004B, 774B]];
--    Cursor.Store[@toilet];
    SELECT why FROM
      newSession =>
	BEGIN
	Cursor.Set[textPointer];
	CheckMemory[];
	DebugOps.InvalidateFileCache[];
	Drum.FlushCodeSegmentCache[];
	Drum.FlushCoreCache[];
	Drum.Initialize[];
	BP.ResetBBs[];
	Source.ResetFrames[];
	SaveSignallerGF[];
	data.loggedIn ← FALSE;
	data.worryBreaks ← FALSE;
	Frames.FlushFrameCache[];
	DPsb.ResetCache[];
	FlushCaches[flushSymbols];
--	Cursor.Set[questionMark];
	Event.Notify[why];
	[] ← TajoMisc.SetState[on];
	END;
      newFiles => 
	BEGIN
	DebugOps.InvalidateFileCache[];
	DSyms.Clean[];
	END;
      flushSymbols =>
	BEGIN
	DSyms.Prune[];
	DSyms.FreeItems[];
	Pc.ResetCache[];
	Dump.ResetPrinters[];
	END;
      resumeSession =>
	BEGIN
	Frames.FlushFrameCache[];
	DPsb.ResetCache[];
--	Cursor.Set[questionMark];
	Event.Notify[why];
	[] ← TajoMisc.SetState[on];
	END;
      resumeDebuggee, abortSession =>
	BEGIN
--	Cursor.Set[questionMark];
	Event.Notify[why];
--	Cursor.Store[@toilet];
	Frames.FlushFrameCache[];
	DPsb.ResetCache[];
	Drum.FlushCodeSegmentCache[];
	Drum.FlushCoreCache[];
	END;
      ENDCASE;
--    Cursor.Set[textPointer];
    END;

  Notify: Event.Notifier = {IF why = newFiles THEN FlushCaches[why]};

  DebugState: TYPE = {installing, initial, ucs, maplog};

  StartDebugger: PUBLIC PROC [boot: BOOLEAN ← TRUE] =
    BEGIN
    case: DebugState ← installing;
    bootLoaded ← ~boot;
    data ← State.GetGS[];
    DO
      Init.WriteHerald[TRUE];
      DebugIt[case !
	DebugOps.UserAborted => {UserInput.ResetUserAbort[]; RESUME};
	Debug => {case ← initial; CONTINUE};
	UCS => {case ← ucs; CONTINUE};
	MapLog => {case ← maplog; CONTINUE}];
      FlushCaches[newSession];
      IF warning # none THEN {CoreSwapMsg[warning]; DOutput.EOL[]};
      ENDLOOP;
    END;

  DebugIt: PROC [case: DebugState] =
    BEGIN
    Init.WriteHerald[];
    SELECT case FROM
      installing => CoreSwap[install];
      ucs => BEGIN UCSHandler[]; CoreSwap[resume] END;
      maplog => CoreSwap[proceed];
      ENDCASE;
    DO
      IF Init.usermessage # NIL THEN Dump.UserText[Init.usermessage];
      Commands.Go[];
      CoreSwap[proceed];
      ENDLOOP;
    END;

  Event.AddNotifier[@event];

  END.