-- XMDebug.Mesa
-- Edited by:  Levin on October 5, 1979  1:39 PM

DIRECTORY
  AltoDefs: FROM  "altodefs" USING [PageSize],
  BootDefs: FROM  "bootdefs" USING [BusyPage, FreePage, PageMap, SystemTableHandle],
  ControlDefs: FROM  "controldefs" USING [FrameCodeBase, GlobalFrameHandle, InstWord],
  DebugData: FROM  "debugdata" USING [ESV],
  DebugUsefulDefs: FROM  "debugusefuldefs" USING [CopyRead, CopyWrite, SREAD],
  DebugUtilityDefs: FROM  "debugutilitydefs" USING [AllocOnDrum, RemoveFromDrum, MapUserSegment],
  DebugXMDefs: FROM  "debugxmdefs",
  InlineDefs: FROM  "inlinedefs" USING [HighHalf, LongNumber],
  MemoryOps: FROM  "memoryops" USING [BankIndex],
  Mopcodes: FROM  "mopcodes" USING [zRBL, zWBL],
  SegmentDefs: FROM  "segmentdefs" USING [DeleteFileSegment, FileSegmentAddress, FileSegmentHandle,
    FileSegmentObject, SegmentHandle, SegmentObject, SwapIn, Unlock],
  XMESA: FROM  "xmesaops" USING [Bank1X, Bank2X, Bank3X, InUseSeal,
    XFileSegmentHandle, XFileSegmentObject, XMremote, XSegInfo];


XMDebug: PROGRAM
  IMPORTS DDptr: DebugData, DebugUsefulDefs, DebugUtilityDefs, InlineDefs, SegmentDefs
  EXPORTS DebugXMDefs
  SHARES XMESA, SegmentDefs =

BEGIN

GFH: TYPE = ControlDefs.GlobalFrameHandle;
SH: TYPE = SegmentDefs.SegmentHandle;
SO: TYPE = SegmentDefs.SegmentObject;
FSH: TYPE = SegmentDefs.FileSegmentHandle;
FSO: TYPE = SegmentDefs.FileSegmentObject;
XFSH: TYPE = XMESA.XFileSegmentHandle;
XFSO: TYPE = XMESA.XFileSegmentObject;
XSegInfo: TYPE = XMESA.XSegInfo;


-- Utilities

DoLongRead: PROCEDURE[LONG POINTER] RETURNS [WORD] =
  MACHINE CODE BEGIN Mopcodes.zRBL, 0; END;

DoLongWrite: PROCEDURE[WORD, LONG POINTER] =
  MACHINE CODE BEGIN Mopcodes.zWBL, 0; END;

XMRead: PUBLIC PROCEDURE [from: LONG POINTER] RETURNS [data: UNSPECIFIED] =
  BEGIN
  data ← DoLongRead[from];
  RETURN
  END;

XMWrite: PUBLIC PROCEDURE [to: LONG POINTER, data: UNSPECIFIED] =
  BEGIN
  seg: SH;
  SegObj: SO;

  DoLongWrite[data, to];

  -- check for codesegment and write on Drum

  seg ← SegmentFromLongPointer[to];
  IF seg = BootDefs.BusyPage OR seg = BootDefs.FreePage THEN RETURN;
  DebugUsefulDefs.CopyRead[to: @SegObj, from: seg, nwords: SIZE[SO]];
  WITH us: SegObj SELECT FROM
    file =>
      IF us.class = code THEN
	BEGIN
	pi: POINTER TO ControlDefs.InstWord;
	chocolate: XFSH = @cSegObj;
	vanilla: FSH = @vSegObj;
	cSegObj: XFSO;
	vSegObj: FSO;
	xs: XSegInfo;
	dseg: FSH;
	ufsh: FSH = LOOPHOLE[seg];
	ChocolateToVanilla[chocolate, vanilla, ufsh];
	dseg ← DebugUtilityDefs.MapUserSegment[ufsh];
	SegmentDefs.SwapIn[dseg];
	dseg.write ← TRUE;
	WITH c: chocolate SELECT FROM
	  remote =>
	    BEGIN
	    IF c.proc # XMESA.XMremote THEN ERROR;
	    DebugUsefulDefs.CopyRead[to: @xs, from: c.info, nwords: SIZE[XSegInfo]];
	    IF xs.seal # XMESA.InUseSeal THEN ERROR;
	    END;
	  ENDCASE => ERROR;
	pi ← SegmentDefs.FileSegmentAddress[dseg]+
	  (LOOPHOLE[to, InlineDefs.LongNumber].lowbits - xs.XMpage*AltoDefs.PageSize);
	pi↑ ← data;
	SegmentDefs.Unlock[dseg];
	SegmentDefs.DeleteFileSegment[dseg];
	VanillaToChocolate[vanilla, chocolate, ufsh];
	END;
    ENDCASE;
  RETURN
  END;

