RESIUtil:
CEDAR PROGRAM
IMPORTS Convert, CacheModel, DragOpsCrossUtils, IO, RI: RESInterpreter, Rope
EXPORTS RESInterpreter = {
Types and Global Data
Value: TYPE = RI.Value;
DValue: TYPE = RI.DValue;
Ptr1: TYPE = RI.Ptr1;
Ptr2: TYPE = RI.Ptr2;
LPtr1: TYPE = RI.LPtr1;
LPtr2: TYPE = RI.LPtr2;
ROPE: TYPE = Rope.ROPE;
Machine:
TYPE =
RI.Machine;
Byte: TYPE = RI.Byte;
Bytes: TYPE = RI.Bytes;
Pair: TYPE = RI.Pair;
FieldDescriptor: TYPE = PrincOps.FieldDescriptor;
LCB: TYPE = RI.LCB;
wordsPerPage: CARDINAL = CacheModel.wordsPerPage;
bytesPerWord: NAT = DragOpsCross.bytesPerWord;
LocalsInRing: NAT = 16;
Word: TYPE = DragOpsCross.Word;
Cache Model stuff
CacheIndex: TYPE = [0..8);
CacheInfoRec:
TYPE =
RECORD [
active: BOOL ← TRUE,
cacheLines: NAT,
cacheQuads: NAT,
iCaches, dCaches: NAT ← 0,
iCache: ARRAY CacheIndex OF CacheModel.CacheBase ← ALL[NIL],
dCache: ARRAY CacheIndex OF CacheModel.CacheBase ← ALL[NIL],
iBufferSize: NAT ← 16,
iBufferBytes: NAT ← 0,
afterJump: BOOL ← FALSE,
lru: BOOL ← FALSE];
CacheInfo: TYPE = REF CacheInfoRec;
FlushAllCaches:
PUBLIC
PROC [m: Machine] = {
cache: CacheInfo ← NARROW[m.cacheData];
IF cache = NIL THEN RETURN;
FOR i: NAT IN [0..cache.iCaches) DO CacheModel.FlushCache[cache.iCache[i]]; ENDLOOP;
FOR i: NAT IN [0..cache.dCaches) DO CacheModel.FlushCache[cache.dCache[i]]; ENDLOOP;
};
ResetCacheModel:
PUBLIC
PROC [m: Machine, instr, data, lines, quads:
NAT, lru:
BOOL] = {
cache: CacheInfo ← NARROW[m.cacheData];
IF cache #
NIL
AND lines = cache.cacheLines
AND quads = cache.cacheQuads
AND instr = cache.iCaches
AND data = cache.dCaches
AND lru = cache.lru
THEN {
FOR i:
NAT
IN [0..instr)
DO
CacheModel.ResetCache[cache.iCache[i]];
ENDLOOP;
FOR i:
NAT
IN [0..data)
DO
CacheModel.ResetCache[cache.dCache[i]];
ENDLOOP;
cache.iBufferBytes ← 0}
ELSE {
m.cacheData ← cache ←
NEW [CacheInfoRec ← [
cacheLines: lines, cacheQuads: quads,
iCaches: instr, dCaches: data, lru: lru]];
FOR i:
NAT
IN [0..instr)
DO
cache.iCache[i] ← CacheModel.NewCache[lines, quads, lru];
ENDLOOP;
FOR i:
NAT
IN [0..data)
DO
cache.dCache[i] ← CacheModel.NewCache[lines, quads, lru];
ENDLOOP};
};
PrintOneCache:
PROC [
os: IO.STREAM, cb: CacheModel.CacheBase, name: ROPE, lines, quads: NAT, lru: BOOL] = {
Realn:
PROC [r:
REAL, n:
NAT]
RETURNS [
IO.Value] = {
RETURN [[rope[Convert.RopeFromReal[r, n]]]]};
quadMisses: INT ← cb.stats.chunkMisses;
misses: INT ← quadMisses + cb.stats.lineMisses;
probes: INT ← cb.stats.probes;
rProbes: REAL ← probes;
rMisses: REAL ← misses;
os.PutF[
"\nStats for %g (lines: %g, quads/line: %g)\n probes: %g\n",
[rope[IF lru THEN Rope.Cat[name, " (pseudo-lru)"] ELSE name]],
[integer[lines]], [integer[quads]], [integer[probes]]];
IF probes = 0 THEN RETURN;
os.PutF[
" misses: %g (%g (%g%%) existing line)\n",
[integer[misses]], [integer[cb.stats.chunkMisses]],
IF misses = 0 THEN [rope["-"]] ELSE Realn[(quadMisses/rMisses)*100, 3]];
IF cb.stats.jumpMisses # 0
THEN os.PutF[
" misses caused by jumps: %g (%g%% of probes)\n",
[integer[cb.stats.jumpMisses]], Realn[(cb.stats.jumpMisses/rProbes)*100, 3]];
IF probes # 0
THEN os.PutF[
" hit rate: %g%%\n",
Realn[((probes - misses)/rProbes)*100, 3]];
os.PutF[
" map misses: %g\n dirty writes: %g\n",
[integer[cb.stats.mapMisses]], [integer[cb.stats.dirtyWrites]]];
};
EnableCacheModel:
PUBLIC
PROC [m: Machine, state:
BOOL, instr, data, lines, quads:
NAT, lru:
BOOL] = {
cache: CacheInfo ← NARROW[m.cacheData];
IF cache =
NIL
THEN {
ResetCacheModel[m: m, instr: instr, data: data, lines: lines, quads: quads, lru: lru];
cache ← NARROW[m.cacheData]};
cache.active ← state};
PrintCacheStats:
PUBLIC
PROC [os:
IO.
STREAM, m: Machine] = {
cache: CacheInfo ← NARROW[m.cacheData];
IF cache #
NIL
THEN {
FOR i:
NAT
IN [0..cache.iCaches)
DO
PrintOneCache[
os, cache.iCache[i],
Rope.Cat["instruction cache ", Convert.RopeFromInt[i]],
cache.cacheLines, cache.cacheQuads, cache.lru];
ENDLOOP;
FOR i:
NAT
IN [0..cache.dCaches)
DO
PrintOneCache[
os, cache.dCache[i],
Rope.Cat["data cache ", Convert.RopeFromInt[i]],
cache.cacheLines, cache.cacheQuads, cache.lru];
ENDLOOP;
};
};
Statistics recording
ReadAtAddress:
PUBLIC
PROC [m: Machine, addr:
LONG
POINTER] =
TRUSTED {
cache: CacheInfo = NARROW[m.cacheData];
IF cache #
NIL
AND cache.active
AND cache.dCaches # 0
THEN {
byteAddress: LONG CARDINAL ← LOOPHOLE[addr, LONG CARDINAL]*2;
wordAddr: Word;
cacheIndex: NAT;
[wordAddr,] ← DragOpsCrossUtils.BytePCToWordAddress[
[DragOpsCrossUtils.CardToWord[byteAddress]]];
cacheIndex ← (DragOpsCrossUtils.WordToCard[wordAddr] / wordsPerPage) MOD cache.dCaches;
cache.dCache[cacheIndex].Fetch[wordAddr]};
};
DoubleReadAtAddress:
PUBLIC
PROC [m: Machine, addr:
LONG
POINTER] =
TRUSTED {
tAddr: Basics.LongNumber = LOOPHOLE[addr];
ReadAtAddress[m, addr];
IF tAddr.lowbits MOD 2 # 0 THEN ReadAtAddress[m, addr+1];
};
ReadLocal:
PUBLIC
PROC [m: Machine, offset:
CARDINAL] =
TRUSTED {
IF offset >= PrincOps.localbase + LocalsInRing
THEN
ReadAtAddress[m, m.l + offset]};
DoubleReadLocal:
PUBLIC
PROC [m: Machine, offset:
CARDINAL] =
TRUSTED {
IF offset >= PrincOps.localbase + LocalsInRing
THEN
ReadAtAddress[m, m.l + offset];
IF offset MOD 2 # 0 THEN ReadAtAddress[m, m.l + offset + 1];
};
WriteAtAddress:
PUBLIC
PROC [m: Machine, addr:
LONG
POINTER] =
TRUSTED {
cache: CacheInfo = NARROW[m.cacheData];
IF cache #
NIL
AND cache.active
AND cache.dCaches # 0
THEN {
byteAddress: LONG CARDINAL ← LOOPHOLE[addr, LONG CARDINAL]*2;
wordAddr: Word;
cacheIndex: NAT;
[wordAddr,] ← DragOpsCrossUtils.BytePCToWordAddress[
[DragOpsCrossUtils.CardToWord[byteAddress]]];
cacheIndex ← (DragOpsCrossUtils.WordToCard[wordAddr] / wordsPerPage) MOD cache.dCaches;
cache.dCache[cacheIndex].Store[wordAddr]};
};
DoubleWriteAtAddress:
PUBLIC
PROC [m: Machine, addr:
LONG
POINTER] =
TRUSTED {
tAddr: Basics.LongNumber = LOOPHOLE[addr];
WriteAtAddress[m, addr+1];
IF tAddr.lowbits MOD 2 # 0 THEN WriteAtAddress[m, addr];
};
StoreLocal:
PUBLIC
PROC [m: Machine, offset:
CARDINAL] =
TRUSTED {
IF offset >= PrincOps.localbase + LocalsInRing
THEN
WriteAtAddress[m, m.l + offset]};
DoubleStoreLocal:
PUBLIC
PROC [m: Machine, offset:
CARDINAL] =
TRUSTED {
IF offset >= PrincOps.localbase + LocalsInRing
THEN
WriteAtAddress[m, m.l + offset+1];
IF offset MOD 2 # 0 THEN WriteAtAddress[m, m.l + offset];
};
NextOpByte:
PUBLIC
PROC [m: Machine, opcode:
BOOL]
RETURNS [b: Byte] = {
note instruction fetch
cache: CacheInfo = NARROW[m.cacheData];
IF cache #
NIL
AND cache.active
AND cache.iCaches # 0
THEN {
IF cache.iBufferBytes = 0
OR (opcode
AND cache.iBufferBytes <= cache.iBufferSize - bytesPerWord)
THEN
TRUSTED {
cacheIndex: NAT;
wordAddrInCache: Word;
byteInWord: [0..bytesPerWord);
byteAddress:
LONG
CARDINAL ←
LOOPHOLE[m.cb,
LONG
CARDINAL]*2 + m.pc;
This is a PrincOps byte address!
[wordAddrInCache, byteInWord] ←
DragOpsCrossUtils.BytePCToWordAddress[
[DragOpsCrossUtils.CardToWord[byteAddress]]];
cacheIndex ← (DragOpsCrossUtils.WordToCard[wordAddrInCache] / wordsPerPage) MOD cache.iCaches;
cache.iCache[cacheIndex].Fetch[wordAddrInCache, cache.afterJump];
cache.iBufferBytes ←
IF cache.iBufferBytes = 0 THEN bytesPerWord - byteInWord
ELSE cache.iBufferBytes + bytesPerWord;
};
cache.iBufferBytes ← cache.iBufferBytes - 1;
cache.afterJump ← FALSE};
b ← LOOPHOLE[m.cb, LONG POINTER TO PACKED ARRAY [0..0) OF Byte][m.pc];
m.pc ← m.pc + 1;
};
SetPc:
PUBLIC PROC [m: Machine, pc:
CARDINAL] = {
note new pc value
WITH m.cacheData
SELECT
FROM
cache: CacheInfo => {cache.iBufferBytes ← 0; cache.afterJump ← TRUE};
ENDCASE;
m.pc ← pc};
UnboundProcTrap: PUBLIC PROC [m: Machine, link: ControlLink] = {ERROR Problem[m, unboundProc]};
ControlTrap: PUBLIC PROC [m: Machine, link: ControlLink] = {ERROR Problem[m, controlFault]};
Problem: PUBLIC ERROR [m: Machine, reason: RI.InterpreterProblem] = CODE;
Confusion: PUBLIC PROC [m: Machine] = {ERROR Problem[m, confused]};
NilFault: PUBLIC PROC [m: Machine] = {ERROR Problem[m, nilcheck]};
BoundsFault:
PUBLIC
PROC [m: Machine] = {
ERROR Problem[m, boundscheck]};
Push:
PUBLIC PROC [m: Machine, v: Value] = {m.stack[m.sd] ← v; m.sd ← m.sd + 1};
Pop:
PUBLIC
PROC [m: Machine]
RETURNS [v: Value] = {m.sd ← m.sd - 1;
RETURN [m.stack[m.sd]]};
Top:
PUBLIC
PROC [m: Machine]
RETURNS [v: Value] = {
RETURN [m.stack[m.sd-1]]};
Push2:
PUBLIC PROC [m: Machine, v: DValue] = {
m.stack[m.sd] ← RI.VCard[v.lo];
m.stack[m.sd+1] ← RI.VCard[v.hi];
m.sd ← m.sd + 2};
Pop2:
PUBLIC
PROC [m: Machine]
RETURNS [v: DValue] = {
m.sd ← m.sd - 2;
RETURN [[lo: RI.CardV[m.stack[m.sd]], hi: RI.CardV[m.stack[m.sd+1]]]]};
Read:
PUBLIC
PROC [m: Machine, p: LPtr1]
RETURNS [Value] =
TRUSTED {
ReadAtAddress[m, p];
RETURN [p^]};
ReadDouble:
PUBLIC
PROC [m: Machine, p: LPtr2]
RETURNS [DValue] =
TRUSTED {
DoubleReadAtAddress[m, p];
RETURN [p^]};
ReadField:
PUBLIC
PROC [m: Machine, p: LPtr1, fd: FieldDescriptor]
RETURNS [Value] =
TRUSTED {
ReadAtAddress[m, p];
RETURN [RI.RFSLOp[p, fd]]};
Write:
PUBLIC
PROC [m: Machine, p: LPtr1, v: Value] =
TRUSTED {
WriteAtAddress[m, p];
p^ ← v};
WriteDouble:
PUBLIC
PROC [m: Machine, p: LPtr2, v: DValue] =
TRUSTED {
DoubleWriteAtAddress[m, p];
p^ ← v};
WriteField:
PUBLIC
PROC [m: Machine, p: LPtr1, fd: FieldDescriptor, v: Value] =
TRUSTED {
ReadAtAddress[m, p];
WriteAtAddress[m, p];
RI.WFSLOp[v: v, p: p, fd: fd]};
}.