The memory unit can be specified at various levels of abstraction. A hardware engineer might describe the implementation using decoders and registers. In our abstract view, we encapsulate the memory in a Java class. The following six files implement an abstraction of the memory unit of a typical hardware machine:
Word
: a class that defines
machine words.
Data
: a class that defines
the machine words that can be used as data.
MachineE
: a class for
all exceptions raised by the machine.
MemoryE
: a class for
exceptions raised by the memory unit of the machine.
MemoryI
: the interface of the memory unit.
Memory
: an implementation
of the memory unit.
CachedMemory
which is an object that behaves like a
regular Memory
but is optimized to use to a small local
cache whenever possible. The idea is that when a fetch
operation is requested from the CachedMemory
, the
operation will first attempt to use the cache; if the cache entry is
not valid or missing, the operation will use the main memory as usual.
Here is an example of how a CachedMemory
operates. Consider a
Memory
of size 70 and a cache of size 10. The cache will be
represented using three arrays of size 10:
Word[] cacheCells
,
boolean[] valid
, and
int[] tag
.
32 / 10
and 32 % 10
which gives us the tag 3 and the index 2.
valid[2]
is true.
tag[2]
is equal to 3.
cacheCells[2]
.
Word
from
location 32 in the main memory (call this Word
X
),
then:
valid[2] = true
,
tag[2] = 3
,
cacheCells[2] = X
, and
X
.
valid
, tag
, and cacheCells
.
CachedMemory
that extends the class
Memory
. The constructor for the class
CachedMemory
should create a Memory
and then
three local arrays cacheCells
, valid
, and
tag
to represent the cache. Initially, every entry in the
array valid
contains false
. The other two
arrays may contain arbitrary values.