src/Sim/Memory/MemOrderManager/MemOrderManager.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/Memory/MemOrderManager/MemOrderManager.h"
00035 
00036 #include "SysDeps/Endian.h"
00037 #include "Utility/RuntimeError.h"
00038 #include "Sim/Dumper/Dumper.h"
00039 
00040 #include "Interface/OpClass.h"
00041 
00042 #include "Sim/Foundation/Hook/HookUtil.h"
00043 #include "Sim/InorderList/InorderList.h"
00044 #include "Sim/Core/Core.h"
00045 #include "Sim/Predictor/DepPred/MemDepPred/MemDepPredIF.h"
00046 #include "Sim/Memory/Cache/Cache.h"
00047 #include "Sim/Memory/Cache/CacheSystem.h"
00048 #include "Sim/Thread/Thread.h"
00049 #include "Sim/Recoverer/Recoverer.h"
00050 #include "Sim/Pipeline/Fetcher/Fetcher.h"
00051 
00052 #include "Sim/Op/Op.h"
00053 
00054 namespace Onikiri
00055 {
00056     MemOrderManager::MemImageAccessHook MemOrderManager::s_writeMemImageHook;
00057     MemOrderManager::MemImageAccessHook MemOrderManager::s_readMemImageHook;
00058 }
00059 
00060 using namespace std;
00061 using namespace Onikiri;
00062 
00063 MemOrderManager::MemOrderManager() :
00064     m_unified(false),
00065     m_unifiedCapacity(0),
00066     m_loadCapacity(0),
00067     m_storeCapacity(0),
00068     m_idealPartialLoad(false),
00069     m_removeOpsOnCommit(false),
00070     m_cacheLatency(0),
00071     m_numExecutedStoreForwarding(0),
00072     m_numRetiredStoreForwarding(0),
00073     m_numExecutedLoadAccess(0),
00074     m_numRetiredLoadAccess(0),
00075     m_cache(0),
00076     m_cacheSystem(0),
00077     m_core(0),
00078     m_emulator(0)
00079 {
00080 }
00081 
00082 MemOrderManager::~MemOrderManager()
00083 {
00084 }
00085 
00086 void MemOrderManager::Initialize( InitPhase phase )
00087 {
00088     if( phase == INIT_PRE_CONNECTION ){
00089         LoadParam();
00090     }
00091     else if( phase == INIT_POST_CONNECTION ){
00092 
00093         // oZbg`FbN
00094         CheckNodeInitialized( "core", m_core );
00095         CheckNodeInitialized( "emulator", m_emulator );
00096         CheckNodeInitialized( "cacheSystem", m_cacheSystem );
00097 
00098         m_cache = m_cacheSystem->GetFirstLevelDataCache();
00099         m_cacheLatency = m_cache->GetStaticLatency();
00100 
00101         // List
00102         m_loadList.resize(*m_core->GetOpArray());
00103         m_storeList.resize(*m_core->GetOpArray());
00104         m_memOperations.SetTargetEndian( m_emulator->GetISAInfo()->IsLittleEndian() );
00105 
00106         int fetchWidth = GetCore()->GetFetcher()->GetFetchWidth();
00107         if( m_unified ){
00108             if( fetchWidth > m_unifiedCapacity ){
00109                 THROW_RUNTIME_ERROR( "The capacity of MemOrderManager is too small. It must be larger than fetch width." );
00110             }
00111         }
00112         else{
00113             if( fetchWidth > m_loadCapacity || fetchWidth > m_storeCapacity ){
00114                 THROW_RUNTIME_ERROR( "The capacity of MemOrderManager is too small. It must be larger than fetch width." );
00115             }
00116         }
00117     }
00118 
00119 }
00120 
00121 void MemOrderManager::Finalize()
00122 {
00123     ReleaseParam();
00124 }
00125 
00126 // Detecting access order violation between 
00127 // a store executed in this cycle and 
00128 // successor loads that are already executed on program order.
00129 void MemOrderManager::DetectAccessOrderViolation( OpIterator store )
00130 {
00131     /*
00132     F
00133     vOI[_
00134 
00135     store1   [A] = Y --- op
00136     load1    U   = [A]
00137     store2   [A] = Z
00138     load2    V   = [A]
00139     
00140      store1 XPW[OAload1, load2XPW[O
00141     Aload1store1タsAload1, load2XPW[O
00142     */
00143 
00144     // store G[
00145     ASSERT( store->GetOpClass().IsStore(), "Not store op." );
00146 
00147     // m store G[
00148     ASSERT( m_storeList.count(store) == 1, "unknown op." );
00149 
00150     OpIterator conflictedConsumer = GetConsumerLoad( store, store->GetMemAccess(), 0 );
00151 
00152     if( !conflictedConsumer.IsNull() ){
00153         
00154         if( store->GetSerialID() >= conflictedConsumer->GetSerialID() ) {
00155             THROW_RUNTIME_ERROR("memory order is not inorder.");
00156         }
00157         
00158         g_dumper.Dump( DS_ADDRESS_PREDICTION_MISS, conflictedConsumer );
00159         
00160         // MemDepPred m
00161         store->GetThread()->GetMemDepPred()->OrderConflicted( store, conflictedConsumer );
00162 
00163         // 
00164         Recoverer* recoverer = store->GetThread()->GetRecoverer();
00165         recoverer->RecoverDataPredMiss( 
00166             store, 
00167             conflictedConsumer, 
00168             Recovery::TYPE_ADDRESS_MATCH 
00169         );
00170 
00171     }
00172 }
00173 
00174 
00175 // Detect and recover from partial read violation.
00176 bool MemOrderManager::DetectPartialLoadViolation( OpIterator op )
00177 {
00178     if( op->GetOpClass().IsLoad() ){
00179         // Validate whether invalid partial read occurs or not.
00180         // If invalid partial read occurs, MAR_READ_INVALID_PARTIAL_READ is 
00181         // set to a result and need to recover.
00182         const MemAccess& mem = op->GetMemAccess();
00183         if( mem.result == MemAccess::MAR_READ_INVALID_PARTIAL_READ ){
00184             OpIterator producer = 
00185                 GetProducerStore( op, mem );
00186             Recoverer* recoverer = op->GetThread()->GetRecoverer();
00187 
00188             recoverer->RecoverDataPredMiss( 
00189                 producer, 
00190                 op, 
00191                 DataPredMissRecovery::TYPE_PARTIAL_LOAD 
00192             );
00193             return true;
00194         }
00195     }
00196     return false;
00197 }
00198 
00199 bool MemOrderManager::CanAllocate( OpIterator* infoArray, int numOp )
00200 {
00201     if( m_unified ){
00202         return m_unifiedCapacity >= (int)m_storeList.size() + (int)m_loadList.size() + numOp;
00203     }
00204     else{
00205         int loads  = 0;
00206         int stores = 0;
00207         for( int i = 0; i < numOp; ++i ){
00208             if( infoArray[i]->GetOpClass().IsStore() ){
00209                 stores++;
00210             }
00211             if( infoArray[i]->GetOpClass().IsLoad() ){
00212                 loads++;
00213             }
00214         }
00215         return 
00216             ( m_loadCapacity  >= ((int)m_loadList.size() + loads) ) &&
00217             ( m_storeCapacity >= ((int)m_storeList.size() + stores) );
00218     }
00219 }
00220 
00221 void MemOrderManager::Allocate(OpIterator op)
00222 {
00223     const OpClass& opClass = op->GetOpClass();
00224     ASSERT( opClass.IsMem() );
00225     if( opClass.IsLoad() ){
00226         m_loadList.push_back( op );
00227     }
00228     else{
00229         m_storeList.push_back( op );
00230     }
00231 }
00232 
00233 // タsI
00234 void MemOrderManager::Finished( OpIterator op )
00235 {
00236     const OpClass& opClass = op->GetOpClass();
00237     // Detect access order violation.
00238     if( opClass.IsStore() ){
00239         ASSERT( m_storeList.count(op) == 1, "unknown op." );
00240         DetectAccessOrderViolation( op );
00241     }
00242 
00243     if( opClass.IsLoad() ){
00244         ASSERT( m_loadList.count(op) == 1, "unknown op." );
00245         DetectPartialLoadViolation( op );
00246     }
00247 }
00248 
00249 // AhXvsstoreMemOrderManagerf
00250 // InnerAccess`FbNs
00251 OpIterator MemOrderManager::GetProducerStore( OpIterator consumer, const MemAccess& access ) const
00252 {
00253     ASSERT( access.address.pid != PID_INVALID );
00254 
00255     // AhXvsstoreMemOrderManagerAMemOrderManagerReads
00256     // m_listopuOT
00257     ASSERT( m_loadList.count(consumer) == 1, "unknown load:\n%s", consumer->ToString().c_str() );
00258 
00259     OpIterator producer = OpIterator(0);
00260 
00261     OpList::const_iterator i = m_storeList.end();
00262     while( i != m_storeList.begin() ) {
00263         --i;
00264 
00265         OpIterator op = *i;
00266 
00267         if( op->GetGlobalSerialID() > consumer->GetGlobalSerialID() ){
00268             continue;
00269         }
00270 
00271         if( op->GetStatus() < OpStatus::OS_EXECUTING ){
00272             continue;
00273         }
00274 
00275         // Gg[OpXgAAhXd
00276         if( op->GetOpClass().IsStore() &&
00277             m_memOperations.IsOverlapped( access, op->GetMemAccess() ) 
00278         ){
00279             producer = op;
00280             break;
00281         }
00282     };
00283 
00284     return producer;
00285 }
00286 
00287 OpIterator MemOrderManager::GetConsumerLoad( OpIterator producer, const MemAccess& producerAccess, int index )
00288 {
00289     ASSERT( producer->GetOpClass().IsStore(), "Not store op." );
00290     ASSERT( m_storeList.count( producer ) == 1, "unknown op." );
00291 
00292     OpIterator consumer;
00293 
00294     int num = 0;
00295     for( OpList::iterator i = m_loadList.begin(); i != m_loadList.end(); ++i ){
00296         
00297         OpIterator op = *i;
00298         if( op->GetGlobalSerialID() < producer->GetGlobalSerialID() ){
00299             continue;
00300         }
00301 
00302         if( op->GetStatus() < OpStatus::OS_EXECUTING ){
00303             continue;
00304         }
00305 
00306         OpClass opClass = op->GetOpClass();
00307         if( !opClass.IsLoad() ){
00308             continue;
00309         }
00310 
00311         if( m_memOperations.IsOverlapped( producerAccess, op->GetMemAccess() ) ){
00312             if( num == index ){
00313                 consumer = op;
00314                 break;
00315             }
00316             num++;
00317         }
00318     }
00319 
00320     return consumer;
00321 
00322 }
00323 
00324 void MemOrderManager::Commit(OpIterator op)
00325 {
00326     // O
00327     const OpClass& opClass = op->GetOpClass();
00328     if( opClass.IsStore() ){
00329 
00330         // G~[^C[W
00331         MemAccess writeAccess = op->GetMemAccess();
00332         WriteMemImage( op, &writeAccess );
00333 
00334         if( writeAccess.result != MemAccess::MAR_SUCCESS ){
00335             RUNTIME_WARNING( 
00336                 "An access violation occurs.\n%s\n%s",
00337                 writeAccess.ToString().c_str(), op->ToString().c_str() 
00338             );
00339         }
00340 
00341         if( m_cache )   {
00342             CacheAccess access( op->GetMemAccess(), op, CacheAccess::OT_WRITE );
00343             CacheAccessResult result = 
00344                 m_cache->Write( access, NULL ); // LbV
00345             op->SetCacheAccessResult( result );
00346         }
00347     }
00348 
00349     if( opClass.IsLoad() ){
00350         const MemAccess& readAccess = op->GetMemAccess();
00351         if( readAccess.result != MemAccess::MAR_SUCCESS ){
00352             RUNTIME_WARNING( 
00353                 "An access violation occurs.\n%s\n%s",
00354                 readAccess.ToString().c_str(), op->ToString().c_str() 
00355             );
00356         }
00357 
00358         // Update dispersion of load accesses
00359         const CacheAccessResult& result = op->GetCacheAccessResult();
00360         if( result.cache == NULL ){ // NULL is store forwarding.
00361             m_numRetiredStoreForwarding++;
00362         }
00363         m_numRetiredLoadAccess++;
00364     }
00365 
00366     if( m_removeOpsOnCommit ){
00367         Delete( op );
00368     }
00369 }
00370 
00371 void MemOrderManager::Retire( OpIterator op )
00372 {
00373     if( !m_removeOpsOnCommit ){
00374         Delete( op );
00375     }
00376 }
00377 
00378 void MemOrderManager::Flush( OpIterator op )
00379 {
00380     Delete( op );
00381 }
00382 
00383 void MemOrderManager::Delete( OpIterator op )
00384 {
00385     if( op->GetStatus() == OpStatus::OS_FETCH ){
00386         return;
00387     }
00388 
00389     const OpClass& opClass = op->GetOpClass();
00390     if( opClass.IsLoad() ) {
00391         m_loadList.erase(op);
00392     }
00393     else if( opClass.IsStore() ){
00394         m_storeList.erase(op);
00395     }
00396 
00397 }
00398 
00399 void MemOrderManager::Read( OpIterator op, MemAccess* access )
00400 {
00401     OpIterator producer = GetProducerStore( op, *access );
00402 
00403     m_numExecutedLoadAccess++;
00404 
00405     if( !producer.IsNull() ){
00406 
00407         // AhXvsstoreMemOrderManagerAMemOrderManagerReads
00408         const MemAccess& producerAccess = producer->GetMemAccess();
00409         if( m_memOperations.IsInnerAccess( *access, producerAccess ) ){
00410             // Normal forwarding
00411             access->value = m_memOperations.ReadPreviousAccess( *access, producerAccess );
00412             m_numExecutedStoreForwarding++;
00413         }
00414         else{
00415             // Partial load forwarding
00416             if( !m_idealPartialLoad ){
00417                 // Partial load is treated as exception.
00418                 access->result = MemAccess::MAR_READ_INVALID_PARTIAL_READ;
00419             }
00420             else{
00421                 // Ideal mode.
00422                 // Store data is forwarded ideally.
00423                 ReadMemImage( op, access );
00424 
00425                 for( OpList::iterator i = m_storeList.begin(); i != m_storeList.end(); ++i ){
00426                     if( (*i)->GetGlobalSerialID() > op->GetGlobalSerialID() ){
00427                         break;
00428                     }
00429                     // Merge a store access to 'access'.
00430                     const MemAccess& storeAccess = (*i)->GetMemAccess();
00431                     if( m_memOperations.IsOverlapped( *access, storeAccess ) ){
00432                         access->value = 
00433                             m_memOperations.MergePartialAccess( *access, storeAccess );
00434                     }
00435                 }
00436             }
00437         }
00438     }
00439     else{
00440 
00441         // AhXvsstoreAemulator C[W
00442         ReadMemImage( op, access );
00443     }
00444 
00445     op->SetMemAccess( *access );
00446 }
00447 
00448 void MemOrderManager::Write( OpIterator op, MemAccess* access )
00449 {
00450     op->SetMemAccess( *access );
00451 }
00452 
00453 // G~[^C[W
00454 void MemOrderManager::ReadMemImage( OpIterator op, MemAccess* access )
00455 {
00456     MemImageAccessParam param = { GetMemImage(), access };
00457 
00458     HOOK_SECTION_OP_PARAM( s_readMemImageHook, op, param )  
00459     {
00460         MemIF* memImage = param.memImage;
00461         memImage->Read( param.memAccess );
00462     }
00463 }
00464 
00465 void MemOrderManager::WriteMemImage( OpIterator op, MemAccess* access )
00466 {
00467     MemImageAccessParam param = { GetMemImage(), access };
00468 
00469     HOOK_SECTION_OP_PARAM( s_writeMemImageHook, op, param ) 
00470     {
00471         MemIF* memImage = param.memImage;
00472         memImage->Write( param.memAccess );
00473     }
00474 }

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