对于classic memory的研究,主要从cache入手;按照常理,首先从config文件入手,发现对于cache的配置,从BaseCache.py文件入手,
然后转到BaseCache.py文件,通过对BaseCache.py的微修改,查看编译的过程,找到BaseCache.py的作用以及与其他文件的关联;
发现:
1. BaseCache.py主要用于生成params/BaseCache.hh文件;
对于其中Repl对象,我是比较关心的,具体的定义在params/Repl.hh中,该代码也是编译器scons生成的:
===========
//略去宏定义;
class Repl;
#include “params/SimObject.hh”
struct ReplParams : public SimobjectParams{};
===========
通过上面的代码,基本可以看到Repl是个空的对象,基本上不起作用的;通过后续的代码分析,的确可以验证我们当前的这个假设;
2. 通过grep命令,可以找到用到”BaseCache.hh”的相关文件有:
a) mem/cache/base.hh;
b) mem/cache/prefetch/base.hh;
c) mem/cache/builder.cc;
3. 查看/mem/cache/base.hh文件,使用的方式主要如下:
typedef BaseCacheParams Params;
BaseCache(const Params *p);
4. 上面的第二行代码是对象创建函数,查看/mem/cache/base.cc文件,其中的代码如下:
BaseCache::BaseCache(constParams *p)
: MemObject(p),
mshrQueue("MSHRs", p->mshrs,4, MSHRQueue_MSHRs),
writeBuffer("write buffer",p->write_buffers, p->mshrs+1000,
MSHRQueue_WriteBuffer),
blkSize(p->block_size),
hitLatency(p->latency),
numTarget(p->tgts_per_mshr),
forwardSnoops(p->forward_snoops),
isTopLevel(p->is_top_level),
blocked(0),
noTargetMSHR(NULL),
missCount(p->max_miss_count),
drainEvent(NULL),
addrRange(p->addr_range),
_numCpus(p->num_cpus)
{
}
上述是一个构建函数,初始化参数都来自于BaseCache.hh中的BaseCacheParams对象;
5. Prefetch部分暂时不考虑,我们关注mem/cache/builder.cc文件,这部分的代码完成cache的创建工作,其中值得留意的代码有:
const void *repl= NULL;
验证我们前面的猜想;
代码主体:
BaseCache *BaseCacheParams::create()
{
int numSets = size / (assoc * block_size);
if (subblock_size == 0) {
subblock_size = block_size;
}
#ifdefined(USE_CACHE_IIC)
// Build IIC params
IIC::Params iic_params;
iic_params.size = size;
iic_params.numSets = numSets;
iic_params.blkSize = block_size;
iic_params.assoc = assoc;
iic_params.hashDelay = hash_delay;
iic_params.hitLatency = latency;
iic_params.rp = repl;
iic_params.subblockSize = subblock_size;
#else
constvoid *repl = NULL;
#endif
BUILD_CACHES;
return NULL;
}
下面的宏完成cache的创建工作:
#defineBUILD_CACHES do { \
if (repl == NULL) { \
if (numSets == 1) { \
BUILD_FALRU_CACHE; \
} else { \
BUILD_LRU_CACHE; \
} \
} else { \
BUILD_IIC_CACHE; \
} \
} while (0)
#if defined(USE_CACHE_LRU)
#define BUILD_LRU_CACHE do { \
LRU *tags = newLRU(numSets, block_size, assoc, latency); \
BUILD_CACHE(LRU,tags); \
} while (0)
#else
#define BUILD_LRU_CACHE BUILD_CACHE_PANIC("lru cache")
#endif
#define BUILD_CACHE(TAGS, tags) \
do { \
BasePrefetcher*pf; \
if (prefetch_policy ==Enums::tagged) { \
pf = newTaggedPrefetcher(this); \
} \
else if(prefetch_policy == Enums::stride) { \
pf = newStridePrefetcher(this); \
} \
else if(prefetch_policy == Enums::ghb) { \
pf = newGHBPrefetcher(this); \
} \
else { \
pf = NULL; \
} \
Cache<TAGS>*retval = \
newCache<TAGS>(this, tags, pf); \
return retval; \
} while (0)
#define BUILD_CACHE_PANIC(x) do { \
panic("%s notcompiled into M5", x); \
} while (0)
上述代码之中的关键在于如下这句:
Cache<TAGS> *retval= \
newCache<TAGS>(this, tags, pf); \
return retval;
6. 这里的cache是一个模板类,将<TAGS>作为参数传递进去后,完成模板的具体化;完成这些操作后,大致就完成cache的创建和操作关联了,
查看上述的代码,一般是采用tag文件夹中的lru.cc,lru.hh来实例化TAG;