-- File IntVM.mesa -- Updated November 26, 1979 8:42 PM by MN -- June 23, 1980 12:12 PM DIRECTORY -- HighByte doesn't work InlineDefs: FROM "InlineDefs" USING [LongNumber, BITOR, LowByte, BITSHIFT, COPY], StringDefs: FROM "StringDefs" USING [AppendNumber, AppendString], ParserErrorDefs: FROM "ParserErrorDefs" USING [Report, ErrorType], IntVMDefs: FROM "IntVMDefs", SystemDefs: FROM "SystemDefs" USING [AllocateResidentPages, FreePages], ovD: FROM "OverviewDefs" USING [ErrorCode, ok, diskFull, diskError], crD: FROM "CoreDefs" USING [DMSUser, UFileHandle, UFilename, DMSName, Password, OpenFile, --DeleteFile,-- ReadPages, WritePages]; IntVM: PROGRAM IMPORTS SystemDefs, crD, ParserErrorDefs, InlineDefs, StringDefs EXPORTS IntVMDefs = BEGIN OPEN IntVMDefs; -- Virtual storage package for use by ParserStorage.mesa. Provides routines to allocate and free blocks in a large virtual memory. VMFull: PUBLIC ERROR = CODE; VMFile: crD.UFileHandle _ NIL; MaxAddr: LONG CARDINAL = 77777777B; -- max number of pages - 1 in VM PageSize: CARDINAL = 256; -- in words, rewrite SepAddr if this is changed MaxLength: LONG CARDINAL = MaxAddr-3; -- free block length SmallestBlock: CARDINAL = 4; -- smallest block allocated nBuffers: CARDINAL = 5; PTEntry: TYPE = RECORD[ PN: CARDINAL, -- page number Written: BOOLEAN]; -- dirty bit PTable: ARRAY [0..nBuffers) OF PTEntry; Buffers: ARRAY [0..nBuffers) OF POINTER TO UNSPECIFIED; NextOut: [0..nBuffers); -- the next page to get thrown out remainder: VMAddr; -- the first free word of VM InitVM: PUBLIC PROCEDURE RETURNS [BOOLEAN] = BEGIN OPEN crD, ovD; i: CARDINAL; buffers: POINTER = SystemDefs.AllocateResidentPages[nBuffers]; Code: ErrorCode; IF VMFile=NIL THEN BEGIN [Code,VMFile] _ OpenFile[ DMSUser[name:DMSName[name:""], password:Password[password:""]], UFilename[filename: "IntVM.scratch$"], update]; IF Code # ok THEN BEGIN OPEN StringDefs; s: STRING _ [50]; AppendString[s,"InitVM Error Opening IntVM.scratch$: "]; AppendNumber[s,Code,10]; ParserErrorDefs.Report[s, Advisory]; RETURN[FALSE]; END; END; FOR i IN [0..nBuffers) DO PTable[i].PN _ i; PTable[i].Written _ FALSE; Buffers[i] _ buffers + i*PageSize; --Buffers[0] is handle on entire buffer region (used in deallocating) ENDLOOP; NextOut _ 0; -- next page to throw out remainder _ 0; PutLong[remainder,MaxLength]; -- set up remainder of storage RETURN [TRUE]; END; FinishVM: PUBLIC PROCEDURE RETURNS [BOOLEAN]= BEGIN SystemDefs.FreePages[Buffers[0]]; --This frees all the buffers --removed to avoid suspected bug causing lost pages [] _ crD.DeleteFile[VMFile]; RETURN[TRUE]; END; -- free block format: -- length of free block (32 bits), including the 4 header words -- next free block (32 bits) -- inuse block: -- length (16 bits) excluding the header word -- data 0 -- ... AllocateBlock: PUBLIC PROCEDURE [size: CARDINAL] RETURNS [VMAddr] = BEGIN ans: VMAddr; -- bookeeping pointers into VM length: CARDINAL; IF size = 177777B THEN ParserErrorDefs.Report["IntVM.AllocateBlock: Block Too Big", FatalInternal]; -- will fail for block of 2^16-1 length _ 1 + MAX[SmallestBlock,size]; -- find a free block that is long enough -- FOR Cur _ Free, Next UNTIL length <= (CurLen_GetLong[Cur]) DO -- Prev _ Cur; -- IF (Next _ GetLong[Cur+2]) = NilVMAddr THEN ERROR VMFull[]; -- ENDLOOP; ans _ MakeNewBlock[length]; PutWord[ans,length-1]; RETURN [ans+1]; END; -- create a block of size size from the remainder of storage, return pointer to first word MakeNewBlock: PROCEDURE [size: CARDINAL] RETURNS [VMAddr] = BEGIN ans: VMAddr; curLen: LONG CARDINAL _ GetLong[remainder]; IF size <= curLen THEN BEGIN ans _ remainder; remainder _ remainder + size; -- next free block PutLong[remainder,curLen-size]; -- update free block length RETURN[ans]; END ELSE ERROR VMFull[]; END; FreeBlock: PUBLIC PROCEDURE [block: VMAddr] = BEGIN NULL; END; -- Put and Get word quantities from VM. PutWord: PUBLIC PROCEDURE [where: VMAddr, val: UNSPECIFIED] = BEGIN Page, Offset: CARDINAL; Ptr: POINTER TO UNSPECIFIED; i : CARDINAL; [Page,Offset] _ SepAddr[where]; Ptr _ Buffers[i _ FetchPage[Page]]; PTable[i].Written _ TRUE; (Ptr+Offset)^ _ val; END; GetWord: PUBLIC PROCEDURE [where: VMAddr] RETURNS [UNSPECIFIED] = BEGIN Page, Offset: CARDINAL; Ptr: POINTER TO UNSPECIFIED; [Page,Offset] _ SepAddr[where]; Ptr _ Buffers[FetchPage[Page]]; RETURN[(Ptr+Offset)^]; END; -- Put and Get long quantities from VM. PutLong: PUBLIC PROCEDURE [where: VMAddr, val: LONG UNSPECIFIED] = BEGIN x: InlineDefs.LongNumber; x.lu _ val; PutWord[where,x.lowbits]; PutWord[where+1,x.highbits]; END; GetLong: PUBLIC PROCEDURE [where: VMAddr] RETURNS [LONG UNSPECIFIED] = BEGIN x: InlineDefs.LongNumber; x.lowbits _ GetWord[where]; x.highbits _ GetWord[where+1]; RETURN[x.lu]; END; -- Put and Get block quantities from VM. PutBlock: PUBLIC PROCEDURE [src: POINTER TO UNSPECIFIED, dest: VMAddr, size: CARDINAL] = BEGIN i: CARDINAL; page, offset: CARDINAL; [page,offset] _ SepAddr[dest]; IF (offset+size) < PageSize THEN BEGIN Ptr: POINTER TO UNSPECIFIED; Ptr _ Buffers[i _ FetchPage[page]]; PTable[i].Written _ TRUE; InlineDefs.COPY[src,size,Ptr+offset]; END ELSE FOR i IN [0..size) DO PutWord[LOOPHOLE[dest+i,VMAddr],(src+i)^]; ENDLOOP; END; GetBlock: PUBLIC PROCEDURE [src: VMAddr, dest: POINTER TO UNSPECIFIED, size: CARDINAL] = BEGIN i: CARDINAL; page, offset: CARDINAL; [page,offset] _ SepAddr[src]; IF (offset+size) < PageSize THEN BEGIN Ptr: POINTER TO UNSPECIFIED; Ptr _ Buffers[FetchPage[page]]; InlineDefs.COPY[Ptr+offset,size,dest]; END ELSE FOR i IN [0..size) DO (dest+i)^ _ GetWord[LOOPHOLE[src+i,VMAddr]]; ENDLOOP; END; -- Private Procedures -- Bring a page into core if it isn't already in FetchPage: PROCEDURE [Page: CARDINAL] RETURNS [[0..nBuffers)] = BEGIN Ans: [0..nBuffers); FOR Ans IN [0..nBuffers) DO IF PTable[Ans].PN = Page THEN RETURN[Ans]; ENDLOOP; Ans _ BufferToGo[]; -- find a page to throw out OutPage[Ans]; -- away it goes InPage[Page,Ans]; -- get the one we want RETURN[Ans]; END; -- Paging algorithm BufferToGo: PROCEDURE RETURNS [[0..nBuffers)] = BEGIN i: [0..nBuffers); i _ NextOut; NextOut _ (NextOut+1) MOD nBuffers; RETURN[i]; END; -- Put a page on backing store OutPage: PROCEDURE [BufNo: [0..nBuffers)] = BEGIN Code: ovD.ErrorCode; IF NOT PTable[BufNo].Written THEN RETURN; IF (Code_crD.WritePages[Buffers[BufNo],2*PageSize, PTable[BufNo].PN,VMFile]) # ovD.ok THEN BEGIN OPEN ParserErrorDefs; SELECT Code FROM ovD.diskFull => Report["IntVM.OutPage Error - Disk Full", FatalInternal]; ovD.diskError => Report["IntVM.OutPage Error - Disk Error", FatalInternal]; ENDCASE => BEGIN OPEN StringDefs; s: STRING _ [40]; AppendString[s,"IntVM.OutPage Error: "]; AppendNumber[s,Code,10]; Report[s, FatalInternal]; END; RETURN; END; END; -- Retrieve a page from backing store InPage: PROCEDURE [Page: CARDINAL,BufNo: [0..nBuffers)] = BEGIN Code: ovD.ErrorCode; Bytes: CARDINAL; [Code,Bytes] _ crD.ReadPages[Buffers[BufNo],2*PageSize,Page,VMFile]; IF Code # ovD.ok THEN BEGIN OPEN StringDefs; s: STRING _ [40]; AppendString[s,"IntVM.InPage Error: "]; AppendNumber[s,Code,10]; ParserErrorDefs.Report[s, FatalInternal]; RETURN; END; PTable[BufNo] _ PTEntry[ PN: Page, Written: FALSE]; END; -- split a VMAddr into page and offset SepAddr: PROCEDURE [n: VMAddr] RETURNS [CARDINAL, CARDINAL] = BEGIN OPEN InlineDefs; x: LongNumber; x.lc _ n; IF x.lc > MaxAddr THEN BEGIN ParserErrorDefs.Report["IntVM.SepAddr: Range Error", FatalInternal]; RETURN[0,0]; END ELSE RETURN[BITOR[BITSHIFT[LowByte[x.highbits],8],BITSHIFT[x.lowbits,-8]], LowByte[x.lowbits]]; END; END.(635)\19b44B312b72B166b15B27b6B254b6B48b6B3i7I64i8I69i9I18i7I26i13I46i8I127i8I34i8I43i8I96b6B77b65B19b30B358i8I31b8B79b108B95i9I61b8B46b116B259b13B219i13I57i13I168i9I210b12B345b9B103b7B270b7B268b7B178b7B230b8B184i8I256b8B183i8I303b9B42i8I24i8I20i8I238b10B25i8I22i8I47i8I56b7B24i8I125i8I158i15I65i15I159i15I80b6B150i8I185i15I131b7B122i7I71i13I