RubyPort.cc revision 11111:6da33e720481
12623SN/A/*
22623SN/A * Copyright (c) 2012-2013 ARM Limited
32623SN/A * All rights reserved.
42623SN/A *
52623SN/A * The license below extends only to copyright in the software and shall
62623SN/A * not be construed as granting a license to any other intellectual
72623SN/A * property including but not limited to intellectual property relating
82623SN/A * to a hardware implementation of the functionality of the software
92623SN/A * licensed hereunder.  You may use the software subject to the license
102623SN/A * terms below provided that you ensure that this notice is replicated
112623SN/A * unmodified and in its entirety in all distributions of the software,
122623SN/A * modified or unmodified, in source code or in binary form.
132623SN/A *
142623SN/A * Copyright (c) 2009 Advanced Micro Devices, Inc.
152623SN/A * Copyright (c) 2011 Mark D. Hill and David A. Wood
162623SN/A * All rights reserved.
172623SN/A *
182623SN/A * Redistribution and use in source and binary forms, with or without
192623SN/A * modification, are permitted provided that the following conditions are
202623SN/A * met: redistributions of source code must retain the above copyright
212623SN/A * notice, this list of conditions and the following disclaimer;
222623SN/A * redistributions in binary form must reproduce the above copyright
232623SN/A * notice, this list of conditions and the following disclaimer in the
242623SN/A * documentation and/or other materials provided with the distribution;
252623SN/A * neither the name of the copyright holders nor the names of its
262623SN/A * contributors may be used to endorse or promote products derived from
272665Ssaidi@eecs.umich.edu * this software without specific prior written permission.
282665Ssaidi@eecs.umich.edu *
292623SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
302623SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
313170Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
322623SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
334040Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
342623SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
352623SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
363348Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
373348Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
382623SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
392901Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
402623SN/A */
412623SN/A
422623SN/A#include "cpu/testers/rubytest/RubyTester.hh"
432623SN/A#include "debug/Config.hh"
442856Srdreslin@umich.edu#include "debug/Drain.hh"
452856Srdreslin@umich.edu#include "debug/Ruby.hh"
462856Srdreslin@umich.edu#include "mem/protocol/AccessPermission.hh"
472856Srdreslin@umich.edu#include "mem/ruby/slicc_interface/AbstractController.hh"
482856Srdreslin@umich.edu#include "mem/ruby/system/RubyPort.hh"
492856Srdreslin@umich.edu#include "mem/simple_mem.hh"
502856Srdreslin@umich.edu#include "sim/full_system.hh"
512856Srdreslin@umich.edu#include "sim/system.hh"
522856Srdreslin@umich.edu
532856Srdreslin@umich.eduRubyPort::RubyPort(const Params *p)
542623SN/A    : MemObject(p), m_ruby_system(p->ruby_system), m_version(p->version),
552623SN/A      m_controller(NULL), m_mandatory_q_ptr(NULL),
562623SN/A      m_usingRubyTester(p->using_ruby_tester), system(p->system),
572623SN/A      pioMasterPort(csprintf("%s.pio-master-port", name()), this),
582623SN/A      pioSlavePort(csprintf("%s.pio-slave-port", name()), this),
592623SN/A      memMasterPort(csprintf("%s.mem-master-port", name()), this),
602680Sktlim@umich.edu      memSlavePort(csprintf("%s-mem-slave-port", name()), this,
612680Sktlim@umich.edu                   p->ruby_system->getAccessBackingStore(), -1),
622623SN/A      gotAddrRanges(p->port_master_connection_count)
632623SN/A{
642680Sktlim@umich.edu    assert(m_version != -1);
652623SN/A
662623SN/A    // create the slave ports based on the number of connected ports
672623SN/A    for (size_t i = 0; i < p->port_slave_connection_count; ++i) {
682623SN/A        slave_ports.push_back(new MemSlavePort(csprintf("%s.slave%d", name(),
692623SN/A            i), this, p->ruby_system->getAccessBackingStore(), i));
703349Sbinkertn@umich.edu    }
712623SN/A
722623SN/A    // create the master ports based on the number of connected ports
732623SN/A    for (size_t i = 0; i < p->port_master_connection_count; ++i) {
742623SN/A        master_ports.push_back(new PioMasterPort(csprintf("%s.master%d",
752623SN/A            name(), i), this));
762623SN/A    }
773349Sbinkertn@umich.edu}
782623SN/A
793184Srdreslin@umich.eduvoid
803184Srdreslin@umich.eduRubyPort::init()
812623SN/A{
822623SN/A    assert(m_controller != NULL);
832623SN/A    m_mandatory_q_ptr = m_controller->getMandatoryQueue();
842623SN/A}
852623SN/A
863647Srdreslin@umich.eduBaseMasterPort &
873647Srdreslin@umich.eduRubyPort::getMasterPort(const std::string &if_name, PortID idx)
883647Srdreslin@umich.edu{
893647Srdreslin@umich.edu    if (if_name == "mem_master_port") {
903647Srdreslin@umich.edu        return memMasterPort;
912631SN/A    }
923647Srdreslin@umich.edu
932631SN/A    if (if_name == "pio_master_port") {
942623SN/A        return pioMasterPort;
952623SN/A    }
962623SN/A
972948Ssaidi@eecs.umich.edu    // used by the x86 CPUs to connect the interrupt PIO and interrupt slave
982948Ssaidi@eecs.umich.edu    // port
993349Sbinkertn@umich.edu    if (if_name != "master") {
1002948Ssaidi@eecs.umich.edu        // pass it along to our super class
1012948Ssaidi@eecs.umich.edu        return MemObject::getMasterPort(if_name, idx);
1022948Ssaidi@eecs.umich.edu    } else {
1032948Ssaidi@eecs.umich.edu        if (idx >= static_cast<PortID>(master_ports.size())) {
1042948Ssaidi@eecs.umich.edu            panic("RubyPort::getMasterPort: unknown index %d\n", idx);
1052623SN/A        }
1063170Sstever@eecs.umich.edu
1073170Sstever@eecs.umich.edu        return *master_ports[idx];
1082623SN/A    }
1092623SN/A}
1103647Srdreslin@umich.edu
1113647Srdreslin@umich.eduBaseSlavePort &
1123647Srdreslin@umich.eduRubyPort::getSlavePort(const std::string &if_name, PortID idx)
1133647Srdreslin@umich.edu{
1142623SN/A    if (if_name == "mem_slave_port") {
1152839Sktlim@umich.edu        return memSlavePort;
1162867Sktlim@umich.edu    }
1173222Sktlim@umich.edu
1182901Ssaidi@eecs.umich.edu    if (if_name == "pio_slave_port")
1192623SN/A        return pioSlavePort;
1202623SN/A
1212623SN/A    // used by the CPUs to connect the caches to the interconnect, and
1222623SN/A    // for the x86 case also the interrupt master
1232623SN/A    if (if_name != "slave") {
1242623SN/A        // pass it along to our super class
1252623SN/A        return MemObject::getSlavePort(if_name, idx);
1262623SN/A    } else {
1272623SN/A        if (idx >= static_cast<PortID>(slave_ports.size())) {
1282623SN/A            panic("RubyPort::getSlavePort: unknown index %d\n", idx);
1292915Sktlim@umich.edu        }
1302915Sktlim@umich.edu
1312623SN/A        return *slave_ports[idx];
1322623SN/A    }
1332623SN/A}
1342623SN/A
1352623SN/ARubyPort::PioMasterPort::PioMasterPort(const std::string &_name,
1362623SN/A                           RubyPort *_port)
1372915Sktlim@umich.edu    : QueuedMasterPort(_name, _port, reqQueue, snoopRespQueue),
1382915Sktlim@umich.edu      reqQueue(*_port, *this), snoopRespQueue(*_port, *this)
1392623SN/A{
1402798Sktlim@umich.edu    DPRINTF(RubyPort, "Created master pioport on sequencer %s\n", _name);
1412798Sktlim@umich.edu}
1422901Ssaidi@eecs.umich.edu
1432839Sktlim@umich.eduRubyPort::PioSlavePort::PioSlavePort(const std::string &_name,
1442798Sktlim@umich.edu                           RubyPort *_port)
1452839Sktlim@umich.edu    : QueuedSlavePort(_name, _port, queue), queue(*_port, *this)
1462798Sktlim@umich.edu{
1472798Sktlim@umich.edu    DPRINTF(RubyPort, "Created slave pioport on sequencer %s\n", _name);
1482901Ssaidi@eecs.umich.edu}
1492901Ssaidi@eecs.umich.edu
1502798Sktlim@umich.eduRubyPort::MemMasterPort::MemMasterPort(const std::string &_name,
1512839Sktlim@umich.edu                           RubyPort *_port)
1522839Sktlim@umich.edu    : QueuedMasterPort(_name, _port, reqQueue, snoopRespQueue),
1532901Ssaidi@eecs.umich.edu      reqQueue(*_port, *this), snoopRespQueue(*_port, *this)
1542798Sktlim@umich.edu{
1552623SN/A    DPRINTF(RubyPort, "Created master memport on ruby sequencer %s\n", _name);
1562623SN/A}
1572623SN/A
1582798Sktlim@umich.eduRubyPort::MemSlavePort::MemSlavePort(const std::string &_name, RubyPort *_port,
1592623SN/A                                     bool _access_backing_store, PortID id)
1602798Sktlim@umich.edu    : QueuedSlavePort(_name, _port, queue, id), queue(*_port, *this),
1613201Shsul@eecs.umich.edu      access_backing_store(_access_backing_store)
1623201Shsul@eecs.umich.edu{
1632867Sktlim@umich.edu    DPRINTF(RubyPort, "Created slave memport on ruby sequencer %s\n", _name);
1642867Sktlim@umich.edu}
1652915Sktlim@umich.edu
1662915Sktlim@umich.edubool
1672915Sktlim@umich.eduRubyPort::PioMasterPort::recvTimingResp(PacketPtr pkt)
1682867Sktlim@umich.edu{
1692867Sktlim@umich.edu    RubyPort *rp = static_cast<RubyPort *>(&owner);
1702867Sktlim@umich.edu    DPRINTF(RubyPort, "Response for address: 0x%#x\n", pkt->getAddr());
1714471Sstever@eecs.umich.edu
1722623SN/A    // send next cycle
1732798Sktlim@umich.edu    rp->pioSlavePort.schedTimingResp(
1742901Ssaidi@eecs.umich.edu            pkt, curTick() + rp->m_ruby_system->clockPeriod());
1753222Sktlim@umich.edu    return true;
1762798Sktlim@umich.edu}
1772798Sktlim@umich.edu
1782798Sktlim@umich.edubool RubyPort::MemMasterPort::recvTimingResp(PacketPtr pkt)
1792798Sktlim@umich.edu{
1802798Sktlim@umich.edu    // got a response from a device
1812798Sktlim@umich.edu    assert(pkt->isResponse());
1822798Sktlim@umich.edu
1833222Sktlim@umich.edu    // First we must retrieve the request port from the sender State
1842867Sktlim@umich.edu    RubyPort::SenderState *senderState =
1852867Sktlim@umich.edu        safe_cast<RubyPort::SenderState *>(pkt->popSenderState());
1862867Sktlim@umich.edu    MemSlavePort *port = senderState->port;
1872867Sktlim@umich.edu    assert(port != NULL);
1882867Sktlim@umich.edu    delete senderState;
1892623SN/A
1902623SN/A    // In FS mode, ruby memory will receive pio responses from devices
1912623SN/A    // and it must forward these responses back to the particular CPU.
1922623SN/A    DPRINTF(RubyPort,  "Pio response for address %#x, going to %s\n",
1932623SN/A            pkt->getAddr(), port->name());
1942623SN/A
1954192Sktlim@umich.edu    // attempt to send the response in the next cycle
1962623SN/A    RubyPort *rp = static_cast<RubyPort *>(&owner);
1972680Sktlim@umich.edu    port->schedTimingResp(pkt, curTick() + rp->m_ruby_system->clockPeriod());
1982623SN/A
1992680Sktlim@umich.edu    return true;
2002680Sktlim@umich.edu}
2012680Sktlim@umich.edu
2022623SN/Abool
2032623SN/ARubyPort::PioSlavePort::recvTimingReq(PacketPtr pkt)
2042623SN/A{
2052623SN/A    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
2063201Shsul@eecs.umich.edu
2073201Shsul@eecs.umich.edu    for (size_t i = 0; i < ruby_port->master_ports.size(); ++i) {
2083201Shsul@eecs.umich.edu        AddrRangeList l = ruby_port->master_ports[i]->getAddrRanges();
2093201Shsul@eecs.umich.edu        for (auto it = l.begin(); it != l.end(); ++it) {
2102623SN/A            if (it->contains(pkt->getAddr())) {
2112623SN/A                // generally it is not safe to assume success here as
2122623SN/A                // the port could be blocked
2132623SN/A                bool M5_VAR_USED success =
2142623SN/A                    ruby_port->master_ports[i]->sendTimingReq(pkt);
2152623SN/A                assert(success);
2162623SN/A                return true;
2172683Sktlim@umich.edu            }
2182623SN/A        }
2192623SN/A    }
2202623SN/A    panic("Should never reach here!\n");
2212623SN/A}
2222623SN/A
2233686Sktlim@umich.edubool
2242623SN/ARubyPort::MemSlavePort::recvTimingReq(PacketPtr pkt)
2254471Sstever@eecs.umich.edu{
2262623SN/A    DPRINTF(RubyPort, "Timing request for address %#x on port %d\n",
2272623SN/A            pkt->getAddr(), id);
2282623SN/A    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
2292623SN/A
2302623SN/A    if (pkt->memInhibitAsserted())
2312623SN/A        panic("RubyPort should never see an inhibited request\n");
2322623SN/A
2332683Sktlim@umich.edu    // Check for pio requests and directly send them to the dedicated
2342623SN/A    // pio port.
2352644Sstever@eecs.umich.edu    if (!isPhysMemAddress(pkt->getAddr())) {
2362623SN/A        assert(ruby_port->memMasterPort.isConnected());
2372644Sstever@eecs.umich.edu        DPRINTF(RubyPort, "Request address %#x assumed to be a pio address\n",
2382644Sstever@eecs.umich.edu                pkt->getAddr());
2392623SN/A
2402623SN/A        // Save the port in the sender state object to be used later to
2412623SN/A        // route the response
2422623SN/A        pkt->pushSenderState(new SenderState(this));
2432623SN/A
2442623SN/A        // send next cycle
2452623SN/A        RubySystem *rs = ruby_port->m_ruby_system;
2462623SN/A        ruby_port->memMasterPort.schedTimingReq(pkt,
2472623SN/A            curTick() + rs->clockPeriod());
2482623SN/A        return true;
2493169Sstever@eecs.umich.edu    }
2503169Sstever@eecs.umich.edu
2513170Sstever@eecs.umich.edu    assert(getOffset(pkt->getAddr()) + pkt->getSize() <=
2522623SN/A           RubySystem::getBlockSizeBytes());
2532623SN/A
2543169Sstever@eecs.umich.edu    // Submit the ruby request
2552623SN/A    RequestStatus requestStatus = ruby_port->makeRequest(pkt);
2562623SN/A
2572623SN/A    // If the request successfully issued then we should return true.
2583169Sstever@eecs.umich.edu    // Otherwise, we need to tell the port to retry at a later point
2592623SN/A    // and return false.
2602623SN/A    if (requestStatus == RequestStatus_Issued) {
2612623SN/A        // Save the port in the sender state object to be used later to
2623349Sbinkertn@umich.edu        // route the response
2634878Sstever@eecs.umich.edu        pkt->pushSenderState(new SenderState(this));
2644878Sstever@eecs.umich.edu
2654878Sstever@eecs.umich.edu        DPRINTF(RubyPort, "Request %s 0x%x issued\n", pkt->cmdString(),
2664878Sstever@eecs.umich.edu                pkt->getAddr());
2673169Sstever@eecs.umich.edu        return true;
2682623SN/A    }
2693169Sstever@eecs.umich.edu
2702623SN/A    //
2713169Sstever@eecs.umich.edu    // Unless one is using the ruby tester, record the stalled M5 port for
2722623SN/A    // later retry when the sequencer becomes free.
2732623SN/A    //
2743169Sstever@eecs.umich.edu    if (!ruby_port->m_usingRubyTester) {
2752623SN/A        ruby_port->addToRetryList(this);
2762623SN/A    }
2774200Ssaidi@eecs.umich.edu
2784200Ssaidi@eecs.umich.edu    DPRINTF(RubyPort, "Request for address %#x did not issued because %s\n",
2794200Ssaidi@eecs.umich.edu            pkt->getAddr(), RequestStatus_to_string(requestStatus));
2804200Ssaidi@eecs.umich.edu
2813658Sktlim@umich.edu    return false;
2823658Sktlim@umich.edu}
2832623SN/A
2842623SN/Avoid
2852623SN/ARubyPort::MemSlavePort::recvFunctional(PacketPtr pkt)
2862623SN/A{
2872623SN/A    DPRINTF(RubyPort, "Functional access for address: %#x\n", pkt->getAddr());
2882623SN/A
2892623SN/A    RubyPort *rp M5_VAR_USED = static_cast<RubyPort *>(&owner);
2902623SN/A    RubySystem *rs = rp->m_ruby_system;
2912623SN/A
2924040Ssaidi@eecs.umich.edu    // Check for pio requests and directly send them to the dedicated
2934040Ssaidi@eecs.umich.edu    // pio port.
2944040Ssaidi@eecs.umich.edu    if (!isPhysMemAddress(pkt->getAddr())) {
2954040Ssaidi@eecs.umich.edu        assert(rp->memMasterPort.isConnected());
2964115Ssaidi@eecs.umich.edu        DPRINTF(RubyPort, "Pio Request for address: 0x%#x\n", pkt->getAddr());
2974115Ssaidi@eecs.umich.edu        panic("RubyPort::PioMasterPort::recvFunctional() not implemented!\n");
2984115Ssaidi@eecs.umich.edu    }
2994115Ssaidi@eecs.umich.edu
3002623SN/A    assert(pkt->getAddr() + pkt->getSize() <=
3012623SN/A           makeLineAddress(pkt->getAddr()) + RubySystem::getBlockSizeBytes());
3022623SN/A
3032623SN/A    if (access_backing_store) {
3042623SN/A        // The attached physmem contains the official version of data.
3052623SN/A        // The following command performs the real functional access.
3062623SN/A        // This line should be removed once Ruby supplies the official version
3072623SN/A        // of data.
3082623SN/A        rs->getPhysMem()->functionalAccess(pkt);
3092623SN/A    } else {
3102623SN/A        bool accessSucceeded = false;
3112623SN/A        bool needsResponse = pkt->needsResponse();
3122623SN/A
3132623SN/A        // Do the functional access on ruby memory
3142623SN/A        if (pkt->isRead()) {
3152623SN/A            accessSucceeded = rs->functionalRead(pkt);
3162623SN/A        } else if (pkt->isWrite()) {
3172623SN/A            accessSucceeded = rs->functionalWrite(pkt);
3182623SN/A        } else {
3192623SN/A            panic("Unsupported functional command %s\n", pkt->cmdString());
3202623SN/A        }
3212623SN/A
3222623SN/A        // Unless the requester explicitly said otherwise, generate an error if
3232623SN/A        // the functional request failed
3242623SN/A        if (!accessSucceeded && !pkt->suppressFuncError()) {
3252623SN/A            fatal("Ruby functional %s failed for address %#x\n",
3262623SN/A                  pkt->isWrite() ? "write" : "read", pkt->getAddr());
3272623SN/A        }
3282623SN/A
3292623SN/A        // turn packet around to go back to requester if response expected
3302623SN/A        if (needsResponse) {
3312623SN/A            pkt->setFunctionalResponseStatus(accessSucceeded);
3322623SN/A        }
3332623SN/A
3342623SN/A        DPRINTF(RubyPort, "Functional access %s!\n",
3352623SN/A                accessSucceeded ? "successful":"failed");
3362623SN/A    }
3372623SN/A}
3382623SN/A
3392623SN/Avoid
3402623SN/ARubyPort::ruby_hit_callback(PacketPtr pkt)
3412623SN/A{
3422623SN/A    DPRINTF(RubyPort, "Hit callback for %s 0x%x\n", pkt->cmdString(),
3433169Sstever@eecs.umich.edu            pkt->getAddr());
3443169Sstever@eecs.umich.edu
3453170Sstever@eecs.umich.edu    // The packet was destined for memory and has not yet been turned
3462623SN/A    // into a response
3474040Ssaidi@eecs.umich.edu    assert(system->isMemAddr(pkt->getAddr()));
3484040Ssaidi@eecs.umich.edu    assert(pkt->isRequest());
3494040Ssaidi@eecs.umich.edu
3504040Ssaidi@eecs.umich.edu    // First we must retrieve the request port from the sender State
3512623SN/A    RubyPort::SenderState *senderState =
3523169Sstever@eecs.umich.edu        safe_cast<RubyPort::SenderState *>(pkt->popSenderState());
3533169Sstever@eecs.umich.edu    MemSlavePort *port = senderState->port;
3542623SN/A    assert(port != NULL);
3552623SN/A    delete senderState;
3564878Sstever@eecs.umich.edu
3573170Sstever@eecs.umich.edu    port->hitCallback(pkt);
3583170Sstever@eecs.umich.edu
3594878Sstever@eecs.umich.edu    //
3604878Sstever@eecs.umich.edu    // If we had to stall the MemSlavePorts, wake them up because the sequencer
3613170Sstever@eecs.umich.edu    // likely has free resources now.
3624878Sstever@eecs.umich.edu    //
3633170Sstever@eecs.umich.edu    if (!retryList.empty()) {
3644878Sstever@eecs.umich.edu        //
3654878Sstever@eecs.umich.edu        // Record the current list of ports to retry on a temporary list before
3664878Sstever@eecs.umich.edu        // calling sendRetry on those ports.  sendRetry will cause an
3674878Sstever@eecs.umich.edu        // immediate retry, which may result in the ports being put back on the
3684878Sstever@eecs.umich.edu        // list. Therefore we want to clear the retryList before calling
3694878Sstever@eecs.umich.edu        // sendRetry.
3704040Ssaidi@eecs.umich.edu        //
3713170Sstever@eecs.umich.edu        std::vector<MemSlavePort *> curRetryList(retryList);
3723170Sstever@eecs.umich.edu
3734878Sstever@eecs.umich.edu        retryList.clear();
3744878Sstever@eecs.umich.edu
3754878Sstever@eecs.umich.edu        for (auto i = curRetryList.begin(); i != curRetryList.end(); ++i) {
3764878Sstever@eecs.umich.edu            DPRINTF(RubyPort,
3773170Sstever@eecs.umich.edu                    "Sequencer may now be free.  SendRetry to port %s\n",
3783170Sstever@eecs.umich.edu                    (*i)->name());
3793170Sstever@eecs.umich.edu            (*i)->sendRetryReq();
3803170Sstever@eecs.umich.edu        }
3813170Sstever@eecs.umich.edu    }
3823170Sstever@eecs.umich.edu
3833170Sstever@eecs.umich.edu    testDrainComplete();
3842623SN/A}
3854200Ssaidi@eecs.umich.edu
3864200Ssaidi@eecs.umich.eduvoid
3874200Ssaidi@eecs.umich.eduRubyPort::testDrainComplete()
3883658Sktlim@umich.edu{
3893658Sktlim@umich.edu    //If we weren't able to drain before, we might be able to now.
3902623SN/A    if (drainState() == DrainState::Draining) {
3912623SN/A        unsigned int drainCount = outstandingCount();
3922623SN/A        DPRINTF(Drain, "Drain count: %u\n", drainCount);
3932623SN/A        if (drainCount == 0) {
3942623SN/A            DPRINTF(Drain, "RubyPort done draining, signaling drain done\n");
3952623SN/A            signalDrainDone();
3962623SN/A        }
3972623SN/A    }
3982623SN/A}
3992623SN/A
4002623SN/ADrainState
4012623SN/ARubyPort::drain()
4024224Sgblack@eecs.umich.edu{
4034224Sgblack@eecs.umich.edu    if (isDeadlockEventScheduled()) {
4044224Sgblack@eecs.umich.edu        descheduleDeadlockEvent();
4054224Sgblack@eecs.umich.edu    }
4064224Sgblack@eecs.umich.edu
4074224Sgblack@eecs.umich.edu    //
4084224Sgblack@eecs.umich.edu    // If the RubyPort is not empty, then it needs to clear all outstanding
4094224Sgblack@eecs.umich.edu    // requests before it should call signalDrainDone()
4104224Sgblack@eecs.umich.edu    //
4114224Sgblack@eecs.umich.edu    DPRINTF(Config, "outstanding count %d\n", outstandingCount());
4122623SN/A    if (outstandingCount() > 0) {
4132623SN/A        DPRINTF(Drain, "RubyPort not drained\n");
4142623SN/A        return DrainState::Draining;
4152623SN/A    } else {
4162623SN/A        return DrainState::Drained;
4172623SN/A    }
4182623SN/A}
4192623SN/A
4202623SN/Avoid
4212623SN/ARubyPort::MemSlavePort::hitCallback(PacketPtr pkt)
4222623SN/A{
4232623SN/A    bool needsResponse = pkt->needsResponse();
4242623SN/A
4252623SN/A    // Unless specified at configuraiton, all responses except failed SC
4262623SN/A    // and Flush operations access M5 physical memory.
4272623SN/A    bool accessPhysMem = access_backing_store;
4282623SN/A
4292623SN/A    if (pkt->isLLSC()) {
4302623SN/A        if (pkt->isWrite()) {
4312623SN/A            if (pkt->req->getExtraData() != 0) {
4322623SN/A                //
4332623SN/A                // Successful SC packets convert to normal writes
4342623SN/A                //
4352623SN/A                pkt->convertScToWrite();
4362623SN/A            } else {
4372623SN/A                //
4382623SN/A                // Failed SC packets don't access physical memory and thus
4392623SN/A                // the RubyPort itself must convert it to a response.
4402623SN/A                //
4412623SN/A                accessPhysMem = false;
4422623SN/A            }
4432623SN/A        } else {
4442623SN/A            //
4452623SN/A            // All LL packets convert to normal loads so that M5 PhysMem does
4462623SN/A            // not lock the blocks.
4472623SN/A            //
4482623SN/A            pkt->convertLlToRead();
4492623SN/A        }
4502623SN/A    }
4512623SN/A
4522623SN/A    // Flush requests don't access physical memory
4532623SN/A    if (pkt->isFlush()) {
4542623SN/A        accessPhysMem = false;
4552623SN/A    }
4562623SN/A
4572623SN/A    DPRINTF(RubyPort, "Hit callback needs response %d\n", needsResponse);
4583387Sgblack@eecs.umich.edu
4593387Sgblack@eecs.umich.edu    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
4602631SN/A    RubySystem *rs = ruby_port->m_ruby_system;
4612663Sstever@eecs.umich.edu    if (accessPhysMem) {
4623170Sstever@eecs.umich.edu        rs->getPhysMem()->access(pkt);
4632662Sstever@eecs.umich.edu    } else if (needsResponse) {
4642623SN/A        pkt->makeResponse();
4654022Sstever@eecs.umich.edu    }
4662623SN/A
4672623SN/A    // turn packet around to go back to requester if response expected
4682623SN/A    if (needsResponse) {
4692630SN/A        DPRINTF(RubyPort, "Sending packet back over port\n");
4702623SN/A        // Send a response in the same cycle. There is no need to delay the
4712623SN/A        // response because the response latency is already incurred in the
4722623SN/A        // Ruby protocol.
4732623SN/A        schedTimingResp(pkt, curTick());
4742623SN/A    } else {
4752623SN/A        delete pkt;
4762623SN/A    }
4772623SN/A
4782623SN/A    DPRINTF(RubyPort, "Hit callback done!\n");
4793658Sktlim@umich.edu}
4803658Sktlim@umich.edu
4812644Sstever@eecs.umich.eduAddrRangeList
4822644Sstever@eecs.umich.eduRubyPort::PioSlavePort::getAddrRanges() const
4832623SN/A{
4843222Sktlim@umich.edu    // at the moment the assumption is that the master does not care
4853222Sktlim@umich.edu    AddrRangeList ranges;
4863222Sktlim@umich.edu    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
4872623SN/A
4882623SN/A    for (size_t i = 0; i < ruby_port->master_ports.size(); ++i) {
4892623SN/A        ranges.splice(ranges.begin(),
4902623SN/A                ruby_port->master_ports[i]->getAddrRanges());
4912644Sstever@eecs.umich.edu    }
4922623SN/A    for (const auto M5_VAR_USED &r : ranges)
4932623SN/A        DPRINTF(RubyPort, "%s\n", r.to_string());
4942623SN/A    return ranges;
4952631SN/A}
4962631SN/A
4972631SN/Abool
4982631SN/ARubyPort::MemSlavePort::isPhysMemAddress(Addr addr) const
4992631SN/A{
5002631SN/A    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
5012623SN/A    return ruby_port->system->isMemAddr(addr);
5022623SN/A}
5032623SN/A
5042623SN/Avoid
5053349Sbinkertn@umich.eduRubyPort::ruby_eviction_callback(Addr address)
5062623SN/A{
5072623SN/A    DPRINTF(RubyPort, "Sending invalidations.\n");
5082623SN/A    // This request is deleted in the stack-allocated packet destructor
5094870Sstever@eecs.umich.edu    // when this function exits
5102623SN/A    // TODO: should this really be using funcMasterId?
5112798Sktlim@umich.edu    RequestPtr req = new Request(address, 0, 0, Request::funcMasterId);
5122623SN/A    // Use a single packet to signal all snooping ports of the invalidation.
5132644Sstever@eecs.umich.edu    // This assumes that snooping ports do NOT modify the packet/request
5143222Sktlim@umich.edu    Packet pkt(req, MemCmd::InvalidateReq);
5153222Sktlim@umich.edu    for (CpuPortIter p = slave_ports.begin(); p != slave_ports.end(); ++p) {
5163222Sktlim@umich.edu        // check if the connected master port is snooping
5172839Sktlim@umich.edu        if ((*p)->isSnooping()) {
5183658Sktlim@umich.edu            // send as a snoop request
5193658Sktlim@umich.edu            (*p)->sendTimingSnoopReq(&pkt);
5203658Sktlim@umich.edu        }
5212839Sktlim@umich.edu    }
5222798Sktlim@umich.edu}
5232798Sktlim@umich.edu
5242798Sktlim@umich.eduvoid
5252623SN/ARubyPort::PioMasterPort::recvRangeChange()
5262644Sstever@eecs.umich.edu{
5272623SN/A    RubyPort &r = static_cast<RubyPort &>(owner);
5282623SN/A    r.gotAddrRanges--;
5293170Sstever@eecs.umich.edu    if (r.gotAddrRanges == 0 && FullSystem) {
5303170Sstever@eecs.umich.edu        r.pioSlavePort.sendRangeChange();
5313170Sstever@eecs.umich.edu    }
5323170Sstever@eecs.umich.edu}
5332644Sstever@eecs.umich.edu