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.