指令传递
(nvmain.cpp中)bool NVMain :: IssueCommand中,预取会插入事件
if( CheckPrefetch( request ) )
{
GetEventQueue()->InsertEvent( EventResponse, this, request,
GetEventQueue()->GetCurrentCycle() + 1 );
return true;
}
继续走孩子
mc_rv = GetChild( request )->IssueCommand( request );
nvmain的孩子是MemoryController(nvmain.cpp的SetConfig中添加子,每个通道一个内存控制器,即一个子,共通道个子;每个MemoryController实际新的是根据其内存控制器调度类型确定的)
for( int i = 0; i < channels; i++ ){
……
/* Initialize memory controller */
memoryControllers[i] = MemoryControllerFactory::CreateNewController( channelConfig[i]->GetString( "MEM_CTL" ) );
……
AddChild( memoryControllers[i] );
……
}
MemoryController *MemoryControllerFactory::CreateNewController( std::string controller )
{
……
if( controller == "FCFS" )
memoryController = new FCFS( );
……
}
MemoryController的调用setConfig中,添加孩子为互连
Interconnect *memory;
……
memory->SetParent( this );
AddChild( memory );
在FCFS中,调用MemoryController的入队函数
bool FCFS::IssueCommand( NVMainRequest *request )
{
/* Allow up to 16 read/writes outstanding. */
if( !IsIssuable( request ) )
return false;
if( request->type == READ )
mem_reads++;
else
mem_writes++;
Enqueue( 0, request );
/*
* Return whether the request could be queued. Return false if the queue is full.
*/
return true;
}
该函数中先获得翻译后的地址(注意信道可能不是原始的物理地址翻译出来的信道,修改过),再推进指定transactionQueues中,(根据调度算法不同,transactionQueues个数不同,FCFS只有一个transactionQueues,而FRFCFS-WQF有读写两个transactionQueues,根据读写放进不同的transactionQueues中)
根据queueModel是PerRankQueues / PerBankQueues / PerSubArrayQueues,以及访问的地址,得到queueId
EffectivelyEmpty函数:如果命令队列为空或在下一个循环中为空,则返回true
如果commandQueues [queueId]为空或马上为空(注意不是transactionQueues)则插入事件EventCycle,时间为当前时间,这样到该事件的时候,就会唤醒这个NVMainObject的Cycle函数
void MemoryController::Enqueue( ncounter_t queueNum, NVMainRequest *request )
{
/* Retranslate once for this channel, but leave channel the same */
ncounter_t channel, rank, bank, row, col, subarray;
GetDecoder( )->Translate( request->address.GetPhysicalAddress( ),
&row, &col, &bank, &rank, &channel, &subarray );
channel = request->address.GetChannel( );
request->address.SetTranslatedAddress( row, col, bank, rank, channel, subarray );
/* Enqueue the request. */
assert( queueNum < transactionQueueCount );
transactionQueues[queueNum].push_back( request );
/* If this command queue is empty, we can schedule a new transaction right away. */
ncounter_t queueId = GetCommandQueueId( request->address );
if( EffectivelyEmpty( queueId ) )
{
ncycle_t nextWakeup = GetEventQueue( )->GetCurrentCycle( );
if( GetEventQueue( )->FindEvent( EventCycle, this, NULL, nextWakeup ) == NULL )
{
GetEventQueue( )->InsertEvent( EventCycle, this, nextWakeup, NULL, transactionQueuePriority );
}
}
}
transactionQueues在FCFS的周期中被使用; FindOldestReadyRequest找到最旧的请求(该地址对应commandQueues为空的请求中最旧的)
if( !commandQueues[queueId].empty() ) continue;
void FCFS::Cycle( ncycle_t steps )
{
NVMainRequest *nextReq = NULL;
/* Simply get the oldest request */
if( !FindOldestReadyRequest( transactionQueues[0], &nextReq ) )
{
/* No oldest ready request, check for non-activated banks. */
(void)FindClosedBankRequest( transactionQueues[0], &nextReq );
}
if( nextReq != NULL )
{
IssueMemoryCommands( nextReq );
}
CycleCommandQueues( );
MemoryController::Cycle( steps );
}
在MemoryController的IssueMemoryCommands中,根据不同情况,将指令压入commandQueues中(还可能根据情况先压入预充电等指令进commandQueues)
ScheduleCommandWake函数暂时没看懂,涉及回调
返回先到先得的周期,调用CycleCommandQueues函数
CycleCommandQueues函数看条件可能会进行(具体待看)
GetChild( )->IssueCommand( queueHead );
GetEventQueue( )->InsertEvent( EventCycle, this, nextWakeup, NULL, transactionQueuePriority );
FCFS的Cycle调用的:: Cycle(steps)可能会
GetEventQueue( )->InsertEvent( EventCycle, this, nextWakeup, NULL, transactionQueuePriority );
MemoryController的孩子是互连
memory = InterconnectFactory :: CreateInterconnect(conf-> GetString(“INTERCONNECT”));可能为OnChipBus / OffChipBus
OffChipBus的调用setConfig中创建子
Rank *nextRank = RankFactory::CreateRankNoWarn( c->GetString( "RankType" ) );
IssueCommand中传给孩子;并且检查等级切换的开销
success = GetChild( req )->IssueCommand( req );
/*
* To preserve rank-to-rank switching time, we need to notify the
* other ranks what the command sent was.
*/
if( success )
{
for( ncounter_t childIdx = 0; childIdx < GetChildCount( ); childIdx++ )
if( GetChild( req ) != GetChild( childIdx ) )
GetChild( childIdx )->Notify( req );
}
根据RankFactory创建的为StandardRank(StandardRank.cpp)
排名的孩子为银行(DDR3Bank)
bank的子为子阵列(subArrayNum = p-> ROWS / MATHeight;所以至少还是有一个subArray)
subArray类包含endrModel和dataEncoder(/ *我们需要在子数组级别创建耐久性模型* /)
subArray不再向下传递,通过GetEventQueue() - > InsertEvent()放进事件队列