-- CoreMap.Mesa
-- Edited by  Sandman on May 21, 1980  12:14 PM
-- Edited by  Bruce on September 26, 1980  7:35 PM
-- Edited by  Johnsson on July 16, 1980  8:21 AM

DIRECTORY
  Actions USING [],
  AltoDefs USING [MaxMDSPage, PageCount, PageNumber, PageSize, PagesPerMDS],
  Ascii USING [CR, SP],
  BcdDefs USING [MTIndex, NameRecord],
  BcdOps USING [BcdBase, MTHandle, NameString, ProcessModules],
  ControlDefs USING [FrameCodeBase, GFT, GlobalFrameHandle, NullGlobalFrame],
  DebugFormat USING [NumberFormat],
  DebugOps USING [ShortCopyREAD, ShortREAD, UserAborted],
  DOutput USING [Blanks, Char, Number, Octal, Text],
  Init USING [bootLoaded],
  Inline USING [BITAND, HighHalf, LongCOPY, LowHalf],
  DLoadState USING [
    AcquireBcd, Enumerate, GetMap, Acquire, Map, ReleaseBcd, Release, ReleaseMap],
  MachineDefs USING [ConfigIndex],
  SegmentDefs USING [BankIndex, FileSegmentHandle, FrameDS, HeapDS, PageCount, PageNumber, SegmentHandle, SegmentObject, SystemDS, TableDS],
  State USING [GetGS],
  Storage USING [Free, FreePages, FreeString, Node, Pages, Prune, String],
  Strings USING [AppendSubString, SubStringDescriptor],
  SwapperOps USING [BusyPage, FreePage, PageMap, RegionTable, SystemTable];


CoreMap: PROGRAM 
  IMPORTS BcdOps, DebugOps, DOutput, DLoadState, Init, Inline, State, Storage, Strings
  EXPORTS Actions
  SHARES SegmentDefs =

