src/Sim/Pipeline/Fetcher/Fetcher.cpp

説明を見る。
00001 // 
00002 // Copyright (c) 2005-2008 Kenichi Watanabe.
00003 // Copyright (c) 2005-2008 Yasuhiro Watari.
00004 // Copyright (c) 2005-2008 Hironori Ichibayashi.
00005 // Copyright (c) 2008-2009 Kazuo Horio.
00006 // Copyright (c) 2009-2013 Naruki Kurata.
00007 // Copyright (c) 2005-2013 Ryota Shioya.
00008 // Copyright (c) 2005-2013 Masahiro Goshima.
00009 // 
00010 // This software is provided 'as-is', without any express or implied
00011 // warranty. In no event will the authors be held liable for any damages
00012 // arising from the use of this software.
00013 // 
00014 // Permission is granted to anyone to use this software for any purpose,
00015 // including commercial applications, and to alter it and redistribute it
00016 // freely, subject to the following restrictions:
00017 // 
00018 // 1. The origin of this software must not be misrepresented; you must not
00019 // claim that you wrote the original software. If you use this software
00020 // in a product, an acknowledgment in the product documentation would be
00021 // appreciated but is not required.
00022 // 
00023 // 2. Altered source versions must be plainly marked as such, and must not be
00024 // misrepresented as being the original software.
00025 // 
00026 // 3. This notice may not be removed or altered from any source
00027 // distribution.
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 };  // namespace Onikiri
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         // Check whether the member variables are set correctly.
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     // These stalls are not implemented by using ClockedResource sytem.
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 // Returns whether 'info' requires serializing or not.
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     // RAXg[
00164     InorderList* inorderList = thread->GetInorderList();
00165     OpIterator frontCommittedOp = inorderList->GetCommittedFrontOp();
00166     OpIterator frontOp          = inorderList->GetFrontOp();
00167 
00168     // In serializing state.
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 // 1fetcho
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         // RAXg[
00194         // In serializing state.
00195         if( IsSerializingRequired( thread ) ){
00196             ++m_stallCycles.currentSyscall;
00197             param.canFetch = false;
00198             return param.canFetch;
00199         }
00200 
00201         // The number of required checkpoints for this fetch group.
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             // tFb`O[v
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         // checkpointMaster `FbN
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             // A
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 // arrayopCo|C^os
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 // pc/infoArray/numOptFb`fetchedOpi[
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,                        // PC*      pc;
00306                 infoArray[ mopIndex ],      // OpInfo* opInfo;
00307                 mopIndex,                   // int      no;
00308                 m_globalClock->GetInsnID(), // u64      globalSerialID;
00309                 baseSerialID + mopIndex,    // u64      serialID;
00310                 baseRetireID + mopIndex,    // u64      retireID;
00311                 core,                       // Core*        core;
00312                 thread                      // Thread*  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         }   // HOOK_SECTION_PARAM( s_fetchHook, param ){
00326 
00327     }   // for( int mopIndex = 0; mopIndex < numOp; ++mopIndex ) {
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 // \s{
00365 void Fetcher::PredictNextPCBody(BranchPredictionHookParam* param)
00366 {
00367     PC predPC;
00368 
00369     PC fetchGroupPC = param->fetchGroupPC;
00370     OpIterator op = param->op;
00371     // {tFb`O[v1BTB
00372     // tFb`O[vBTB
00373     if (op->GetOpClass().IsBranch()) {
00374         predPC = GetBPred()->Predict( op, fetchGroupPC );
00375 
00376         // BTB/RAS Gg CPID
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     ASSERT(
00388         op->GetPC().pid == op->GetPredPC().pid,
00389         "predicted pid not match."
00390     );
00391 */
00392 
00393 }
00394 
00395 // \s
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, &param);
00403 }
00404 
00405 // Enter an op to a fetcher pipeline.
00406 // An op is send to a renamer automatically when the op exits a fetch pipeline.
00407 // A renamer is set to a fetcher by the renamer itself in SetUpperPipelineNode
00408 // that calls SetLowerPipelineNode of the fetcher.
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     // Actually fetched ops in this cycle are determined with 'updated'.
00432     Evaluated updated;
00433     updated.fetchThread = GetFetchThread( false );
00434     
00435     if( updated.fetchThread ){
00436         updated.fetchPC = updated.fetchThread->GetFetchPC();
00437 
00438         // In serializing state.
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     // tFb`O[v (CanFetchgp) 
00457     m_numBranchInFetchGroup = 0;
00458 
00459     Thread* fetchThread = GetFetchThread( true );
00460     if( !fetchThread ){
00461         // RASXbhI
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         // Branch prediction miss recovery is done 
00474         return;
00475     }
00476 
00477     int numFetchedPC = 0;
00478 
00479     for(int i = 0; i < GetFetchWidth(); ++i) {
00480         // emu
00481         const SimPC pc = fetchThread->GetFetchPC();
00482 
00483         if( m_idealMode )
00484             fetchGroupPC = pc;
00485 
00486         if( pc.address == 0 )
00487             break;
00488 
00489         // LbVCEtFb`I
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         // emulator nPCI
00503         if( opArray == 0 || opArray[0] == 0)
00504             break;
00505 
00506         // tFb`tFb`I
00507         if( !CanFetch(fetchThread, pc, opArray, numOp) ) {
00508             break;
00509         }
00510 
00511         /*
00512         for( int k = 0; k < numOp; ++k ) {
00513         // fetch
00514         // checkpoint at decode
00515         ...
00516         // next pc update
00517         // checkpoint at dispatch
00518         // dispatch
00519         }
00520         `R
00521 
00522         PCOp11APCr
00523         `FbN|Cg\
00524         AtFb`PCPsA
00525         XVPCPs
00526 
00527         F
00528         PCrタsNextPC
00529         \~XolKv
00530         */
00531 
00532         // fetch
00533         FetchedOpArray fetchedOp;
00534         Fetch( fetchThread, fetchedOp, pc, opArray, numOp );
00535 
00536         // Kv`FbN|Cg
00537         ForEachOp( fetchedOp, numOp, &Fetcher::CreateCheckpoint );
00538         ForEachOpArg1( fetchedOp, numOp, true/*before*/, &Fetcher::BackupOnCheckpoint );
00539 
00540         fetchThread->AddOpSerialID( numOp );
00541         fetchThread->AddOpRetiredID( numOp );
00542 
00543         // update serialID & retireID
00544         m_numFetchedOp              += numOp;
00545         numFetchedPC++;
00546 
00547         // bpred
00548         ForEachOpArg1( fetchedOp, numOp, fetchGroupPC, &Fetcher::PredictNextPC );
00549 
00550         // next pc update
00551         fetchThread->SetFetchPC( fetchedOp[numOp - 1]->GetPredPC() );
00552         
00553         ForEachOpArg1( fetchedOp, numOp, false/*before*/, &Fetcher::BackupOnCheckpoint );
00554 
00555         // Register the fetched ops to the fetch pipeline.
00556         // Delay of I-Cache miss is implemented in the following stall process.
00557         ForEachOpArg1( fetchedOp, numOp, m_fetchLatency - 1, &Fetcher::EnterPipeline );
00558 
00559         // I-Cache Hit/miss decision
00560         int iCacheReadLatency = GetICacheReadLatency(pc);
00561 
00562         // -1 CTCN
00563         int stallCycles = iCacheReadLatency - m_fetchLatency - 1;   
00564         if( stallCycles > 0 ) {
00565             StallNextCycle( stallCycles );
00566         }
00567 
00568         // <TODO> tFb`O[vuwKE\
00569         // takentFb`O[vI
00570         if( !m_idealMode && 
00571             fetchedOp[numOp - 1]->GetPredPC() != pc.Next() 
00572         ){
00573             break;
00574         }
00575     }
00576 
00577     // 1tFb`tFb`O[v
00578     if( numFetchedPC > 0 ){
00579         m_numFetchGroup++;
00580     }
00581 
00582     m_numFetchedPC += numFetchedPC;
00583 }
00584 
00585 
00586 // Decide a thread that fetches ops in this cycle.
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     // LbVANZXL
00602     // pANZX
00603     CacheAccess access;
00604     access.address = pc;
00605     access.type = CacheAccess::OT_READ;
00606     access.op = OpIterator();   // Todo: add a valid op
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     // Todo: thread retireID lR[h
00616 }

Onikiri2に対してTue Jun 18 14:34:24 2013に生成されました。  doxygen 1.4.7