/* * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * $Id$ * */ /*------------------------------------------------------------------------*/ /* Includes */ /*------------------------------------------------------------------------*/ #include "OpalInterface.hh" #include "interface.hh" #include "System.hh" #include "SubBlock.hh" #include "mf_api.hh" #include "Chip.hh" #include "RubyConfig.hh" //#include "XactIsolationChecker.hh" //gem5:Arka for decomissioning ruby/log_tm // #include "TransactionInterfaceManager.hh" //#include "TransactionVersionManager.hh" //gem5:Arka for decomissioning ruby/log_tm #include "Sequencer.hh" /*------------------------------------------------------------------------*/ /* Forward declarations */ /*------------------------------------------------------------------------*/ static CacheRequestType get_request_type( OpalMemop_t opaltype ); static OpalMemop_t get_opal_request_type( CacheRequestType type ); /// The static opalinterface instance OpalInterface *OpalInterface::inst = NULL; /*------------------------------------------------------------------------*/ /* Constructor(s) / destructor */ /*------------------------------------------------------------------------*/ //************************************************************************** OpalInterface::OpalInterface(System* sys_ptr) { clearStats(); ASSERT( inst == NULL ); inst = this; m_opal_intf = NULL; } /*------------------------------------------------------------------------*/ /* Public methods */ /*------------------------------------------------------------------------*/ //************************************************************************** void OpalInterface::printConfig(ostream& out) const { out << "Opal_ruby_multiplier: " << OPAL_RUBY_MULTIPLIER << endl; out << endl; } void OpalInterface::printStats(ostream& out) const { out << endl; out << "Opal Interface Stats" << endl; out << "----------------------" << endl; out << endl; } //************************************************************************** void OpalInterface::clearStats() { } //************************************************************************** integer_t OpalInterface::getInstructionCount(int procID) const { return ((*m_opal_intf->getInstructionCount)(procID)); } //************************************************************************* uint64 OpalInterface::getOpalTime(int procID) const { return ((*m_opal_intf->getOpalTime)(procID)); } /************ For WATTCH power stats ************************************/ //************************************************************************* void OpalInterface::incrementL2Access(int procID) const{ ((*m_opal_intf->incrementL2Access)(procID)); } //************************************************************************* void OpalInterface::incrementPrefetcherAccess(int procID, int num_prefetches, int isinstr) const{ ((*m_opal_intf->incrementPrefetcherAccess)(procID, num_prefetches, isinstr)); } /******************** END WATTCH power stats ****************************/ // Notifies Opal of an L2 miss //************************************************************************* void OpalInterface::notifyL2Miss(int procID, physical_address_t physicalAddr, OpalMemop_t type, int tagexists) const{ ((*m_opal_intf->notifyL2Miss)(procID, physicalAddr, type, tagexists)); } /****************************************************************** * void hitCallback(int cpuNumber) * Called by Sequencer. Calls opal. ******************************************************************/ //************************************************************************** void OpalInterface::hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread) { // notify opal that the transaction has completed (*m_opal_intf->hitCallback)( proc, data.getAddress().getAddress(), get_opal_request_type(type), thread ); } //************************************************************************** // Useful functions if Ruby needs to read/write physical memory when running with Opal integer_t OpalInterface::readPhysicalMemory(int procID, physical_address_t address, int len ){ return SIMICS_read_physical_memory(procID, address, len); } //************************************************************************** void OpalInterface::writePhysicalMemory( int procID, physical_address_t address, integer_t value, int len ){ SIMICS_write_physical_memory(procID, address, value, len); } //*************************************************************** // notifies Opal to print debug info void OpalInterface::printDebug(){ (*m_opal_intf->printDebug)(); } //*************************************************************** /****************************************************************** * Called by opal's memory operations (memop.C) * May call Sequencer. ******************************************************************/ //**************************************************************************** int OpalInterface::getNumberOutstanding( int cpuNumber ){ Sequencer* targetSequencer_ptr = g_system_ptr->getChip(cpuNumber/RubyConfig::numberOfProcsPerChip())->getSequencer(cpuNumber%RubyConfig::numberOfProcsPerChip()); return targetSequencer_ptr->getNumberOutstanding(); } //**************************************************************************** int OpalInterface::getNumberOutstandingDemand( int cpuNumber ){ Sequencer* targetSequencer_ptr = g_system_ptr->getChip(cpuNumber/RubyConfig::numberOfProcsPerChip())->getSequencer(cpuNumber%RubyConfig::numberOfProcsPerChip()); return targetSequencer_ptr->getNumberOutstandingDemand(); } //**************************************************************************** int OpalInterface::getNumberOutstandingPrefetch( int cpuNumber ){ Sequencer* targetSequencer_ptr = g_system_ptr->getChip(cpuNumber/RubyConfig::numberOfProcsPerChip())->getSequencer(cpuNumber%RubyConfig::numberOfProcsPerChip()); return targetSequencer_ptr->getNumberOutstandingPrefetch(); } //************************************************************************** int OpalInterface::isReady( int cpuNumber, la_t logicalAddr, pa_t physicalAddr, OpalMemop_t typeOfRequest, int thread ) { // Send request to sequencer Sequencer* targetSequencer_ptr = g_system_ptr->getChip(cpuNumber/RubyConfig::numberOfProcsPerChip())->getSequencer(cpuNumber%RubyConfig::numberOfProcsPerChip()); // FIXME - some of these fields have bogus values sinced isReady() // doesn't need them. However, it would be cleaner if all of these // fields were exact. return (targetSequencer_ptr->isReady(CacheMsg(Address( physicalAddr ), Address( physicalAddr ), get_request_type(typeOfRequest), Address(0), AccessModeType_UserMode, // User/supervisor mode 0, // Size in bytes of request PrefetchBit_No, // Not a prefetch 0, // Version number Address(logicalAddr), // Virtual Address thread, // SMT thread 0, // TM specific - timestamp of memory request false // TM specific - whether request is part of escape action ) )); } // FIXME: duplicated code should be avoided //************************************************************************** void OpalInterface::makeRequest(int cpuNumber, la_t logicalAddr, pa_t physicalAddr, int requestSize, OpalMemop_t typeOfRequest, la_t virtualPC, int isPriv, int thread) { // Issue the request to the sequencer. // set access type (user/supervisor) AccessModeType access_mode; if (isPriv) { access_mode = AccessModeType_SupervisorMode; } else { access_mode = AccessModeType_UserMode; } // Send request to sequencer Sequencer* targetSequencer_ptr = g_system_ptr->getChip(cpuNumber/RubyConfig::numberOfProcsPerChip())->getSequencer(cpuNumber%RubyConfig::numberOfProcsPerChip()); targetSequencer_ptr->makeRequest(CacheMsg(Address( physicalAddr ), Address( physicalAddr ), get_request_type(typeOfRequest), Address(virtualPC), access_mode, // User/supervisor mode requestSize, // Size in bytes of request PrefetchBit_No, // Not a prefetch 0, // Version number Address(logicalAddr), // Virtual Address thread, // SMT thread 0, // TM specific - timestamp of memory request false // TM specific - whether request is part of escape action ) ); } //************************************************************************** void OpalInterface::makePrefetch(int cpuNumber, la_t logicalAddr, pa_t physicalAddr, int requestSize, OpalMemop_t typeOfRequest, la_t virtualPC, int isPriv, int thread) { DEBUG_MSG(SEQUENCER_COMP,MedPrio,"Making prefetch request"); // Issue the request to the sequencer. // set access type (user/supervisor) AccessModeType access_mode; if (isPriv) { access_mode = AccessModeType_SupervisorMode; } else { access_mode = AccessModeType_UserMode; } // make the prefetch Sequencer* targetSequencer_ptr = g_system_ptr->getChip(cpuNumber/RubyConfig::numberOfProcsPerChip())->getSequencer(cpuNumber%RubyConfig::numberOfProcsPerChip()); targetSequencer_ptr->makeRequest(CacheMsg(Address( physicalAddr ), Address( physicalAddr ), get_request_type(typeOfRequest), Address(virtualPC), access_mode, requestSize, PrefetchBit_Yes, // True means this is a prefetch 0, // Version number Address(logicalAddr), // Virtual Address thread, // SMT thread 0, // TM specific - timestamp of memory request false // TM specific - whether request is part of escape action ) ); return; } //************************************************************************** int OpalInterface::staleDataRequest( int cpuNumber, pa_t physicalAddr, int requestSize, int8 *buffer ) { // Find sequencer Sequencer* targetSequencer_ptr = g_system_ptr->getChip(cpuNumber/RubyConfig::numberOfProcsPerChip())->getSequencer(cpuNumber%RubyConfig::numberOfProcsPerChip()); assert(targetSequencer_ptr != NULL); // query the cache for stale data values (if any) bool hit = false; //hit = targetSequencer_ptr->staleDataAccess( Address(physicalAddr), // requestSize, buffer ); return hit; } //************************************************************************** void OpalInterface::notify( int status ) { if (OpalInterface::inst == NULL) { if (status == 1) { // notify system that opal is now loaded g_system_ptr->opalLoadNotify(); } else { return; } } // opal interface must be allocated now ASSERT( OpalInterface::inst != NULL ); if ( status == 0 ) { } else if ( status == 1 ) { // install notification: query opal for its interface OpalInterface::inst->queryOpalInterface(); if ( OpalInterface::inst->m_opal_intf != NULL ) { cout << "OpalInterface: installation successful." << endl; // test: (*(OpalInterface::inst->m_opal_intf->hitCallback))( 0, 0xFFULL ); } } else if ( status == 2 ) { // unload notification // NOTE: this is not tested, as we can't unload ruby or opal right now. OpalInterface::inst->removeOpalInterface(); } } // advance ruby time //************************************************************************** int OpalInterface::s_advance_counter = 0; void OpalInterface::advanceTime( void ) { s_advance_counter++; if (s_advance_counter == OPAL_RUBY_MULTIPLIER) { Time time = g_eventQueue_ptr->getTime() + 1; DEBUG_EXPR(NODE_COMP, HighPrio, time); g_eventQueue_ptr->triggerEvents(time); s_advance_counter = 0; } } // return ruby's time //************************************************************************** unsigned long long OpalInterface::getTime( void ) { return (g_eventQueue_ptr->getTime()); } // print's Ruby outstanding request table void OpalInterface::printProgress(int cpuNumber){ Sequencer* targetSequencer_ptr = g_system_ptr->getChip(cpuNumber/RubyConfig::numberOfProcsPerChip())->getSequencer(cpuNumber%RubyConfig::numberOfProcsPerChip()); assert(targetSequencer_ptr != NULL); targetSequencer_ptr->printProgress(cout); } // Non-method helper function //************************************************************************** static CacheRequestType get_request_type( OpalMemop_t opaltype ) { CacheRequestType type; if (opaltype == OPAL_LOAD) { type = CacheRequestType_LD; } else if (opaltype == OPAL_STORE){ type = CacheRequestType_ST; } else if (opaltype == OPAL_IFETCH){ type = CacheRequestType_IFETCH; } else if (opaltype == OPAL_ATOMIC){ type = CacheRequestType_ATOMIC; } else { ERROR_MSG("Error: Strange memory transaction type: not a LD or a ST"); } return type; } //************************************************************************** static OpalMemop_t get_opal_request_type( CacheRequestType type ) { OpalMemop_t opal_type; if(type == CacheRequestType_LD){ opal_type = OPAL_LOAD; } else if( type == CacheRequestType_ST){ opal_type = OPAL_STORE; } else if( type == CacheRequestType_IFETCH){ opal_type = OPAL_IFETCH; } else if( type == CacheRequestType_ATOMIC){ opal_type = OPAL_ATOMIC; } else{ ERROR_MSG("Error: Strange memory transaction type: not a LD or a ST"); } //cout << "get_opal_request_type() CacheRequestType[ " << type << " ] opal_type[ " << opal_type << " ] " << endl; return opal_type; } //************************************************************************** void OpalInterface::removeOpalInterface( void ) { cout << "ruby: opal uninstalled. reinstalling timing model." << endl; SIMICS_install_timing_model(); } //************************************************************************** bool OpalInterface::isOpalLoaded( void ) { if (!g_SIMICS) { return false; } else { mf_opal_api_t *opal_interface = SIMICS_get_opal_interface(); if ( opal_interface == NULL ) { return false; } else { return true; } } } //************************************************************************** void OpalInterface::queryOpalInterface( void ) { m_opal_intf = SIMICS_get_opal_interface(); if ( m_opal_intf == NULL ) { WARN_MSG("error: OpalInterface: opal does not implement mf-opal-api interface.\n"); } else { // opal is loaded -- remove the timing_model interface cout << "Ruby: ruby-opal link established. removing timing_model." << endl; SIMICS_remove_timing_model(); if (m_opal_intf->notifyCallback != NULL) { cout << "opalinterface: doing notify callback\n"; (*m_opal_intf->notifyCallback)( 1 ); } else { // 2/27/2005, removed spurious error message (MRM) // cout << "error: opalinterface: mf-opal-api has NULL notify callback.\n"; } } } // install the opal interface to simics //************************************************************************** void OpalInterface::installInterface( mf_ruby_api_t *api ) { // install ruby interface api->isReady = &OpalInterface::isReady; api->makeRequest = &OpalInterface::makeRequest; api->makePrefetch = &OpalInterface::makePrefetch; api->advanceTime = &OpalInterface::advanceTime; api->getTime = &OpalInterface::getTime; api->staleDataRequest = &OpalInterface::staleDataRequest; api->notifyCallback = &OpalInterface::notify; api->getNumberOutstanding = &OpalInterface::getNumberOutstanding; api->getNumberOutstandingDemand = &OpalInterface::getNumberOutstandingDemand; api->getNumberOutstandingPrefetch = &OpalInterface::getNumberOutstandingPrefetch; api->printProgress = &OpalInterface::printProgress; }