<> <> <> <> DIRECTORY Environment USING [wordsPerPage], Inline USING [LongCOPY, LongDivMod, LongMult], MB USING [Handle, Zero], MBStorage USING [FreeWords, Words], MBVM USING [Base]; MBCache: PROGRAM IMPORTS Inline, MB, MBStorage EXPORTS MB, MBVM = BEGIN pageSize: CARDINAL = Environment.wordsPerPage; increment: CARDINAL = pageSize/SIZE[CSElement]; csArray: CSArray; CSArray: TYPE = LONG DESCRIPTOR FOR ARRAY OF CSElement; CSElement: TYPE = RECORD [ lp: LONG POINTER, page: CARDINAL ]; data: MB.Handle _ NIL; csElements: CARDINAL; cachePage: CARDINAL; cacheLP: LONG POINTER; InitCache: PUBLIC PROC [h: MB.Handle] = { data _ h; csArray _ DESCRIPTOR[MBStorage.Words[increment*SIZE[CSElement]], increment]; csArray[0] _ [page: 0, lp: InitPage[]]; csArray[1] _ [page: LAST[CARDINAL], lp: NIL]; csElements _ 2; cachePage _ LAST[CARDINAL]; cacheLP _ NIL; }; FinishCache: PUBLIC PROC = { FOR i: CARDINAL IN [0..csElements) DO MBStorage.FreeWords[csArray[i].lp] ENDLOOP; MBStorage.FreeWords[BASE[csArray]]; data _ NIL; }; GetPage: PUBLIC PROC [page: MBVM.Base] RETURNS [LONG POINTER] = { i, j, h: CARDINAL; IF page = cachePage THEN RETURN[cacheLP]; IF page = 0 THEN {cachePage _ page; RETURN[cacheLP _ csArray[0].lp]}; i _ 0; j _ csElements-1; UNTIL i + 1 = j DO h _ (i+j)/2; SELECT csArray[h].page FROM < page => i _ h; > page => j _ h; ENDCASE => { -- found at h cachePage _ page; cacheLP _ csArray[h].lp; RETURN[cacheLP] }; ENDLOOP; IF csElements = LENGTH[csArray] THEN ExpandArray[]; FOR k: CARDINAL DECREASING IN [i+1..csElements) DO csArray[k+1] _ csArray[k]; ENDLOOP; cacheLP _ InitPage[]; cachePage _ page; csArray[i+1] _ [lp: cacheLP, page: cachePage]; csElements _ csElements+1; RETURN[cacheLP] }; ExpandArray: PROC = { newLength: CARDINAL = LENGTH[csArray] + increment; newArray: CSArray _ DESCRIPTOR[MBStorage.Words[newLength*SIZE[CSElement]], newLength]; Inline.LongCOPY[ from: BASE[csArray], to: BASE[newArray], nwords: LENGTH[csArray]*SIZE[CSElement]]; MBStorage.FreeWords[BASE[csArray]]; csArray _ newArray; }; InitPage: PROC RETURNS [lp: LONG POINTER] = { lp _ MBStorage.Words[pageSize]; MB.Zero[lp, pageSize]; }; Read: PUBLIC PROC [p: POINTER] RETURNS [UNSPECIFIED] = { RETURN[LongRead[Inline.LongMult[data.mdsBase, pageSize] + LOOPHOLE[p, CARDINAL]]]}; Write: PUBLIC PROC [p: POINTER, v: UNSPECIFIED] = { LongWrite[Inline.LongMult[data.mdsBase, pageSize] + LOOPHOLE[p, CARDINAL], v]}; CopyRead: PUBLIC PROC [from, to: POINTER, nwords: CARDINAL] = { FOR i: CARDINAL IN [0..nwords) DO (to+i)^ _ Read[from+i] ENDLOOP}; CopyWrite: PUBLIC PROC [from, to: POINTER, nwords: CARDINAL] = { FOR i: CARDINAL IN [0..nwords) DO Write[to+i, (from+i)^] ENDLOOP}; LongRead: PUBLIC PROC [p: LONG UNSPECIFIED] RETURNS [UNSPECIFIED] = { memPage: MBVM.Base; offset: CARDINAL; [quotient: memPage, remainder: offset] _ Inline.LongDivMod[LOOPHOLE[p], pageSize]; RETURN[(GetPage[memPage]+offset)^] }; LongWrite: PUBLIC PROC [p: LONG UNSPECIFIED, v: UNSPECIFIED] = { memPage: MBVM.Base; offset: CARDINAL; [quotient: memPage, remainder: offset] _ Inline.LongDivMod[LOOPHOLE[p], pageSize]; (GetPage[memPage]+offset)^ _ v; }; LongCopyRead: PUBLIC PROC [ from: LONG POINTER, to: LONG POINTER, nwords: CARDINAL] = { FOR i: CARDINAL IN [0..nwords) DO (to+i)^ _ LongRead[from+i] ENDLOOP}; LongCopyWrite: PUBLIC PROC [ from: LONG POINTER, to: LONG POINTER, nwords: CARDINAL] = { FOR i: CARDINAL IN [0..nwords) DO LongWrite[to+i, (from+i)^] ENDLOOP}; END.