mem: Remove redundant is_top_level cache parameter
This patch takes the final step in removing the is_top_level parameter from the cache. With the recent changes to read requests and write invalidations, the parameter is no longer needed, and consequently removed. This also means that asymmetric cache hierarchies are now fully supported (and we are actually using them already with L1 caches, but no table-walker caches, connected to a shared L2).
This commit is contained in:
parent
71856cfbbc
commit
b93c912013
8 changed files with 15 additions and 29 deletions
|
@ -52,7 +52,6 @@ class L1Cache(BaseCache):
|
||||||
response_latency = 2
|
response_latency = 2
|
||||||
mshrs = 4
|
mshrs = 4
|
||||||
tgts_per_mshr = 20
|
tgts_per_mshr = 20
|
||||||
is_top_level = True
|
|
||||||
|
|
||||||
class L1_ICache(L1Cache):
|
class L1_ICache(L1Cache):
|
||||||
is_read_only = True
|
is_read_only = True
|
||||||
|
@ -76,7 +75,6 @@ class IOCache(BaseCache):
|
||||||
size = '1kB'
|
size = '1kB'
|
||||||
tgts_per_mshr = 12
|
tgts_per_mshr = 12
|
||||||
forward_snoops = False
|
forward_snoops = False
|
||||||
is_top_level = True
|
|
||||||
|
|
||||||
class PageTableWalkerCache(BaseCache):
|
class PageTableWalkerCache(BaseCache):
|
||||||
assoc = 2
|
assoc = 2
|
||||||
|
@ -86,7 +84,6 @@ class PageTableWalkerCache(BaseCache):
|
||||||
size = '1kB'
|
size = '1kB'
|
||||||
tgts_per_mshr = 12
|
tgts_per_mshr = 12
|
||||||
forward_snoops = False
|
forward_snoops = False
|
||||||
is_top_level = True
|
|
||||||
# the x86 table walker actually writes to the table-walker cache
|
# the x86 table walker actually writes to the table-walker cache
|
||||||
if buildEnv['TARGET_ISA'] == 'x86':
|
if buildEnv['TARGET_ISA'] == 'x86':
|
||||||
is_read_only = False
|
is_read_only = False
|
||||||
|
|
|
@ -149,7 +149,6 @@ class O3_ARM_v7a_ICache(BaseCache):
|
||||||
tgts_per_mshr = 8
|
tgts_per_mshr = 8
|
||||||
size = '32kB'
|
size = '32kB'
|
||||||
assoc = 2
|
assoc = 2
|
||||||
is_top_level = True
|
|
||||||
forward_snoops = False
|
forward_snoops = False
|
||||||
is_read_only = True
|
is_read_only = True
|
||||||
|
|
||||||
|
@ -162,7 +161,6 @@ class O3_ARM_v7a_DCache(BaseCache):
|
||||||
size = '32kB'
|
size = '32kB'
|
||||||
assoc = 2
|
assoc = 2
|
||||||
write_buffers = 16
|
write_buffers = 16
|
||||||
is_top_level = True
|
|
||||||
|
|
||||||
# TLB Cache
|
# TLB Cache
|
||||||
# Use a cache as a L2 TLB
|
# Use a cache as a L2 TLB
|
||||||
|
@ -174,7 +172,6 @@ class O3_ARM_v7aWalkCache(BaseCache):
|
||||||
size = '1kB'
|
size = '1kB'
|
||||||
assoc = 8
|
assoc = 8
|
||||||
write_buffers = 16
|
write_buffers = 16
|
||||||
is_top_level = True
|
|
||||||
forward_snoops = False
|
forward_snoops = False
|
||||||
is_read_only = True
|
is_read_only = True
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,7 @@ for t, m in zip(testerspec, multiplier):
|
||||||
# Define a prototype L1 cache that we scale for all successive levels
|
# Define a prototype L1 cache that we scale for all successive levels
|
||||||
proto_l1 = BaseCache(size = '32kB', assoc = 4,
|
proto_l1 = BaseCache(size = '32kB', assoc = 4,
|
||||||
hit_latency = 1, response_latency = 1,
|
hit_latency = 1, response_latency = 1,
|
||||||
tgts_per_mshr = 8, is_top_level = True)
|
tgts_per_mshr = 8)
|
||||||
|
|
||||||
if options.blocking:
|
if options.blocking:
|
||||||
proto_l1.mshrs = 1
|
proto_l1.mshrs = 1
|
||||||
|
@ -179,7 +179,6 @@ for scale in cachespec[:-1]:
|
||||||
next.response_latency = prev.response_latency * 10
|
next.response_latency = prev.response_latency * 10
|
||||||
next.assoc = prev.assoc * scale
|
next.assoc = prev.assoc * scale
|
||||||
next.mshrs = prev.mshrs * scale
|
next.mshrs = prev.mshrs * scale
|
||||||
next.is_top_level = False
|
|
||||||
cache_proto.insert(0, next)
|
cache_proto.insert(0, next)
|
||||||
|
|
||||||
# Create a config to be used by all the traffic generators
|
# Create a config to be used by all the traffic generators
|
||||||
|
|
|
@ -177,7 +177,7 @@ else:
|
||||||
# Define a prototype L1 cache that we scale for all successive levels
|
# Define a prototype L1 cache that we scale for all successive levels
|
||||||
proto_l1 = BaseCache(size = '32kB', assoc = 4,
|
proto_l1 = BaseCache(size = '32kB', assoc = 4,
|
||||||
hit_latency = 1, response_latency = 1,
|
hit_latency = 1, response_latency = 1,
|
||||||
tgts_per_mshr = 8, is_top_level = True)
|
tgts_per_mshr = 8)
|
||||||
|
|
||||||
if options.blocking:
|
if options.blocking:
|
||||||
proto_l1.mshrs = 1
|
proto_l1.mshrs = 1
|
||||||
|
@ -197,7 +197,6 @@ for scale in cachespec[:-1]:
|
||||||
next.response_latency = prev.response_latency * 10
|
next.response_latency = prev.response_latency * 10
|
||||||
next.assoc = prev.assoc * scale
|
next.assoc = prev.assoc * scale
|
||||||
next.mshrs = prev.mshrs * scale
|
next.mshrs = prev.mshrs * scale
|
||||||
next.is_top_level = False
|
|
||||||
cache_proto.insert(0, next)
|
cache_proto.insert(0, next)
|
||||||
|
|
||||||
# Make a prototype for the tester to be used throughout
|
# Make a prototype for the tester to be used throughout
|
||||||
|
|
1
src/mem/cache/BaseCache.py
vendored
1
src/mem/cache/BaseCache.py
vendored
|
@ -64,7 +64,6 @@ class BaseCache(MemObject):
|
||||||
|
|
||||||
forward_snoops = Param.Bool(True,
|
forward_snoops = Param.Bool(True,
|
||||||
"Forward snoops from mem side to cpu side")
|
"Forward snoops from mem side to cpu side")
|
||||||
is_top_level = Param.Bool(False, "Is this cache at the top level (e.g. L1)")
|
|
||||||
is_read_only = Param.Bool(False, "Is this cache read only (e.g. inst)")
|
is_read_only = Param.Bool(False, "Is this cache read only (e.g. inst)")
|
||||||
|
|
||||||
prefetcher = Param.BasePrefetcher(NULL,"Prefetcher attached to cache")
|
prefetcher = Param.BasePrefetcher(NULL,"Prefetcher attached to cache")
|
||||||
|
|
1
src/mem/cache/base.cc
vendored
1
src/mem/cache/base.cc
vendored
|
@ -78,7 +78,6 @@ BaseCache::BaseCache(const Params *p)
|
||||||
responseLatency(p->response_latency),
|
responseLatency(p->response_latency),
|
||||||
numTarget(p->tgts_per_mshr),
|
numTarget(p->tgts_per_mshr),
|
||||||
forwardSnoops(p->forward_snoops),
|
forwardSnoops(p->forward_snoops),
|
||||||
isTopLevel(p->is_top_level),
|
|
||||||
isReadOnly(p->is_read_only),
|
isReadOnly(p->is_read_only),
|
||||||
blocked(0),
|
blocked(0),
|
||||||
order(0),
|
order(0),
|
||||||
|
|
5
src/mem/cache/base.hh
vendored
5
src/mem/cache/base.hh
vendored
|
@ -304,11 +304,6 @@ class BaseCache : public MemObject
|
||||||
/** Do we forward snoops from mem side port through to cpu side port? */
|
/** Do we forward snoops from mem side port through to cpu side port? */
|
||||||
const bool forwardSnoops;
|
const bool forwardSnoops;
|
||||||
|
|
||||||
/** Is this cache a toplevel cache (e.g. L1, I/O cache). If so we should
|
|
||||||
* never try to forward ownership and similar optimizations to the cpu
|
|
||||||
* side */
|
|
||||||
const bool isTopLevel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this cache read only, for example the instruction cache, or
|
* Is this cache read only, for example the instruction cache, or
|
||||||
* table-walker cache. A cache that is read only should never see
|
* table-walker cache. A cache that is read only should never see
|
||||||
|
|
25
src/mem/cache/cache_impl.hh
vendored
25
src/mem/cache/cache_impl.hh
vendored
|
@ -179,7 +179,15 @@ Cache::satisfyCpuSideRequest(PacketPtr pkt, CacheBlk *blk,
|
||||||
blk->trackLoadLocked(pkt);
|
blk->trackLoadLocked(pkt);
|
||||||
}
|
}
|
||||||
pkt->setDataFromBlock(blk->data, blkSize);
|
pkt->setDataFromBlock(blk->data, blkSize);
|
||||||
if (pkt->getSize() == blkSize) {
|
// determine if this read is from a (coherent) cache, or not
|
||||||
|
// by looking at the command type; we could potentially add a
|
||||||
|
// packet attribute such as 'FromCache' to make this check a
|
||||||
|
// bit cleaner
|
||||||
|
if (pkt->cmd == MemCmd::ReadExReq ||
|
||||||
|
pkt->cmd == MemCmd::ReadSharedReq ||
|
||||||
|
pkt->cmd == MemCmd::ReadCleanReq ||
|
||||||
|
pkt->cmd == MemCmd::SCUpgradeFailReq) {
|
||||||
|
assert(pkt->getSize() == blkSize);
|
||||||
// special handling for coherent block requests from
|
// special handling for coherent block requests from
|
||||||
// upper-level caches
|
// upper-level caches
|
||||||
if (pkt->needsExclusive()) {
|
if (pkt->needsExclusive()) {
|
||||||
|
@ -211,7 +219,7 @@ Cache::satisfyCpuSideRequest(PacketPtr pkt, CacheBlk *blk,
|
||||||
|
|
||||||
if (blk->isDirty()) {
|
if (blk->isDirty()) {
|
||||||
// special considerations if we're owner:
|
// special considerations if we're owner:
|
||||||
if (!deferred_response && !isTopLevel) {
|
if (!deferred_response) {
|
||||||
// if we are responding immediately and can
|
// if we are responding immediately and can
|
||||||
// signal that we're transferring ownership
|
// signal that we're transferring ownership
|
||||||
// along with exclusivity, do so
|
// along with exclusivity, do so
|
||||||
|
@ -526,7 +534,6 @@ Cache::promoteWholeLineWrites(PacketPtr pkt)
|
||||||
(pkt->getSize() == blkSize) && (pkt->getOffset(blkSize) == 0)) {
|
(pkt->getSize() == blkSize) && (pkt->getOffset(blkSize) == 0)) {
|
||||||
pkt->cmd = MemCmd::WriteLineReq;
|
pkt->cmd = MemCmd::WriteLineReq;
|
||||||
DPRINTF(Cache, "packet promoted from Write to WriteLineReq\n");
|
DPRINTF(Cache, "packet promoted from Write to WriteLineReq\n");
|
||||||
assert(isTopLevel); // should only happen at L1 or I/O cache
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -696,7 +703,7 @@ Cache::recvTimingReq(PacketPtr pkt)
|
||||||
// processing happens before any MSHR munging on the behalf of
|
// processing happens before any MSHR munging on the behalf of
|
||||||
// this request because this new Request will be the one stored
|
// this request because this new Request will be the one stored
|
||||||
// into the MSHRs, not the original.
|
// into the MSHRs, not the original.
|
||||||
if (pkt->cmd.isSWPrefetch() && isTopLevel) {
|
if (pkt->cmd.isSWPrefetch()) {
|
||||||
assert(needsResponse);
|
assert(needsResponse);
|
||||||
assert(pkt->req->hasPaddr());
|
assert(pkt->req->hasPaddr());
|
||||||
assert(!pkt->req->isUncacheable());
|
assert(!pkt->req->isUncacheable());
|
||||||
|
@ -905,7 +912,6 @@ Cache::getBusPacket(PacketPtr cpu_pkt, CacheBlk *blk,
|
||||||
// the line in exclusive state, and invalidates all other
|
// the line in exclusive state, and invalidates all other
|
||||||
// copies
|
// copies
|
||||||
cmd = MemCmd::InvalidateReq;
|
cmd = MemCmd::InvalidateReq;
|
||||||
assert(isTopLevel);
|
|
||||||
} else {
|
} else {
|
||||||
// block is invalid
|
// block is invalid
|
||||||
cmd = needsExclusive ? MemCmd::ReadExReq :
|
cmd = needsExclusive ? MemCmd::ReadExReq :
|
||||||
|
@ -1034,17 +1040,12 @@ Cache::recvAtomic(PacketPtr pkt)
|
||||||
pkt->makeAtomicResponse();
|
pkt->makeAtomicResponse();
|
||||||
pkt->copyError(bus_pkt);
|
pkt->copyError(bus_pkt);
|
||||||
} else if (pkt->cmd == MemCmd::InvalidateReq) {
|
} else if (pkt->cmd == MemCmd::InvalidateReq) {
|
||||||
assert(!isTopLevel);
|
|
||||||
if (blk) {
|
if (blk) {
|
||||||
// invalidate response to a cache that received
|
// invalidate response to a cache that received
|
||||||
// an invalidate request
|
// an invalidate request
|
||||||
satisfyCpuSideRequest(pkt, blk);
|
satisfyCpuSideRequest(pkt, blk);
|
||||||
}
|
}
|
||||||
} else if (pkt->cmd == MemCmd::WriteLineReq) {
|
} else if (pkt->cmd == MemCmd::WriteLineReq) {
|
||||||
// invalidate response to the cache that
|
|
||||||
// received the original write-line request
|
|
||||||
assert(isTopLevel);
|
|
||||||
|
|
||||||
// note the use of pkt, not bus_pkt here.
|
// note the use of pkt, not bus_pkt here.
|
||||||
|
|
||||||
// write-line request to the cache that promoted
|
// write-line request to the cache that promoted
|
||||||
|
@ -1256,7 +1257,7 @@ Cache::recvTimingResp(PacketPtr pkt)
|
||||||
completion_time = pkt->headerDelay;
|
completion_time = pkt->headerDelay;
|
||||||
|
|
||||||
// Software prefetch handling for cache closest to core
|
// Software prefetch handling for cache closest to core
|
||||||
if (tgt_pkt->cmd.isSWPrefetch() && isTopLevel) {
|
if (tgt_pkt->cmd.isSWPrefetch()) {
|
||||||
// a software prefetch would have already been ack'd immediately
|
// a software prefetch would have already been ack'd immediately
|
||||||
// with dummy data so the core would be able to retire it.
|
// with dummy data so the core would be able to retire it.
|
||||||
// this request completes right here, so we deallocate it.
|
// this request completes right here, so we deallocate it.
|
||||||
|
@ -2148,7 +2149,7 @@ Cache::getNextMSHR()
|
||||||
bool
|
bool
|
||||||
Cache::isCachedAbove(const PacketPtr pkt) const
|
Cache::isCachedAbove(const PacketPtr pkt) const
|
||||||
{
|
{
|
||||||
if (isTopLevel)
|
if (!forwardSnoops)
|
||||||
return false;
|
return false;
|
||||||
// Mirroring the flow of HardPFReqs, the cache sends CleanEvict and
|
// Mirroring the flow of HardPFReqs, the cache sends CleanEvict and
|
||||||
// Writeback snoops into upper level caches to check for copies of the
|
// Writeback snoops into upper level caches to check for copies of the
|
||||||
|
|
Loading…
Reference in a new issue