MBCache.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Sandman on 6-Aug-81 15:39:33
Lewis on 17-Sep-81 11:50:33
Levin on January 12, 1984 2:01 pm
Russ Atkinson (RRA) March 8, 1985 4:59:32 pm PST
DIRECTORY
Basics USING [LongDivMod, LongMult],
MB USING [Handle],
MBVM USING [Base],
PrincOps USING [wordsPerPage];
MBCache:
CEDAR
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] =
TRUSTED {
FOR i: CARDINAL IN [0..nwords) DO (to+i)^ ← Read[from+i]; ENDLOOP;
};
CopyWrite:
PUBLIC
PROC [from, to:
POINTER, nwords:
CARDINAL] =
TRUSTED {
FOR i: CARDINAL IN [0..nwords) DO Write[to+i, (from+i)^]; ENDLOOP;
};
LongRead:
PUBLIC
PROC [p:
LONG
UNSPECIFIED]
RETURNS [
UNSPECIFIED] =
TRUSTED {
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] =
TRUSTED {
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] = TRUSTED {
FOR i: CARDINAL IN [0..nwords) DO (to+i)^ ← LongRead[from+i]; ENDLOOP;
};
LongCopyWrite:
PUBLIC
PROC [
from: LONG POINTER, to: LONG POINTER, nwords: CARDINAL] = TRUSTED {
FOR i: CARDINAL IN [0..nwords) DO LongWrite[to+i, (from+i)^]; ENDLOOP;
};
END.