RubyPort.cc revision 8706
11689SN/A/* 22325SN/A * Copyright (c) 2009 Advanced Micro Devices, Inc. 31689SN/A * All rights reserved. 41689SN/A * 51689SN/A * Redistribution and use in source and binary forms, with or without 61689SN/A * modification, are permitted provided that the following conditions are 71689SN/A * met: redistributions of source code must retain the above copyright 81689SN/A * notice, this list of conditions and the following disclaimer; 91689SN/A * redistributions in binary form must reproduce the above copyright 101689SN/A * notice, this list of conditions and the following disclaimer in the 111689SN/A * documentation and/or other materials provided with the distribution; 121689SN/A * neither the name of the copyright holders nor the names of its 131689SN/A * contributors may be used to endorse or promote products derived from 141689SN/A * this software without specific prior written permission. 151689SN/A * 161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu */ 282665Ssaidi@eecs.umich.edu 292756Sksewell@umich.edu#include "cpu/testers/rubytest/RubyTester.hh" 301689SN/A#include "debug/Config.hh" 311689SN/A#include "debug/Ruby.hh" 321858SN/A#include "mem/protocol/AccessPermission.hh" 332733Sktlim@umich.edu#include "mem/ruby/slicc_interface/AbstractController.hh" 341858SN/A#include "mem/ruby/system/RubyPort.hh" 351858SN/A 362356SN/ARubyPort::RubyPort(const Params *p) 371060SN/A : MemObject(p) 381060SN/A{ 391060SN/A m_version = p->version; 401060SN/A assert(m_version != -1); 411060SN/A 422325SN/A physmem = p->physmem; 432683Sktlim@umich.edu 442680Sktlim@umich.edu m_controller = NULL; 452817Sksewell@umich.edu m_mandatory_q_ptr = NULL; 461717SN/A 471060SN/A m_request_cnt = 0; 484167Sbinkertn@umich.edu pio_port = NULL; 492292SN/A physMemPort = NULL; 502292SN/A 512794Sktlim@umich.edu m_usingRubyTester = p->using_ruby_tester; 522794Sktlim@umich.edu access_phys_mem = p->access_phys_mem; 532794Sktlim@umich.edu 542794Sktlim@umich.edu drainEvent = NULL; 551060SN/A 562669Sktlim@umich.edu ruby_system = p->ruby_system; 571060SN/A waitingOnSequencer = false; 582733Sktlim@umich.edu} 592292SN/A 601060SN/Avoid 611060SN/ARubyPort::init() 621060SN/A{ 632292SN/A assert(m_controller != NULL); 642733Sktlim@umich.edu m_mandatory_q_ptr = m_controller->getMandatoryQueue(); 652292SN/A} 662292SN/A 672292SN/APort * 682292SN/ARubyPort::getPort(const std::string &if_name, int idx) 691060SN/A{ 701755SN/A if (if_name == "port") { 711060SN/A M5Port* cpuPort = new M5Port(csprintf("%s-port%d", name(), idx), 721060SN/A this, ruby_system, access_phys_mem); 731060SN/A cpu_ports.push_back(cpuPort); 741060SN/A return cpuPort; 751060SN/A } 761060SN/A 771755SN/A if (if_name == "pio_port") { 781060SN/A // ensure there is only one pio port 791060SN/A assert(pio_port == NULL); 801060SN/A 811060SN/A pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx), this); 821060SN/A 831060SN/A return pio_port; 841755SN/A } 851060SN/A 864873Sstever@eecs.umich.edu if (if_name == "physMemPort") { 871060SN/A // RubyPort should only have one port to physical memory 881060SN/A assert (physMemPort == NULL); 891060SN/A 902829Sksewell@umich.edu physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this, 913221Sktlim@umich.edu ruby_system, access_phys_mem); 922829Sksewell@umich.edu 932829Sksewell@umich.edu return physMemPort; 942829Sksewell@umich.edu } 952829Sksewell@umich.edu 962829Sksewell@umich.edu if (if_name == "functional") { 972829Sksewell@umich.edu // Calls for the functional port only want to access 982829Sksewell@umich.edu // functional memory. Therefore, directly pass these calls 992829Sksewell@umich.edu // ports to physmem. 1002829Sksewell@umich.edu assert(physmem != NULL); 1012829Sksewell@umich.edu return physmem->getPort(if_name, idx); 1022829Sksewell@umich.edu } 1032829Sksewell@umich.edu 1042829Sksewell@umich.edu return NULL; 1052829Sksewell@umich.edu} 1062829Sksewell@umich.edu 1072829Sksewell@umich.eduRubyPort::PioPort::PioPort(const std::string &_name, 1082829Sksewell@umich.edu RubyPort *_port) 1092829Sksewell@umich.edu : SimpleTimingPort(_name, _port) 1102829Sksewell@umich.edu{ 1112829Sksewell@umich.edu DPRINTF(RubyPort, "creating port to ruby sequencer to cpu %s\n", _name); 1122829Sksewell@umich.edu ruby_port = _port; 1132829Sksewell@umich.edu} 1142829Sksewell@umich.edu 1154873Sstever@eecs.umich.eduRubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port, 1162829Sksewell@umich.edu RubySystem *_system, bool _access_phys_mem) 1172829Sksewell@umich.edu : SimpleTimingPort(_name, _port) 1182829Sksewell@umich.edu{ 1192875Sksewell@umich.edu DPRINTF(RubyPort, "creating port from ruby sequcner to cpu %s\n", _name); 1203859Sbinkertn@umich.edu ruby_port = _port; 1212875Sksewell@umich.edu ruby_system = _system; 1222875Sksewell@umich.edu _onRetryList = false; 1232875Sksewell@umich.edu access_phys_mem = _access_phys_mem; 1242875Sksewell@umich.edu} 1252875Sksewell@umich.edu 1262875Sksewell@umich.eduTick 1273859Sbinkertn@umich.eduRubyPort::PioPort::recvAtomic(PacketPtr pkt) 1282875Sksewell@umich.edu{ 1292875Sksewell@umich.edu panic("RubyPort::PioPort::recvAtomic() not implemented!\n"); 1302875Sksewell@umich.edu return 0; 1313859Sbinkertn@umich.edu} 1322875Sksewell@umich.edu 1332875Sksewell@umich.eduTick 1342875Sksewell@umich.eduRubyPort::M5Port::recvAtomic(PacketPtr pkt) 1352875Sksewell@umich.edu{ 1362875Sksewell@umich.edu panic("RubyPort::M5Port::recvAtomic() not implemented!\n"); 1372875Sksewell@umich.edu return 0; 1382875Sksewell@umich.edu} 1393221Sktlim@umich.edu 1403221Sktlim@umich.edu 1412875Sksewell@umich.edubool 1422875Sksewell@umich.eduRubyPort::PioPort::recvTiming(PacketPtr pkt) 1432875Sksewell@umich.edu{ 1442875Sksewell@umich.edu // In FS mode, ruby memory will receive pio responses from devices 1452875Sksewell@umich.edu // and it must forward these responses back to the particular CPU. 1462875Sksewell@umich.edu DPRINTF(RubyPort, "Pio response for address %#x\n", pkt->getAddr()); 1474873Sstever@eecs.umich.edu 1482875Sksewell@umich.edu assert(pkt->isResponse()); 1492875Sksewell@umich.edu 1502875Sksewell@umich.edu // First we must retrieve the request port from the sender State 1514329Sktlim@umich.edu RubyPort::SenderState *senderState = 1522733Sktlim@umich.edu safe_cast<RubyPort::SenderState *>(pkt->senderState); 1533781Sgblack@eecs.umich.edu M5Port *port = senderState->port; 1543781Sgblack@eecs.umich.edu assert(port != NULL); 1553781Sgblack@eecs.umich.edu 1563781Sgblack@eecs.umich.edu // pop the sender state from the packet 1571060SN/A pkt->senderState = senderState->saved; 1582292SN/A delete senderState; 1594329Sktlim@umich.edu 1604329Sktlim@umich.edu port->sendTiming(pkt); 1614329Sktlim@umich.edu 1624329Sktlim@umich.edu return true; 1634329Sktlim@umich.edu} 1641060SN/A 1654329Sktlim@umich.edubool 1664329Sktlim@umich.eduRubyPort::M5Port::recvTiming(PacketPtr pkt) 1671060SN/A{ 1682831Sksewell@umich.edu DPRINTF(RubyPort, 1692292SN/A "Timing access caught for address %#x\n", pkt->getAddr()); 1702292SN/A 1711060SN/A //dsm: based on SimpleTimingPort::recvTiming(pkt); 1724329Sktlim@umich.edu 1734329Sktlim@umich.edu // The received packets should only be M5 requests, which should never 1742292SN/A // get nacked. There used to be code to hanldle nacks here, but 1752292SN/A // I'm pretty sure it didn't work correctly with the drain code, 1761060SN/A // so that would need to be fixed if we ever added it back. 1772831Sksewell@umich.edu assert(pkt->isRequest()); 1782292SN/A 1792292SN/A if (pkt->memInhibitAsserted()) { 1802292SN/A warn("memInhibitAsserted???"); 1812292SN/A // snooper will supply based on copy of packet 1821060SN/A // still target's responsibility to delete packet 1832873Sktlim@umich.edu delete pkt; 1842873Sktlim@umich.edu return true; 1852873Sktlim@umich.edu } 1862873Sktlim@umich.edu 1872873Sktlim@umich.edu // Save the port in the sender state object to be used later to 1882873Sktlim@umich.edu // route the response 1892873Sktlim@umich.edu pkt->senderState = new SenderState(this, pkt->senderState); 1902873Sktlim@umich.edu 1911060SN/A // Check for pio requests and directly send them to the dedicated 1921060SN/A // pio port. 1931858SN/A if (!isPhysMemAddress(pkt->getAddr())) { 1942292SN/A assert(ruby_port->pio_port != NULL); 1951060SN/A DPRINTF(RubyPort, 1961060SN/A "Request for address 0x%#x is assumed to be a pio request\n", 1972843Sktlim@umich.edu pkt->getAddr()); 1982316SN/A 1992316SN/A return ruby_port->pio_port->sendTiming(pkt); 2001060SN/A } 2013221Sktlim@umich.edu 2023221Sktlim@umich.edu assert(Address(pkt->getAddr()).getOffset() + pkt->getSize() <= 2033221Sktlim@umich.edu RubySystem::getBlockSizeBytes()); 2043221Sktlim@umich.edu 2053221Sktlim@umich.edu // Submit the ruby request 2061681SN/A RequestStatus requestStatus = ruby_port->makeRequest(pkt); 2074598Sbinkertn@umich.edu 2082794Sktlim@umich.edu // If the request successfully issued then we should return true. 2092316SN/A // Otherwise, we need to delete the senderStatus we just created and return 2102316SN/A // false. 2112316SN/A if (requestStatus == RequestStatus_Issued) { 2122316SN/A DPRINTF(RubyPort, "Request %#x issued\n", pkt->getAddr()); 2132316SN/A return true; 2144598Sbinkertn@umich.edu } 2154598Sbinkertn@umich.edu 2164598Sbinkertn@umich.edu // 2172794Sktlim@umich.edu // Unless one is using the ruby tester, record the stalled M5 port for 2182316SN/A // later retry when the sequencer becomes free. 2191858SN/A // 2202292SN/A if (!ruby_port->m_usingRubyTester) { 2212292SN/A ruby_port->addToRetryList(this); 2221681SN/A } 2231681SN/A 2242325SN/A DPRINTF(RubyPort, 2252325SN/A "Request for address %#x did not issue because %s\n", 2262325SN/A pkt->getAddr(), RequestStatus_to_string(requestStatus)); 2271060SN/A 2282292SN/A SenderState* senderState = safe_cast<SenderState*>(pkt->senderState); 2292292SN/A pkt->senderState = senderState->saved; 2302292SN/A delete senderState; 2312292SN/A return false; 2322292SN/A} 2332292SN/A 2341060SN/Abool 2351060SN/ARubyPort::M5Port::doFunctionalRead(PacketPtr pkt) 2361060SN/A{ 2371060SN/A Address address(pkt->getAddr()); 2381060SN/A Address line_address(address); 2391060SN/A line_address.makeLineAddress(); 2401060SN/A 2411060SN/A AccessPermission access_perm = AccessPermission_NotPresent; 2421060SN/A int num_controllers = ruby_system->m_abs_cntrl_vec.size(); 2431060SN/A 2441060SN/A DPRINTF(RubyPort, "Functional Read request for %s\n",address); 2452292SN/A 2461060SN/A unsigned int num_ro = 0; 2471060SN/A unsigned int num_rw = 0; 2481060SN/A unsigned int num_busy = 0; 2491060SN/A unsigned int num_backing_store = 0; 2501060SN/A unsigned int num_invalid = 0; 2511060SN/A 2521060SN/A // In this loop we count the number of controllers that have the given 2531060SN/A // address in read only, read write and busy states. 2542292SN/A for (int i = 0; i < num_controllers; ++i) { 2552292SN/A access_perm = ruby_system->m_abs_cntrl_vec[i]-> 2562292SN/A getAccessPermission(line_address); 2572292SN/A if (access_perm == AccessPermission_Read_Only) 2582292SN/A num_ro++; 2592307SN/A else if (access_perm == AccessPermission_Read_Write) 2602831Sksewell@umich.edu num_rw++; 2612831Sksewell@umich.edu else if (access_perm == AccessPermission_Busy) 2622831Sksewell@umich.edu num_busy++; 2632831Sksewell@umich.edu else if (access_perm == AccessPermission_Backing_Store) 2642831Sksewell@umich.edu // See RubySlicc_Exports.sm for details, but Backing_Store is meant 2652831Sksewell@umich.edu // to represent blocks in memory *for Broadcast/Snooping protocols*, 2662292SN/A // where memory has no idea whether it has an exclusive copy of data 2672307SN/A // or not. 2682292SN/A num_backing_store++; 2692292SN/A else if (access_perm == AccessPermission_Invalid || 2702316SN/A access_perm == AccessPermission_NotPresent) 2712292SN/A num_invalid++; 2722292SN/A } 2732292SN/A assert(num_rw <= 1); 2742292SN/A 2752292SN/A uint8* data = pkt->getPtr<uint8_t>(true); 2762292SN/A unsigned int size_in_bytes = pkt->getSize(); 2771060SN/A unsigned startByte = address.getAddress() - line_address.getAddress(); 2782292SN/A 2792292SN/A // This if case is meant to capture what happens in a Broadcast/Snoop 2801060SN/A // protocol where the block does not exist in the cache hierarchy. You 2812292SN/A // only want to read from the Backing_Store memory if there is no copy in 2822307SN/A // the cache hierarchy, otherwise you want to try to read the RO or RW 2832292SN/A // copies existing in the cache hierarchy (covered by the else statement). 2842292SN/A // The reason is because the Backing_Store memory could easily be stale, if 2852292SN/A // there are copies floating around the cache hierarchy, so you want to read 2862325SN/A // it only if it's not in the cache hierarchy at all. 2872292SN/A if (num_invalid == (num_controllers - 1) && 2882292SN/A num_backing_store == 1) 2892292SN/A { 2902325SN/A DPRINTF(RubyPort, "only copy in Backing_Store memory, read from it\n"); 2912292SN/A for (int i = 0; i < num_controllers; ++i) { 2922292SN/A access_perm = ruby_system->m_abs_cntrl_vec[i] 2932292SN/A ->getAccessPermission(line_address); 2942292SN/A if (access_perm == AccessPermission_Backing_Store) { 2952292SN/A DataBlock& block = ruby_system->m_abs_cntrl_vec[i] 2962292SN/A ->getDataBlock(line_address); 2972292SN/A 2982292SN/A DPRINTF(RubyPort, "reading from %s block %s\n", 2992292SN/A ruby_system->m_abs_cntrl_vec[i]->name(), block); 3002292SN/A for (unsigned i = 0; i < size_in_bytes; ++i) { 3012292SN/A data[i] = block.getByte(i + startByte); 3022325SN/A } 3032292SN/A return true; 3042292SN/A } 3052292SN/A } 3062325SN/A } else { 3072292SN/A // In Broadcast/Snoop protocols, this covers if you know the block 3082292SN/A // exists somewhere in the caching hierarchy, then you want to read any 3092292SN/A // valid RO or RW block. In directory protocols, same thing, you want 3102292SN/A // to read any valid readable copy of the block. 3112292SN/A DPRINTF(RubyPort, "num_busy = %d, num_ro = %d, num_rw = %d\n", 3122292SN/A num_busy, num_ro, num_rw); 3132292SN/A // In this loop, we try to figure which controller has a read only or 3142292SN/A // a read write copy of the given address. Any valid copy would suffice 3153221Sktlim@umich.edu // for a functional read. 3163221Sktlim@umich.edu for(int i = 0;i < num_controllers;++i) { 3173221Sktlim@umich.edu access_perm = ruby_system->m_abs_cntrl_vec[i] 3182292SN/A ->getAccessPermission(line_address); 3192292SN/A if(access_perm == AccessPermission_Read_Only || 3202292SN/A access_perm == AccessPermission_Read_Write) 3212292SN/A { 3222292SN/A DataBlock& block = ruby_system->m_abs_cntrl_vec[i] 3232292SN/A ->getDataBlock(line_address); 3242292SN/A 3252292SN/A DPRINTF(RubyPort, "reading from %s block %s\n", 3262292SN/A ruby_system->m_abs_cntrl_vec[i]->name(), block); 3271060SN/A for (unsigned i = 0; i < size_in_bytes; ++i) { 3282292SN/A data[i] = block.getByte(i + startByte); 3291060SN/A } 3301060SN/A return true; 3312292SN/A } 3322292SN/A } 3332292SN/A } 3342829Sksewell@umich.edu return false; 3352829Sksewell@umich.edu} 3363093Sksewell@umich.edu 3373093Sksewell@umich.edubool 3383093Sksewell@umich.eduRubyPort::M5Port::doFunctionalWrite(PacketPtr pkt) 3393093Sksewell@umich.edu{ 3403093Sksewell@umich.edu Address addr(pkt->getAddr()); 3412292SN/A Address line_addr = line_address(addr); 3421060SN/A AccessPermission access_perm = AccessPermission_NotPresent; 3431060SN/A int num_controllers = ruby_system->m_abs_cntrl_vec.size(); 3441060SN/A 3451755SN/A DPRINTF(RubyPort, "Functional Write request for %s\n",addr); 3461060SN/A 3471060SN/A unsigned int num_ro = 0; 3481060SN/A unsigned int num_rw = 0; 3491060SN/A unsigned int num_busy = 0; 3501060SN/A unsigned int num_backing_store = 0; 3511755SN/A unsigned int num_invalid = 0; 3521062SN/A 3532733Sktlim@umich.edu // In this loop we count the number of controllers that have the given 3542292SN/A // address in read only, read write and busy states. 3552733Sktlim@umich.edu for(int i = 0;i < num_controllers;++i) { 3562292SN/A access_perm = ruby_system->m_abs_cntrl_vec[i]-> 3572292SN/A getAccessPermission(line_addr); 3582292SN/A if (access_perm == AccessPermission_Read_Only) 3592292SN/A num_ro++; 3602292SN/A else if (access_perm == AccessPermission_Read_Write) 3612292SN/A num_rw++; 3622292SN/A else if (access_perm == AccessPermission_Busy) 3632292SN/A num_busy++; 3642292SN/A else if (access_perm == AccessPermission_Backing_Store) 3652292SN/A // See RubySlicc_Exports.sm for details, but Backing_Store is meant 3662292SN/A // to represent blocks in memory *for Broadcast/Snooping protocols*, 3672292SN/A // where memory has no idea whether it has an exclusive copy of data 3682292SN/A // or not. 3692292SN/A num_backing_store++; 3702292SN/A else if (access_perm == AccessPermission_Invalid || 3712292SN/A access_perm == AccessPermission_NotPresent) 3722292SN/A num_invalid++; 3732292SN/A } 3742292SN/A 3752292SN/A // If the number of read write copies is more than 1, then there is bug in 3762292SN/A // coherence protocol. Otherwise, if all copies are in stable states, i.e. 3772292SN/A // num_busy == 0, we update all the copies. If there is at least one copy 3782292SN/A // in busy state, then we check if there is read write copy. If yes, then 3792292SN/A // also we let the access go through. Or, if there is no copy in the cache 3802292SN/A // hierarchy at all, we still want to do the write to the memory 3812292SN/A // (Backing_Store) instead of failing. 3822292SN/A 3832292SN/A DPRINTF(RubyPort, "num_busy = %d, num_ro = %d, num_rw = %d\n", 3842292SN/A num_busy, num_ro, num_rw); 3854392Sktlim@umich.edu assert(num_rw <= 1); 3862292SN/A 3872292SN/A uint8* data = pkt->getPtr<uint8_t>(true); 3882292SN/A unsigned int size_in_bytes = pkt->getSize(); 3892292SN/A unsigned startByte = addr.getAddress() - line_addr.getAddress(); 3902292SN/A 3914392Sktlim@umich.edu if ((num_busy == 0 && num_ro > 0) || num_rw == 1 || 3922292SN/A (num_invalid == (num_controllers - 1) && num_backing_store == 1)) 3932292SN/A { 3942292SN/A for(int i = 0; i < num_controllers;++i) { 3952292SN/A access_perm = ruby_system->m_abs_cntrl_vec[i]-> 3962292SN/A getAccessPermission(line_addr); 3974392Sktlim@umich.edu if(access_perm == AccessPermission_Read_Only || 3982292SN/A access_perm == AccessPermission_Read_Write|| 3992292SN/A access_perm == AccessPermission_Maybe_Stale || 4002292SN/A access_perm == AccessPermission_Backing_Store) 4012292SN/A { 4022292SN/A DataBlock& block = ruby_system->m_abs_cntrl_vec[i] 4034392Sktlim@umich.edu ->getDataBlock(line_addr); 4042292SN/A 4051062SN/A DPRINTF(RubyPort, "%s\n",block); 4061062SN/A for (unsigned i = 0; i < size_in_bytes; ++i) { 4071062SN/A block.setByte(i + startByte, data[i]); 4082871Sktlim@umich.edu } 4092871Sktlim@umich.edu DPRINTF(RubyPort, "%s\n",block); 4102871Sktlim@umich.edu } 4112871Sktlim@umich.edu } 4122871Sktlim@umich.edu return true; 4132871Sktlim@umich.edu } 4142871Sktlim@umich.edu return false; 4152871Sktlim@umich.edu} 4162871Sktlim@umich.edu 4172871Sktlim@umich.eduvoid 4182871Sktlim@umich.eduRubyPort::M5Port::recvFunctional(PacketPtr pkt) 4192871Sktlim@umich.edu{ 4201062SN/A DPRINTF(RubyPort, "Functional access caught for address %#x\n", 4211755SN/A pkt->getAddr()); 4221060SN/A 4232733Sktlim@umich.edu // Check for pio requests and directly send them to the dedicated 4241060SN/A // pio port. 4252292SN/A if (!isPhysMemAddress(pkt->getAddr())) { 4262292SN/A assert(ruby_port->pio_port != NULL); 4272325SN/A DPRINTF(RubyPort, "Request for address 0x%#x is a pio request\n", 4282292SN/A pkt->getAddr()); 4292292SN/A panic("RubyPort::PioPort::recvFunctional() not implemented!\n"); 4301060SN/A } 4311060SN/A 4321060SN/A assert(pkt->getAddr() + pkt->getSize() <= 4331060SN/A line_address(Address(pkt->getAddr())).getAddress() + 4341060SN/A RubySystem::getBlockSizeBytes()); 4351060SN/A 4361060SN/A bool accessSucceeded = false; 4371060SN/A bool needsResponse = pkt->needsResponse(); 4381060SN/A 4391060SN/A // Do the functional access on ruby memory 4402292SN/A if (pkt->isRead()) { 4412292SN/A accessSucceeded = doFunctionalRead(pkt); 4422292SN/A } else if (pkt->isWrite()) { 4432292SN/A accessSucceeded = doFunctionalWrite(pkt); 4442292SN/A } else { 4451060SN/A panic("RubyPort: unsupported functional command %s\n", 4461060SN/A pkt->cmdString()); 4471060SN/A } 4481060SN/A 4491060SN/A // Unless the requester explicitly said otherwise, generate an error if 4501060SN/A // the functional request failed 4511060SN/A if (!accessSucceeded && !pkt->suppressFuncError()) { 4522325SN/A fatal("Ruby functional %s failed for address %#x\n", 4532292SN/A pkt->isWrite() ? "write" : "read", pkt->getAddr()); 4542292SN/A } 4552292SN/A 4562292SN/A if (access_phys_mem) { 4572292SN/A // The attached physmem contains the official version of data. 4582325SN/A // The following command performs the real functional access. 4592867Sktlim@umich.edu // This line should be removed once Ruby supplies the official version 4602905Sktlim@umich.edu // of data. 4613226Sktlim@umich.edu ruby_port->physMemPort->sendFunctional(pkt); 4622325SN/A } 4632325SN/A 4643221Sktlim@umich.edu // turn packet around to go back to requester if response expected 4653226Sktlim@umich.edu if (needsResponse) { 4662325SN/A pkt->setFunctionalResponseStatus(accessSucceeded); 4672325SN/A 4682325SN/A // @todo There should not be a reverse call since the response is 4694030Sktlim@umich.edu // communicated through the packet pointer 4703226Sktlim@umich.edu // DPRINTF(RubyPort, "Sending packet back over port\n"); 4712325SN/A // sendFunctional(pkt); 4722292SN/A } 4732292SN/A DPRINTF(RubyPort, "Functional access %s!\n", 4742292SN/A accessSucceeded ? "successful":"failed"); 4752292SN/A} 4762292SN/A 4772292SN/Avoid 4781060SN/ARubyPort::ruby_hit_callback(PacketPtr pkt) 4791060SN/A{ 4801060SN/A // Retrieve the request port from the sender State 4811060SN/A RubyPort::SenderState *senderState = 4821755SN/A safe_cast<RubyPort::SenderState *>(pkt->senderState); 4831060SN/A M5Port *port = senderState->port; 4842307SN/A assert(port != NULL); 4852680Sktlim@umich.edu 4862292SN/A // pop the sender state from the packet 4871060SN/A pkt->senderState = senderState->saved; 4882292SN/A delete senderState; 4892292SN/A 4902292SN/A port->hitCallback(pkt); 4912292SN/A 4922292SN/A // 4932292SN/A // If we had to stall the M5Ports, wake them up because the sequencer 4941858SN/A // likely has free resources now. 4952680Sktlim@umich.edu // 4961681SN/A if (waitingOnSequencer) { 4972680Sktlim@umich.edu // 4981681SN/A // Record the current list of ports to retry on a temporary list before 4992292SN/A // calling sendRetry on those ports. sendRetry will cause an 5002680Sktlim@umich.edu // immediate retry, which may result in the ports being put back on the 5012292SN/A // list. Therefore we want to clear the retryList before calling 5021060SN/A // sendRetry. 5031060SN/A // 5042292SN/A std::list<M5Port*> curRetryList(retryList); 5052680Sktlim@umich.edu 5062292SN/A retryList.clear(); 5072292SN/A waitingOnSequencer = false; 5082292SN/A 5092292SN/A for (std::list<M5Port*>::iterator i = curRetryList.begin(); 5102292SN/A i != curRetryList.end(); ++i) { 5112292SN/A DPRINTF(RubyPort, 5122292SN/A "Sequencer may now be free. SendRetry to port %s\n", 5132316SN/A (*i)->name()); 5142292SN/A (*i)->onRetryList(false); 5152292SN/A (*i)->sendRetry(); 5162292SN/A } 5172292SN/A } 5182292SN/A 5192292SN/A testDrainComplete(); 5202292SN/A} 5212292SN/A 5222292SN/Avoid 5232292SN/ARubyPort::testDrainComplete() 5242875Sksewell@umich.edu{ 5252875Sksewell@umich.edu //If we weren't able to drain before, we might be able to now. 5262875Sksewell@umich.edu if (drainEvent != NULL) { 5272875Sksewell@umich.edu unsigned int drainCount = getDrainCount(drainEvent); 5282875Sksewell@umich.edu DPRINTF(Config, "Drain count: %u\n", drainCount); 5293226Sktlim@umich.edu if (drainCount == 0) { 5303226Sktlim@umich.edu drainEvent->process(); 5312875Sksewell@umich.edu // Clear the drain event once we're done with it. 5322875Sksewell@umich.edu drainEvent = NULL; 5332875Sksewell@umich.edu } 5342875Sksewell@umich.edu } 5352875Sksewell@umich.edu} 5362875Sksewell@umich.edu 5372875Sksewell@umich.eduunsigned int 5382875Sksewell@umich.eduRubyPort::getDrainCount(Event *de) 5392875Sksewell@umich.edu{ 5402875Sksewell@umich.edu int count = 0; 5412875Sksewell@umich.edu // 5422875Sksewell@umich.edu // If the sequencer is not empty, then requests need to drain. 5432875Sksewell@umich.edu // The outstandingCount is the number of requests outstanding and thus the 5442875Sksewell@umich.edu // number of times M5's timing port will process the drain event. 5452875Sksewell@umich.edu // 5462875Sksewell@umich.edu count += outstandingCount(); 5473226Sktlim@umich.edu 5483226Sktlim@umich.edu DPRINTF(Config, "outstanding count %d\n", outstandingCount()); 5492875Sksewell@umich.edu 5502875Sksewell@umich.edu // To simplify the draining process, the sequencer's deadlock detection 5512875Sksewell@umich.edu // event should have been descheduled. 5522875Sksewell@umich.edu assert(isDeadlockEventScheduled() == false); 5532875Sksewell@umich.edu 5542875Sksewell@umich.edu if (pio_port != NULL) { 5552875Sksewell@umich.edu count += pio_port->drain(de); 5562875Sksewell@umich.edu DPRINTF(Config, "count after pio check %d\n", count); 5572875Sksewell@umich.edu } 5582875Sksewell@umich.edu if (physMemPort != NULL) { 5592875Sksewell@umich.edu count += physMemPort->drain(de); 5602875Sksewell@umich.edu DPRINTF(Config, "count after physmem check %d\n", count); 5612875Sksewell@umich.edu } 5622875Sksewell@umich.edu 5632875Sksewell@umich.edu for (CpuPortIter p_iter = cpu_ports.begin(); p_iter != cpu_ports.end(); 5642875Sksewell@umich.edu p_iter++) { 5652875Sksewell@umich.edu M5Port* cpu_port = *p_iter; 5662875Sksewell@umich.edu count += cpu_port->drain(de); 5672875Sksewell@umich.edu DPRINTF(Config, "count after cpu port check %d\n", count); 5682875Sksewell@umich.edu } 5693221Sktlim@umich.edu 5702875Sksewell@umich.edu DPRINTF(Config, "final count %d\n", count); 5712875Sksewell@umich.edu 5722875Sksewell@umich.edu return count; 5732875Sksewell@umich.edu} 5742875Sksewell@umich.edu 5752875Sksewell@umich.eduunsigned int 5762875Sksewell@umich.eduRubyPort::drain(Event *de) 5772875Sksewell@umich.edu{ 5782875Sksewell@umich.edu if (isDeadlockEventScheduled()) { 5792875Sksewell@umich.edu descheduleDeadlockEvent(); 5802875Sksewell@umich.edu } 5812875Sksewell@umich.edu 5822875Sksewell@umich.edu int count = getDrainCount(de); 5832875Sksewell@umich.edu 5843221Sktlim@umich.edu // Set status 5853221Sktlim@umich.edu if (count != 0) { 5862875Sksewell@umich.edu drainEvent = de; 5872875Sksewell@umich.edu 5882875Sksewell@umich.edu changeState(SimObject::Draining); 5892875Sksewell@umich.edu return count; 5902875Sksewell@umich.edu } 5913221Sktlim@umich.edu 5923221Sktlim@umich.edu changeState(SimObject::Drained); 5932875Sksewell@umich.edu return 0; 5942875Sksewell@umich.edu} 5953221Sktlim@umich.edu 5963221Sktlim@umich.eduvoid 5973221Sktlim@umich.eduRubyPort::M5Port::hitCallback(PacketPtr pkt) 5982875Sksewell@umich.edu{ 5992875Sksewell@umich.edu bool needsResponse = pkt->needsResponse(); 6002875Sksewell@umich.edu 6012875Sksewell@umich.edu // 6022875Sksewell@umich.edu // Unless specified at configuraiton, all responses except failed SC 6032875Sksewell@umich.edu // and Flush operations access M5 physical memory. 6042875Sksewell@umich.edu // 6052875Sksewell@umich.edu bool accessPhysMem = access_phys_mem; 6063221Sktlim@umich.edu 6073221Sktlim@umich.edu if (pkt->isLLSC()) { 6083859Sbinkertn@umich.edu if (pkt->isWrite()) { 6093859Sbinkertn@umich.edu if (pkt->req->getExtraData() != 0) { 6102910Sksewell@umich.edu // 6112875Sksewell@umich.edu // Successful SC packets convert to normal writes 6122875Sksewell@umich.edu // 6132875Sksewell@umich.edu pkt->convertScToWrite(); 6142875Sksewell@umich.edu } else { 6152875Sksewell@umich.edu // 6162875Sksewell@umich.edu // Failed SC packets don't access physical memory and thus 6172875Sksewell@umich.edu // the RubyPort itself must convert it to a response. 6182910Sksewell@umich.edu // 6192910Sksewell@umich.edu accessPhysMem = false; 6203221Sktlim@umich.edu } 6212875Sksewell@umich.edu } else { 6222875Sksewell@umich.edu // 6232875Sksewell@umich.edu // All LL packets convert to normal loads so that M5 PhysMem does 6242875Sksewell@umich.edu // not lock the blocks. 6252292SN/A // 6262292SN/A pkt->convertLlToRead(); 6272847Sksewell@umich.edu } 6282292SN/A } 6292683Sktlim@umich.edu 6302292SN/A // 6312680Sktlim@umich.edu // Flush requests don't access physical memory 6322292SN/A // 6332847Sksewell@umich.edu if (pkt->isFlush()) { 6342292SN/A accessPhysMem = false; 6352292SN/A } 6362292SN/A 6372292SN/A DPRINTF(RubyPort, "Hit callback needs response %d\n", needsResponse); 6382292SN/A 6392292SN/A if (accessPhysMem) { 6402292SN/A ruby_port->physMemPort->sendAtomic(pkt); 6412292SN/A } else if (needsResponse) { 6422292SN/A pkt->makeResponse(); 6432292SN/A } 6442292SN/A 6452292SN/A // turn packet around to go back to requester if response expected 6462292SN/A if (needsResponse) { 6472292SN/A DPRINTF(RubyPort, "Sending packet back over port\n"); 6482292SN/A sendTiming(pkt); 6492292SN/A } else { 6502292SN/A delete pkt; 6512292SN/A } 6522292SN/A DPRINTF(RubyPort, "Hit callback done!\n"); 6532847Sksewell@umich.edu} 6542292SN/A 6552847Sksewell@umich.edubool 6562847Sksewell@umich.eduRubyPort::M5Port::sendTiming(PacketPtr pkt) 6572847Sksewell@umich.edu{ 6582847Sksewell@umich.edu //minimum latency, must be > 0 6592292SN/A schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock())); 6602680Sktlim@umich.edu return true; 6612292SN/A} 6622292SN/A 6632292SN/Abool 6642292SN/ARubyPort::PioPort::sendTiming(PacketPtr pkt) 6652292SN/A{ 6662292SN/A //minimum latency, must be > 0 6672292SN/A schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock())); 6682292SN/A return true; 6692292SN/A} 6702292SN/A 6712292SN/Abool 6722292SN/ARubyPort::M5Port::isPhysMemAddress(Addr addr) 6732877Sksewell@umich.edu{ 6742847Sksewell@umich.edu AddrRangeList physMemAddrList; 6752847Sksewell@umich.edu bool snoop = false; 6762847Sksewell@umich.edu ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop); 6772847Sksewell@umich.edu for (AddrRangeIter iter = physMemAddrList.begin(); 6782847Sksewell@umich.edu iter != physMemAddrList.end(); 6792847Sksewell@umich.edu iter++) { 6802292SN/A if (addr >= iter->start && addr <= iter->end) { 6812292SN/A DPRINTF(RubyPort, "Request found in %#llx - %#llx range\n", 6822292SN/A iter->start, iter->end); 6832292SN/A return true; 6842292SN/A } 6852292SN/A } 6862292SN/A return false; 6872847Sksewell@umich.edu} 6882292SN/A 6892292SN/Aunsigned 6902292SN/ARubyPort::M5Port::deviceBlockSize() const 6912292SN/A{ 6922292SN/A return (unsigned) RubySystem::getBlockSizeBytes(); 6932292SN/A} 6942292SN/A