src/Sim/System/ForwardEmulator.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 #include "Sim/System/ForwardEmulator.h"
00034 
00035 #include "Sim/Thread/Thread.h"
00036 #include "Sim/Core/Core.h"
00037 #include "Sim/Op/Op.h"
00038 #include "Sim/Foundation/SimPC.h"
00039 
00040 using namespace Onikiri;
00041 
00042 ForwardEmulator::ForwardEmulator() : 
00043     m_emulator( NULL ),
00044     m_enable( false )
00045 {
00046 }
00047 
00048 ForwardEmulator::~ForwardEmulator()
00049 {
00050 }
00051 
00052 void ForwardEmulator::Initialize( InitPhase phase )
00053 {
00054     if( phase == INIT_PRE_CONNECTION ){
00055         LoadParam();
00056     }
00057     else if( phase == INIT_POST_CONNECTION ){
00058         m_memOperations.SetTargetEndian( m_emulator->GetISAInfo()->IsLittleEndian() );
00059     }
00060 }
00061 
00062 void ForwardEmulator::Finalize()
00063 {
00064     ReleaseParam();
00065 }
00066 
00067 void ForwardEmulator::SetContext( const ArchitectureStateList& context )
00068 {
00069     m_context = context;
00070     m_inflightOps.clear();
00071     m_inflightOps.resize( m_context.size() );
00072 
00073     m_threadContext.resize( m_context.size() );
00074     for( size_t i = 0; i < m_context.size(); ++i ){
00075         m_threadContext[i].nextFixedPC = context[i].pc;
00076     }
00077 }
00078 
00079 void ForwardEmulator::OnFetch( OpIterator simOp )
00080 {
00081     if( !m_enable )
00082         return;
00083 
00084     int tid = simOp->GetTID();
00085     ArchitectureState* context  = &m_context[ tid ];
00086     InflightOpList* inflightOps = &m_inflightOps[ tid ];
00087 
00088     // Return when emulation is already done on recovery 
00089     // from branch miss prediction.
00090     if( inflightOps->size() > 0 ){
00091         InflightOp* entry = &inflightOps->back();
00092         if( entry->retireId >= simOp->GetRetireID() ){
00093             // Already executed in ForwardEmulator.
00094             UpdateFixedPath( simOp );
00095             return;
00096         }
00097 
00098         // System calls are treated specially.
00099         // The execution of system calls is delayed to OnCommit, because
00100         // executing system calls immediately affect architecture state such as memory image.
00101         // A system call may be divided to multiple micro ops and second or later divided ops
00102         // are not pushed to 'm_inflightOps', so PCs do not match.
00103         if( entry->emuOp.GetOpInfo()->GetOpClass().IsSyscall() &&
00104             entry->emuOp.GetPC() != simOp->GetPC()
00105         ){
00106             return;
00107         }
00108     }
00109 
00110 
00111     //
00112     // Execution
00113     //
00114 
00115     inflightOps->push_back( InflightOp() );
00116     InflightOp* entry = &inflightOps->back();
00117     entry->simOp    = simOp;
00118     entry->retireId = simOp->GetRetireID();
00119 
00120     // Get OpInfo
00121     std::pair<OpInfo**, int> ops = 
00122         m_emulator->GetOp( context->pc );
00123     OpInfo** opInfoArray = ops.first;
00124     int opCount          = ops.second;
00125     ASSERT( context->microOpIndex < opCount );
00126     OpInfo* opInfo = opInfoArray[ context->microOpIndex ];
00127     entry->updatePC = context->microOpIndex >= opCount - 1;
00128     entry->isStore  = opInfo->GetOpClass().IsStore();
00129 
00130     // Initialize an emu op.
00131     EmulationOp* emuOp = &entry->emuOp;
00132     emuOp->SetMem( this );
00133     emuOp->SetPC( context->pc );
00134     emuOp->SetTakenPC( Addr( tid, simOp->GetTID(), context->pc.address + SimISAInfo::INSTRUCTION_WORD_BYTE_SIZE ) );
00135     emuOp->SetOpInfo( opInfo );
00136     emuOp->SetTaken( false );
00137     // Set source operands.
00138     int srcCount = opInfo->GetSrcNum();
00139     for( int i = 0; i < srcCount; i++ ) {
00140         emuOp->SetSrc(i, context->registerValue[ opInfo->GetSrcOperand( i ) ] );
00141     }
00142 
00143     // Execution
00144     if( opInfo->GetOpClass().IsSyscall() ){
00145         // System calls are treated specially.
00146         // The execution of system calls is delayed to OnCommit, because
00147         // executing system calls immediately affect architecture state such as memory image.
00148         entry->updateMicroOpIndex = false;
00149         context->microOpIndex++;
00150         return;
00151     }
00152     else{
00153         m_emulator->Execute( emuOp, opInfo );
00154         UpdateArchContext( context, emuOp, opInfo, entry->updatePC, true );
00155         UpdateFixedPath( simOp );
00156     }
00157 }
00158 
00159 void ForwardEmulator::UpdateArchContext( 
00160     ArchitectureState* context, 
00161     OpStateIF* state, 
00162     OpInfo* info, 
00163     bool updatePC, 
00164     bool updateMicroOpIndex  
00165 ){
00166     // Get results.
00167     int dstCount = info->GetDstNum();
00168     for (int i = 0; i < dstCount; i ++) {
00169         context->registerValue[ info->GetDstOperand(i) ] = state->GetDst(i);
00170     }
00171 
00172     // Update PCs
00173     if( updateMicroOpIndex )
00174         context->microOpIndex++;
00175 
00176     if( updatePC ){
00177         context->microOpIndex = 0;
00178         context->pc = GetExecutedNextPC( context->pc, state );
00179     }
00180 }
00181 
00182 
00183 void ForwardEmulator::OnCommit( OpIterator simOp )
00184 {
00185     if( !m_enable )
00186         return;
00187 
00188     int tid = simOp->GetTID();
00189     InflightOpList* inflightOps = &m_inflightOps[ tid ];
00190     InflightOpList::iterator front = inflightOps->begin();
00191     
00192     ASSERT(
00193         front != inflightOps->end(),
00194         "A list of in-flight ops is empty." 
00195     );
00196     ASSERT(
00197         front->retireId == simOp->GetRetireID(),
00198         "A retire-id of a forwardly emulated op (%lld) and that of a simulated op (%lld) are inconsistent.",
00199         front->retireId,
00200         simOp->GetRetireID()
00201     );
00202 
00203     EmulationOp* emuOp = &( front->emuOp );
00204 
00205     const OpInfo* emuOpInfo = emuOp->GetOpInfo();
00206     const OpClass& emuOpClass = emuOpInfo->GetOpClass();
00207 
00208     if( emuOpClass.IsSyscall() ){
00209         // System calls are treated specially.
00210         // The execution of system calls is delayed to OnCommit, because
00211         // executing system calls immediately affect architecture state such as memory image.
00212         ArchitectureState* context  = &m_context[ tid ];
00213         UpdateArchContext( 
00214             context,
00215             simOp.GetOp(), 
00216             simOp->GetOpInfo(), 
00217             front->updatePC, 
00218             front->updateMicroOpIndex 
00219         );
00220         UpdateFixedPath( simOp );
00221         //ASSERT( inflightOps->size() == 1, "System call must be serialized." );
00222     }
00223     else{
00224         u64 simDst = simOp->GetDstRegNum() > 0 ? simOp->GetDst(0) : 0;
00225         u64 emuDst = emuOpInfo->GetDstNum() > 0 ? emuOp->GetDst(0) : 0;
00226         u64 simPC  = simOp->GetPC().address;
00227         u64 emuPC  = emuOp->GetPC().address;
00228         u64 simAddr = emuOpClass.IsMem() ? simOp->GetMemAccess().address.address : 0;
00229         u64 emuAddr = emuOpClass.IsMem() ? front->memAccess.address.address : 0;
00230 
00231         if( simDst != emuDst || simPC != emuPC || simAddr != emuAddr ){
00232             THROW_RUNTIME_ERROR( 
00233                 "Simulation result is incorrect.\n" 
00234                 "Forward emulation result:  '%08x%08x'\n"
00235                 "Simulation result:         '%08x%08x'\n"
00236                 "Forward emulation pc:      '%08x%08x'\n"
00237                 "Simulation pc:             '%08x%08x'\n"
00238                 "Forward emulation address: '%08x%08x'\n"
00239                 "Simulation address:        '%08x%08x'\n"
00240                 "%s\n%s",
00241                 (u32)(emuDst >> 32), (u32)(emuDst & 0xffffffff),
00242                 (u32)(simDst >> 32), (u32)(simDst & 0xffffffff),
00243                 (u32)(emuPC >> 32),  (u32)(emuPC & 0xffffffff),
00244                 (u32)(simPC >> 32),  (u32)(simPC & 0xffffffff),
00245                 (u32)(emuAddr >> 32),  (u32)(emuAddr & 0xffffffff),
00246                 (u32)(simAddr >> 32),  (u32)(simAddr & 0xffffffff),
00247                 simOp->ToString().c_str(),
00248                 simOp->GetOpInfo()->GetMnemonic()
00249             );
00250         }
00251     }
00252 
00253 
00254 
00255     inflightOps->pop_front();
00256 }
00257 
00258 
00259 // Get a pre-executed result corresponding to 'op'
00260 const OpStateIF* ForwardEmulator::GetExecutionResult( OpIterator op )
00261 {
00262     InflightOp* ifOp = GetInflightOp( op );
00263     return (ifOp != NULL ) ? &ifOp->emuOp : NULL;
00264 }
00265 
00266 const MemAccess* ForwardEmulator::GetMemoryAccessResult( OpIterator op )
00267 {
00268     InflightOp* ifOp = GetInflightOp( op );
00269     return (ifOp != NULL ) ? &ifOp->memAccess : NULL;
00270 }
00271 
00272 // Returns whether 'op' is in miss predicted path or not.
00273 bool ForwardEmulator::IsInMissPredictedPath( OpIterator op )
00274 {
00275     int tid = op->GetTID();
00276     ThreadContext* threadContext = &m_threadContext[ tid ];
00277     return ( op->GetRetireID() >= threadContext->nextFixedRetireID ) ? true : false;
00278 }
00279 
00280 void ForwardEmulator::Read( MemAccess* access )
00281 {
00282     int tid = access->address.tid;
00283     InflightOpList* inflightOps = &m_inflightOps[ tid ];
00284     InflightOp* entry = &inflightOps->back();
00285 
00286     entry->memAccess = *access;
00287     InflightOp* producer = GetProducerStore( *entry );
00288 
00289     bool partial = false;
00290     if( producer != NULL ){
00291         if( m_memOperations.IsInnerAccess( *access, producer->memAccess ) ){
00292             access->value = m_memOperations.ReadPreviousAccess( *access, producer->memAccess );
00293             entry->memAccess = *access;
00294             return;
00295         }
00296         else{
00297             partial = true;
00298             //THROW_RUNTIME_ERROR( "A partial read access in ForwardEmulator is not supported yet." );
00299         }
00300     }
00301 
00302     if( partial ){
00303 
00304         // Merge multiple stores to one load.
00305         MemAccess base = *access;
00306         m_emulator->GetMemImage()->Read( &base );
00307 
00308         for( InflightOpList::iterator i = inflightOps->begin(); i != inflightOps->end(); ++i ){
00309             if( !i->isStore ){
00310                 continue;
00311             }
00312 
00313             if( m_memOperations.IsOverlapped( base, i->memAccess ) ){
00314                 base.value = 
00315                     m_memOperations.MergePartialAccess( base, i->memAccess );
00316             }
00317         }
00318 
00319         *access = base;
00320         entry->memAccess = base;
00321         return;
00322     }
00323 
00324     m_emulator->GetMemImage()->Read( access );
00325     entry->memAccess = *access;
00326 }
00327 
00328 void ForwardEmulator::Write( MemAccess* access )
00329 {
00330     int tid = access->address.tid;
00331     InflightOpList* inflightOps = &m_inflightOps[ tid ];
00332     InflightOp* op = &inflightOps->back();
00333     op->memAccess = *access;
00334 }
00335 
00336 // When 'reverse' is true, an in-flight op is searched from the back of 'inflightOps'.
00337 ForwardEmulator::InflightOp* ForwardEmulator::GetInflightOp( OpIterator op, bool reverse )
00338 {
00339     int tid = op->GetTID();
00340     InflightOpList* inflightOps = &m_inflightOps[ tid ];
00341 
00342     u64 retireID = op->GetRetireID();
00343 
00344     if( reverse ){
00345         for( InflightOpList::reverse_iterator i = inflightOps->rbegin(); i != inflightOps->rend(); ++i ){
00346             if( i->retireId == retireID ){
00347                 return &(*i);
00348             }
00349         }
00350     }
00351     else{
00352         for( InflightOpList::iterator i = inflightOps->begin(); i != inflightOps->end(); ++i ){
00353             if( i->retireId == retireID ){
00354                 return &(*i);
00355             }
00356         }
00357     }
00358     return NULL;
00359 }
00360 
00361 ForwardEmulator::InflightOp*
00362     ForwardEmulator::GetProducerStore( const InflightOp& consumerLoad )  
00363 {
00364     const MemAccess& access = consumerLoad.memAccess;
00365     int tid = access.address.tid;
00366     InflightOpList* inflightOps = &m_inflightOps[ tid ];
00367 
00368     InflightOpList::reverse_iterator end = inflightOps->rend();
00369     for( InflightOpList::reverse_iterator i = inflightOps->rbegin(); i != end; ++i ){
00370         if( !i->isStore ){
00371             continue;
00372         }
00373         if( consumerLoad.retireId < i->retireId ){
00374             continue;
00375         }
00376 
00377         if( m_memOperations.IsOverlapped( access, i->memAccess ) ){
00378             return &(*i);
00379         }
00380     }
00381     return NULL;
00382 }
00383 
00384 // Calculate a next PC from the executed state of an op.
00385 PC ForwardEmulator::GetExecutedNextPC( PC current, OpStateIF* state ) const
00386 {
00387     if( state->GetTaken() ){
00388         return state->GetTakenPC();
00389     }
00390     else{
00391         current.address += SimISAInfo::INSTRUCTION_WORD_BYTE_SIZE;
00392         return current;
00393     }
00394 }
00395 
00396 // Update fixed pc/retirement id with execution results.
00397 void ForwardEmulator::UpdateFixedPath( OpIterator simOp )
00398 {
00399     int tid = simOp->GetTID();
00400     ThreadContext* thread = &m_threadContext[ tid ];
00401     u64 rid = simOp->GetRetireID();
00402 
00403     if( ( thread->nextFixedRetireID == rid && thread->nextFixedPC == simOp->GetPC() ) ||
00404         thread->nextFixedRetireID > rid 
00405     ){
00406         // When re-fetch recovery occurs (nextFixedRetireID > rid ),
00407         // nextFixedRetireID and nextFixedPC must be set to a recovered ones. 
00408 
00409         // 'reverse' is set to false, because it may be found near the head of 'inflightOps'.
00410         InflightOp* inflightOp = GetInflightOp( simOp ); 
00411         ASSERT( inflightOp != NULL );
00412 
00413         if( inflightOp->updatePC ){
00414             thread->nextFixedPC = 
00415                 GetExecutedNextPC( inflightOp->emuOp.GetPC(), &inflightOp->emuOp );
00416         }
00417         else
00418         {
00419             // You must overwrite nextFixedPC because
00420             // it might hold illegal PC as a result of recovery.
00421             thread->nextFixedPC = inflightOp->emuOp.GetPC();
00422         }
00423         thread->nextFixedRetireID = rid + 1;
00424     }
00425 
00426     ASSERT(
00427         ((s64)rid - (s64)thread->nextFixedRetireID) < MAX_RID_DIFFERENCE, 
00428         "The difference between a current retirement id and a next fixed retirement id is too large."
00429     );
00430 
00431 }

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