地址翻译是每个部件的核心,也是NVMain每个模块的关键部分,这个部分一般情况下是通过ADDCHILD继承得来的,下面我分析一下地址翻译的核心部件。
在nvmain的现有版本中,工厂类按照配置选项,动态从三个可以使用的地址翻译子类中选择,分别是DRCDecoder,Migrator,以及AddressTranslator.
这里从最简单的AddressTranslator.开始,下面贴出它的定义
class AddressTranslator
{
public:
AddressTranslator( );
virtual ~AddressTranslator( );
virtual void SetConfig( Config * /*config*/, bool /*createChildren*/ = true ) { }
void SetBusWidth( int );
void SetBurstLength( int );
void SetTranslationMethod( TranslationMethod *m );
TranslationMethod *GetTranslationMethod( );
virtual void Translate( uint64_t address, uint64_t *row, uint64_t *col, uint64_t *bank,
uint64_t *rank, uint64_t *channel, uint64_t *subarray );
virtual void Translate( NVMainRequest *request, uint64_t *row, uint64_t *col, uint64_t *bank,
uint64_t *rank, uint64_t *channel, uint64_t *subarray );
virtual uint64_t ReverseTranslate( const uint64_t& row, const uint64_t& col,
const uint64_t& bank, const uint64_t& rank,
const uint64_t& channel, const uint64_t& subarray );
virtual uint64_t Translate( uint64_t address );
virtual uint64_t Translate( NVMainRequest *request );
virtual void SetDefaultField( TranslationField f );
void SetStats( Stats *stats );
Stats *GetStats( );
void StatName( std::string name );
std::string StatName( );
virtual void RegisterStats( ) { }
virtual void CalculateStats( ) { }
virtual void CreateCheckpoint( std::string /*dir*/ ) { }
virtual void RestoreCheckpoint( std::string /*dir*/ ) { }
private:
TranslationMethod *method;
TranslationField defaultField;
int busWidth;
int burstLength;
int lowColBits;
Stats *stats;
std::string statName;
protected:
uint64_t Divide( uint64_t partSize, MemoryPartition partition );
uint64_t Modulo( uint64_t partialAddr, MemoryPartition partition );
void FindOrder( int order, MemoryPartition *p );
};
void AddressTranslator::Translate( uint64_t address, uint64_t *row, uint64_t *col, uint64_t *bank,
uint64_t *rank, uint64_t *channel, uint64_t *subarray )
这个函数,它的核心是下面的一个循环
for( int i = 0; i < 6; i++ )
{
FindOrder( i, &part );
/*
* The new memsize does not include this partition, so dividing by the
* new memsize will give us the right channel/rank/bank/whatever.
*/
*partitions[part] = Modulo( refAddress, part );
/*
* "Mask off" the first partition number we got. For example if memsize = 1000
* and the address is 8343, the partition would be 8, and we will look at 343
* to determine the rest of the address now.
*/
refAddress = Divide( refAddress, part );
}
我们来分析一次循环调用的具体过程。
首先FindOrder,按照配置文件中地址中各个部件地址的排列顺序【例如:R:RK:BK:CH:C】 【阅读顺序从右至左】
找到第一个出现的是Col, 那么在FindOrder就把part这个枚举变量设置位Col
然后,partitions[part] = Modulo( refAddress, part );
partitions的【part】得到了COL部分的具体数值。
最后,因为COL部分已经被解析出来,调用
refAddress = Divide( refAddress, part );
让地址右移。