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.