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