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/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
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
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
00127
00128
00129 void MemOrderManager::DetectAccessOrderViolation( OpIterator store )
00130 {
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145 ASSERT( store->GetOpClass().IsStore(), "Not store op." );
00146
00147
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
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
00176 bool MemOrderManager::DetectPartialLoadViolation( OpIterator op )
00177 {
00178 if( op->GetOpClass().IsLoad() ){
00179
00180
00181
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
00234 void MemOrderManager::Finished( OpIterator op )
00235 {
00236 const OpClass& opClass = op->GetOpClass();
00237
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
00250
00251 OpIterator MemOrderManager::GetProducerStore( OpIterator consumer, const MemAccess& access ) const
00252 {
00253 ASSERT( access.address.pid != PID_INVALID );
00254
00255
00256
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
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
00327 const OpClass& opClass = op->GetOpClass();
00328 if( opClass.IsStore() ){
00329
00330
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 );
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
00359 const CacheAccessResult& result = op->GetCacheAccessResult();
00360 if( result.cache == NULL ){
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
00408 const MemAccess& producerAccess = producer->GetMemAccess();
00409 if( m_memOperations.IsInnerAccess( *access, producerAccess ) ){
00410
00411 access->value = m_memOperations.ReadPreviousAccess( *access, producerAccess );
00412 m_numExecutedStoreForwarding++;
00413 }
00414 else{
00415
00416 if( !m_idealPartialLoad ){
00417
00418 access->result = MemAccess::MAR_READ_INVALID_PARTIAL_READ;
00419 }
00420 else{
00421
00422
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
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
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
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 }