Sequencer.cc revision 6285
16145Snate@binkert.org 26145Snate@binkert.org/* 36145Snate@binkert.org * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 46145Snate@binkert.org * All rights reserved. 56145Snate@binkert.org * 66145Snate@binkert.org * Redistribution and use in source and binary forms, with or without 76145Snate@binkert.org * modification, are permitted provided that the following conditions are 86145Snate@binkert.org * met: redistributions of source code must retain the above copyright 96145Snate@binkert.org * notice, this list of conditions and the following disclaimer; 106145Snate@binkert.org * redistributions in binary form must reproduce the above copyright 116145Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 126145Snate@binkert.org * documentation and/or other materials provided with the distribution; 136145Snate@binkert.org * neither the name of the copyright holders nor the names of its 146145Snate@binkert.org * contributors may be used to endorse or promote products derived from 156145Snate@binkert.org * this software without specific prior written permission. 166145Snate@binkert.org * 176145Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 186145Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 196145Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 206145Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 216145Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 226145Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 236145Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 246145Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 256145Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 266145Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 276145Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 286145Snate@binkert.org */ 296145Snate@binkert.org 306154Snate@binkert.org#include "mem/ruby/common/Global.hh" 316154Snate@binkert.org#include "mem/ruby/system/Sequencer.hh" 326154Snate@binkert.org#include "mem/ruby/system/System.hh" 336154Snate@binkert.org#include "mem/protocol/Protocol.hh" 346154Snate@binkert.org#include "mem/ruby/profiler/Profiler.hh" 356154Snate@binkert.org#include "mem/ruby/system/CacheMemory.hh" 366285Snate@binkert.org#include "mem/protocol/CacheMsg.hh" 376285Snate@binkert.org#include "mem/ruby/recorder/Tracer.hh" 386154Snate@binkert.org#include "mem/ruby/common/SubBlock.hh" 396154Snate@binkert.org#include "mem/protocol/Protocol.hh" 406154Snate@binkert.org#include "mem/gems_common/Map.hh" 416285Snate@binkert.org#include "mem/ruby/buffers/MessageBuffer.hh" 426285Snate@binkert.org#include "mem/ruby/slicc_interface/AbstractController.hh" 436145Snate@binkert.org 446285Snate@binkert.org//Sequencer::Sequencer(int core_id, MessageBuffer* mandatory_q) 456145Snate@binkert.org 466285Snate@binkert.orgSequencer::Sequencer(const string & name) 476285Snate@binkert.org :RubyPort(name) 486285Snate@binkert.org{ 496285Snate@binkert.org} 506285Snate@binkert.org 516285Snate@binkert.orgvoid Sequencer::init(const vector<string> & argv) 526285Snate@binkert.org{ 536145Snate@binkert.org m_deadlock_check_scheduled = false; 546145Snate@binkert.org m_outstanding_count = 0; 556145Snate@binkert.org 566285Snate@binkert.org m_max_outstanding_requests = 0; 576285Snate@binkert.org m_deadlock_threshold = 0; 586285Snate@binkert.org m_version = -1; 596285Snate@binkert.org m_instCache_ptr = NULL; 606285Snate@binkert.org m_dataCache_ptr = NULL; 616285Snate@binkert.org m_controller = NULL; 626285Snate@binkert.org for (size_t i=0; i<argv.size(); i+=2) { 636285Snate@binkert.org if ( argv[i] == "controller") { 646285Snate@binkert.org m_controller = RubySystem::getController(argv[i+1]); // args[i] = "L1Cache" 656285Snate@binkert.org m_mandatory_q_ptr = m_controller->getMandatoryQueue(); 666285Snate@binkert.org } else if ( argv[i] == "icache") 676285Snate@binkert.org m_instCache_ptr = RubySystem::getCache(argv[i+1]); 686285Snate@binkert.org else if ( argv[i] == "dcache") 696285Snate@binkert.org m_dataCache_ptr = RubySystem::getCache(argv[i+1]); 706285Snate@binkert.org else if ( argv[i] == "version") 716285Snate@binkert.org m_version = atoi(argv[i+1].c_str()); 726285Snate@binkert.org else if ( argv[i] == "max_outstanding_requests") 736285Snate@binkert.org m_max_outstanding_requests = atoi(argv[i+1].c_str()); 746285Snate@binkert.org else if ( argv[i] == "deadlock_threshold") 756285Snate@binkert.org m_deadlock_threshold = atoi(argv[i+1].c_str()); 766285Snate@binkert.org else { 776285Snate@binkert.org cerr << "WARNING: Sequencer: Unkown configuration parameter: " << argv[i] << endl; 786285Snate@binkert.org assert(false); 796285Snate@binkert.org } 806145Snate@binkert.org } 816285Snate@binkert.org assert(m_max_outstanding_requests > 0); 826285Snate@binkert.org assert(m_deadlock_threshold > 0); 836285Snate@binkert.org assert(m_version > -1); 846285Snate@binkert.org assert(m_instCache_ptr != NULL); 856285Snate@binkert.org assert(m_dataCache_ptr != NULL); 866285Snate@binkert.org assert(m_controller != NULL); 876145Snate@binkert.org} 886145Snate@binkert.org 896145Snate@binkert.orgSequencer::~Sequencer() { 906285Snate@binkert.org 916145Snate@binkert.org} 926145Snate@binkert.org 936145Snate@binkert.orgvoid Sequencer::wakeup() { 946145Snate@binkert.org // Check for deadlock of any of the requests 956145Snate@binkert.org Time current_time = g_eventQueue_ptr->getTime(); 966145Snate@binkert.org 976145Snate@binkert.org // Check across all outstanding requests 986145Snate@binkert.org int total_outstanding = 0; 996285Snate@binkert.org 1006285Snate@binkert.org Vector<Address> keys = m_readRequestTable.keys(); 1016285Snate@binkert.org for (int i=0; i<keys.size(); i++) { 1026285Snate@binkert.org SequencerRequest* request = m_readRequestTable.lookup(keys[i]); 1036285Snate@binkert.org if (current_time - request->issue_time >= m_deadlock_threshold) { 1046285Snate@binkert.org WARN_MSG("Possible Deadlock detected"); 1056285Snate@binkert.org WARN_EXPR(request); 1066285Snate@binkert.org WARN_EXPR(m_version); 1076285Snate@binkert.org WARN_EXPR(keys.size()); 1086285Snate@binkert.org WARN_EXPR(current_time); 1096285Snate@binkert.org WARN_EXPR(request->issue_time); 1106285Snate@binkert.org WARN_EXPR(current_time - request->issue_time); 1116285Snate@binkert.org ERROR_MSG("Aborting"); 1126145Snate@binkert.org } 1136285Snate@binkert.org } 1146145Snate@binkert.org 1156285Snate@binkert.org keys = m_writeRequestTable.keys(); 1166285Snate@binkert.org for (int i=0; i<keys.size(); i++) { 1176285Snate@binkert.org SequencerRequest* request = m_writeRequestTable.lookup(keys[i]); 1186285Snate@binkert.org if (current_time - request->issue_time >= m_deadlock_threshold) { 1196285Snate@binkert.org WARN_MSG("Possible Deadlock detected"); 1206285Snate@binkert.org WARN_EXPR(request); 1216285Snate@binkert.org WARN_EXPR(m_version); 1226285Snate@binkert.org WARN_EXPR(current_time); 1236285Snate@binkert.org WARN_EXPR(request->issue_time); 1246285Snate@binkert.org WARN_EXPR(current_time - request->issue_time); 1256285Snate@binkert.org WARN_EXPR(keys.size()); 1266285Snate@binkert.org ERROR_MSG("Aborting"); 1276145Snate@binkert.org } 1286285Snate@binkert.org } 1296285Snate@binkert.org total_outstanding += m_writeRequestTable.size() + m_readRequestTable.size(); 1306285Snate@binkert.org 1316145Snate@binkert.org assert(m_outstanding_count == total_outstanding); 1326145Snate@binkert.org 1336145Snate@binkert.org if (m_outstanding_count > 0) { // If there are still outstanding requests, keep checking 1346285Snate@binkert.org g_eventQueue_ptr->scheduleEvent(this, m_deadlock_threshold); 1356145Snate@binkert.org } else { 1366145Snate@binkert.org m_deadlock_check_scheduled = false; 1376145Snate@binkert.org } 1386145Snate@binkert.org} 1396145Snate@binkert.org 1406145Snate@binkert.orgvoid Sequencer::printProgress(ostream& out) const{ 1416285Snate@binkert.org /* 1426145Snate@binkert.org int total_demand = 0; 1436145Snate@binkert.org out << "Sequencer Stats Version " << m_version << endl; 1446145Snate@binkert.org out << "Current time = " << g_eventQueue_ptr->getTime() << endl; 1456145Snate@binkert.org out << "---------------" << endl; 1466145Snate@binkert.org out << "outstanding requests" << endl; 1476145Snate@binkert.org 1486285Snate@binkert.org Vector<Address> rkeys = m_readRequestTable.keys(); 1496285Snate@binkert.org int read_size = rkeys.size(); 1506285Snate@binkert.org out << "proc " << m_version << " Read Requests = " << read_size << endl; 1516285Snate@binkert.org // print the request table 1526285Snate@binkert.org for(int i=0; i < read_size; ++i){ 1536285Snate@binkert.org SequencerRequest * request = m_readRequestTable.lookup(rkeys[i]); 1546285Snate@binkert.org out << "\tRequest[ " << i << " ] = " << request->type << " Address " << rkeys[i] << " Posted " << request->issue_time << " PF " << PrefetchBit_No << endl; 1556285Snate@binkert.org total_demand++; 1566285Snate@binkert.org } 1576145Snate@binkert.org 1586285Snate@binkert.org Vector<Address> wkeys = m_writeRequestTable.keys(); 1596285Snate@binkert.org int write_size = wkeys.size(); 1606285Snate@binkert.org out << "proc " << m_version << " Write Requests = " << write_size << endl; 1616285Snate@binkert.org // print the request table 1626285Snate@binkert.org for(int i=0; i < write_size; ++i){ 1636285Snate@binkert.org CacheMsg & request = m_writeRequestTable.lookup(wkeys[i]); 1646145Snate@binkert.org out << "\tRequest[ " << i << " ] = " << request.getType() << " Address " << wkeys[i] << " Posted " << request.getTime() << " PF " << request.getPrefetch() << endl; 1656145Snate@binkert.org if( request.getPrefetch() == PrefetchBit_No ){ 1666145Snate@binkert.org total_demand++; 1676145Snate@binkert.org } 1686285Snate@binkert.org } 1696145Snate@binkert.org 1706285Snate@binkert.org out << endl; 1716285Snate@binkert.org 1726145Snate@binkert.org out << "Total Number Outstanding: " << m_outstanding_count << endl; 1736145Snate@binkert.org out << "Total Number Demand : " << total_demand << endl; 1746145Snate@binkert.org out << "Total Number Prefetches : " << m_outstanding_count - total_demand << endl; 1756145Snate@binkert.org out << endl; 1766145Snate@binkert.org out << endl; 1776285Snate@binkert.org */ 1786145Snate@binkert.org} 1796145Snate@binkert.org 1806285Snate@binkert.orgvoid Sequencer::printConfig(ostream& out) const { 1816285Snate@binkert.org out << "Seqeuncer config: " << m_name << endl; 1826285Snate@binkert.org out << " controller: " << m_controller->getName() << endl; 1836285Snate@binkert.org out << " version: " << m_version << endl; 1846285Snate@binkert.org out << " max_outstanding_requests: " << m_max_outstanding_requests << endl; 1856285Snate@binkert.org out << " deadlock_threshold: " << m_deadlock_threshold << endl; 1866145Snate@binkert.org} 1876145Snate@binkert.org 1886145Snate@binkert.org// Insert the request on the correct request table. Return true if 1896145Snate@binkert.org// the entry was already present. 1906285Snate@binkert.orgbool Sequencer::insertRequest(SequencerRequest* request) { 1916285Snate@binkert.org int total_outstanding = m_writeRequestTable.size() + m_readRequestTable.size(); 1926285Snate@binkert.org 1936145Snate@binkert.org assert(m_outstanding_count == total_outstanding); 1946145Snate@binkert.org 1956145Snate@binkert.org // See if we should schedule a deadlock check 1966145Snate@binkert.org if (m_deadlock_check_scheduled == false) { 1976285Snate@binkert.org g_eventQueue_ptr->scheduleEvent(this, m_deadlock_threshold); 1986145Snate@binkert.org m_deadlock_check_scheduled = true; 1996145Snate@binkert.org } 2006145Snate@binkert.org 2016285Snate@binkert.org Address line_addr(request->ruby_request.paddr); 2026285Snate@binkert.org line_addr.makeLineAddress(); 2036285Snate@binkert.org if ((request->ruby_request.type == RubyRequestType_ST) || 2046285Snate@binkert.org (request->ruby_request.type == RubyRequestType_RMW)) { 2056285Snate@binkert.org if (m_writeRequestTable.exist(line_addr)) { 2066285Snate@binkert.org m_writeRequestTable.lookup(line_addr) = request; 2076285Snate@binkert.org // return true; 2086285Snate@binkert.org assert(0); // drh5: isn't this an error? do you lose the initial request? 2096145Snate@binkert.org } 2106285Snate@binkert.org m_writeRequestTable.allocate(line_addr); 2116285Snate@binkert.org m_writeRequestTable.lookup(line_addr) = request; 2126145Snate@binkert.org m_outstanding_count++; 2136145Snate@binkert.org } else { 2146285Snate@binkert.org if (m_readRequestTable.exist(line_addr)) { 2156285Snate@binkert.org m_readRequestTable.lookup(line_addr) = request; 2166285Snate@binkert.org // return true; 2176285Snate@binkert.org assert(0); // drh5: isn't this an error? do you lose the initial request? 2186145Snate@binkert.org } 2196285Snate@binkert.org m_readRequestTable.allocate(line_addr); 2206285Snate@binkert.org m_readRequestTable.lookup(line_addr) = request; 2216145Snate@binkert.org m_outstanding_count++; 2226145Snate@binkert.org } 2236145Snate@binkert.org 2246145Snate@binkert.org g_system_ptr->getProfiler()->sequencerRequests(m_outstanding_count); 2256145Snate@binkert.org 2266285Snate@binkert.org total_outstanding = m_writeRequestTable.size() + m_readRequestTable.size(); 2276285Snate@binkert.org assert(m_outstanding_count == total_outstanding); 2286145Snate@binkert.org 2296145Snate@binkert.org return false; 2306145Snate@binkert.org} 2316145Snate@binkert.org 2326285Snate@binkert.orgvoid Sequencer::removeRequest(SequencerRequest* srequest) { 2336145Snate@binkert.org 2346285Snate@binkert.org assert(m_outstanding_count == m_writeRequestTable.size() + m_readRequestTable.size()); 2356285Snate@binkert.org 2366285Snate@binkert.org const RubyRequest & ruby_request = srequest->ruby_request; 2376285Snate@binkert.org Address line_addr(ruby_request.paddr); 2386285Snate@binkert.org line_addr.makeLineAddress(); 2396285Snate@binkert.org if ((ruby_request.type == RubyRequestType_ST) || 2406285Snate@binkert.org (ruby_request.type == RubyRequestType_RMW)) { 2416285Snate@binkert.org m_writeRequestTable.deallocate(line_addr); 2426145Snate@binkert.org } else { 2436285Snate@binkert.org m_readRequestTable.deallocate(line_addr); 2446145Snate@binkert.org } 2456145Snate@binkert.org m_outstanding_count--; 2466145Snate@binkert.org 2476285Snate@binkert.org assert(m_outstanding_count == m_writeRequestTable.size() + m_readRequestTable.size()); 2486145Snate@binkert.org} 2496145Snate@binkert.org 2506145Snate@binkert.orgvoid Sequencer::writeCallback(const Address& address, DataBlock& data) { 2516145Snate@binkert.org 2526145Snate@binkert.org assert(address == line_address(address)); 2536285Snate@binkert.org assert(m_writeRequestTable.exist(line_address(address))); 2546145Snate@binkert.org 2556285Snate@binkert.org SequencerRequest* request = m_writeRequestTable.lookup(address); 2566145Snate@binkert.org removeRequest(request); 2576145Snate@binkert.org 2586285Snate@binkert.org assert((request->ruby_request.type == RubyRequestType_ST) || 2596285Snate@binkert.org (request->ruby_request.type == RubyRequestType_RMW)); 2606145Snate@binkert.org 2616285Snate@binkert.org hitCallback(request, data); 2626145Snate@binkert.org} 2636145Snate@binkert.org 2646145Snate@binkert.orgvoid Sequencer::readCallback(const Address& address, DataBlock& data) { 2656145Snate@binkert.org 2666285Snate@binkert.org assert(address == line_address(address)); 2676285Snate@binkert.org assert(m_readRequestTable.exist(line_address(address))); 2686145Snate@binkert.org 2696285Snate@binkert.org SequencerRequest* request = m_readRequestTable.lookup(address); 2706285Snate@binkert.org removeRequest(request); 2716285Snate@binkert.org 2726285Snate@binkert.org assert((request->ruby_request.type == RubyRequestType_LD) || 2736285Snate@binkert.org (request->ruby_request.type == RubyRequestType_IFETCH)); 2746285Snate@binkert.org 2756285Snate@binkert.org hitCallback(request, data); 2766145Snate@binkert.org} 2776145Snate@binkert.org 2786285Snate@binkert.orgvoid Sequencer::hitCallback(SequencerRequest* srequest, DataBlock& data) { 2796285Snate@binkert.org const RubyRequest & ruby_request = srequest->ruby_request; 2806285Snate@binkert.org int size = ruby_request.len; 2816285Snate@binkert.org Address request_address(ruby_request.paddr); 2826285Snate@binkert.org Address request_line_address(ruby_request.paddr); 2836285Snate@binkert.org request_line_address.makeLineAddress(); 2846285Snate@binkert.org RubyRequestType type = ruby_request.type; 2856285Snate@binkert.org Time issued_time = srequest->issue_time; 2866145Snate@binkert.org 2876145Snate@binkert.org // Set this cache entry to the most recently used 2886285Snate@binkert.org if (type == RubyRequestType_IFETCH) { 2896285Snate@binkert.org if (m_instCache_ptr->isTagPresent(request_line_address) ) 2906285Snate@binkert.org m_instCache_ptr->setMRU(request_line_address); 2916145Snate@binkert.org } else { 2926285Snate@binkert.org if (m_dataCache_ptr->isTagPresent(request_line_address) ) 2936285Snate@binkert.org m_dataCache_ptr->setMRU(request_line_address); 2946145Snate@binkert.org } 2956145Snate@binkert.org 2966145Snate@binkert.org assert(g_eventQueue_ptr->getTime() >= issued_time); 2976145Snate@binkert.org Time miss_latency = g_eventQueue_ptr->getTime() - issued_time; 2986145Snate@binkert.org 2996285Snate@binkert.org // Profile the miss latency for all non-zero demand misses 3006285Snate@binkert.org if (miss_latency != 0) { 3016285Snate@binkert.org g_system_ptr->getProfiler()->missLatency(miss_latency, type); 3026285Snate@binkert.org 3036285Snate@binkert.org if (Debug::getProtocolTrace()) { 3046285Snate@binkert.org g_system_ptr->getProfiler()->profileTransition("Seq", m_version, Address(ruby_request.paddr), 3056285Snate@binkert.org "", "Done", "", int_to_string(miss_latency)+" cycles"); 3066285Snate@binkert.org } 3076285Snate@binkert.org } 3086285Snate@binkert.org /* 3096285Snate@binkert.org if (request.getPrefetch() == PrefetchBit_Yes) { 3106285Snate@binkert.org return; // Ignore the prefetch 3116285Snate@binkert.org } 3126285Snate@binkert.org */ 3136285Snate@binkert.org 3146285Snate@binkert.org // update the data 3156285Snate@binkert.org if (ruby_request.data != NULL) { 3166285Snate@binkert.org if ((type == RubyRequestType_LD) || 3176285Snate@binkert.org (type == RubyRequestType_IFETCH)) { 3186285Snate@binkert.org memcpy(ruby_request.data, data.getData(request_address.getOffset(), ruby_request.len), ruby_request.len); 3196285Snate@binkert.org } else { 3206285Snate@binkert.org data.setData(ruby_request.data, request_address.getOffset(), ruby_request.len); 3216285Snate@binkert.org } 3226145Snate@binkert.org } 3236145Snate@binkert.org 3246285Snate@binkert.org m_hit_callback(srequest->id); 3256285Snate@binkert.org delete srequest; 3266285Snate@binkert.org} 3276285Snate@binkert.org 3286285Snate@binkert.org// Returns true if the sequencer already has a load or store outstanding 3296285Snate@binkert.orgbool Sequencer::isReady(const RubyRequest& request) const { 3306285Snate@binkert.org // POLINA: check if we are currently flushing the write buffer, if so Ruby is returned as not ready 3316285Snate@binkert.org // to simulate stalling of the front-end 3326285Snate@binkert.org // Do we stall all the sequencers? If it is atomic instruction - yes! 3336285Snate@binkert.org if (m_outstanding_count >= m_max_outstanding_requests) { 3346285Snate@binkert.org return false; 3356145Snate@binkert.org } 3366145Snate@binkert.org 3376285Snate@binkert.org if( m_writeRequestTable.exist(line_address(Address(request.paddr))) || 3386285Snate@binkert.org m_readRequestTable.exist(line_address(Address(request.paddr))) ){ 3396285Snate@binkert.org //cout << "OUTSTANDING REQUEST EXISTS " << p << " VER " << m_version << endl; 3406145Snate@binkert.org //printProgress(cout); 3416145Snate@binkert.org return false; 3426145Snate@binkert.org } 3436145Snate@binkert.org 3446145Snate@binkert.org return true; 3456145Snate@binkert.org} 3466145Snate@binkert.org 3476285Snate@binkert.orgbool Sequencer::empty() const { 3486285Snate@binkert.org return (m_writeRequestTable.size() == 0) && (m_readRequestTable.size() == 0); 3496145Snate@binkert.org} 3506145Snate@binkert.org 3516285Snate@binkert.orgint64_t Sequencer::makeRequest(const RubyRequest & request) 3526285Snate@binkert.org{ 3536285Snate@binkert.org assert(Address(request.paddr).getOffset() + request.len <= RubySystem::getBlockSizeBytes()); 3546285Snate@binkert.org if (isReady(request)) { 3556285Snate@binkert.org int64_t id = makeUniqueRequestID(); 3566285Snate@binkert.org SequencerRequest *srequest = new SequencerRequest(request, id, g_eventQueue_ptr->getTime()); 3576285Snate@binkert.org bool found = insertRequest(srequest); 3586285Snate@binkert.org if (!found) 3596285Snate@binkert.org issueRequest(request); 3606145Snate@binkert.org 3616285Snate@binkert.org // TODO: issue hardware prefetches here 3626285Snate@binkert.org return id; 3636145Snate@binkert.org } 3646285Snate@binkert.org else { 3656285Snate@binkert.org return -1; 3666145Snate@binkert.org } 3676145Snate@binkert.org} 3686145Snate@binkert.org 3696285Snate@binkert.orgvoid Sequencer::issueRequest(const RubyRequest& request) { 3706285Snate@binkert.org 3716285Snate@binkert.org // TODO: get rid of CacheMsg, CacheRequestType, and AccessModeTYpe, & have SLICC use RubyRequest and subtypes natively 3726285Snate@binkert.org CacheRequestType ctype; 3736285Snate@binkert.org switch(request.type) { 3746285Snate@binkert.org case RubyRequestType_IFETCH: 3756285Snate@binkert.org ctype = CacheRequestType_IFETCH; 3766285Snate@binkert.org break; 3776285Snate@binkert.org case RubyRequestType_LD: 3786285Snate@binkert.org ctype = CacheRequestType_LD; 3796285Snate@binkert.org break; 3806285Snate@binkert.org case RubyRequestType_ST: 3816285Snate@binkert.org ctype = CacheRequestType_ST; 3826285Snate@binkert.org break; 3836285Snate@binkert.org case RubyRequestType_RMW: 3846285Snate@binkert.org ctype = CacheRequestType_ATOMIC; 3856285Snate@binkert.org break; 3866285Snate@binkert.org default: 3876285Snate@binkert.org assert(0); 3886145Snate@binkert.org } 3896285Snate@binkert.org AccessModeType amtype; 3906285Snate@binkert.org switch(request.access_mode){ 3916285Snate@binkert.org case RubyAccessMode_User: 3926285Snate@binkert.org amtype = AccessModeType_UserMode; 3936285Snate@binkert.org break; 3946285Snate@binkert.org case RubyAccessMode_Supervisor: 3956285Snate@binkert.org amtype = AccessModeType_SupervisorMode; 3966285Snate@binkert.org break; 3976285Snate@binkert.org case RubyAccessMode_Device: 3986285Snate@binkert.org amtype = AccessModeType_UserMode; 3996285Snate@binkert.org break; 4006285Snate@binkert.org default: 4016285Snate@binkert.org assert(0); 4026285Snate@binkert.org } 4036285Snate@binkert.org Address line_addr(request.paddr); 4046285Snate@binkert.org line_addr.makeLineAddress(); 4056285Snate@binkert.org CacheMsg msg(line_addr, Address(request.paddr), ctype, Address(request.pc), amtype, request.len, PrefetchBit_No); 4066285Snate@binkert.org 4076285Snate@binkert.org if (Debug::getProtocolTrace()) { 4086285Snate@binkert.org g_system_ptr->getProfiler()->profileTransition("Seq", m_version, Address(request.paddr), 4096285Snate@binkert.org "", "Begin", "", RubyRequestType_to_string(request.type)); 4106285Snate@binkert.org } 4116285Snate@binkert.org 4126285Snate@binkert.org if (g_system_ptr->getTracer()->traceEnabled()) { 4136285Snate@binkert.org g_system_ptr->getTracer()->traceRequest(m_name, line_addr, Address(request.pc), 4146285Snate@binkert.org request.type, g_eventQueue_ptr->getTime()); 4156285Snate@binkert.org } 4166285Snate@binkert.org 4176285Snate@binkert.org Time latency = 0; // initialzed to an null value 4186285Snate@binkert.org 4196285Snate@binkert.org if (request.type == RubyRequestType_IFETCH) 4206285Snate@binkert.org latency = m_instCache_ptr->getLatency(); 4216285Snate@binkert.org else 4226285Snate@binkert.org latency = m_dataCache_ptr->getLatency(); 4236285Snate@binkert.org 4246285Snate@binkert.org // Send the message to the cache controller 4256285Snate@binkert.org assert(latency > 0); 4266285Snate@binkert.org 4276285Snate@binkert.org 4286285Snate@binkert.org m_mandatory_q_ptr->enqueue(msg, latency); 4296285Snate@binkert.org} 4306285Snate@binkert.org/* 4316285Snate@binkert.orgbool Sequencer::tryCacheAccess(const Address& addr, CacheRequestType type, 4326285Snate@binkert.org AccessModeType access_mode, 4336285Snate@binkert.org int size, DataBlock*& data_ptr) { 4346285Snate@binkert.org if (type == CacheRequestType_IFETCH) { 4356285Snate@binkert.org return m_instCache_ptr->tryCacheAccess(line_address(addr), type, data_ptr); 4366285Snate@binkert.org } else { 4376285Snate@binkert.org return m_dataCache_ptr->tryCacheAccess(line_address(addr), type, data_ptr); 4386145Snate@binkert.org } 4396145Snate@binkert.org} 4406285Snate@binkert.org*/ 4416145Snate@binkert.org 4426145Snate@binkert.orgvoid Sequencer::print(ostream& out) const { 4436285Snate@binkert.org out << "[Sequencer: " << m_version 4446145Snate@binkert.org << ", outstanding requests: " << m_outstanding_count; 4456145Snate@binkert.org 4466285Snate@binkert.org out << ", read request table: " << m_readRequestTable 4476285Snate@binkert.org << ", write request table: " << m_writeRequestTable; 4486145Snate@binkert.org out << "]"; 4496145Snate@binkert.org} 4506145Snate@binkert.org 4516145Snate@binkert.org// this can be called from setState whenever coherence permissions are upgraded 4526145Snate@binkert.org// when invoked, coherence violations will be checked for the given block 4536145Snate@binkert.orgvoid Sequencer::checkCoherence(const Address& addr) { 4546145Snate@binkert.org#ifdef CHECK_COHERENCE 4556145Snate@binkert.org g_system_ptr->checkGlobalCoherenceInvariant(addr); 4566145Snate@binkert.org#endif 4576145Snate@binkert.org} 4586145Snate@binkert.org 4596285Snate@binkert.org/* 4606145Snate@binkert.orgbool Sequencer::getRubyMemoryValue(const Address& addr, char* value, 4616285Snate@binkert.org unsigned int size_in_bytes ) 4626285Snate@binkert.org{ 4636285Snate@binkert.org bool found = false; 4646285Snate@binkert.org const Address lineAddr = line_address(addr); 4656285Snate@binkert.org DataBlock data; 4666285Snate@binkert.org PhysAddress paddr(addr); 4676285Snate@binkert.org DataBlock* dataPtr = &data; 4686285Snate@binkert.org 4696285Snate@binkert.org MachineID l2_mach = map_L2ChipId_to_L2Cache(addr, m_chip_ptr->getID() ); 4706285Snate@binkert.org int l2_ver = l2_mach.num%RubyConfig::numberOfL2CachePerChip(); 4716285Snate@binkert.org 4726285Snate@binkert.org if (Protocol::m_TwoLevelCache) { 4736285Snate@binkert.org if(Protocol::m_CMP){ 4746285Snate@binkert.org assert(n->m_L2Cache_L2cacheMemory_vec[l2_ver] != NULL); 4756285Snate@binkert.org } 4766285Snate@binkert.org else{ 4776285Snate@binkert.org assert(n->m_L1Cache_cacheMemory_vec[m_version] != NULL); 4786285Snate@binkert.org } 4796285Snate@binkert.org } 4806285Snate@binkert.org 4816285Snate@binkert.org if (n->m_L1Cache_L1IcacheMemory_vec[m_version]->tryCacheAccess(lineAddr, CacheRequestType_IFETCH, dataPtr)){ 4826285Snate@binkert.org n->m_L1Cache_L1IcacheMemory_vec[m_version]->getMemoryValue(addr, value, size_in_bytes); 4836285Snate@binkert.org found = true; 4846285Snate@binkert.org } else if (n->m_L1Cache_L1DcacheMemory_vec[m_version]->tryCacheAccess(lineAddr, CacheRequestType_LD, dataPtr)){ 4856285Snate@binkert.org n->m_L1Cache_L1DcacheMemory_vec[m_version]->getMemoryValue(addr, value, size_in_bytes); 4866285Snate@binkert.org found = true; 4876285Snate@binkert.org } else if (Protocol::m_CMP && n->m_L2Cache_L2cacheMemory_vec[l2_ver]->tryCacheAccess(lineAddr, CacheRequestType_LD, dataPtr)){ 4886285Snate@binkert.org n->m_L2Cache_L2cacheMemory_vec[l2_ver]->getMemoryValue(addr, value, size_in_bytes); 4896285Snate@binkert.org found = true; 4906285Snate@binkert.org // } else if (n->TBE_TABLE_MEMBER_VARIABLE->isPresent(lineAddr)){ 4916285Snate@binkert.org// ASSERT(n->TBE_TABLE_MEMBER_VARIABLE->isPresent(lineAddr)); 4926285Snate@binkert.org// L1Cache_TBE tbeEntry = n->TBE_TABLE_MEMBER_VARIABLE->lookup(lineAddr); 4936285Snate@binkert.org 4946285Snate@binkert.org// int offset = addr.getOffset(); 4956285Snate@binkert.org// for(int i=0; i<size_in_bytes; ++i){ 4966285Snate@binkert.org// value[i] = tbeEntry.getDataBlk().getByte(offset + i); 4976285Snate@binkert.org// } 4986285Snate@binkert.org 4996285Snate@binkert.org// found = true; 5006285Snate@binkert.org } else { 5016285Snate@binkert.org // Address not found 5026285Snate@binkert.org //cout << " " << m_chip_ptr->getID() << " NOT IN CACHE, Value at Directory is: " << (int) value[0] << endl; 5036285Snate@binkert.org n = dynamic_cast<Chip*>(g_system_ptr->getChip(map_Address_to_DirectoryNode(addr)/RubyConfig::numberOfDirectoryPerChip())); 5046285Snate@binkert.org int dir_version = map_Address_to_DirectoryNode(addr)%RubyConfig::numberOfDirectoryPerChip(); 5056285Snate@binkert.org for(unsigned int i=0; i<size_in_bytes; ++i){ 5066285Snate@binkert.org int offset = addr.getOffset(); 5076285Snate@binkert.org value[i] = n->m_Directory_directory_vec[dir_version]->lookup(lineAddr).m_DataBlk.getByte(offset + i); 5086285Snate@binkert.org } 5096285Snate@binkert.org // Address not found 5106285Snate@binkert.org //WARN_MSG("Couldn't find address"); 5116285Snate@binkert.org //WARN_EXPR(addr); 5126285Snate@binkert.org found = false; 5136285Snate@binkert.org } 5146285Snate@binkert.org return true; 5156145Snate@binkert.org} 5166145Snate@binkert.org 5176145Snate@binkert.orgbool Sequencer::setRubyMemoryValue(const Address& addr, char *value, 5186145Snate@binkert.org unsigned int size_in_bytes) { 5196145Snate@binkert.org char test_buffer[64]; 5206145Snate@binkert.org 5216285Snate@binkert.org // idea here is that coherent cache should find the 5226285Snate@binkert.org // latest data, the update it 5236285Snate@binkert.org bool found = false; 5246285Snate@binkert.org const Address lineAddr = line_address(addr); 5256285Snate@binkert.org PhysAddress paddr(addr); 5266285Snate@binkert.org DataBlock data; 5276285Snate@binkert.org DataBlock* dataPtr = &data; 5286285Snate@binkert.org Chip* n = dynamic_cast<Chip*>(m_chip_ptr); 5296285Snate@binkert.org 5306285Snate@binkert.org MachineID l2_mach = map_L2ChipId_to_L2Cache(addr, m_chip_ptr->getID() ); 5316285Snate@binkert.org int l2_ver = l2_mach.num%RubyConfig::numberOfL2CachePerChip(); 5326285Snate@binkert.org 5336285Snate@binkert.org assert(n->m_L1Cache_L1IcacheMemory_vec[m_version] != NULL); 5346285Snate@binkert.org assert(n->m_L1Cache_L1DcacheMemory_vec[m_version] != NULL); 5356285Snate@binkert.org if (Protocol::m_TwoLevelCache) { 5366285Snate@binkert.org if(Protocol::m_CMP){ 5376285Snate@binkert.org assert(n->m_L2Cache_L2cacheMemory_vec[l2_ver] != NULL); 5386285Snate@binkert.org } 5396285Snate@binkert.org else{ 5406285Snate@binkert.org assert(n->m_L1Cache_cacheMemory_vec[m_version] != NULL); 5416285Snate@binkert.org } 5426285Snate@binkert.org } 5436285Snate@binkert.org 5446285Snate@binkert.org if (n->m_L1Cache_L1IcacheMemory_vec[m_version]->tryCacheAccess(lineAddr, CacheRequestType_IFETCH, dataPtr)){ 5456285Snate@binkert.org n->m_L1Cache_L1IcacheMemory_vec[m_version]->setMemoryValue(addr, value, size_in_bytes); 5466285Snate@binkert.org found = true; 5476285Snate@binkert.org } else if (n->m_L1Cache_L1DcacheMemory_vec[m_version]->tryCacheAccess(lineAddr, CacheRequestType_LD, dataPtr)){ 5486285Snate@binkert.org n->m_L1Cache_L1DcacheMemory_vec[m_version]->setMemoryValue(addr, value, size_in_bytes); 5496285Snate@binkert.org found = true; 5506285Snate@binkert.org } else if (Protocol::m_CMP && n->m_L2Cache_L2cacheMemory_vec[l2_ver]->tryCacheAccess(lineAddr, CacheRequestType_LD, dataPtr)){ 5516285Snate@binkert.org n->m_L2Cache_L2cacheMemory_vec[l2_ver]->setMemoryValue(addr, value, size_in_bytes); 5526285Snate@binkert.org found = true; 5536285Snate@binkert.org } else { 5546285Snate@binkert.org // Address not found 5556285Snate@binkert.org n = dynamic_cast<Chip*>(g_system_ptr->getChip(map_Address_to_DirectoryNode(addr)/RubyConfig::numberOfDirectoryPerChip())); 5566285Snate@binkert.org int dir_version = map_Address_to_DirectoryNode(addr)%RubyConfig::numberOfDirectoryPerChip(); 5576285Snate@binkert.org for(unsigned int i=0; i<size_in_bytes; ++i){ 5586285Snate@binkert.org int offset = addr.getOffset(); 5596285Snate@binkert.org n->m_Directory_directory_vec[dir_version]->lookup(lineAddr).m_DataBlk.setByte(offset + i, value[i]); 5606285Snate@binkert.org } 5616285Snate@binkert.org found = false; 5626285Snate@binkert.org } 5636285Snate@binkert.org 5646285Snate@binkert.org if (found){ 5656285Snate@binkert.org found = getRubyMemoryValue(addr, test_buffer, size_in_bytes); 5666285Snate@binkert.org assert(found); 5676285Snate@binkert.org if(value[0] != test_buffer[0]){ 5686285Snate@binkert.org WARN_EXPR((int) value[0]); 5696285Snate@binkert.org WARN_EXPR((int) test_buffer[0]); 5706285Snate@binkert.org ERROR_MSG("setRubyMemoryValue failed to set value."); 5716285Snate@binkert.org } 5726285Snate@binkert.org } 5736285Snate@binkert.org 5746285Snate@binkert.org return true; 5756285Snate@binkert.org} 5766285Snate@binkert.org*/ 5776285Snate@binkert.org/* 5786285Snate@binkert.org 5796285Snate@binkert.orgvoid 5806285Snate@binkert.orgSequencer::rubyMemAccess(const uint64 paddr, char* data, const int len, const AccessType type) 5816285Snate@binkert.org{ 5826285Snate@binkert.org if ( type == AccessType_Read || type == AccessType_Write ) { 5836285Snate@binkert.org // need to break up the packet data 5846285Snate@binkert.org uint64 guest_ptr = paddr; 5856285Snate@binkert.org Vector<DataBlock*> datablocks; 5866285Snate@binkert.org while (paddr + len != guest_ptr) { 5876285Snate@binkert.org Address addr(guest_ptr); 5886285Snate@binkert.org Address line_addr = line_address(addr); 5896285Snate@binkert.org 5906285Snate@binkert.org int bytes_copied; 5916285Snate@binkert.org if (addr.getOffset() == 0) { 5926285Snate@binkert.org bytes_copied = (guest_ptr + RubyConfig::dataBlockBytes() > paddr + len)? 5936285Snate@binkert.org (paddr + len - guest_ptr): 5946285Snate@binkert.org RubyConfig::dataBlockBytes(); 5956285Snate@binkert.org } else { 5966285Snate@binkert.org bytes_copied = RubyConfig::dataBlockBytes() - addr.getOffset(); 5976285Snate@binkert.org if (guest_ptr + bytes_copied > paddr + len) 5986285Snate@binkert.org bytes_copied = paddr + len - guest_ptr; 5996285Snate@binkert.org } 6006285Snate@binkert.org 6016285Snate@binkert.org // first we need to find all data blocks that have to be updated for a write 6026285Snate@binkert.org // and the highest block for a read 6036285Snate@binkert.org for(int i=0;i<RubyConfig::numberOfProcessors();i++) { 6046285Snate@binkert.org if (Protocol::m_TwoLevelCache){ 6056285Snate@binkert.org if(m_chip_ptr->m_L1Cache_L1IcacheMemory_vec[i]->isTagPresent(line_address(addr))) 6066285Snate@binkert.org datablocks.insertAtBottom(&m_chip_ptr->m_L1Cache_L1IcacheMemory_vec[i]->lookup(line_addr).getDataBlk()); 6076285Snate@binkert.org if(m_chip_ptr->m_L1Cache_L1DcacheMemory_vec[i]->isTagPresent(line_address(addr))) 6086285Snate@binkert.org datablocks.insertAtBottom(&m_chip_ptr->m_L1Cache_L1DcacheMemory_vec[i]->lookup(line_addr).getDataBlk()); 6096285Snate@binkert.org } else { 6106285Snate@binkert.org if(m_chip_ptr->m_L1Cache_cacheMemory_vec[i]->isTagPresent(line_address(addr))) 6116285Snate@binkert.org datablocks.insertAtBottom(&m_chip_ptr->m_L1Cache_cacheMemory_vec[i]->lookup(line_addr).getDataBlk()); 6126285Snate@binkert.org } 6136285Snate@binkert.org } 6146285Snate@binkert.org if (Protocol::m_TwoLevelCache){ 6156285Snate@binkert.org int l2_bank = map_L2ChipId_to_L2Cache(addr, 0).num; // TODO: ONLY WORKS WITH CMP!!! 6166285Snate@binkert.org if (m_chip_ptr->m_L2Cache_L2cacheMemory_vec[l2_bank]->isTagPresent(line_address(Address(paddr)))) { 6176285Snate@binkert.org datablocks.insertAtBottom(&m_chip_ptr->m_L2Cache_L2cacheMemory_vec[l2_bank]->lookup(addr).getDataBlk()); 6186285Snate@binkert.org } 6196285Snate@binkert.org } 6206285Snate@binkert.org assert(dynamic_cast<Chip*>(m_chip_ptr)->m_Directory_directory_vec.size() > map_Address_to_DirectoryNode(addr)); 6216285Snate@binkert.org DirectoryMemory* dir = dynamic_cast<Chip*>(m_chip_ptr)->m_Directory_directory_vec[map_Address_to_DirectoryNode(addr)]; 6226285Snate@binkert.org Directory_Entry& entry = dir->lookup(line_addr); 6236285Snate@binkert.org datablocks.insertAtBottom(&entry.getDataBlk()); 6246285Snate@binkert.org 6256285Snate@binkert.org if (pkt->isRead()){ 6266285Snate@binkert.org datablocks[0]->copyData(pkt_data, addr.getOffset(), bytes_copied); 6276285Snate@binkert.org } else {// pkt->isWrite() { 6286285Snate@binkert.org for (int i=0;i<datablocks.size();i++) 6296285Snate@binkert.org datablocks[i]->setData(pkt_data, addr.getOffset(), bytes_copied); 6306285Snate@binkert.org } 6316285Snate@binkert.org 6326285Snate@binkert.org guest_ptr += bytes_copied; 6336285Snate@binkert.org pkt_data += bytes_copied; 6346285Snate@binkert.org datablocks.clear(); 6356285Snate@binkert.org } 6366145Snate@binkert.org} 6376153Sgibson@cs.wisc.edu 6386285Snate@binkert.org*/ 639