-- XDSwap.Mesa  Edited by:
  -- Bruce on October 8, 1980  6:56 PM
  -- Sandman on July 23, 1980  10:30 AM

DIRECTORY
  AltoDefs USING [MaxMDSPage],
  AltoHardware USING [BankRegister, BankRegisters],
  BcplOps USING [BcplInLd, BcplJSR, BcplOutLd],
  BP USING [Validate],
  Commands USING [Go],
  ControlDefs USING [SVPointer, TraceOff, TrapStatus],
  CoreSwapDefs USING [
    ExternalStateVector, PuntInfo, PuntTable, SVPointer, SwapReason, VersionID],
  DebugOps USING [Abort, ShortCopyREAD, ShortREAD],
  DHeap USING [Zero],
  DPsb USING [State],
  Dump USING [UserText],
  FrameDefs USING [UnlockCode],
  FrameOps USING [MyGlobalFrame, MyLocalFrame],
  Gf USING [NewLink],
  ImageDefs USING [StopMesa, UserCleanupProc],
  Init USING [
    Break, CoreSwapMsg, Debug, FlushCaches, GetUserMessage, NewLoadState, UCSHandler,
    usermessage, warning, bootLoaded],
  InitXD USING [ourBitmapSeg],
  Inline USING [LowHalf],
  OsStaticDefs USING [OsStaticRecord, OsStatics],
  Pc USING [EvalStackEmpty],
  PrincOps USING [SignalDesc],
  ProcessDefs USING [DisableInterrupts, EnableInterrupts],
  ProcessOps USING [ReadWDC, WriteWDC],
  Region USING [Handle, Index],
  SDDefs USING [SD, sXferTrap],
  SegmentDefs USING [
    DataSegmentHandle, DeleteDataSegment, memConfig, ObjectHandle, SwapOut],
  State USING [GetGS, GSHandle],
  SwapperOps USING [DisableBank, EnumerateObjects, mdsIndex, regions, SwapOutCodeSeg],
  TrapOps USING [ReadXTS, WriteXTS],
  TajoMisc USING [SetState],
  UserTerminalOps USING [SetBitmapSpace];

