void MESI_SMPCache::writeLine(uint32_t wrPC, uint32_t addr){ /*This method implements actions taken when instruction wrPC *writes to memory location addr*/ /*Find the line to which this address maps*/ MESI_SMPCacheState * st = (MESI_SMPCacheState *)cache->findLine(addr); /* *If the tags didn't match, or the line was invalid, it is a *write miss */ if(!st || (st && !(st->isValid())) ){ numWriteMisses++; if(st){ /*We're writing to an invalid line*/ numWriteOnInvalidMisses++; } /* * Let the other caches snoop this write access and update their * state accordingly. This action is effectively putting the write * on the bus. */ MESI_SMPCache::InvalidateReply inv_ack = writeRemoteAction(addr); numInvalidatesSent++; /*Fill the line with the new written block*/ fillLine(addr,MESI_MODIFIED); return; }else if(st->getState() == MESI_SHARED || st->getState() == MESI_EXCLUSIVE){ /* If the block is shared and we're writing, still count it as a cache hit, * but we need to invalidate all of the sharers' copies and upgrade to Modified * in order to write. */ numWriteHits++; if (st->getState() == MESI_SHARED){ /*Write-on-shared Coherence Misses*/ numWriteOnSharedMisses++; /*Let the other sharers snoop this write, and invalidate themselves*/ MESI_SMPCache::InvalidateReply inv_ack = writeRemoteAction(addr); numInvalidatesSent++; } /*Change the state of the line to Modified to reflect the write*/ st->changeStateTo(MESI_MODIFIED); return; }else{ //Write Hit /*Already have it writable: No coherence action required!*/ numWriteHits++; return; } }
/** Make a write request. * @param access the memory access being made * @param doStoreBufferAccess whether to use the det store buffer for this write */ virtual void write( const DataAccess& access, bool doStoreBufferAccess ) { State* myLine = NULL; CacheResponse r = L1cache->search( access.addr(), myLine ); if ( r != MISSED_TO_MEMORY ) { switch (r) { case L1_HIT: timeInMemoryHierarchy += L1_HIT_LATENCY; // default det cache latency is an L1 hit, so it doesn't matter whether we hit to a dirty line or not deterministicTimeInMemoryHierarchy += L1_HIT_LATENCY; break; case L2_HIT: { timeInMemoryHierarchy += L2_HIT_LATENCY; if ( myLine->isDirty() ) { deterministicTimeInMemoryHierarchy += L2_HIT_LATENCY; } else { deterministicTimeInMemoryHierarchy += L1_HIT_LATENCY; } break; } case L3_HIT: timeInMemoryHierarchy += L3_HIT_LATENCY; // shared cache hits aren't det deterministicTimeInMemoryHierarchy += L1_HIT_LATENCY; break; default: assert(false); } // we either hit somewhere in our private cache(s) or we hit in the shared cache, // but we may not have write permissions L1cache->access( access.addr(), myLine ); switch ( myLine->getState() ) { case MESI_SHARED: // upgrade miss numUpgradeMisses++; writeRemoteAction( access ); // invalidate other copies timeInMemoryHierarchy += REMOTE_HIT_LATENCY; myLine->changeStateTo( MESI_MODIFIED ); if ( useDetStoreBuffers && doStoreBufferAccess ) { myLine->setDirty(); StoreBufferIsEmpty = false; } return; case MESI_EXCLUSIVE: // write hit case MESI_MODIFIED: numWriteHits++; // TODO: fix this duplication from the MESI_SHARED case myLine->changeStateTo( MESI_MODIFIED ); if ( useDetStoreBuffers && doStoreBufferAccess ) { myLine->setDirty(); StoreBufferIsEmpty = false; } return; default: assert(false); } } // we didn't have the line at all - need to check for remote copies InvalidateReply inv_ack = writeRemoteAction( access ); // remote hits and missing to memory aren't det deterministicTimeInMemoryHierarchy += L1_HIT_LATENCY; if ( inv_ack.nobodyHasThisLine ) { numWriteMisses++; timeInMemoryHierarchy += MEMORY_ACCESS_LATENCY; } else { numWriteRemoteHits++; timeInMemoryHierarchy += REMOTE_HIT_LATENCY; } L1cache->access( access.addr(), myLine ); myLine->changeStateTo( MESI_MODIFIED ); if ( useDetStoreBuffers && doStoreBufferAccess ) { myLine->setDirty(); StoreBufferIsEmpty = false; } } // end write()