-- RealMemoryImplDLion.mesa
-- Last edited by Luniewski, March 27, 1981  11:15 AM

DIRECTORY
  DeviceCleanup USING [Await, Item, Reason],
  DLionInputOutput USING [firstReservedPage, numberVirtualPages,
    ReservedMemoryUse],
  Environment USING [bitsPerWord, PageCount, PageNumber, wordsPerPage],
  HeadStartChain USING [Start],
  Inline USING [LongCOPY],
  PageMap USING [Assoc, Flags, flagsClean, flagsVacant, GetF, RealPageNumber,
    SetF, Value, valueVacant],
  PrincOps USING [BytePC, ControlLink, EPRange, PrefixHandle],
  PrincOpsRuntime USING [GFT],
  RealMemory USING [],
  Runtime USING [GlobalFrame],
  RuntimeInternal USING [Codebase],
  Space USING [Create, Delete, GetAttributes, GetHandle, Handle, LongPointer,
    LongPointerFromPage, PageFromLongPointer, virtualMemory, VMPageNumber],
  SpecialSpace USING [DonateDedicatedRealMemory];

RealMemoryImplDLion: MONITOR
  IMPORTS DeviceCleanup, Inline, PageMap,
    RemainingHeads: HeadStartChain, Runtime, RuntimeInternal, Space,
    SpecialSpace
  EXPORTS DLionInputOutput, HeadStartChain, RealMemory
  SHARES PageMap =
BEGIN

maxDLionRealPages: CARDINAL = 768*4; -- "Fat" Dandelions can have up to 768K words

allocMap: PUBLIC DESCRIPTOR FOR ARRAY OF WORD ← DESCRIPTOR[allocMapArray];
allocMapArray:
  ARRAY [0..
    (maxDLionRealPages + Environment.bitsPerWord - 1)
      /Environment.bitsPerWord) OF WORD;
  -- initial state not important

currentReservedMemoryUse: DLionInputOutput.ReservedMemoryUse ← notBusy;

firstGermRealPage: PageMap.RealPageNumber ← maxDLionRealPages;
  -- gets set to proper value by initialization code
lastLFPage: PageMap.RealPageNumber = 205;
  -- 64 words per line * 808 lines + 4 pages of cursor bitmap
lastAvailReservedPage: PageMap.RealPageNumber;


ReservedMemoryHandle: PROCEDURE = {};
firstTime: BOOLEAN ← TRUE;

MoveToDisplayMemory: PUBLIC PROCEDURE
  [proc: PROCEDURE] =
  BEGIN OPEN PageMap;
  -- Note on variable names:
  --   page count names are prefixed with 'n
  --   real page numbers are prefixed with 'r
  --   virtual page numbers are prefixed with 'v

  hSource: Space.Handle = Space.GetHandle[PageFromProc[LOOPHOLE[proc]]];
  vSource: Environment.PageNumber = Space.VMPageNumber[hSource];
  nSource: Environment.PageCount = Space.GetAttributes[hSource].size;
  pSource: LONG POINTER = Space.LongPointerFromPage[vSource];

  nBuffer: Environment.PageCount =
    MIN[nSource, lastAvailReservedPage-lastLFPage];
  hBuffer: Space.Handle;
  pBuffer: LONG POINTER;
  vBuffer: Environment.PageNumber;

  rDest: RealPageNumber = (lastAvailReservedPage - nBuffer) + 1;

  IF nBuffer = 0 THEN RETURN;
  hBuffer ← Space.Create[nBuffer, Space.virtualMemory];
  pBuffer ← Space.LongPointer[hBuffer];
  vBuffer ← Space.PageFromLongPointer[pBuffer];
  AssocBlock[
    vPage: vBuffer, rPage: rDest, flags: flagsClean, count: nBuffer];
    -- put display memory under buffer
  Inline.LongCOPY[from: pSource, to: pBuffer,
    nwords: nBuffer*Environment.wordsPerPage];
    -- copy data to be moved into buffer (and into display rm)
  FOR i: CARDINAL IN [0..nBuffer) DO -- swap mapping of source and buffer
    tValue: Value;
    [] ← SetF[vBuffer+i, valueVacant];
    tValue ← GetF[vSource+i];
    Assoc[page: vSource+i, value: [logSingleError: FALSE,
	flags: tValue.flags, realPage: rDest+i]];
    Assoc[vBuffer+i, [FALSE, flagsClean, tValue.realPage]];
    ENDLOOP;
  SpecialSpace.DonateDedicatedRealMemory[vBuffer, nBuffer];
    -- free original rm
  lastAvailReservedPage ← lastAvailReservedPage - nBuffer;
  Space.Delete[hBuffer];
  IF firstTime THEN
    {firstTime ← FALSE; MoveToDisplayMemory[ReservedMemoryHandle]};
  END;

