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 #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
00089
00090 if( inflightOps->size() > 0 ){
00091 InflightOp* entry = &inflightOps->back();
00092 if( entry->retireId >= simOp->GetRetireID() ){
00093
00094 UpdateFixedPath( simOp );
00095 return;
00096 }
00097
00098
00099
00100
00101
00102
00103 if( entry->emuOp.GetOpInfo()->GetOpClass().IsSyscall() &&
00104 entry->emuOp.GetPC() != simOp->GetPC()
00105 ){
00106 return;
00107 }
00108 }
00109
00110
00111
00112
00113
00114
00115 inflightOps->push_back( InflightOp() );
00116 InflightOp* entry = &inflightOps->back();
00117 entry->simOp = simOp;
00118 entry->retireId = simOp->GetRetireID();
00119
00120
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
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
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
00144 if( opInfo->GetOpClass().IsSyscall() ){
00145
00146
00147
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
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
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
00210
00211
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
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
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
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
00299 }
00300 }
00301
00302 if( partial ){
00303
00304
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
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
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
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
00407
00408
00409
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
00420
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 }