00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <pch.h>
00033
00034 #include "Sim/Pipeline/Fetcher/Fetcher.h"
00035 #include "Sim/Pipeline/Fetcher/Steerer/FetchThreadSteererIF.h"
00036
00037 #include "Env/Env.h"
00038 #include "Sim/Dumper/Dumper.h"
00039 #include "Utility/RuntimeError.h"
00040
00041 #include "Interface/EmulatorIF.h"
00042
00043 #include "Sim/InorderList/InorderList.h"
00044 #include "Sim/Thread/Thread.h"
00045 #include "Sim/Core/Core.h"
00046 #include "Sim/Pipeline/Scheduler/Scheduler.h"
00047 #include "Sim/Predictor/DepPred/RegDepPred/RegDepPredIF.h"
00048 #include "Sim/Predictor/DepPred/MemDepPred/MemDepPredIF.h"
00049 #include "Sim/Memory/Cache/Cache.h"
00050 #include "Sim/Memory/Cache/CacheSystem.h"
00051 #include "Sim/System/ForwardEmulator.h"
00052
00053 #include "Sim/Foundation/Hook/HookUtil.h"
00054 #include "Sim/System/GlobalClock.h"
00055 #include "Sim/Op/Op.h"
00056 #include "Sim/Op/OpInitArgs.h"
00057 #include "Sim/Predictor/BPred/BPred.h"
00058 #include "Sim/Dependency/PhyReg/PhyReg.h"
00059 #include "Sim/Memory/MemOrderManager/MemOrderManager.h"
00060 #include "Sim/Foundation/SimPC.h"
00061
00062 using namespace std;
00063 using namespace boost;
00064 using namespace Onikiri;
00065
00066
00067 namespace Onikiri
00068 {
00069 HookPoint<Fetcher, Fetcher::FetchHookParam> Fetcher::s_fetchHook;
00070 HookPoint<Fetcher, Fetcher::SteeringHookParam> Fetcher::s_fetchSteeringHook;
00071 HookPoint<Fetcher, Fetcher::FetchDecisionHookParam> Fetcher::s_fetchDecisionHook;
00072 HookPoint<Fetcher, Fetcher::BranchPredictionHookParam> Fetcher::s_branchPredictionHook;
00073 };
00074
00075 Fetcher::Fetcher() :
00076 m_fetchWidth(0),
00077 m_fetchLatency(0),
00078 m_numFetchedOp(0),
00079 m_numFetchedPC(0),
00080 m_numFetchGroup(0),
00081 m_numBranchInFetchGroup(0),
00082 m_idealMode(false),
00083 m_checkLatencyMismatch(false),
00084 m_currentFetchThread(0),
00085 m_bpred(0),
00086 m_cacheSystem(0),
00087 m_emulator(0),
00088 m_globalClock(0),
00089 m_forwardEmulator(0),
00090 m_fetchThreadSteerer(0)
00091 {
00092 }
00093
00094 Fetcher::~Fetcher()
00095 {
00096 }
00097
00098 void Fetcher::Initialize(InitPhase phase)
00099 {
00100 PipelineNodeBase::Initialize(phase);
00101
00102 if(phase == INIT_PRE_CONNECTION){
00103 LoadParam();
00104 }
00105 else if(phase == INIT_POST_CONNECTION){
00106
00107
00108 CheckNodeInitialized( "emulator", m_emulator );
00109 CheckNodeInitialized( "bpred", m_bpred );
00110 CheckNodeInitialized( "cacheSystem", m_cacheSystem );
00111 CheckNodeInitialized( "globalClock", m_globalClock );
00112
00113 int iCacheLatency = m_cacheSystem->GetFirstLevelInsnCache()->GetStaticLatency();
00114 if( m_checkLatencyMismatch && m_fetchLatency != iCacheLatency ){
00115 THROW_RUNTIME_ERROR(
00116 "'@FetchLatency' and the latency of the L1 I-cache do not match. "
00117 "If this configuration is intended, disable '@CheckLatencyMismatch'."
00118 );
00119 }
00120
00121 if( m_fetchLatency < iCacheLatency ){
00122 THROW_RUNTIME_ERROR(
00123 "'@FetchLatency' is shorter than the latency of the L1 I-cache."
00124 );
00125 }
00126
00127 if( GetLowerPipelineNode() == NULL ){
00128 THROW_RUNTIME_ERROR( "Renamer is not connected." );
00129 }
00130
00131 DisableLatch();
00132 }
00133 }
00134
00135 void Fetcher::Finalize()
00136 {
00137 m_stallCycles.others = GetStalledCycles();
00138
00139 m_stallCycles.total = m_stallCycles.others;
00140
00141 m_stallCycles.total +=
00142 m_stallCycles.currentSyscall +
00143 m_stallCycles.nextSyscall +
00144 m_stallCycles.checkpoint +
00145 m_stallCycles.inorderList;
00146
00147 ReleaseParam();
00148 }
00149
00150
00151 bool Fetcher::IsSerializingRequired( const OpInfo* const info ) const
00152 {
00153 return info->GetOpClass().IsSyscall();
00154 }
00155
00156 bool Fetcher::IsSerializingRequired( OpIterator op ) const
00157 {
00158 return IsSerializingRequired( op->GetOpInfo() );
00159 }
00160
00161 bool Fetcher::IsSerializingRequired( Thread* thread ) const
00162 {
00163
00164 InorderList* inorderList = thread->GetInorderList();
00165 OpIterator frontCommittedOp = inorderList->GetCommittedFrontOp();
00166 OpIterator frontOp = inorderList->GetFrontOp();
00167
00168
00169 if( !inorderList->IsEmpty() &&
00170 ( ( !frontOp.IsNull() && IsSerializingRequired( frontOp ) ) ||
00171 ( !frontCommittedOp.IsNull() && IsSerializingRequired( frontCommittedOp ) ) )
00172 ){
00173 return true;
00174 }
00175 else{
00176 return false;
00177 }
00178 }
00179
00180
00181
00182 void Fetcher::CanFetchBody( FetchDecisionHookParam* param )
00183 {
00184 }
00185
00186
00187 bool Fetcher::CanFetch( Thread* thread, PC pc, OpInfo** infoArray, int numOp )
00188 {
00189 FetchDecisionHookParam param = { thread, pc, infoArray, numOp, false };
00190
00191 HOOK_SECTION_PARAM( s_fetchDecisionHook, param )
00192 {
00193
00194
00195 if( IsSerializingRequired( thread ) ){
00196 ++m_stallCycles.currentSyscall;
00197 param.canFetch = false;
00198 return param.canFetch;
00199 }
00200
00201
00202 int numCheckpointReq = 0;
00203
00204
00205 bool reqSerializing = false;
00206
00207 for( int k = 0; k < numOp; ++k ) {
00208 OpInfo* info = infoArray[k];
00209
00210 if( IsSerializingRequired(info) ) {
00211 reqSerializing = true;
00212 }
00213
00214
00215 if( !m_idealMode && info->GetOpClass().IsBranch() ) {
00216 if( m_numBranchInFetchGroup >= m_maxBranchInFetchGroup ){
00217 param.canFetch = false;
00218 return param.canFetch;
00219 }
00220 ++m_numBranchInFetchGroup;
00221 }
00222
00223 if( GetCore()->IsRequiredCheckpointBefore(pc, info) ) {
00224 ++numCheckpointReq;
00225 }
00226
00227 if( GetCore()->IsRequiredCheckpointAfter(pc, info) ) {
00228 ++numCheckpointReq;
00229 }
00230 }
00231
00232
00233 if( !thread->GetCheckpointMaster()->CanCreate( numCheckpointReq ) ) {
00234 ++m_stallCycles.checkpoint;
00235 param.canFetch = false;
00236 return param.canFetch;
00237 }
00238
00239 if( !thread->GetInorderList()->CanAllocate( numOp ) ){
00240 ++m_stallCycles.inorderList;
00241 param.canFetch = false;
00242 return param.canFetch;
00243 }
00244
00245
00246 if( reqSerializing ){
00247
00248 InorderList* inorderList = thread->GetInorderList();
00249 if( m_evaluated.isInorderListEmpty && inorderList->IsEmpty() ){
00250 param.canFetch = true;
00251 return param.canFetch;
00252 }
00253 else {
00254 ++m_stallCycles.nextSyscall;
00255 param.canFetch = false;
00256 return param.canFetch;
00257 }
00258 }
00259
00260 param.canFetch = true;
00261 }
00262 return param.canFetch;
00263
00264 }
00265
00266
00267 inline void Fetcher::ForEachOp(
00268 FetchedOpArray& c,
00269 int size,
00270 void (Fetcher::*func)(OpIterator) )
00271 {
00272 for( int i = 0; i < size; i++ ){
00273 (this->*func)(c[i]);
00274 }
00275 }
00276
00277 template <typename T1>
00278 inline void Fetcher::ForEachOpArg1(
00279 FetchedOpArray& c,
00280 int size,
00281 T1 arg1,
00282 void (Fetcher::*func)(OpIterator, T1) )
00283 {
00284 for( int i = 0; i < size; i++ ){
00285 (this->*func)(c[i], arg1);
00286 }
00287 }
00288
00289
00290 void Fetcher::Fetch(Thread* thread, FetchedOpArray& fetchedOp, PC pc, OpInfo** infoArray, int numOp )
00291 {
00292 InorderList* InorderList = thread->GetInorderList();
00293 Core* core = GetCore();
00294
00295 u64 baseSerialID = thread->GetOpSerialID();
00296 u64 baseRetireID = thread->GetOpRetiredID();
00297
00298 fetchedOp.clear();
00299 for( int mopIndex = 0; mopIndex < numOp; ++mopIndex ) {
00300
00301 FetchHookParam param;
00302 HOOK_SECTION_PARAM( s_fetchHook, param ){
00303 OpInitArgs args =
00304 {
00305 &pc,
00306 infoArray[ mopIndex ],
00307 mopIndex,
00308 m_globalClock->GetInsnID(),
00309 baseSerialID + mopIndex,
00310 baseRetireID + mopIndex,
00311 core,
00312 thread
00313 };
00314
00315 OpIterator op = InorderList->ConstructOp( args );
00316 param.op = op;
00317
00318 g_dumper.Dump( DS_FETCH, op );
00319
00320 fetchedOp.push_back( op );
00321 InorderList->PushBack( op );
00322
00323 m_globalClock->AddInsnID( 1 );
00324 m_forwardEmulator->OnFetch( op );
00325 }
00326
00327 }
00328 }
00329
00330 void Fetcher::CreateCheckpoint( OpIterator op )
00331 {
00332 const PC& pc = op->GetPC();
00333 OpInfo* const opInfo = op->GetOpInfo();
00334
00335 if( GetCore()->IsRequiredCheckpointBefore(pc, opInfo) ){
00336 CheckpointMaster* master = op->GetThread()->GetCheckpointMaster();
00337 Checkpoint* newCheckpoint = master->CreateCheckpoint();
00338 op->SetBeforeCheckpoint( newCheckpoint );
00339 }
00340
00341 if( GetCore()->IsRequiredCheckpointAfter(pc, opInfo) ){
00342 CheckpointMaster* master = op->GetThread()->GetCheckpointMaster();
00343 Checkpoint* newCheckpoint = master->CreateCheckpoint();
00344 op->SetAfterCheckpoint( newCheckpoint );
00345 }
00346 }
00347
00348 void Fetcher::BackupOnCheckpoint( OpIterator op, bool before )
00349 {
00350 const PC& pc = op->GetPC();
00351 OpInfo* const opInfo = op->GetOpInfo();
00352
00353 if( before && GetCore()->IsRequiredCheckpointBefore(pc, opInfo) ) {
00354 CheckpointMaster* master = op->GetThread()->GetCheckpointMaster();
00355 master->Backup(op->GetBeforeCheckpoint(), CheckpointMaster::SLOT_FETCH);
00356 }
00357
00358 if( !before && GetCore()->IsRequiredCheckpointAfter( pc, opInfo ) ) {
00359 CheckpointMaster* master = op->GetThread()->GetCheckpointMaster();
00360 master->Backup(op->GetAfterCheckpoint(), CheckpointMaster::SLOT_FETCH);
00361 }
00362 }
00363
00364
00365 void Fetcher::PredictNextPCBody(BranchPredictionHookParam* param)
00366 {
00367 PC predPC;
00368
00369 PC fetchGroupPC = param->fetchGroupPC;
00370 OpIterator op = param->op;
00371
00372
00373 if (op->GetOpClass().IsBranch()) {
00374 predPC = GetBPred()->Predict( op, fetchGroupPC );
00375
00376
00377 predPC.pid = fetchGroupPC.pid;
00378 predPC.tid = fetchGroupPC.tid;
00379 }
00380 else {
00381 SimPC pc(op->GetPC());
00382 predPC = pc.Next();
00383 }
00384
00385 op->SetPredPC( predPC );
00386
00387
00388
00389
00390
00391
00392
00393 }
00394
00395
00396 void Fetcher::PredictNextPC(OpIterator op, PC fetchGroupPC)
00397 {
00398 BranchPredictionHookParam param;
00399 param.fetchGroupPC = fetchGroupPC;
00400 param.op = op;
00401
00402 HookEntry( this, &Fetcher::PredictNextPCBody, &s_branchPredictionHook, ¶m);
00403 }
00404
00405
00406
00407
00408
00409 void Fetcher::EnterPipeline( OpIterator op, int nextEventCycle )
00410 {
00411 GetLowerPipeline()->EnterPipeline(
00412 op,
00413 nextEventCycle,
00414 GetLowerPipelineNode()
00415 );
00416 op->SetStatus( OpStatus::OS_FETCH );
00417 }
00418
00419 void Fetcher::Finished(OpIterator op)
00420 {
00421 GetBPred()->Finished(op);
00422 }
00423
00424 void Fetcher::Commit(OpIterator op)
00425 {
00426 GetBPred()->Commit(op);
00427 }
00428
00429 void Fetcher::Evaluate()
00430 {
00431
00432 Evaluated updated;
00433 updated.fetchThread = GetFetchThread( false );
00434
00435 if( updated.fetchThread ){
00436 updated.fetchPC = updated.fetchThread->GetFetchPC();
00437
00438
00439 InorderList* inorderList = updated.fetchThread->GetInorderList();
00440 updated.isInorderListEmpty = inorderList->IsEmpty();
00441 updated.reqSerializing =
00442 ( !updated.isInorderListEmpty && IsSerializingRequired( updated.fetchThread ) );
00443 }
00444
00445 m_evaluated = updated;
00446 BaseType::Evaluate();
00447 }
00448
00449
00450 void Fetcher::Update()
00451 {
00452
00453 const int cacheOffsetBitSize =
00454 m_cacheSystem->GetFirstLevelInsnCache()->GetOffsetBitSize();
00455
00456
00457 m_numBranchInFetchGroup = 0;
00458
00459 Thread* fetchThread = GetFetchThread( true );
00460 if( !fetchThread ){
00461
00462 return;
00463 }
00464 if( m_evaluated.reqSerializing ){
00465 ++m_stallCycles.currentSyscall;
00466 return;
00467 }
00468
00469 ASSERT( m_evaluated.fetchThread == fetchThread );
00470
00471 PC fetchGroupPC = fetchThread->GetFetchPC();
00472 if( fetchGroupPC != m_evaluated.fetchPC ){
00473
00474 return;
00475 }
00476
00477 int numFetchedPC = 0;
00478
00479 for(int i = 0; i < GetFetchWidth(); ++i) {
00480
00481 const SimPC pc = fetchThread->GetFetchPC();
00482
00483 if( m_idealMode )
00484 fetchGroupPC = pc;
00485
00486 if( pc.address == 0 )
00487 break;
00488
00489
00490 if( !m_idealMode &&
00491 (fetchGroupPC.address >> cacheOffsetBitSize) !=
00492 (pc.address >> cacheOffsetBitSize)
00493 ){
00494 break;
00495 }
00496
00497 pair<OpInfo**, int> ops = m_emulator->GetOp(pc);
00498
00499 OpInfo** opArray = ops.first;
00500 int numOp = ops.second;
00501
00502
00503 if( opArray == 0 || opArray[0] == 0)
00504 break;
00505
00506
00507 if( !CanFetch(fetchThread, pc, opArray, numOp) ) {
00508 break;
00509 }
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533 FetchedOpArray fetchedOp;
00534 Fetch( fetchThread, fetchedOp, pc, opArray, numOp );
00535
00536
00537 ForEachOp( fetchedOp, numOp, &Fetcher::CreateCheckpoint );
00538 ForEachOpArg1( fetchedOp, numOp, true, &Fetcher::BackupOnCheckpoint );
00539
00540 fetchThread->AddOpSerialID( numOp );
00541 fetchThread->AddOpRetiredID( numOp );
00542
00543
00544 m_numFetchedOp += numOp;
00545 numFetchedPC++;
00546
00547
00548 ForEachOpArg1( fetchedOp, numOp, fetchGroupPC, &Fetcher::PredictNextPC );
00549
00550
00551 fetchThread->SetFetchPC( fetchedOp[numOp - 1]->GetPredPC() );
00552
00553 ForEachOpArg1( fetchedOp, numOp, false, &Fetcher::BackupOnCheckpoint );
00554
00555
00556
00557 ForEachOpArg1( fetchedOp, numOp, m_fetchLatency - 1, &Fetcher::EnterPipeline );
00558
00559
00560 int iCacheReadLatency = GetICacheReadLatency(pc);
00561
00562
00563 int stallCycles = iCacheReadLatency - m_fetchLatency - 1;
00564 if( stallCycles > 0 ) {
00565 StallNextCycle( stallCycles );
00566 }
00567
00568
00569
00570 if( !m_idealMode &&
00571 fetchedOp[numOp - 1]->GetPredPC() != pc.Next()
00572 ){
00573 break;
00574 }
00575 }
00576
00577
00578 if( numFetchedPC > 0 ){
00579 m_numFetchGroup++;
00580 }
00581
00582 m_numFetchedPC += numFetchedPC;
00583 }
00584
00585
00586
00587 Thread* Fetcher::GetFetchThread( bool update )
00588 {
00589 SteeringHookParam hookParam = { NULL, &m_thread, update };
00590
00591 HOOK_SECTION_PARAM( s_fetchSteeringHook, hookParam ){
00592 hookParam.targetThread = m_fetchThreadSteerer->SteerThread(update);
00593 }
00594
00595
00596 return hookParam.targetThread;
00597 }
00598
00599 const int Fetcher::GetICacheReadLatency(const PC& pc)
00600 {
00601
00602
00603 CacheAccess access;
00604 access.address = pc;
00605 access.type = CacheAccess::OT_READ;
00606 access.op = OpIterator();
00607 CacheAccessResult result =
00608 m_cacheSystem->GetFirstLevelInsnCache()->Read( access, NULL );
00609 return result.latency;
00610 }
00611
00612 void Fetcher::SetInitialNumFetchedOp(u64 num)
00613 {
00614 m_numFetchedOp = num;
00615
00616 }