XMAllocOnDrum: PUBLIC PROCEDURE[g: GFH] RETURNS[p: POINTER] =
  BEGIN
  chocolate: XFSH = @cSegObj;
  vanilla: FSH = @vSegObj;
  cSegObj: XFSO;
  vSegObj: FSO;
  seg: FSH;

  seg ← SegmentFromFrame[g];
  ChocolateToVanilla[chocolate, vanilla, seg];
  p ← DebugUtilityDefs.AllocOnDrum[seg
	!UNWIND => VanillaToChocolate[vanilla, chocolate, seg]];
  VanillaToChocolate[vanilla, chocolate, seg];
  RETURN
  END;

XMFreeOnDrum: PUBLIC PROCEDURE[g: GFH] =
  BEGIN
  chocolate: XFSH = @cSegObj;
  vanilla: FSH = @vSegObj;
  cSegObj: XFSO;
  vSegObj: FSO;
  seg: FSH;

  seg ← SegmentFromFrame[g];
  ChocolateToVanilla[chocolate, vanilla, seg];
  DebugUtilityDefs.RemoveFromDrum[seg
	!UNWIND => VanillaToChocolate[vanilla, chocolate, seg]];
  VanillaToChocolate[vanilla, chocolate, seg];
  END;


ChocolateToVanilla: PROCEDURE [chocolate: XFSH, vanilla: FSH, seg: FSH] =
  BEGIN
  xs: XSegInfo;

  DebugUsefulDefs.CopyRead[to: chocolate, from: seg, nwords: SIZE[XFSO]];
  vanilla↑ ← LOOPHOLE[chocolate↑];
  WITH c: chocolate SELECT FROM
    remote =>
      BEGIN
      IF c.proc # XMESA.XMremote THEN ERROR;
      DebugUsefulDefs.CopyRead[to: @xs, from: c.info, nwords: SIZE[XSegInfo]];
      IF xs.seal # XMESA.InUseSeal THEN ERROR;
      END;
    ENDCASE => ERROR;
  vanilla.location ← disk[xs.hint];
  DebugUsefulDefs.CopyWrite[to: seg, from: vanilla, nwords: SIZE[FSO]];
  END;


VanillaToChocolate: PROCEDURE [vanilla: FSH, chocolate: XFSH, seg: FSH] =
  BEGIN
  xs: XSegInfo;

  DebugUsefulDefs.CopyRead[to: vanilla, from: seg, nwords: SIZE[FSO]];
  chocolate.file ← vanilla.file;
  chocolate.base ← vanilla.base;
  chocolate.pages ← vanilla.pages;
  chocolate.lock ← vanilla.lock;
  WITH v: vanilla SELECT FROM
    disk =>
      WITH c: chocolate SELECT FROM
	remote =>
	  BEGIN
	  DebugUsefulDefs.CopyRead[to: @xs, from: c.info, nwords: SIZE[XSegInfo]];
	  IF xs.seal # XMESA.InUseSeal THEN ERROR;
	  xs.hint ← v.hint;
	  DebugUsefulDefs.CopyWrite[to: c.info, from: @xs, nwords: SIZE[XSegInfo]];
	  END;
	ENDCASE => ERROR;
    ENDCASE => ERROR;
  DebugUsefulDefs.CopyWrite[to: seg, from: chocolate, nwords: SIZE[XFSO]];
  END;


SegmentFromFrame: PROCEDURE [g: GFH] RETURNS [FSH] =
  BEGIN
  seg: SH;
  segment: SO;
  c: ControlDefs.FrameCodeBase;
  DebugUsefulDefs.CopyRead[from: @g.code, to: @c, nwords: SIZE[ControlDefs.FrameCodeBase]];
  IF c.highByte # 0 THEN RETURN[c.handle];
  seg ← SegmentFromLongPointer[c.longbase];
  IF seg = BootDefs.FreePage OR seg = BootDefs.BusyPage THEN ERROR;
  DebugUsefulDefs.CopyRead[from: seg, to: @segment, nwords: SIZE[SO]];
  WITH segment SELECT FROM file => RETURN[LOOPHOLE[seg]]; ENDCASE => ERROR
  END;

SegmentFromLongPointer: PROCEDURE [p: LONG POINTER] RETURNS [seg: SH] =
  BEGIN
  bank: MemoryOps.BankIndex;
  page: [0..256);
  table: BootDefs.SystemTableHandle = DDptr.ESV.tables;

  bank ← InlineDefs.HighHalf[p];
  IF bank ~IN MemoryOps.BankIndex THEN ERROR;
  page ← LOOPHOLE[p, InlineDefs.LongNumber].lowbits/AltoDefs.PageSize;
  IF table ~= NIL THEN
    BEGIN OPEN DebugUsefulDefs;
    page0map: POINTER TO ARRAY [0..XMESA.Bank3X] OF SegmentDefs.SegmentHandle ← SREAD[@table.pagemap];
    pagemap: POINTER TO BootDefs.PageMap;

    pagemap ←
      SELECT bank FROM
	1 => SREAD[@page0map[XMESA.Bank1X]],
	2 => SREAD[@page0map[XMESA.Bank2X]],
	3 => SREAD[@page0map[XMESA.Bank3X]],
	ENDCASE => page0map;
    IF pagemap = NIL THEN ERROR;
    RETURN[SREAD[@pagemap[page]]]
    END
  ELSE ERROR
  END;

END...