-- 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