BlkValid = 0x01,
/** write permission */
BlkWritable = 0x02,
+ /** read permission (yes, block can be valid but not readable) */
+ BlkReadable = 0x04,
/** dirty (modified) */
- BlkDirty = 0x04,
+ BlkDirty = 0x08,
/** block was referenced */
BlkReferenced = 0x10,
/** block was a hardware prefetch yet unaccessed*/
}
/**
- * Checks that a block is valid (readable).
+ * Checks the read permissions of this block. Note that a block
+ * can be valid but not readable if there is an outstanding write
+ * upgrade miss.
+ * @return True if the block is readable.
+ */
+ bool isReadable() const
+ {
+ const int needed_bits = BlkReadable | BlkValid;
+ return (status & needed_bits) == needed_bits;
+ }
+
+ /**
+ * Checks that a block is valid.
* @return True if the block is valid.
*/
bool isValid() const
}
}
- if (pkt->needsExclusive() ? blk->isWritable() : blk->isValid()) {
+ if (pkt->needsExclusive() ? blk->isWritable() : blk->isReadable()) {
// OK to satisfy access
hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
satisfyCpuSideRequest(pkt, blk);
incMissCount(pkt);
return false;
}
- blk->status = BlkValid;
+ blk->status = BlkValid | BlkReadable;
}
std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
blk->status |= BlkDirty;
}
int lat = hitLatency;
- bool satisfied = false;
-
- Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
- MSHR *mshr = mshrQueue.findMatch(blk_addr);
-
- if (!mshr) {
- // no outstanding access to this block, look up in cache
- // (otherwise if we allow reads while there's an outstanding
- // write miss, the read could return stale data out of the
- // cache block... a more aggressive system could detect the
- // overlap (if any) and forward data out of the MSHRs, but we
- // don't do that yet)
- BlkType *blk = NULL;
- satisfied = access(pkt, blk, lat);
- }
+ BlkType *blk = NULL;
+ bool satisfied = access(pkt, blk, lat);
#if 0
/** @todo make the fast write alloc (wh64) work with coherence. */
if (prefetchMiss)
prefetcher->handleMiss(pkt, time);
+ Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
+ MSHR *mshr = mshrQueue.findMatch(blk_addr);
+
if (mshr) {
// MSHR hit
//@todo remove hw_pf here
if (pkt->cmd == MemCmd::Writeback) {
allocateWriteBuffer(pkt, time, true);
} else {
+ if (blk && blk->isValid()) {
+ // If we have a write miss to a valid block, we
+ // need to mark the block non-readable. Otherwise
+ // if we allow reads while there's an outstanding
+ // write miss, the read could return stale data
+ // out of the cache block... a more aggressive
+ // system could detect the overlap (if any) and
+ // forward data out of the MSHRs, but we don't do
+ // that yet. Note that we do need to leave the
+ // block valid so that it stays in the cache, in
+ // case we get an upgrade response (and hence no
+ // new data) when the write miss completes.
+ // As long as CPUs do proper store/load forwarding
+ // internally, and have a sufficiently weak memory
+ // model, this is probably unnecessary, but at some
+ // point it must have seemed like we needed it...
+ assert(pkt->needsExclusive() && !blk->isWritable());
+ blk->status &= ~BlkReadable;
+ }
+
allocateMissBuffer(pkt, time, true);
}
}
}
if (!pkt->sharedAsserted()) {
- blk->status = BlkValid | BlkWritable;
+ blk->status = BlkValid | BlkReadable | BlkWritable;
} else {
assert(!pkt->needsExclusive());
- blk->status = BlkValid;
+ blk->status = BlkValid | BlkReadable;
}
DPRINTF(Cache, "Block addr %x moving from state %i to %i\n",