i
i
i
i
i
i
i
i
7.2. CACHE COHERENCE IN BUS-BASED MULTIPROCESSORS 229
copies exist, since through an earlier invalidation, we have made sure that only one modified copy
can exist in the system.
If the cache block is present in the cache in an owned state, this means that it is dirty and
the block is shared in other caches. A processor read can just fetch the value from the cache. A
processor write must invalidate other cached copies by posting a BusUpgr transaction.
Now let us look at how the finite state machine reacts to snooped bus transactions. If the cache
does not have the block or the block is in invalid state, any snooped BusRd or BusRdX/BusUpgr
should not affect it, so they are ignored.
If the cache block is in an exclusive state, when a BusRd request is snooped, the block is flushed
to the cache using FlushOpt, and the state transitions to shared. When a BusRdX request is snooped,
the block is flushed using FlushOpt and the state transitions to invalid.
If the cache block is in a shared state, when a BusRd transaction is snooped, that means another
processor suffered a read miss and is trying to fetch the block. Therefore, the state remains shared,
and since only the owner is responsible for flushing the block, the local cache does not flush the
block. Note that there may be an owner (in case of dirty sharing) or there may not be an owner
(clean sharing). In the case that there is no owner (clean sharing), the main memory can supply
the block, although using a MESI-like FlushOpt is also possible here. If a BusRdX or BusUpgr is
snooped, the block’s state transitions to invalid. Again, the owner (if there is one) is responsible for
flushing the block, so, in contrast to MESI, the non-owner caches do not need to flush their block
copies.
If the cache block is in the modified state, the copy in the cache is the only valid copy in the
entire system (no other cached copies exist and the value in the main memory is stale). Therefore,
when a BusRd transaction is snooped, the block must be flushed for ensuring write propagation, and
the state transitions to owned. The reason for transitioning to the owned state is based on a heuristic
that has been discussed earlier. Note that by transitioning to the owned state, the local cache has
become the supplier of the block and is responsible for flushing it when required.
If the cache block is in the owned state, it indicates that there is dirty sharing, with the local
cache being responsible as the supplier of the block. Hence, when a BusRd is snooped, it flushes
the block and remains in the owned state (i.e., remains the owner). If a BusRdX is snooped, it
supplies the block by flushing it, and transitions into the invalid state. If a BusUpgr is snooped, it
transitions into the invalid state without flushing the block. Note that because or dirty sharing, the
flushes from this state is a correctness requirement, rather than a performance enhancement because
potentially, nobody else in the system has a valid copy of the block (some sharers which obtain the
block from the owner may have a valid copy, but there is no guarantee that there are sharers).
When the block in the owned state is evicted from the cache, the ownership disappears since
other caches have the copy in the shared state. Hence, at this point dirty sharing must be converted
into clean sharing. The owner is responsible for flushing the block to the memory so that the memory
can update its copy. This is achieved by posting a FlushWB request on the bus. In contrast to Flush
or FlushOpt requests that are ignored by the memory controller, a FlushWB request is picked up by
the memory controller to update the value in the main memory.
Two mechanisms ensure write propagation. First, by invalidating other copies on a write to
a cache block, other caches are forced to reload the block through cache misses. Secondly, with
dirty sharing, a cache acts as an owner and flushes the block when it snoops a BusRd or BusRdX,
ensuring the correct block value is passed on. With clean sharing, the memory supplies the block.