AssocBlock: PROCEDURE
  [vPage: Environment.PageNumber,
  rPage: PageMap.RealPageNumber,
  count: Environment.PageCount, flags: PageMap.Flags] =
  BEGIN
  FOR i: Environment.PageNumber IN [0..count) DO
    PageMap.Assoc[vPage+i, [FALSE, flags, rPage+i]] ENDLOOP;
  END;

PageFromProc: PROCEDURE [proc: procedure PrincOps.ControlLink]
  RETURNS [code: Environment.PageNumber] =
  -- Returns VM page number of procedure's code.
  -- TEMP until function exported by RuntimeInternal (.Code[])!
  BEGIN
  codeBase: LONG PrincOps.PrefixHandle;
  startPC: PrincOps.BytePC;
  evi: CARDINAL;

  codeBase ← RuntimeInternal.Codebase[Runtime.GlobalFrame[proc]];
  evi ← PrincOpsRuntime.GFT[proc.gfi].epbias*PrincOps.EPRange + proc.ep;
  startPC ← codeBase.entry[evi].initialpc;
  RETURN[Space.PageFromLongPointer[codeBase + startPC]];
  END;

DonateReservedMemory: PUBLIC PROCEDURE
  [pagesToKeep: Environment.PageCount] =
  BEGIN
  firstRealPageFreed: PageMap.RealPageNumber =
    DLionInputOutput.firstReservedPage + pagesToKeep;
  space: Space.Handle;
  vp: Environment.PageNumber;
  space ← Space.Create[
    size: (lastAvailReservedPage - firstRealPageFreed) + 1,
    parent: Space.virtualMemory];
  vp ← Space.VMPageNumber[space];
  FOR p: PageMap.RealPageNumber
    IN [firstRealPageFreed..lastAvailReservedPage]
    DO PageMap.Assoc[vp, [FALSE, PageMap.flagsClean, p]]; vp ← vp + 1 ENDLOOP;
  SpecialSpace.DonateDedicatedRealMemory[
    Space.VMPageNumber[space], firstGermRealPage - firstRealPageFreed];
  Space.Delete[space];
  END;

InitializeCleanup: PROCEDURE =
  BEGIN
  item: DeviceCleanup.Item;
  DO
    reason: DeviceCleanup.Reason = DeviceCleanup.Await[@item];
    IF reason#disconnect THEN LOOP;
    FOR p: Environment.PageNumber
      IN [0..DLionInputOutput.numberVirtualPages) DO
      value: PageMap.Value = PageMap.GetF[p];
      IF value.flags = PageMap.flagsVacant THEN LOOP;
      IF value.realPage NOT IN
        [DLionInputOutput.firstReservedPage..firstGermRealPage)
	THEN LOOP;
      PageMap.Assoc[p, PageMap.valueVacant];
      ENDLOOP;
    ENDLOOP;
  END;
  
MemoryConfigurationError: ERROR = CODE;

SetReservedMemoryUse: PUBLIC PROC [
  use: DLionInputOutput.ReservedMemoryUse,
  pagesNeeded: Environment.PageCount] =
  BEGIN
  availableReservedMemory: Environment.PageCount =
    (lastAvailReservedPage-DLionInputOutput.firstReservedPage) + 1;
  IF (SELECT use FROM
    notBusy => FALSE,
    Raven =>
      currentReservedMemoryUse=Display
      OR pagesNeeded > availableReservedMemory,
    Display =>
      currentReservedMemoryUse=Raven
      OR lastAvailReservedPage<lastLFPage,
    ENDCASE => TRUE) THEN ERROR MemoryConfigurationError;
  currentReservedMemoryUse ← use
  END;

Start: PUBLIC PROCEDURE =
-- Initialize cleanup proc
  {InitializeCleanup[]; RemainingHeads.Start[]};

-- This procedure is called before Mesa runtime is initialized, so we must
-- leave the cleanup proc initialization to be done in Start, above
Initialize: PUBLIC PROCEDURE =
  BEGIN
  -- scan virtual memory looking for lowest page mapped - we then use this
  -- page as the top of the area to use for "resident cool" code
  FOR i: CARDINAL IN [0..DLionInputOutput.numberVirtualPages) DO
    tValue: PageMap.Value = PageMap.GetF[i];
    IF tValue.flags#PageMap.flagsVacant THEN
      firstGermRealPage ← MIN[tValue.realPage, firstGermRealPage];
    ENDLOOP;
  lastAvailReservedPage ← firstGermRealPage - 1;
  END;


END...

LOG

Time: January 15, 1981  3:13 PM	By: Gobbel
	Created file

Time: March 16, 1981  11:08 AM	By: Luniewski
	maxDLionRealPages = 768*4 for "Fat" Dandelions

Time: March 27, 1981  11:14 AM	By: Luniewski
	Only swap nBuffer pages worth of mapping in MoveToDisplayMemory