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
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 #include <pch.h>
00061
00062 #include "Sim/Memory/Cache/Cache.h"
00063 #include "Sim/Op/Op.h"
00064 #include "Sim/Foundation/Hook/HookUtil.h"
00065 #include "Sim/Memory/Cache/CacheMissedAccessList.h"
00066 #include "Sim/Memory/Prefetcher/PrefetcherIF.h"
00067 #include "Sim/Memory/Cache/CacheExtraStateTable.h"
00068 #include "Sim/Memory/Cache/CacheAccessRequestQueue.h"
00069
00070
00071
00072
00073 namespace Onikiri
00074 {
00075 HookPoint<Cache, CacheHookParam> Cache::s_readHook;
00076 HookPoint<Cache, CacheHookParam> Cache::s_writeHook;
00077 HookPoint<Cache, CacheHookParam> Cache::s_invalidateHook;
00078 HookPoint<Cache, CacheHookParam> Cache::s_tableUpdateHook;
00079 };
00080
00081 using namespace Onikiri;
00082
00083 Cache::Cache() :
00084 m_latency (0),
00085 m_nextLevelCache (0),
00086 m_prefetcher (0),
00087 m_perfect (0),
00088 m_writePolicy (WP_INVALID),
00089 m_missedAccessList (0),
00090 m_accessQueue (0),
00091 m_level (0),
00092 m_indexBitSize (0),
00093 m_offsetBitSize (0),
00094 m_numWays (0),
00095 m_numPorts (0),
00096 m_reqQueueSize (0),
00097 m_missedAccessListSize(0),
00098 m_numReadHit (0),
00099 m_numReadMiss (0),
00100 m_numReadAccess (0),
00101 m_numReadPendingHit (0),
00102 m_numPrefetchHit (0),
00103 m_numPrefetchMiss (0),
00104 m_numPrefetchPendingHit(0),
00105 m_numPrefetchAccess (0),
00106 m_numWriteHit (0),
00107 m_numWriteMiss (0),
00108 m_numWriteAccess (0),
00109 m_numWritePendingHit(0),
00110 m_numInvalidated (0),
00111 m_capacityKB (0)
00112 {
00113 m_lineBitSize = 0;
00114 m_capacityKB = 0;
00115 m_cacheTable = 0;
00116 m_lineState = new ExtraStateTableType();
00117 }
00118
00119 Cache::~Cache()
00120 {
00121 ReleaseParam();
00122
00123 if( m_lineState != NULL ){
00124 delete m_lineState;
00125 m_lineState = NULL;
00126 }
00127
00128 if( m_missedAccessList != NULL ){
00129 delete m_missedAccessList;
00130 m_missedAccessList = NULL;
00131 }
00132
00133 if( m_accessQueue != NULL ){
00134 delete m_accessQueue;
00135 m_accessQueue = NULL;
00136 }
00137 }
00138
00139 void Cache::Initialize( InitPhase phase )
00140 {
00141 PipelineNodeBase::Initialize( phase );
00142
00143 if(phase == INIT_PRE_CONNECTION){
00144
00145 LoadParam();
00146 m_lineBitSize = m_offsetBitSize;
00147 int lineSize = (1 << m_lineBitSize);
00148
00149 m_capacityKB =
00150 m_numWays *
00151 (1 << m_indexBitSize) *
00152 lineSize /
00153 1024;
00154
00155
00156 if( m_exclusiveAccessCycles == 0 || m_numPorts == 0 ){
00157 m_maxThroughputBytesPerCycle = "Infinite";
00158 }
00159 else{
00160 m_maxThroughputBytesPerCycle.format(
00161 "%f",
00162 (double)lineSize / (double)m_exclusiveAccessCycles * m_numPorts
00163 );
00164 }
00165
00166
00167 if( m_latency < m_exclusiveAccessCycles ){
00168 THROW_RUNTIME_ERROR(
00169 "The latency is less than the exclusive access cycles. "
00170 "This means that the cache/memory cannot transfer whole "
00171 "line data within the latency because the bandwidth "
00172 "is too narow."
00173 );
00174 };
00175
00176 if( m_numPorts != 0 ){
00177 if( m_exclusiveAccessCycles*m_reqQueueSize/m_numPorts + m_latency >
00178 GetLowerPipeline()->GetWheelSize()
00179 ){
00180 RUNTIME_WARNING(
00181 "The size of the time wheel may not be enough. "
00182 "Inclease the time wheel size or decrease @ExclusiveAccessCycles/@NumRequestListSize "
00183 );
00184 }
00185 }
00186
00187 m_cacheTable =
00188 new Cache::TableType(
00189 HasherType( m_indexBitSize, m_offsetBitSize ),
00190 m_numWays
00191 );
00192
00193 }
00194 else if( phase == INIT_POST_CONNECTION ){
00195
00196 int offset = m_offsetBitSize;
00197
00198 m_missedAccessList =
00199 new CacheMissedAccessList( GetLowerPipeline(), offset );
00200
00201 m_accessQueue =
00202 new CacheAccessRequestQueue( GetLowerPipeline(), m_numPorts, m_exclusiveAccessCycles );
00203
00204 if( m_prevLevelCaches.GetSize() == 0 &&
00205 ( m_exclusiveAccessCycles != 0 || m_numPorts != 0)
00206 ){
00207
00208
00209
00210 THROW_RUNTIME_ERROR( "Band width limit of a top level cache is not support." );
00211 }
00212
00213 if( !m_perfect && !m_nextLevelCache ){
00214 THROW_RUNTIME_ERROR( "The last level of a memory hierarchy must be 'perfect'." );
00215 }
00216
00217 LineState initState;
00218 initState.dirty = false;
00219 m_lineState->Resize( this, initState );
00220
00221 DisableLatch();
00222 }
00223 }
00224
00225
00226 void Cache::ChangeSimulationMode( PhysicalResourceNode::SimulationMode mode )
00227 {
00228 ASSERT( m_missedAccessList );
00229 ASSERT( m_accessQueue );
00230
00231 bool isSimulation = ( mode == PhysicalResourceNode::SM_SIMULATION );
00232
00233
00234
00235
00236 m_missedAccessList->SetEnabled( isSimulation );
00237 m_accessQueue->SetEnabled( isSimulation );
00238 }
00239
00240
00241
00242 void Cache::UpdateStatistics( const Access& access, Result::State state )
00243 {
00244 switch( access.type ){
00245
00246 case AOT_READ:
00247 case AOT_READ_FOR_WRITE_ALLOCATE:
00248 m_numReadAccess++;
00249 switch( state ){
00250 case Result::ST_HIT: m_numReadHit++; break;
00251 case Result::ST_PENDING_HIT: m_numReadPendingHit++; break;
00252 case Result::ST_MISS: m_numReadMiss++; break;
00253 case Result::ST_NOT_ACCESSED: ASSERT(0); break;
00254 }
00255 break;
00256
00257 case AOT_WRITE:
00258 case AOT_WRITE_BACK:
00259 m_numWriteAccess++;
00260 switch( state ){
00261 case Result::ST_HIT: m_numWriteHit++; break;
00262 case Result::ST_PENDING_HIT: m_numWritePendingHit++; break;
00263 case Result::ST_MISS: m_numWriteMiss++; break;
00264 case Result::ST_NOT_ACCESSED: ASSERT(0); break;
00265 }
00266 break;
00267
00268 case AOT_PREFETCH:
00269 m_numPrefetchAccess++;
00270 switch( state ){
00271 case Result::ST_HIT: m_numPrefetchHit++; break;
00272 case Result::ST_PENDING_HIT: m_numPrefetchPendingHit++; break;
00273 case Result::ST_MISS: m_numPrefetchMiss++; break;
00274 case Result::ST_NOT_ACCESSED: ASSERT(0); break;
00275 }
00276 break;
00277
00278 }
00279 }
00280
00281
00282
00283 void Cache::CheckValidAddress( const Addr& addr )
00284 {
00285 ASSERT(
00286 addr.pid != PID_INVALID && addr.tid != TID_INVALID,
00287 "The address has an invalid id (PID:%d, TID:%d).",
00288 addr.pid, addr.tid
00289 );
00290 }
00291
00292
00293
00294 void Cache::AddToMissedAccessList(
00295 const Access& access,
00296 const Result& result,
00297 CacheAccessNotifieeIF* notifee,
00298 const NotifyParam& param
00299 ){
00300 CacheAccessNotifieeIF* notifeeList[2] = { this, notifee };
00301 int notifieeCount = notifee != NULL ? 2 : 1;
00302
00303
00304 m_missedAccessList->Add(
00305 access,
00306 result,
00307 notifeeList,
00308 notifieeCount,
00309 param
00310 );
00311 }
00312
00313
00314 Cache::Result Cache::OnReadHit( const Access& access)
00315 {
00316
00317 if( !m_perfect ){
00318 m_cacheTable->read( access.address );
00319 }
00320
00321 Result result( (int)m_latency, Result::ST_HIT, this );
00322
00323
00324 result.latency =
00325 (int)m_accessQueue->Push(
00326 access,
00327 m_latency,
00328 NULL,
00329 NotifyParam()
00330 );
00331
00332 return result;
00333 }
00334
00335
00336
00337 Cache::Result Cache::OnReadPendingHit(
00338 const Access& access,
00339 const Result& phResult,
00340 CacheAccessNotifieeIF* notifee
00341 ){
00342 ASSERT( !m_perfect );
00343
00344 Result result ( phResult.latency, Result::ST_PENDING_HIT, this );
00345 if( result.latency < m_latency ){
00346 result.latency = m_latency;
00347 }
00348
00349 NotifyParam notification( CAET_FILL_FROM_MAL_FINISHED, result );
00350 AddToMissedAccessList( access, result, notifee, notification );
00351
00352 return result;
00353 }
00354
00355
00356
00357 Cache::Result Cache::OnReadMiss(
00358 const Access& access,
00359 CacheAccessNotifieeIF* notifee
00360 ){
00361
00362 Result nextResult = m_nextLevelCache->Read( access, NULL );
00363 int nextLatency = nextResult.latency;
00364
00365 Result result( m_latency + nextLatency, Result::ST_MISS, nextResult.cache );
00366
00367 NotifyParam notification( CAET_FILL_FROM_NEXT_CACHE_FINISHED, result );
00368 AddToMissedAccessList( access, result, notifee, notification );
00369
00370 return result;
00371 }
00372
00373
00374
00375
00376 void Cache::ReadBody( CacheHookParam* param )
00377 {
00378 const Access& access = *param->access;
00379
00380 Addr addr = access.address;
00381 CheckValidAddress( addr );
00382
00383 Result result;
00384
00385 if( m_perfect ){
00386
00387 result = OnReadHit( access );
00388 }
00389 else{
00390 CacheTableIterator line = m_cacheTable->find( addr );
00391 if( line != m_cacheTable->end() ){
00392
00393 result = OnReadHit( access );
00394 param->line = line;
00395 }
00396 else{
00397
00398 Result phResult = m_missedAccessList->Find( addr );
00399 CacheAccessNotifieeIF* notifee = param->notifiee;
00400 if( phResult.state == Result::ST_HIT ){
00401
00402 result = OnReadPendingHit( access, phResult, notifee );
00403 }
00404 else{
00405
00406 result = OnReadMiss( access, notifee );
00407 }
00408 }
00409 }
00410
00411
00412 UpdateStatistics( access, result.state );
00413 param->result = result;
00414 }
00415
00416 Cache::Result Cache::Read( const Access& access, NotifieeIF* notifiee )
00417 {
00418 CacheHookParam param;
00419 param.access = &access;
00420 param.table = m_cacheTable;
00421 param.address = &access.address;
00422 param.notifiee = notifiee;
00423 param.line = m_cacheTable->end();
00424
00425 HookEntry( this, &Cache::ReadBody, &s_readHook, ¶m );
00426
00427 if( m_prefetcher ){
00428 m_prefetcher->OnCacheRead( this, ¶m );
00429 }
00430
00431 return param.result;
00432 }
00433
00434
00435
00436 Cache::Result Cache::OnWriteHit( const Access& access )
00437 {
00438 Result result( (int)m_latency, Result::ST_HIT, this );
00439 NotifyParam notification( CAET_WRITE_ACCESS_FINISHED, result );
00440
00441
00442 result.latency =
00443 (int)m_accessQueue->Push(
00444 access,
00445 m_latency,
00446 this,
00447 notification
00448 );
00449
00450 return result;
00451 }
00452
00453
00454 Cache::Result Cache::OnWritePendingHit(
00455 const Access& access,
00456 const Result& phResult,
00457 CacheAccessNotifieeIF* notifee
00458 ){
00459 Access writeAllocate = access;
00460 writeAllocate.type = Access::OT_READ_FOR_WRITE_ALLOCATE;
00461
00462
00463 NotifyParam notification( CAET_WRITE_ALLOCATE_FINISHED, phResult );
00464 AddToMissedAccessList( writeAllocate, phResult, notifee, notification );
00465
00466 return Result(
00467 m_latency + phResult.latency,
00468 Result::ST_MISS,
00469 this
00470 );
00471 }
00472
00473
00474 Cache::Result Cache::OnWriteMiss(
00475 const Access& access,
00476 CacheAccessNotifieeIF* notifee
00477 ){
00478
00479 Access writeAllocate = access;
00480 writeAllocate.type = Access::OT_READ_FOR_WRITE_ALLOCATE;
00481 Result nextResult =
00482 m_nextLevelCache->Read( writeAllocate, NULL );
00483
00484 int nextLatency = nextResult.latency;
00485
00486 NotifyParam notification( CAET_WRITE_ALLOCATE_FINISHED, nextResult );
00487 AddToMissedAccessList( writeAllocate, nextResult, notifee, notification );
00488
00489 return Result(
00490 m_latency + nextLatency,
00491 Result::ST_MISS,
00492 nextResult.cache
00493 );
00494 }
00495
00496
00497
00498
00499 Cache::Result Cache::Write( const Access& access, NotifieeIF* notifiee )
00500 {
00501 CacheHookParam param;
00502 param.access = &access;
00503 param.address = &access.address;
00504 param.table = m_cacheTable;
00505 param.notifiee = notifiee;
00506 param.line = m_cacheTable->end();
00507
00508 HookEntry( this, &Cache::WriteBody, &s_writeHook, ¶m );
00509
00510 if( m_prefetcher ){
00511 m_prefetcher->OnCacheWrite( this, ¶m );
00512 }
00513
00514 return param.result;
00515 }
00516
00517 void Cache::WriteBody( CacheHookParam* param )
00518 {
00519 const Access& access = *param->access;
00520
00521 Addr addr = access.address;
00522 CheckValidAddress( addr );
00523
00524 Result result;
00525
00526 if( m_perfect ){
00527
00528 result = OnWriteHit( access );
00529 }
00530 else{
00531
00532 CacheTableIterator line = m_cacheTable->find( addr );
00533 if( line != m_cacheTable->end() ){
00534
00535 result = OnWriteHit( access );
00536 param->line = line;
00537 }
00538 else{
00539 CacheAccessNotifieeIF* notifee = param->notifiee;
00540 Result phResult = m_missedAccessList->Find( addr );
00541 if( phResult.state == Result::ST_HIT ){
00542
00543 result = OnWritePendingHit( access, phResult, notifee );
00544 }
00545 else{
00546
00547 result = OnWriteMiss( access, notifee );
00548 }
00549 }
00550 }
00551
00552
00553 UpdateStatistics( access, result.state );
00554
00555 param->result = result;
00556 }
00557
00558
00559 void Cache::UpdateTableBody( CacheHookParam* param )
00560 {
00561 const CacheAccess& access = *param->access;
00562 bool dirty = access.IsWirte();
00563
00564 bool replaced;
00565 CacheLine replacedLine;
00566 Addr replacedAddr;
00567 TableType::iterator line =
00568 m_cacheTable->write( access.address, Value(), &replaced, &replacedAddr, &replacedLine );
00569 param->line = line;
00570 param->replaced = replaced;
00571
00572 if( replaced ){
00573
00574
00575 for( int i = 0; i < m_prevLevelCaches.GetSize(); i++ ){
00576 m_prevLevelCaches[i]->Invalidate( replacedAddr );
00577 }
00578
00579
00580 if( m_writePolicy == WP_WRITE_BACK && !m_perfect ){
00581 if( (*m_lineState)[ line ].dirty ){
00582 Access writeBack = access;
00583 writeBack.address = replacedAddr;
00584 writeBack.value = 0;
00585 writeBack.lineValue = replacedLine.value;
00586 writeBack.type = AOT_WRITE_BACK;
00587 m_nextLevelCache->Write( writeBack, NULL );
00588 }
00589 }
00590 }
00591
00592
00593 (*m_lineState)[ line ].dirty = dirty;
00594 }
00595
00596
00597 void Cache::UpdateTable( const Access& access )
00598 {
00599 CacheHookParam param;
00600 param.access = &access;
00601 param.table = m_cacheTable;
00602 param.line = m_cacheTable->end();
00603
00604 HookEntry( this, &Cache::UpdateTableBody, &s_tableUpdateHook, ¶m );
00605
00606 if( m_prefetcher ){
00607 m_prefetcher->OnCacheTableUpdate( this, ¶m );
00608 }
00609 }
00610
00611
00612
00613 void Cache::Invalidate( const Addr& addr )
00614 {
00615 CacheHookParam param;
00616 param.address = &addr;
00617 param.table = m_cacheTable;
00618 param.line = m_cacheTable->end();
00619
00620 HookEntry( this, &Cache::InvalidateBody, &s_invalidateHook, ¶m );
00621
00622 if( m_prefetcher ){
00623 m_prefetcher->OnCacheInvalidation( this, ¶m );
00624 }
00625 }
00626
00627 void Cache::InvalidateBody( CacheHookParam* param )
00628 {
00629 CacheTableIterator line = m_cacheTable->invalidate( *param->address );
00630 if( line != m_cacheTable->end() ){
00631 m_numInvalidated++;
00632 }
00633 param->line = line;
00634 }
00635
00636
00637 void Cache::AccessFinished( const Access& access, const NotifyParam& param )
00638 {
00639 CheckValidAddress( access.address );
00640
00641 switch( param.type ){
00642 case CAET_FILL_FROM_MAL_FINISHED:
00643 ASSERT( !access.IsWirte() );
00644 break;
00645
00646 case CAET_FILL_FROM_NEXT_CACHE_FINISHED:
00647 ASSERT( !access.IsWirte() );
00648 UpdateTable( access );
00649 break;
00650
00651 case CAET_WRITE_ALLOCATE_FINISHED:
00652 {
00653 ASSERT( !access.IsWirte() );
00654 Access writeAccess = access;
00655 writeAccess.type = Access::OT_WRITE;
00656 OnWriteHit( writeAccess );
00657 break;
00658 }
00659
00660 case CAET_WRITE_ACCESS_FINISHED:
00661 ASSERT( access.IsWirte() );
00662 UpdateTable( access );
00663 if( m_writePolicy == WP_WRITE_THROUGH && !m_perfect ){
00664 m_nextLevelCache->Write( access, NULL );
00665 }
00666 break;
00667
00668 default:
00669 ASSERT(0);
00670 break;
00671 }
00672
00673 }
00674
00675
00676 Cache* Cache::GetNextCache()
00677 {
00678 if( m_nextLevelCache != 0 ){
00679 return m_nextLevelCache;
00680 }
00681 else{
00682 return 0;
00683 }
00684 }
00685
00686 void Cache::SetNextCache( PhysicalResourceArray<Cache>& next )
00687 {
00688 m_nextLevelCache = next[0];
00689 m_nextLevelCache->AddPreviousLevelCache( this );
00690 }
00691
00692
00693 void Cache::AddPreviousLevelCache( Cache* prev )
00694 {
00695 for( int i = 0; i < m_prevLevelCaches.GetSize(); i++ ){
00696 if( m_prevLevelCaches[i] == prev ){
00697 THROW_RUNTIME_ERROR( "A same previous level cache is added more than once." );
00698 }
00699 }
00700
00701 m_prevLevelCaches.Add( prev );
00702 }
00703
00704 int Cache::GetOffsetBitSize() const
00705 {
00706 return m_offsetBitSize;
00707 }
00708
00709
00710 bool Cache::IsStallRequired()
00711 {
00712
00713 if( m_nextLevelCache && m_nextLevelCache->IsStallRequired() ){
00714 return true;
00715 }
00716
00717 if( m_reqQueueSize != 0 &&
00718 (int)m_accessQueue->GetSize() >= m_reqQueueSize
00719 ){
00720 return true;
00721 }
00722
00723 if( m_missedAccessListSize != 0 &&
00724 (int)m_missedAccessList->GetSize() >= m_missedAccessListSize
00725 ){
00726 return true;
00727 }
00728
00729 return false;
00730 }
00731
00732
00733 void Cache::Update()
00734 {
00735 }