XDSwap: PROGRAM
  IMPORTS BcplOps, BP, Commands, DebugOps, DHeap, DPsb, Dump,
    FrameDefs, FrameOps, Gf, ImageDefs, Init, InitXD, Inline,
    Pc, ProcessDefs, ProcessOps, SegmentDefs, SwapperOps,
    State, TrapOps, TajoMisc, UserTerminalOps
  EXPORTS Init, InitXD
  SHARES SegmentDefs =
  BEGIN OPEN Init, PrincOps;

  data: State.GSHandle ← State.GetGS[];
  saveDWT: AltoHardware.BankRegister ← AltoHardware.BankRegisters[Emulator];

  AbandonHyperspace: PUBLIC PROCEDURE =
    BEGIN OPEN SegmentDefs, SwapperOps;
    UpdateSegs: PROC [object: ObjectHandle] RETURNS [BOOLEAN] = {
      WITH o: object SELECT FROM
	segment => IF o.VMpage > AltoDefs.MaxMDSPage THEN
	  WITH s: o SELECT FROM
	    file =>
	      IF s.class = code THEN SwapOutCodeSeg[@s] ELSE SwapOut[@s];
	    data => DeleteDataSegment[@s];
	  ENDCASE;
	ENDCASE;
      RETURN[FALSE]};
    r: Region.Handle;
    IF InitXD.ourBitmapSeg # NIL THEN {
      DeleteDataSegment[InitXD.ourBitmapSeg]; InitXD.ourBitmapSeg ← NIL};
    FOR i: Region.Index IN Region.Index DO
      IF i = mdsIndex THEN LOOP;
      IF (r ← regions[i]) # NIL THEN r.disable[TRUE];
      ENDLOOP;
    [] ← EnumerateObjects[segment, UpdateSegs];
    FOR i: Region.Index IN Region.Index DO
      IF i = mdsIndex THEN LOOP;
      IF regions[i] # NIL THEN DisableBank[i];
      ENDLOOP;
    FrameDefs.UnlockCode[FrameOps.MyGlobalFrame[]];
    END;

  CoreSwap: PUBLIC PROCEDURE [why: CoreSwapDefs.SwapReason] =
    BEGIN OPEN BcplOps, ControlDefs, SDDefs;
    ourDWT: AltoHardware.BankRegister;
    wdc: CARDINAL;
    xferTrapStatus: TrapStatus;
    xferTrapHandler: UNSPECIFIED;
    e: CoreSwapDefs.ExternalStateVector ← data.ESV;
    alto2xm: BOOLEAN ← SegmentDefs.memConfig.AltoType = AltoIIXM;
    flag: [0..2];

    IF Init.bootLoaded THEN
      BEGIN
      IF why = quit OR why = kill THEN ImageDefs.StopMesa[];
      CoreSwapMsg[cantSwap];
      SIGNAL DebugOps.Abort;
      END;
    DO
    e.reason ← why;
    FlushCaches[IF why = kill THEN abortSession ELSE resumeDebuggee];
    IF why = install THEN {
      [] ← TajoMisc.SetState[disconnected]; UserTerminalOps.SetBitmapSpace[NIL,0]}
    ELSE [] ← TajoMisc.SetState[off];
    ImageDefs.UserCleanupProc[OutLd];
    data.worryEntry ← FALSE;
    ProcessDefs.DisableInterrupts[];
    xferTrapHandler ← SD[sXferTrap];
    SD[sXferTrap] ← FrameOps.MyLocalFrame[];
    xferTrapStatus ← TrapOps.ReadXTS[];
    TrapOps.WriteXTS[TraceOff];
    wdc ← ProcessOps.ReadWDC[];
    IF alto2xm THEN ourDWT ← AltoHardware.BankRegisters[DWT];
    flag ← BcplOutLd[OutLd, @data.selfFP, @e];
    ProcessOps.WriteWDC[wdc];
    SD[sXferTrap] ← xferTrapHandler;
    ProcessDefs.EnableInterrupts[];
    IF flag = 0 THEN	-- just completed OutLd
      BEGIN
      IF why = install THEN ImageDefs.StopMesa[];
      IF alto2xm THEN AltoHardware.BankRegisters[DWT] ← saveDWT;
      IF why = cleanmaplog THEN RETURN;
      e.level ← data.level;
      BcplInLd[InLd,@data.debuggeeFP,@e];
      END;
    IF alto2xm THEN 
      BEGIN
      saveDWT ← AltoHardware.BankRegisters[DWT];
      AltoHardware.BankRegisters[DWT] ← ourDWT;
      END;
    TrapOps.WriteXTS[xferTrapStatus];
    IF e.level # data.level THEN AbandonHyperspace[];
    ImageDefs.UserCleanupProc[InLd];

    [] ← TajoMisc.SetState[disconnected];
    data.ESV ← e;
    data.StatePtr ← e.state;
    data.signal ← LOOPHOLE[0];
    data.breakFrame ← NIL;
    usermessage ← NIL;
    warning ← none;

    SELECT flag FROM
      1 =>	-- just started by InLd
	BEGIN
	SetDebugeeType[];
	Init.bootLoaded ← FALSE;
	SELECT e.reason FROM
	  breakpoint, worrybreak, interrupt =>
	    BEGIN
	    IF e.reason = worrybreak THEN data.worryEntry ← TRUE;
	    IF ~BP.Validate[e.state] OR e.reason = interrupt THEN
	      BEGIN
	      IF ~Pc.EvalStackEmpty[] THEN warning ← evalstack;
	      IF e.level # data.level THEN
		BEGIN
		data.restartMsg ← interrupt;
		NewLoadState[debug];
		END;
	      FlushCaches[resumeSession];
	      CoreSwapMsg[interrupt];
	      Commands.Go[];
	      END
	    ELSE {FlushCaches[resumeSession]; Break[]};
	    why ← proceed;
	    END;
	  explicitcall, worrycall =>
	    BEGIN
	    GetUserMessage[];
	    IF e.reason = worrycall THEN data.worryEntry ← TRUE;
	    IF e.level # data.level THEN NewLoadState[debug];
	    FlushCaches[resumeSession];
	    IF usermessage # NIL THEN Dump.UserText[usermessage];
	    Commands.Go[];
	    why ← proceed;
	    END;
	  uncaughtsignal =>
	    BEGIN
	    data.signal ←
	      LOOPHOLE[Gf.NewLink[DebugOps.ShortREAD[@e.state.stk[1]]]];
	    IF e.level # data.level THEN NewLoadState[ucs];
	    FlushCaches[resumeSession];
	    UCSHandler[];
	    why ← resume;
	    END;
	  punt =>
	    BEGIN
	    data.restartMsg ← punt;
	    Init.bootLoaded ← TRUE;
	    data.StatePtr ← data.ESV.state ← Inline.LowHalf[DPsb.State[]]; 
	    NewLoadState[debug];
	    END;
	  return => {FlushCaches[resumeSession]; EXIT};
	  ENDCASE => InvalidMessage[];
	END;
      2 =>	-- just booted
	BEGIN OPEN CoreSwapDefs;
	punt: POINTER TO PuntTable = DebugOps.ShortREAD[PuntInfo];
	Init.bootLoaded ← TRUE;
	SetDebugeeType[];  --so data can be intialized before READs
	data.restartMsg ← bootloaded;
	IF punt # NIL THEN DebugOps.ShortCopyREAD[
	  from: @punt.puntESV, to: @data.ESV, nwords: SIZE[ExternalStateVector]]
	ELSE DHeap.Zero[@data.ESV, SIZE[ExternalStateVector]];
	data.ESV.bitmap ← NIL;
	data.StatePtr ← data.ESV.state ← Inline.LowHalf[DPsb.State[]]; 
	NewLoadState[debug];
	END;
      ENDCASE;
    ENDLOOP;

    data.ESV ← e;
    RETURN
    END;

  SetDebugeeType: PROCEDURE =
    BEGIN OPEN OsStaticDefs, BcplOps;
    vers: ARRAY [0..1] OF WORD ← [61014B, 1400B];
    OsStatics.AltoVersion ← BcplJSR[JSR, @vers, 0];
    data.mds ← 0;
    IF data.ESV.versionident = CoreSwapDefs.VersionID OR Init.bootLoaded THEN RETURN;
    InvalidMessage[];
    END;

  InvalidMessage: PROCEDURE =
    BEGIN
    data.restartMsg ← invalid;
    SIGNAL Debug;
    END;

END.