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/Retirer/Retirer.h"
00035
00036 #include "Env/Env.h"
00037 #include "Utility/RuntimeError.h"
00038 #include "Sim/Dumper/Dumper.h"
00039 #include "Sim/Op/OpContainer/OpList.h"
00040 #include "Sim/Foundation/Hook/HookUtil.h"
00041 #include "Sim/Op/Op.h"
00042 #include "Sim/Core/Core.h"
00043 #include "Sim/InorderList/InorderList.h"
00044 #include "Sim/Thread/Thread.h"
00045 #include "Sim/System/ForwardEmulator.h"
00046 #include "Sim/Pipeline/Retirer/RetireEvent.h"
00047 #include "Sim/Recoverer/Recoverer.h"
00048
00049 using namespace Onikiri;
00050
00051
00052 namespace Onikiri
00053 {
00054 Retirer::CommitHookPoint Retirer::s_commitHook;
00055 Retirer::RetireHookPoint Retirer::s_retireHook;
00056 Retirer::CommitSteeringHookPoint Retirer::s_commitSteeringHook;
00057 Retirer::CommitDecisionHookPoint Retirer::s_commitDecisionHook;
00058 };
00059
00060 void Retirer::Evaluated::Reset()
00061 {
00062 committing.clear();
00063 exceptionOccur = false;
00064 exceptionCauser = OpIterator(0);
00065 evaluated = false;
00066 storePortFull = false;
00067 }
00068
00069 Retirer::Retirer() :
00070 m_commitWidth(0),
00071 m_retireWidth(0),
00072 m_noCommitLimit(0),
00073 m_commitLatency(0),
00074 m_fixCommitLatency(false),
00075 m_committableStatus( OpStatus::OS_INVALID ),
00076 m_numCommittedOps(0),
00077 m_numCommittedInsns(0),
00078 m_numRetiredOps(0),
00079 m_numRetiredInsns(0),
00080 m_numStorePortFullStalledCycles(0),
00081 m_noCommittedCycle(0),
00082 m_numSimulationEndInsns(0),
00083 m_currentRetireThread(0),
00084 m_endOfProgram(false),
00085 m_emulator(0),
00086 m_forwardEmulator(0)
00087 {
00088 }
00089
00090 Retirer::~Retirer()
00091 {
00092 ReleaseParam();
00093 }
00094
00095 void Retirer::Initialize( InitPhase phase )
00096 {
00097 PipelineNodeBase::Initialize( phase );
00098
00099 if( phase == INIT_PRE_CONNECTION ){
00100 SetPriority( RP_COMMIT );
00101 LoadParam();
00102 }
00103 else if( phase == INIT_POST_CONNECTION ){
00104 DisableLatch();
00105 }
00106
00107 }
00108
00109 void Retirer::Evaluate()
00110 {
00111 m_evaluated.Reset();
00112 EvaluateCommit();
00113 PipelineNodeBase::Evaluate();
00114 }
00115
00116
00117 void Retirer::EvaluateCommit()
00118 {
00119 Thread* thread = GetCommitableThread();
00120 if( !thread ){
00121 m_evaluated.evaluated = true;
00122 return;
00123 }
00124
00125 InorderList* inorderList = thread->GetInorderList();
00126
00127 int comittedOps = 0;
00128
00129 OpIterator headOp = inorderList->GetFrontOp();
00130 if( !headOp.IsNull() && headOp->GetException().exception ){
00131 m_evaluated.exceptionOccur = true;
00132 m_evaluated.exceptionCauser = headOp;
00133
00134
00135 CheckCommitCounters( 0, inorderList );
00136 m_evaluated.evaluated = true;
00137 return;
00138 }
00139
00140
00141 for( OpIterator op = inorderList->GetFrontOp();
00142 !op.IsNull() && CanCommitInsn( op ) ;
00143
00144 ){
00145 if( m_numSimulationEndInsns != 0 &&
00146 m_numCommittedInsns + comittedOps >= m_numSimulationEndInsns
00147 ){
00148 break;
00149 }
00150
00151 int microOpNum = op->GetOpInfo()->GetMicroOpNum();
00152 if( comittedOps + microOpNum > m_commitWidth ){
00153 break;
00154 }
00155
00156
00157 for( int i = 0; i < microOpNum; i++ ){
00158 m_evaluated.committing.push_back( op );
00159 op = inorderList->GetNextIndexOp( op );
00160 comittedOps++;
00161 }
00162 }
00163
00164
00165 CheckCommitCounters( comittedOps, inorderList );
00166
00167 m_evaluated.evaluated = true;
00168 if( m_evaluated.storePortFull ){
00169 m_numStorePortFullStalledCycles++;
00170 }
00171 }
00172
00173 void Retirer::Transition()
00174 {
00175 BaseType::Transition();
00176
00177
00178
00179 if( IsStalledThisCycle() ){
00180 m_evaluated.Reset();
00181 }
00182 }
00183
00184
00185 void Retirer::Update()
00186 {
00187 if( m_numSimulationEndInsns != 0 && m_numRetiredInsns > m_numSimulationEndInsns ){
00188 THROW_RUNTIME_ERROR( "Simulation was done in excess of 'System/@SimulationInsns'" );
00189 }
00190
00191 UpdateException();
00192 UpdateCommit();
00193 }
00194
00195
00196
00197 void Retirer::SetInitialNumRetiredOp( s64 numInsns, s64 numOp, s64 simulationEndInsns )
00198 {
00199 m_numCommittedInsns = numInsns;
00200 m_numCommittedOps = numOp;
00201
00202 m_numRetiredInsns = numInsns;
00203 m_numRetiredOps = numOp;
00204
00205 m_numSimulationEndInsns = simulationEndInsns;
00206 }
00207
00208
00209 void Retirer::Retire( OpIterator op )
00210 {
00211 HOOK_SECTION_OP( s_retireHook, op )
00212 {
00213 op->GetInorderList()->Retire( op );
00214
00215 if( op->GetNo() == 0 ) {
00216 m_numRetiredInsns++;
00217 }
00218 m_numRetiredOps++;
00219 }
00220 }
00221
00222
00223 void Retirer::Flush( OpIterator op )
00224 {
00225 #if ONIKIRI_DEBUG
00226 CommitingOps* committing = &m_evaluated.committing;
00227 for( CommitingOps::iterator i = committing->begin(); i != committing->end(); ){
00228
00229
00230 ASSERT( op != *i, "A committing op is flushed.\n%s", op->ToString().c_str() );
00231 ++i;
00232 }
00233
00234
00235
00236
00237
00238
00239 #endif
00240 }
00241
00242
00243 bool Retirer::CanCommitOp( OpIterator op )
00244 {
00245 CommitDecisionHookParam param = { op, false };
00246 HOOK_SECTION_OP_PARAM( s_commitDecisionHook, op, param )
00247 {
00248 param.canCommit = true;
00249
00250 if( op->GetException().exception ){
00251
00252 param.canCommit = false;
00253 }
00254 else{
00255
00256
00257 if( op->GetStatus() < m_committableStatus ){
00258 param.canCommit = false;
00259 }
00260 else{
00261
00262 const OpClass& opClass = op->GetOpClass();
00263 if( opClass.IsStore() ){
00264 ExecUnitIF* execUnit = op->GetExecUnit();
00265 if( execUnit->CanReserve( op, 0 ) ){
00266 execUnit->Reserve( op, 0 );
00267 }
00268 else{
00269 param.canCommit = false;
00270 m_evaluated.storePortFull = true;
00271 }
00272 }
00273 }
00274 }
00275 }
00276
00277 return param.canCommit;
00278 }
00279
00280
00281 bool Retirer::CanCommitInsn( OpIterator op )
00282 {
00283 OpInfo* opInfo = op->GetOpInfo();
00284 InorderList* inorderList = op->GetInorderList();
00285
00286 int microOps = opInfo->GetMicroOpNum();
00287 OpIterator cur = inorderList->GetFrontOpOfSamePC( op );
00288
00289 for( int i = 0; i < microOps; i++ ){
00290 ASSERT( cur->GetNo() == i, "Micro op indices mismatch." );
00291 if( cur.IsNull() || !CanCommitOp( cur ) ){
00292 return false;
00293 }
00294 cur = inorderList->GetNextIndexOp( cur );
00295 }
00296
00297 return true;
00298 }
00299
00300
00301 Thread* Retirer::GetCommitableThread()
00302 {
00303 CommitSteeringHookParam param = { &m_thread, NULL };
00304 HOOK_SECTION_PARAM( s_commitSteeringHook, param )
00305 {
00306 int index;
00307 int count = 0;
00308 int threadSize = m_thread.GetSize();
00309 do{
00310 index = m_currentRetireThread;
00311 m_currentRetireThread++;
00312 if( m_currentRetireThread >= threadSize ){
00313 m_currentRetireThread = 0;
00314 }
00315
00316 count++;
00317 if( count > threadSize ){
00318 THROW_RUNTIME_ERROR( "No thread can retire." );
00319 }
00320 }
00321 while( !m_thread[index]->IsActive() );
00322
00323 param.targetThread = m_thread[index];
00324 }
00325 return param.targetThread;
00326 }
00327
00328 void Retirer::Commit( OpIterator op )
00329 {
00330 HOOK_SECTION_OP( s_commitHook, op )
00331 {
00332
00333
00334 if( op->GetOpClass().IsBranch() && op->GetTakenPC().address == 0 ) {
00335 FinishThread( op->GetThread() );
00336 }
00337
00338 m_forwardEmulator->OnCommit( op );
00339 m_emulator->Commit( &(*op), op->GetOpInfo() );
00340 op->GetInorderList()->Commit( op );
00341
00342
00343 int commitLatency = m_commitLatency;
00344 if( !m_fixCommitLatency && op->GetOpClass().IsStore() ){
00345
00346
00347 int storeLatency = op->GetCacheAccessResult().latency;
00348 commitLatency = std::max( storeLatency, commitLatency );
00349 }
00350 EventPtr retireEvent( OpRetireEvent::Construct( op, this ) );
00351 op->AddEvent( retireEvent, GetLowerPipeline(), commitLatency );
00352 }
00353 }
00354
00355 void Retirer::UpdateCommit()
00356 {
00357 int committedOps = 0;
00358 for( CommitingOps::iterator i = m_evaluated.committing.begin(); i != m_evaluated.committing.end(); i++ ){
00359
00360 OpIterator op = *i;
00361
00362
00363 Commit( op );
00364
00365 ++m_numCommittedOps;
00366 ++committedOps;
00367
00368
00369
00370
00371 if( op->GetNo() == 0 ) {
00372 ++m_numCommittedInsns;
00373 }
00374 }
00375
00376
00377 if( committedOps > 0 ) {
00378 m_noCommittedCycle = 0;
00379 } else {
00380 ++m_noCommittedCycle;
00381 }
00382 }
00383
00384 void Retirer::UpdateException()
00385 {
00386 if( m_evaluated.exceptionOccur ){
00387 OpIterator causer = m_evaluated.exceptionCauser;
00388 Recoverer* recoverer = causer->GetThread()->GetRecoverer();
00389 recoverer->RecoverException( causer );
00390 m_evaluated.exceptionOccur = false;
00391 }
00392 }
00393
00394
00395 void Retirer::CheckCommitCounters( int committedOps, InorderList* inorderList )
00396 {
00397 if( m_noCommittedCycle >= m_noCommitLimit ) {
00398 OpIterator uncommitted = inorderList->GetFrontOp();
00399 if( uncommitted.IsNull() ) {
00400 if( inorderList->IsEmpty() ){
00401 THROW_RUNTIME_ERROR(
00402 "InOrderList is empty and no op commits while %d cycle(numRetiredOp = %d). ",
00403 m_noCommittedCycle, m_numCommittedOps
00404 );
00405 }
00406 else{
00407 THROW_RUNTIME_ERROR(
00408 "No op committed while %d cycle. A next retireable op( the front of InOrderList ) is %s",
00409 m_noCommittedCycle, inorderList->GetCommittedFrontOp()->ToString(6).c_str()
00410 );
00411 }
00412 }
00413 else {
00414 THROW_RUNTIME_ERROR(
00415 "No op committed while %d cycle. Next committable op( the front of InOrderList ) is %s",
00416 m_noCommittedCycle, uncommitted->ToString(6).c_str()
00417 );
00418 }
00419 }
00420 }
00421
00422
00423 void Retirer::FinishThread( Thread* tread )
00424 {
00425 tread->Activate( false );
00426 Core* core = GetCore();
00427
00428
00429 bool active = false;
00430 for( int i = 0; i < core->GetThreadCount(); i++ ){
00431 if( core->GetThread(i)->IsActive() ){
00432 active = true;
00433 }
00434 }
00435
00436 m_endOfProgram = !active;
00437 }
00438