BEGIN
OPEN AltoDefs, Ascii, DOutput, SegmentDefs, MachineDefs;

  byte: DebugFormat.NumberFormat = [8,FALSE,TRUE,3];
  pageNF: DebugFormat.NumberFormat = [8,FALSE,TRUE,4];
  typeNF: DebugFormat.NumberFormat = [8,FALSE,TRUE,0];
  word: DebugFormat.NumberFormat = [8,FALSE,TRUE,6];

  WriteLongPointer: PROCEDURE [p: LONG POINTER] =
    BEGIN OPEN Inline;
    high: CARDINAL =
      (IF CARDINAL[LowHalf[p]] > 77777B THEN 1 ELSE 0) + 2*HighHalf[p];
    IF high # 0 THEN Number[high, [8,FALSE,TRUE,2]]
    ELSE Blanks[2];
    Number[BITAND[LowHalf[p], 77777B],[8,high # 0,TRUE,5]];
    RETURN
    END;

  LongAddressFromPage: PROCEDURE [page: PageNumber] RETURNS [LONG POINTER] =
    BEGIN
    RETURN[LOOPHOLE[LONG[page]*PageSize]]
    END;

  PrintNonSeg: PROCEDURE [
    state: {free, busy}, bank: CARDINAL, page: PageNumber, count: PageCount] =
    BEGIN
    segBase: PageNumber;
    segBase ← bank*PagesPerMDS + page;
    Number[segBase, pageNF]; Char[SP];
    WriteLongPointer[LongAddressFromPage[segBase]];
    Blanks[5];
    Number[count,pageNF];
    Text[SELECT state FROM
      free => " free"L,
      ENDCASE => " busy"L];
    END;

  PrintSeg: PROCEDURE [
    bank: CARDINAL, page: PageNumber, seg: SegmentHandle, count: PageCount] =
    BEGIN
    copiedSeg:  SegmentObject;
    segBase: PageNumber;
    IF seg = SwapperOps.FreePage THEN
      {PrintNonSeg[free, bank, page, count]; Char[CR]; RETURN};
    IF seg = SwapperOps.BusyPage THEN
      {PrintNonSeg[busy, bank, page, count]; Char[CR]; RETURN};
    DebugOps.ShortCopyREAD[
      to: @copiedSeg, from: seg, nwords: SIZE[SegmentObject]];
    segBase ← copiedSeg.VMpage;
    Number[segBase, pageNF]; Char[SP];
    WriteLongPointer[LongAddressFromPage[segBase]];
    WITH s: copiedSeg SELECT FROM
      data =>
	BEGIN
	Blanks[5];
	Number[count,pageNF];
	Text[" data "L];
	SELECT s.type FROM
	  FrameDS => Text["frames"L];
	  SystemDS => Text["system"L];
	  HeapDS => Text["heap"L];
	  TableDS => Text["table"L];
	  5 => Text["bitmap"L];
	  6 => Text["stream buffer"L];
	  7 => Text["pup buffer"L];
	  ENDCASE => Number[s.type,typeNF];
	END;
      file =>
	BEGIN
	part1: CARDINAL = DebugOps.ShortREAD[@s.file.fp.serial];
	Char[SP];
	Number[s.base,pageNF];  Char[SP];
	Number[s.pages,byte];
	Text[" file SN"L];
	IF part1 # 0 THEN {Octal[part1]; Text[", "L]};
	Octal[DebugOps.ShortREAD[@s.file.fp.serial.part2]];
	SELECT s.class FROM
	  code => Text[" code"L];
	  ENDCASE;
	Char[' ];
	IF ~s.write THEN Char[' ] ELSE Char['W];
	IF s.lock > 0 THEN
	  BEGIN
	  Text[" lock="L];
	  Octal[s.lock];
	  END;
	SELECT s.class FROM
	  code => PrintFileName[LOOPHOLE[seg]];
	  ENDCASE;
	END;
      ENDCASE;
    Char[CR];
    END;

  PrintFileName: PROCEDURE[seg: FileSegmentHandle] =
    BEGIN
    node:  POINTER TO NameItem;
    found: BOOLEAN ← FALSE;
    FOR node ← NameList, node.next UNTIL node = NIL DO
      IF node.code = seg THEN
	BEGIN
	Char[SP];
	Text[node.module];
	found ← TRUE;
	END;
      ENDLOOP;
    RETURN
    END;

  NameItem:  TYPE = RECORD [
    next:  POINTER TO NameItem,
    code: FileSegmentHandle,
    module:  STRING];

  NameList: POINTER TO NameItem ← NIL;

  SegmentFromFrame: PROCEDURE [g: ControlDefs.GlobalFrameHandle] RETURNS [seg: FileSegmentHandle] =
    BEGIN
    c: ControlDefs.FrameCodeBase;
    DebugOps.ShortCopyREAD[
      from: @g.code, to: @c, nwords: SIZE[ControlDefs.FrameCodeBase]];
    seg ← SegmentFromCodePointer[c];
    IF seg = SwapperOps.FreePage OR seg=SwapperOps.BusyPage THEN RETURN[NIL];
    RETURN
    END;
  
  SegmentFromCodePointer: PROCEDURE [c: ControlDefs.FrameCodeBase] RETURNS [seg: FileSegmentHandle] =
    BEGIN
    s: SegmentHandle;
    IF c.highByte # 0 THEN RETURN[c.handle];
    s ← SegFromPage[bank: c.otherByte, p: c.offset/AltoDefs.PageSize];
    RETURN[LOOPHOLE[s]];
    END;

  FindFrameNames: PROCEDURE = 
    BEGIN OPEN DLoadState;
    DoOneBcd: PROCEDURE [config: ConfigIndex] RETURNS [BOOLEAN] =
      BEGIN
      bcd: BcdOps.BcdBase = AcquireBcd[config];
      map: Map = GetMap[config];
      DoOneModule: PROCEDURE [mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOLEAN] =
	BEGIN OPEN ControlDefs;
	frame: GlobalFrameHandle =
  	  DebugOps.ShortREAD[@GFT[map[mth.gfi]].frame];
	seg: FileSegmentHandle;
	IF frame = NullGlobalFrame THEN RETURN[FALSE];
	seg ← SegmentFromFrame[frame];
	IF seg # NIL THEN AddName[seg, bcd, mth.name];
	RETURN[FALSE];
	END;
      [] ← BcdOps.ProcessModules[bcd, DoOneModule];
      ReleaseMap[map];
      ReleaseBcd[bcd];
      RETURN[FALSE];
      END;

    [] ← Acquire[ ! ANY => GOTO noNames];
    [] ← Enumerate[recentfirst, DoOneBcd];
    Release[];
    EXITS
      noNames => NULL;
    END;

  AddName: PROCEDURE [code: FileSegmentHandle, bcd: BcdOps.BcdBase, name: BcdDefs.NameRecord] =
    BEGIN
    ssb: BcdOps.NameString = LOOPHOLE[bcd+bcd.ssOffset];
    ss: Strings.SubStringDescriptor ←
      [base: @ssb.string, offset: name, length: ssb.size[name]];
    s: STRING ← Storage.String[ssb.size[name]];
    node: POINTER TO NameItem ← Storage.Node[SIZE[NameItem]];
    Strings.AppendSubString[s, @ss];
    node↑ ← [next: NameList, code: code, module: s];
    NameList ← node;
    END;

  FreeNames: PROCEDURE =
    BEGIN
    node:  POINTER TO NameItem;
    FOR node ← NameList, NameList UNTIL node = NIL DO
      NameList ← node.next;
      Storage.FreeString[node.module];
      Storage.Free[node];
      ENDLOOP;
    [] ← Storage.Prune[];
    END;

  pageTables: ARRAY BankIndex OF SwapperOps.PageMap ← ALL[NIL];

  SegFromPage: PROCEDURE [
    bank: CARDINAL, p: PageNumber] RETURNS [SegmentHandle] =
    BEGIN
    IF pageTables[bank] = NIL THEN RETURN[NIL];
    RETURN[pageTables[bank][p]]
    END;

  LP: PROCEDURE [low, high: CARDINAL] RETURNS [LONG POINTER] =
    MACHINE CODE BEGIN END;

  GetPageMaps: PROCEDURE =
    BEGIN OPEN SwapperOps;
    table: POINTER TO SystemTable = State.GetGS[].gsh.ESV.tables;
    regions: RegionTable;
    bank: BankIndex;
    Masks: ARRAY BankIndex OF CARDINAL = [
      100000B, 40000B, 20000B, 10000B, 4000B, 2000B, 1000B, 400B, 200B,
      100B, 40B, 20B, 10B, 4B, 2B, 1B];
    DebugOps.ShortCopyREAD[
      to: @regions,
      from: DebugOps.ShortREAD[@table.regions],
      nwords: SIZE[RegionTable]];
    pageTables ← ALL[NIL];
    pageTables[0] ← Storage.Pages[1];
    DebugOps.ShortCopyREAD[
      from: DebugOps.ShortREAD[@table.mdsMap], to: pageTables[0], nwords: PagesPerMDS];
    IF Init.bootLoaded THEN RETURN;
    FOR bank IN [1..LAST[BankIndex]] DO
      IF regions[bank] # NIL THEN
	BEGIN
	pageTables[bank] ← Storage.Pages[1];
	Inline.LongCOPY[
	  from: LP[0, bank], to: pageTables[bank], nwords: PagesPerMDS];
	END;
      ENDLOOP;
    END;

  FreePageMaps: PROCEDURE =
    BEGIN
    bank: BankIndex;
    FOR bank IN BankIndex DO
      IF pageTables[bank] # NIL THEN Storage.FreePages[pageTables[bank]];
      ENDLOOP;
    END;

  PrintCoremap: PUBLIC PROCEDURE =
    BEGIN
    bank: BankIndex;
    curSeg, nextSeg: SegmentHandle;
    count: PageCount;
    page, startPage: PageNumber;
    BEGIN ENABLE UNWIND => BEGIN FreePageMaps[]; FreeNames[]; END;
    GetPageMaps[];
    FindFrameNames[];
    Char[CR];
    FOR bank IN BankIndex DO
      IF pageTables[bank] = NIL THEN LOOP;
      curSeg ← SegFromPage[bank, startPage ← 0];
      page ← count ← 1;
      UNTIL page > MaxMDSPage DO
        ENABLE DebugOps.UserAborted => EXIT;
        nextSeg ← SegFromPage[bank, page];
        IF nextSeg # curSeg THEN
	  BEGIN
	  PrintSeg[bank, startPage, curSeg, count];
	  curSeg ← nextSeg;
	  startPage ← page;
	  count ← 1;
	  END
        ELSE count ← count + 1;
        page ← page + 1;
        REPEAT
          FINISHED => PrintSeg[bank, startPage, curSeg, count];
        ENDLOOP;
      ENDLOOP;
    END;
    FreePageMaps[];    FreeNames[];
    Char[CR];
    RETURN
    END;

  END...