MBCache.mesa
Edited by Sandman on 6-Aug-81 15:39:33
Edited by Lewis on 17-Sep-81 11:50:33
Edited by Levin on September 30, 1983 11:56 am
DIRECTORY
Basics USING [LongDivMod, LongMult],
MB USING [Handle],
MBVM USING [Base],
PrincOps USING [wordsPerPage];
MBCache: PROGRAM
IMPORTS Basics
EXPORTS MB, MBVM =
BEGIN
wordsPerPage: NAT = PrincOps.wordsPerPage;
increment: NAT = wordsPerPage/SIZE[CachedPage];
cache: Cache;
Cache: TYPE = REF CacheObject;
CacheObject: TYPE = RECORD [
nPages: NAT,
pages: SEQUENCE length: NAT OF CachedPage
];
CachedPage: TYPE = RECORD [
lp: REF PageOfWords,
page: CARDINAL
];
PageOfWords: TYPE = ARRAY[0..wordsPerPage) OF WORD;
data: MB.Handle ← NIL;
lastTouched: CachedPage;
InitCache: PUBLIC PROC [h: MB.Handle] = {
data ← h;
cache ← NEW[CacheObject[increment]];
cache.pages[0] ← [page: 0, lp: InitPage[]];
cache.pages[1] ← [page: LAST[CARDINAL], lp: NIL];
cache.nPages ← 2;
lastTouched ← [page: LAST[CARDINAL], lp: NIL];
};
FinishCache: PUBLIC PROC = {
cache ← NIL;
data ← NIL;
};
GetPage: PUBLIC PROC [page: MBVM.Base] RETURNS [LONG POINTER] = {
low: NAT ← 0;
high: NAT ← cache.nPages - 1;
IF page = lastTouched.page THEN RETURN[LOOPHOLE[lastTouched.lp]];
DO
probe: NAT = (low+high)/2;
SELECT cache.pages[probe].page FROM
< page => IF probe = low THEN EXIT ELSE low ← probe;
> page => IF probe = high THEN EXIT ELSE high ← probe;
ENDCASE => RETURN[LOOPHOLE[(lastTouched ← cache[probe]).lp]];
ENDLOOP;
IF cache.nPages = cache.length THEN ExpandArray[];
FOR k: NAT DECREASING IN [low+1..cache.nPages) DO
cache[k+1] ← cache[k];
ENDLOOP;
lastTouched ← cache[low+1] ← [lp: InitPage[], page: page];
cache.nPages ← cache.nPages.SUCC;
RETURN[LOOPHOLE[lastTouched.lp]]
};
ExpandArray: PROC = {
newLength: NAT = cache.length + increment;
newCache: Cache = NEW[CacheObject[newLength]];
newCache.nPages ← cache.nPages;
FOR i: NAT IN [0..cache.nPages) DO
newCache.pages[i] ← cache.pages[i];
ENDLOOP;
cache ← newCache;
};
InitPage: PROC RETURNS [lp: REF PageOfWords] = {
lp ← NEW[PageOfWords];
FOR i: CARDINAL IN [0..wordsPerPage) DO lp[i] ← 0; ENDLOOP;
};
Read/Write operations
Read: PUBLIC PROC [p: POINTER] RETURNS [UNSPECIFIED] = {
RETURN[LongRead[Basics.LongMult[data.mdsBase, wordsPerPage] + LOOPHOLE[p, CARDINAL]]]};
Write: PUBLIC PROC [p: POINTER, v: UNSPECIFIED] = {
LongWrite[Basics.LongMult[data.mdsBase, wordsPerPage] + 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] ← Basics.LongDivMod[LOOPHOLE[p], wordsPerPage];
RETURN[(GetPage[memPage]+offset)^]
};
LongWrite: PUBLIC PROC [p: LONG UNSPECIFIED, v: UNSPECIFIED] = {
memPage: MBVM.Base;
offset: CARDINAL;
[quotient: memPage, remainder: offset] ← Basics.LongDivMod[LOOPHOLE[p], wordsPerPage];
(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.