RubyPort.cc revision 8436
113531Sjairo.balart@metempsy.com/*
213531Sjairo.balart@metempsy.com * Copyright (c) 2009 Advanced Micro Devices, Inc.
313531Sjairo.balart@metempsy.com * All rights reserved.
413531Sjairo.balart@metempsy.com *
513531Sjairo.balart@metempsy.com * Redistribution and use in source and binary forms, with or without
613531Sjairo.balart@metempsy.com * modification, are permitted provided that the following conditions are
713531Sjairo.balart@metempsy.com * met: redistributions of source code must retain the above copyright
813531Sjairo.balart@metempsy.com * notice, this list of conditions and the following disclaimer;
913531Sjairo.balart@metempsy.com * redistributions in binary form must reproduce the above copyright
1013531Sjairo.balart@metempsy.com * notice, this list of conditions and the following disclaimer in the
1113531Sjairo.balart@metempsy.com * documentation and/or other materials provided with the distribution;
1213531Sjairo.balart@metempsy.com * neither the name of the copyright holders nor the names of its
1313531Sjairo.balart@metempsy.com * contributors may be used to endorse or promote products derived from
1413531Sjairo.balart@metempsy.com * this software without specific prior written permission.
1513531Sjairo.balart@metempsy.com *
1613531Sjairo.balart@metempsy.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1713531Sjairo.balart@metempsy.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1813531Sjairo.balart@metempsy.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1913531Sjairo.balart@metempsy.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2013531Sjairo.balart@metempsy.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2113531Sjairo.balart@metempsy.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2213531Sjairo.balart@metempsy.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2313531Sjairo.balart@metempsy.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2413531Sjairo.balart@metempsy.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2513531Sjairo.balart@metempsy.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2613531Sjairo.balart@metempsy.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2713531Sjairo.balart@metempsy.com */
2813531Sjairo.balart@metempsy.com
2913531Sjairo.balart@metempsy.com#include "config/the_isa.hh"
3013531Sjairo.balart@metempsy.com#if THE_ISA == X86_ISA
3113531Sjairo.balart@metempsy.com#include "arch/x86/insts/microldstop.hh"
3213531Sjairo.balart@metempsy.com#endif // X86_ISA
3313531Sjairo.balart@metempsy.com#include "cpu/testers/rubytest/RubyTester.hh"
3413531Sjairo.balart@metempsy.com#include "debug/Ruby.hh"
3513531Sjairo.balart@metempsy.com#include "mem/protocol/AccessPermission.hh"
3613531Sjairo.balart@metempsy.com#include "mem/ruby/slicc_interface/AbstractController.hh"
3713531Sjairo.balart@metempsy.com#include "mem/ruby/system/RubyPort.hh"
3813531Sjairo.balart@metempsy.com#include "mem/physical.hh"
3913531Sjairo.balart@metempsy.com
4013531Sjairo.balart@metempsy.comRubyPort::RubyPort(const Params *p)
4113531Sjairo.balart@metempsy.com    : MemObject(p)
4213531Sjairo.balart@metempsy.com{
4313531Sjairo.balart@metempsy.com    m_version = p->version;
4413531Sjairo.balart@metempsy.com    assert(m_version != -1);
4513531Sjairo.balart@metempsy.com
4613531Sjairo.balart@metempsy.com    physmem = p->physmem;
4713531Sjairo.balart@metempsy.com
4813531Sjairo.balart@metempsy.com    m_controller = NULL;
4913531Sjairo.balart@metempsy.com    m_mandatory_q_ptr = NULL;
5013531Sjairo.balart@metempsy.com
5113531Sjairo.balart@metempsy.com    m_request_cnt = 0;
5213531Sjairo.balart@metempsy.com    pio_port = NULL;
5313531Sjairo.balart@metempsy.com    physMemPort = NULL;
5413531Sjairo.balart@metempsy.com
5513531Sjairo.balart@metempsy.com    m_usingRubyTester = p->using_ruby_tester;
5613531Sjairo.balart@metempsy.com    access_phys_mem = p->access_phys_mem;
5713531Sjairo.balart@metempsy.com
5813531Sjairo.balart@metempsy.com    ruby_system = p->ruby_system;
5913531Sjairo.balart@metempsy.com}
6013531Sjairo.balart@metempsy.com
6113531Sjairo.balart@metempsy.comvoid
6213531Sjairo.balart@metempsy.comRubyPort::init()
6313531Sjairo.balart@metempsy.com{
6413531Sjairo.balart@metempsy.com    assert(m_controller != NULL);
6513531Sjairo.balart@metempsy.com    m_mandatory_q_ptr = m_controller->getMandatoryQueue();
6613531Sjairo.balart@metempsy.com}
6713531Sjairo.balart@metempsy.com
6813760Sjairo.balart@metempsy.comPort *
6913531Sjairo.balart@metempsy.comRubyPort::getPort(const std::string &if_name, int idx)
7013531Sjairo.balart@metempsy.com{
7113531Sjairo.balart@metempsy.com    if (if_name == "port") {
7213531Sjairo.balart@metempsy.com        return new M5Port(csprintf("%s-port%d", name(), idx), this,
7313531Sjairo.balart@metempsy.com                          ruby_system, access_phys_mem);
7413531Sjairo.balart@metempsy.com    }
7513531Sjairo.balart@metempsy.com
7613531Sjairo.balart@metempsy.com    if (if_name == "pio_port") {
7713531Sjairo.balart@metempsy.com        // ensure there is only one pio port
7813531Sjairo.balart@metempsy.com        assert(pio_port == NULL);
7913531Sjairo.balart@metempsy.com
8013531Sjairo.balart@metempsy.com        pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx), this);
8113531Sjairo.balart@metempsy.com
8213760Sjairo.balart@metempsy.com        return pio_port;
8313531Sjairo.balart@metempsy.com    }
8413531Sjairo.balart@metempsy.com
8513531Sjairo.balart@metempsy.com    if (if_name == "physMemPort") {
8613531Sjairo.balart@metempsy.com        // RubyPort should only have one port to physical memory
8713531Sjairo.balart@metempsy.com        assert (physMemPort == NULL);
8813531Sjairo.balart@metempsy.com
8913531Sjairo.balart@metempsy.com        physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this,
9013531Sjairo.balart@metempsy.com                                 ruby_system, access_phys_mem);
9113531Sjairo.balart@metempsy.com
9213531Sjairo.balart@metempsy.com        return physMemPort;
9313531Sjairo.balart@metempsy.com    }
9413531Sjairo.balart@metempsy.com
9513580Sgabeblack@google.com    if (if_name == "functional") {
9613531Sjairo.balart@metempsy.com        // Calls for the functional port only want to access
9713531Sjairo.balart@metempsy.com        // functional memory.  Therefore, directly pass these calls
9813580Sgabeblack@google.com        // ports to physmem.
9913531Sjairo.balart@metempsy.com        assert(physmem != NULL);
10013531Sjairo.balart@metempsy.com        return physmem->getPort(if_name, idx);
10113531Sjairo.balart@metempsy.com    }
10213531Sjairo.balart@metempsy.com
10313760Sjairo.balart@metempsy.com    return NULL;
10413531Sjairo.balart@metempsy.com}
10513531Sjairo.balart@metempsy.com
10613531Sjairo.balart@metempsy.comRubyPort::PioPort::PioPort(const std::string &_name,
10713531Sjairo.balart@metempsy.com                           RubyPort *_port)
10813531Sjairo.balart@metempsy.com    : SimpleTimingPort(_name, _port)
10913531Sjairo.balart@metempsy.com{
11013531Sjairo.balart@metempsy.com    DPRINTF(RubyPort, "creating port to ruby sequencer to cpu %s\n", _name);
11113531Sjairo.balart@metempsy.com    ruby_port = _port;
11213531Sjairo.balart@metempsy.com}
11313531Sjairo.balart@metempsy.com
11413531Sjairo.balart@metempsy.comRubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port,
11513531Sjairo.balart@metempsy.com                         RubySystem *_system, bool _access_phys_mem)
11613531Sjairo.balart@metempsy.com    : SimpleTimingPort(_name, _port)
11713531Sjairo.balart@metempsy.com{
11813531Sjairo.balart@metempsy.com    DPRINTF(RubyPort, "creating port from ruby sequcner to cpu %s\n", _name);
11913531Sjairo.balart@metempsy.com    ruby_port = _port;
12013531Sjairo.balart@metempsy.com    ruby_system = _system;
12113531Sjairo.balart@metempsy.com    _onRetryList = false;
12213531Sjairo.balart@metempsy.com    access_phys_mem = _access_phys_mem;
12313531Sjairo.balart@metempsy.com}
12413531Sjairo.balart@metempsy.com
12513531Sjairo.balart@metempsy.comTick
12613760Sjairo.balart@metempsy.comRubyPort::PioPort::recvAtomic(PacketPtr pkt)
12713531Sjairo.balart@metempsy.com{
12813531Sjairo.balart@metempsy.com    panic("RubyPort::PioPort::recvAtomic() not implemented!\n");
12913531Sjairo.balart@metempsy.com    return 0;
13013531Sjairo.balart@metempsy.com}
13113531Sjairo.balart@metempsy.com
13213531Sjairo.balart@metempsy.comTick
13313531Sjairo.balart@metempsy.comRubyPort::M5Port::recvAtomic(PacketPtr pkt)
13413531Sjairo.balart@metempsy.com{
13513531Sjairo.balart@metempsy.com    panic("RubyPort::M5Port::recvAtomic() not implemented!\n");
13613531Sjairo.balart@metempsy.com    return 0;
13713531Sjairo.balart@metempsy.com}
13813531Sjairo.balart@metempsy.com
13913531Sjairo.balart@metempsy.com
14013531Sjairo.balart@metempsy.combool
14113531Sjairo.balart@metempsy.comRubyPort::PioPort::recvTiming(PacketPtr pkt)
14213531Sjairo.balart@metempsy.com{
14313531Sjairo.balart@metempsy.com    // In FS mode, ruby memory will receive pio responses from devices
14413531Sjairo.balart@metempsy.com    // and it must forward these responses back to the particular CPU.
14513531Sjairo.balart@metempsy.com    DPRINTF(RubyPort,  "Pio response for address %#x\n", pkt->getAddr());
14613531Sjairo.balart@metempsy.com
14713531Sjairo.balart@metempsy.com    assert(pkt->isResponse());
14813531Sjairo.balart@metempsy.com
14913760Sjairo.balart@metempsy.com    // First we must retrieve the request port from the sender State
15013531Sjairo.balart@metempsy.com    RubyPort::SenderState *senderState =
15113531Sjairo.balart@metempsy.com      safe_cast<RubyPort::SenderState *>(pkt->senderState);
15213531Sjairo.balart@metempsy.com    M5Port *port = senderState->port;
15313760Sjairo.balart@metempsy.com    assert(port != NULL);
15413531Sjairo.balart@metempsy.com
15513531Sjairo.balart@metempsy.com    // pop the sender state from the packet
15613531Sjairo.balart@metempsy.com    pkt->senderState = senderState->saved;
15713531Sjairo.balart@metempsy.com    delete senderState;
15813531Sjairo.balart@metempsy.com
15913760Sjairo.balart@metempsy.com    port->sendTiming(pkt);
16013531Sjairo.balart@metempsy.com
16113531Sjairo.balart@metempsy.com    return true;
16213531Sjairo.balart@metempsy.com}
16313760Sjairo.balart@metempsy.com
16413531Sjairo.balart@metempsy.combool
16513531Sjairo.balart@metempsy.comRubyPort::M5Port::recvTiming(PacketPtr pkt)
16613531Sjairo.balart@metempsy.com{
16713531Sjairo.balart@metempsy.com    DPRINTF(RubyPort,
16813531Sjairo.balart@metempsy.com            "Timing access caught for address %#x\n", pkt->getAddr());
16913760Sjairo.balart@metempsy.com
17013760Sjairo.balart@metempsy.com    //dsm: based on SimpleTimingPort::recvTiming(pkt);
17113760Sjairo.balart@metempsy.com
17213739Sgiacomo.travaglini@arm.com    // The received packets should only be M5 requests, which should never
17313760Sjairo.balart@metempsy.com    // get nacked.  There used to be code to hanldle nacks here, but
17413760Sjairo.balart@metempsy.com    // I'm pretty sure it didn't work correctly with the drain code,
17513531Sjairo.balart@metempsy.com    // so that would need to be fixed if we ever added it back.
17613531Sjairo.balart@metempsy.com    assert(pkt->isRequest());
17713531Sjairo.balart@metempsy.com
17813760Sjairo.balart@metempsy.com    if (pkt->memInhibitAsserted()) {
17913531Sjairo.balart@metempsy.com        warn("memInhibitAsserted???");
18013531Sjairo.balart@metempsy.com        // snooper will supply based on copy of packet
18113531Sjairo.balart@metempsy.com        // still target's responsibility to delete packet
18213531Sjairo.balart@metempsy.com        delete pkt;
18313531Sjairo.balart@metempsy.com        return true;
18413531Sjairo.balart@metempsy.com    }
18513760Sjairo.balart@metempsy.com
18613760Sjairo.balart@metempsy.com    // Save the port in the sender state object to be used later to
18713760Sjairo.balart@metempsy.com    // route the response
18813531Sjairo.balart@metempsy.com    pkt->senderState = new SenderState(this, pkt->senderState);
18913760Sjairo.balart@metempsy.com
19013760Sjairo.balart@metempsy.com    // Check for pio requests and directly send them to the dedicated
19113531Sjairo.balart@metempsy.com    // pio port.
19213531Sjairo.balart@metempsy.com    if (!isPhysMemAddress(pkt->getAddr())) {
19313760Sjairo.balart@metempsy.com        assert(ruby_port->pio_port != NULL);
19413760Sjairo.balart@metempsy.com        DPRINTF(RubyPort,
19513760Sjairo.balart@metempsy.com                "Request for address 0x%#x is assumed to be a pio request\n",
19613531Sjairo.balart@metempsy.com                pkt->getAddr());
19713531Sjairo.balart@metempsy.com
19813531Sjairo.balart@metempsy.com        return ruby_port->pio_port->sendTiming(pkt);
19913531Sjairo.balart@metempsy.com    }
20013531Sjairo.balart@metempsy.com
20113531Sjairo.balart@metempsy.com    // For DMA and CPU requests, translate them to ruby requests before
20213531Sjairo.balart@metempsy.com    // sending them to our assigned ruby port.
20313531Sjairo.balart@metempsy.com    RubyRequestType type = RubyRequestType_NULL;
20413760Sjairo.balart@metempsy.com
20513531Sjairo.balart@metempsy.com    // If valid, copy the pc to the ruby request
20613531Sjairo.balart@metempsy.com    Addr pc = 0;
20713531Sjairo.balart@metempsy.com    if (pkt->req->hasPC()) {
20813531Sjairo.balart@metempsy.com        pc = pkt->req->getPC();
20913531Sjairo.balart@metempsy.com    }
21013760Sjairo.balart@metempsy.com
21113531Sjairo.balart@metempsy.com    if (pkt->isLLSC()) {
21213531Sjairo.balart@metempsy.com        if (pkt->isWrite()) {
21313531Sjairo.balart@metempsy.com            DPRINTF(RubyPort, "Issuing SC\n");
21413531Sjairo.balart@metempsy.com            type = RubyRequestType_Store_Conditional;
21513531Sjairo.balart@metempsy.com        } else {
21613531Sjairo.balart@metempsy.com            DPRINTF(RubyPort, "Issuing LL\n");
21713531Sjairo.balart@metempsy.com            assert(pkt->isRead());
21813531Sjairo.balart@metempsy.com            type = RubyRequestType_Load_Linked;
21913531Sjairo.balart@metempsy.com        }
22013531Sjairo.balart@metempsy.com    } else if (pkt->req->isLocked()) {
22113760Sjairo.balart@metempsy.com        if (pkt->isWrite()) {
22213531Sjairo.balart@metempsy.com            DPRINTF(RubyPort, "Issuing Locked RMW Write\n");
22313531Sjairo.balart@metempsy.com            type = RubyRequestType_Locked_RMW_Write;
22413531Sjairo.balart@metempsy.com        } else {
22513531Sjairo.balart@metempsy.com            DPRINTF(RubyPort, "Issuing Locked RMW Read\n");
22613531Sjairo.balart@metempsy.com            assert(pkt->isRead());
22713760Sjairo.balart@metempsy.com            type = RubyRequestType_Locked_RMW_Read;
22813531Sjairo.balart@metempsy.com        }
22913531Sjairo.balart@metempsy.com    } else {
23013760Sjairo.balart@metempsy.com        if (pkt->isRead()) {
23113531Sjairo.balart@metempsy.com            if (pkt->req->isInstFetch()) {
23213531Sjairo.balart@metempsy.com                type = RubyRequestType_IFETCH;
23313760Sjairo.balart@metempsy.com            } else {
23413531Sjairo.balart@metempsy.com#if THE_ISA == X86_ISA
23513531Sjairo.balart@metempsy.com                uint32_t flags = pkt->req->getFlags();
23613531Sjairo.balart@metempsy.com                bool storeCheck = flags &
23713531Sjairo.balart@metempsy.com                        (TheISA::StoreCheck << TheISA::FlagShift);
23813531Sjairo.balart@metempsy.com#else
23913531Sjairo.balart@metempsy.com                bool storeCheck = false;
24013760Sjairo.balart@metempsy.com#endif // X86_ISA
24113531Sjairo.balart@metempsy.com                if (storeCheck) {
24213531Sjairo.balart@metempsy.com                    type = RubyRequestType_RMW_Read;
24313531Sjairo.balart@metempsy.com                } else {
24413531Sjairo.balart@metempsy.com                    type = RubyRequestType_LD;
24513531Sjairo.balart@metempsy.com                }
24613531Sjairo.balart@metempsy.com            }
24713531Sjairo.balart@metempsy.com        } else if (pkt->isWrite()) {
24813531Sjairo.balart@metempsy.com            //
24913531Sjairo.balart@metempsy.com            // Note: M5 packets do not differentiate ST from RMW_Write
25013531Sjairo.balart@metempsy.com            //
25113760Sjairo.balart@metempsy.com            type = RubyRequestType_ST;
25213531Sjairo.balart@metempsy.com        } else if (pkt->isFlush()) {
25313531Sjairo.balart@metempsy.com            type = RubyRequestType_FLUSH;
25413531Sjairo.balart@metempsy.com        } else {
25513531Sjairo.balart@metempsy.com            panic("Unsupported ruby packet type\n");
25613531Sjairo.balart@metempsy.com        }
25713760Sjairo.balart@metempsy.com    }
25813531Sjairo.balart@metempsy.com
25913531Sjairo.balart@metempsy.com    RubyRequest ruby_request(pkt->getAddr(), pkt->getPtr<uint8_t>(true),
26013760Sjairo.balart@metempsy.com                             pkt->getSize(), pc, type,
26113531Sjairo.balart@metempsy.com                             RubyAccessMode_Supervisor, pkt);
26213531Sjairo.balart@metempsy.com
26313760Sjairo.balart@metempsy.com    assert(ruby_request.m_PhysicalAddress.getOffset() + ruby_request.m_Size <=
26413531Sjairo.balart@metempsy.com        RubySystem::getBlockSizeBytes());
26513531Sjairo.balart@metempsy.com
26613531Sjairo.balart@metempsy.com    // Submit the ruby request
26713531Sjairo.balart@metempsy.com    RequestStatus requestStatus = ruby_port->makeRequest(ruby_request);
26813531Sjairo.balart@metempsy.com
26913531Sjairo.balart@metempsy.com    // If the request successfully issued then we should return true.
27013760Sjairo.balart@metempsy.com    // Otherwise, we need to delete the senderStatus we just created and return
27113531Sjairo.balart@metempsy.com    // false.
27213531Sjairo.balart@metempsy.com    if (requestStatus == RequestStatus_Issued) {
27313531Sjairo.balart@metempsy.com        DPRINTF(RubyPort, "Request %#x issued\n", pkt->getAddr());
27413531Sjairo.balart@metempsy.com        return true;
27513531Sjairo.balart@metempsy.com    }
27613531Sjairo.balart@metempsy.com
27713531Sjairo.balart@metempsy.com    //
27813531Sjairo.balart@metempsy.com    // Unless one is using the ruby tester, record the stalled M5 port for
27913760Sjairo.balart@metempsy.com    // later retry when the sequencer becomes free.
28013531Sjairo.balart@metempsy.com    //
28113760Sjairo.balart@metempsy.com    if (!ruby_port->m_usingRubyTester) {
28213760Sjairo.balart@metempsy.com        ruby_port->addToRetryList(this);
28313760Sjairo.balart@metempsy.com    }
28413760Sjairo.balart@metempsy.com
28513760Sjairo.balart@metempsy.com    DPRINTF(RubyPort,
28613531Sjairo.balart@metempsy.com            "Request for address %#x did not issue because %s\n",
28713531Sjairo.balart@metempsy.com            pkt->getAddr(), RequestStatus_to_string(requestStatus));
28813531Sjairo.balart@metempsy.com
28913531Sjairo.balart@metempsy.com    SenderState* senderState = safe_cast<SenderState*>(pkt->senderState);
29013531Sjairo.balart@metempsy.com    pkt->senderState = senderState->saved;
29113531Sjairo.balart@metempsy.com    delete senderState;
29213531Sjairo.balart@metempsy.com    return false;
29313760Sjairo.balart@metempsy.com}
29413760Sjairo.balart@metempsy.com
29513760Sjairo.balart@metempsy.combool
29613760Sjairo.balart@metempsy.comRubyPort::M5Port::doFunctionalRead(PacketPtr pkt)
29713760Sjairo.balart@metempsy.com{
29813531Sjairo.balart@metempsy.com    Address address(pkt->getAddr());
29913531Sjairo.balart@metempsy.com    Address line_address(address);
30013531Sjairo.balart@metempsy.com    line_address.makeLineAddress();
30113531Sjairo.balart@metempsy.com
30213531Sjairo.balart@metempsy.com    AccessPermission accessPerm = AccessPermission_NotPresent;
30313760Sjairo.balart@metempsy.com    int num_controllers = ruby_system->m_abs_cntrl_vec.size();
30413760Sjairo.balart@metempsy.com
30513760Sjairo.balart@metempsy.com    // In this loop, we try to figure which controller has a read only or
30613760Sjairo.balart@metempsy.com    // a read write copy of the given address. Any valid copy would suffice
30713760Sjairo.balart@metempsy.com    // for a functional read.
30813531Sjairo.balart@metempsy.com
30913531Sjairo.balart@metempsy.com    DPRINTF(RubyPort, "Functional Read request for %s\n",address);
31013531Sjairo.balart@metempsy.com    for(int i = 0;i < num_controllers;++i)
31113531Sjairo.balart@metempsy.com    {
31213531Sjairo.balart@metempsy.com        accessPerm = ruby_system->m_abs_cntrl_vec[i]
31313531Sjairo.balart@metempsy.com                                          ->getAccessPermission(line_address);
31413531Sjairo.balart@metempsy.com        if(accessPerm == AccessPermission_Read_Only ||
31513531Sjairo.balart@metempsy.com           accessPerm == AccessPermission_Read_Write)
31613531Sjairo.balart@metempsy.com        {
31713531Sjairo.balart@metempsy.com            unsigned startByte = address.getAddress() - line_address.getAddress();
31813531Sjairo.balart@metempsy.com
31913531Sjairo.balart@metempsy.com            uint8* data = pkt->getPtr<uint8_t>(true);
32013531Sjairo.balart@metempsy.com            unsigned int size_in_bytes = pkt->getSize();
32113531Sjairo.balart@metempsy.com            DataBlock& block = ruby_system->m_abs_cntrl_vec[i]
32213531Sjairo.balart@metempsy.com                                                 ->getDataBlock(line_address);
32313531Sjairo.balart@metempsy.com
32413531Sjairo.balart@metempsy.com            DPRINTF(RubyPort, "reading from %s block %s\n",
32513531Sjairo.balart@metempsy.com                    ruby_system->m_abs_cntrl_vec[i]->name(), block);
32613531Sjairo.balart@metempsy.com            for (unsigned i = 0; i < size_in_bytes; ++i)
32713531Sjairo.balart@metempsy.com            {
32813531Sjairo.balart@metempsy.com                data[i] = block.getByte(i + startByte);
32913531Sjairo.balart@metempsy.com            }
33013531Sjairo.balart@metempsy.com            return true;
33113760Sjairo.balart@metempsy.com        }
33213760Sjairo.balart@metempsy.com    }
33313760Sjairo.balart@metempsy.com    return false;
33413531Sjairo.balart@metempsy.com}
33513531Sjairo.balart@metempsy.com
33613531Sjairo.balart@metempsy.combool
33713531Sjairo.balart@metempsy.comRubyPort::M5Port::doFunctionalWrite(PacketPtr pkt)
33813760Sjairo.balart@metempsy.com{
33913531Sjairo.balart@metempsy.com    Address addr(pkt->getAddr());
34013531Sjairo.balart@metempsy.com    Address line_addr = line_address(addr);
34113531Sjairo.balart@metempsy.com    AccessPermission accessPerm = AccessPermission_NotPresent;
34213760Sjairo.balart@metempsy.com    int num_controllers = ruby_system->m_abs_cntrl_vec.size();
34313760Sjairo.balart@metempsy.com
34413531Sjairo.balart@metempsy.com    DPRINTF(RubyPort, "Functional Write request for %s\n",addr);
34513531Sjairo.balart@metempsy.com
34613531Sjairo.balart@metempsy.com    unsigned int num_ro = 0;
34713531Sjairo.balart@metempsy.com    unsigned int num_rw = 0;
34813531Sjairo.balart@metempsy.com    unsigned int num_busy = 0;
34913531Sjairo.balart@metempsy.com
35013531Sjairo.balart@metempsy.com    // In this loop we count the number of controllers that have the given
35113760Sjairo.balart@metempsy.com    // address in read only, read write and busy states.
35213531Sjairo.balart@metempsy.com    for(int i = 0;i < num_controllers;++i)
35313760Sjairo.balart@metempsy.com    {
35413531Sjairo.balart@metempsy.com        accessPerm = ruby_system->m_abs_cntrl_vec[i]->
35513531Sjairo.balart@metempsy.com                                            getAccessPermission(line_addr);
35613531Sjairo.balart@metempsy.com        if(accessPerm == AccessPermission_Read_Only) num_ro++;
35713531Sjairo.balart@metempsy.com        else if(accessPerm == AccessPermission_Read_Write) num_rw++;
35813531Sjairo.balart@metempsy.com        else if(accessPerm == AccessPermission_Busy) num_busy++;
35913531Sjairo.balart@metempsy.com    }
36013531Sjairo.balart@metempsy.com
36113531Sjairo.balart@metempsy.com    // If the number of read write copies is more than 1, then there is bug in
36213531Sjairo.balart@metempsy.com    // coherence protocol. Otherwise, if all copies are in stable states, i.e.
36313531Sjairo.balart@metempsy.com    // num_busy == 0, we update all the copies. If there is at least one copy
36413531Sjairo.balart@metempsy.com    // in busy state, then we check if there is read write copy. If yes, then
36513531Sjairo.balart@metempsy.com    // also we let the access go through.
36613531Sjairo.balart@metempsy.com
36713531Sjairo.balart@metempsy.com    DPRINTF(RubyPort, "num_busy = %d, num_ro = %d, num_rw = %d\n",
36813760Sjairo.balart@metempsy.com            num_busy, num_ro, num_rw);
36913531Sjairo.balart@metempsy.com    assert(num_rw <= 1);
37013760Sjairo.balart@metempsy.com    if((num_busy == 0 && num_ro > 0) || num_rw == 1)
37113760Sjairo.balart@metempsy.com    {
37213760Sjairo.balart@metempsy.com        uint8* data = pkt->getPtr<uint8_t>(true);
37313531Sjairo.balart@metempsy.com        unsigned int size_in_bytes = pkt->getSize();
37413531Sjairo.balart@metempsy.com        unsigned startByte = addr.getAddress() - line_addr.getAddress();
37513531Sjairo.balart@metempsy.com
37613760Sjairo.balart@metempsy.com        for(int i = 0; i < num_controllers;++i)
37713760Sjairo.balart@metempsy.com        {
37813760Sjairo.balart@metempsy.com            accessPerm = ruby_system->m_abs_cntrl_vec[i]->
37913531Sjairo.balart@metempsy.com                                                getAccessPermission(line_addr);
38013760Sjairo.balart@metempsy.com            if(accessPerm == AccessPermission_Read_Only ||
38113760Sjairo.balart@metempsy.com               accessPerm == AccessPermission_Read_Write||
38213531Sjairo.balart@metempsy.com               accessPerm == AccessPermission_Maybe_Stale)
38313531Sjairo.balart@metempsy.com            {
38413760Sjairo.balart@metempsy.com                DataBlock& block = ruby_system->m_abs_cntrl_vec[i]
38513760Sjairo.balart@metempsy.com                                                      ->getDataBlock(line_addr);
38613760Sjairo.balart@metempsy.com
38713531Sjairo.balart@metempsy.com                DPRINTF(RubyPort, "%s\n",block);
38813531Sjairo.balart@metempsy.com                for (unsigned i = 0; i < size_in_bytes; ++i)
38913531Sjairo.balart@metempsy.com                {
39013531Sjairo.balart@metempsy.com                  block.setByte(i + startByte, data[i]);
39113531Sjairo.balart@metempsy.com                }
39213531Sjairo.balart@metempsy.com                DPRINTF(RubyPort, "%s\n",block);
39313760Sjairo.balart@metempsy.com            }
39413531Sjairo.balart@metempsy.com        }
39513760Sjairo.balart@metempsy.com        return true;
39613531Sjairo.balart@metempsy.com    }
39713531Sjairo.balart@metempsy.com    return false;
39813531Sjairo.balart@metempsy.com}
39913531Sjairo.balart@metempsy.com
40013531Sjairo.balart@metempsy.comvoid
40113531Sjairo.balart@metempsy.comRubyPort::M5Port::recvFunctional(PacketPtr pkt)
40213531Sjairo.balart@metempsy.com{
40313531Sjairo.balart@metempsy.com    DPRINTF(RubyPort, "Functional access caught for address %#x\n",
40413531Sjairo.balart@metempsy.com                                                           pkt->getAddr());
40513531Sjairo.balart@metempsy.com
40613531Sjairo.balart@metempsy.com    // Check for pio requests and directly send them to the dedicated
40713531Sjairo.balart@metempsy.com    // pio port.
40813531Sjairo.balart@metempsy.com    if (!isPhysMemAddress(pkt->getAddr())) {
40913531Sjairo.balart@metempsy.com        assert(ruby_port->pio_port != NULL);
41013531Sjairo.balart@metempsy.com        DPRINTF(RubyPort, "Request for address 0x%#x is a pio request\n",
41113531Sjairo.balart@metempsy.com                                                           pkt->getAddr());
41213531Sjairo.balart@metempsy.com        panic("RubyPort::PioPort::recvFunctional() not implemented!\n");
41313531Sjairo.balart@metempsy.com    }
41413531Sjairo.balart@metempsy.com
41513531Sjairo.balart@metempsy.com    assert(pkt->getAddr() + pkt->getSize() <=
41613531Sjairo.balart@metempsy.com                line_address(Address(pkt->getAddr())).getAddress() +
41713760Sjairo.balart@metempsy.com                RubySystem::getBlockSizeBytes());
41813531Sjairo.balart@metempsy.com
41913531Sjairo.balart@metempsy.com    bool accessSucceeded = false;
42013531Sjairo.balart@metempsy.com    bool needsResponse = pkt->needsResponse();
42113531Sjairo.balart@metempsy.com
42213531Sjairo.balart@metempsy.com    // Do the functional access on ruby memory
42313760Sjairo.balart@metempsy.com    if (pkt->isRead()) {
42413531Sjairo.balart@metempsy.com        accessSucceeded = doFunctionalRead(pkt);
42513531Sjairo.balart@metempsy.com    } else if (pkt->isWrite()) {
42613760Sjairo.balart@metempsy.com        accessSucceeded = doFunctionalWrite(pkt);
42713760Sjairo.balart@metempsy.com    } else {
42813531Sjairo.balart@metempsy.com        panic("RubyPort: unsupported functional command %s\n",
42913531Sjairo.balart@metempsy.com              pkt->cmdString());
43013760Sjairo.balart@metempsy.com    }
43113531Sjairo.balart@metempsy.com
43213531Sjairo.balart@metempsy.com    // Unless the requester explicitly said otherwise, generate an error if
43313531Sjairo.balart@metempsy.com    // the functional request failed
43413531Sjairo.balart@metempsy.com    if (!accessSucceeded && !pkt->suppressFuncError()) {
43513531Sjairo.balart@metempsy.com        fatal("Ruby functional %s failed for address %#x\n",
43613760Sjairo.balart@metempsy.com              pkt->isWrite() ? "write" : "read", pkt->getAddr());
43713531Sjairo.balart@metempsy.com    }
43813760Sjairo.balart@metempsy.com
43913531Sjairo.balart@metempsy.com    if (access_phys_mem) {
44013531Sjairo.balart@metempsy.com        // The attached physmem contains the official version of data.
44113531Sjairo.balart@metempsy.com        // The following command performs the real functional access.
44213531Sjairo.balart@metempsy.com        // This line should be removed once Ruby supplies the official version
44313531Sjairo.balart@metempsy.com        // of data.
44413531Sjairo.balart@metempsy.com        ruby_port->physMemPort->sendFunctional(pkt);
44513531Sjairo.balart@metempsy.com    }
44613531Sjairo.balart@metempsy.com
44713531Sjairo.balart@metempsy.com    // turn packet around to go back to requester if response expected
44813760Sjairo.balart@metempsy.com    if (needsResponse) {
44913531Sjairo.balart@metempsy.com        pkt->setFunctionalResponseStatus(accessSucceeded);
45013760Sjairo.balart@metempsy.com        DPRINTF(RubyPort, "Sending packet back over port\n");
45113531Sjairo.balart@metempsy.com        sendFunctional(pkt);
45213531Sjairo.balart@metempsy.com    }
45313531Sjairo.balart@metempsy.com    DPRINTF(RubyPort, "Functional access %s!\n",
45413531Sjairo.balart@metempsy.com            accessSucceeded ? "successful":"failed");
45513531Sjairo.balart@metempsy.com}
45613531Sjairo.balart@metempsy.com
45713531Sjairo.balart@metempsy.comvoid
45813531Sjairo.balart@metempsy.comRubyPort::ruby_hit_callback(PacketPtr pkt)
45913531Sjairo.balart@metempsy.com{
46013531Sjairo.balart@metempsy.com    // Retrieve the request port from the sender State
46113531Sjairo.balart@metempsy.com    RubyPort::SenderState *senderState =
46213531Sjairo.balart@metempsy.com        safe_cast<RubyPort::SenderState *>(pkt->senderState);
46313531Sjairo.balart@metempsy.com    M5Port *port = senderState->port;
46413531Sjairo.balart@metempsy.com    assert(port != NULL);
46513531Sjairo.balart@metempsy.com
46613531Sjairo.balart@metempsy.com    // pop the sender state from the packet
46713531Sjairo.balart@metempsy.com    pkt->senderState = senderState->saved;
46813531Sjairo.balart@metempsy.com    delete senderState;
46913531Sjairo.balart@metempsy.com
47013531Sjairo.balart@metempsy.com    port->hitCallback(pkt);
47113531Sjairo.balart@metempsy.com
47213760Sjairo.balart@metempsy.com    //
47313531Sjairo.balart@metempsy.com    // If we had to stall the M5Ports, wake them up because the sequencer
47413531Sjairo.balart@metempsy.com    // likely has free resources now.
47513531Sjairo.balart@metempsy.com    //
47613531Sjairo.balart@metempsy.com    if (waitingOnSequencer) {
47713531Sjairo.balart@metempsy.com        //
47813760Sjairo.balart@metempsy.com        // Record the current list of ports to retry on a temporary list before
47913531Sjairo.balart@metempsy.com        // calling sendRetry on those ports.  sendRetry will cause an
48013531Sjairo.balart@metempsy.com        // immediate retry, which may result in the ports being put back on the
48113760Sjairo.balart@metempsy.com        // list. Therefore we want to clear the retryList before calling
48213760Sjairo.balart@metempsy.com        // sendRetry.
48313531Sjairo.balart@metempsy.com        //
48413531Sjairo.balart@metempsy.com        std::list<M5Port*> curRetryList(retryList);
48513760Sjairo.balart@metempsy.com
48613531Sjairo.balart@metempsy.com        retryList.clear();
48713531Sjairo.balart@metempsy.com        waitingOnSequencer = false;
48813531Sjairo.balart@metempsy.com
48913531Sjairo.balart@metempsy.com        for (std::list<M5Port*>::iterator i = curRetryList.begin();
49013531Sjairo.balart@metempsy.com             i != curRetryList.end(); ++i) {
49113760Sjairo.balart@metempsy.com            DPRINTF(RubyPort,
49213531Sjairo.balart@metempsy.com                    "Sequencer may now be free.  SendRetry to port %s\n",
49313760Sjairo.balart@metempsy.com                    (*i)->name());
49413531Sjairo.balart@metempsy.com            (*i)->onRetryList(false);
49513531Sjairo.balart@metempsy.com            (*i)->sendRetry();
49613531Sjairo.balart@metempsy.com        }
49713531Sjairo.balart@metempsy.com    }
49813531Sjairo.balart@metempsy.com}
49913531Sjairo.balart@metempsy.com
50013531Sjairo.balart@metempsy.comvoid
50113531Sjairo.balart@metempsy.comRubyPort::M5Port::hitCallback(PacketPtr pkt)
50213531Sjairo.balart@metempsy.com{
50313760Sjairo.balart@metempsy.com    bool needsResponse = pkt->needsResponse();
50413531Sjairo.balart@metempsy.com
50513760Sjairo.balart@metempsy.com    //
50613531Sjairo.balart@metempsy.com    // Unless specified at configuraiton, all responses except failed SC
50713531Sjairo.balart@metempsy.com    // and Flush operations access M5 physical memory.
50813531Sjairo.balart@metempsy.com    //
50913531Sjairo.balart@metempsy.com    bool accessPhysMem = access_phys_mem;
51013531Sjairo.balart@metempsy.com
51113760Sjairo.balart@metempsy.com    if (pkt->isLLSC()) {
51213760Sjairo.balart@metempsy.com        if (pkt->isWrite()) {
51313760Sjairo.balart@metempsy.com            if (pkt->req->getExtraData() != 0) {
51413760Sjairo.balart@metempsy.com                //
51513760Sjairo.balart@metempsy.com                // Successful SC packets convert to normal writes
51613760Sjairo.balart@metempsy.com                //
51713760Sjairo.balart@metempsy.com                pkt->convertScToWrite();
51813760Sjairo.balart@metempsy.com            } else {
51913760Sjairo.balart@metempsy.com                //
52013760Sjairo.balart@metempsy.com                // Failed SC packets don't access physical memory and thus
52113760Sjairo.balart@metempsy.com                // the RubyPort itself must convert it to a response.
52213531Sjairo.balart@metempsy.com                //
52313531Sjairo.balart@metempsy.com                accessPhysMem = false;
52413760Sjairo.balart@metempsy.com            }
52513531Sjairo.balart@metempsy.com        } else {
52613531Sjairo.balart@metempsy.com            //
52713531Sjairo.balart@metempsy.com            // All LL packets convert to normal loads so that M5 PhysMem does
52813531Sjairo.balart@metempsy.com            // not lock the blocks.
52913760Sjairo.balart@metempsy.com            //
53013760Sjairo.balart@metempsy.com            pkt->convertLlToRead();
53113760Sjairo.balart@metempsy.com        }
53213760Sjairo.balart@metempsy.com    }
53313760Sjairo.balart@metempsy.com
53413760Sjairo.balart@metempsy.com    //
53513531Sjairo.balart@metempsy.com    // Flush requests don't access physical memory
53613760Sjairo.balart@metempsy.com    //
53713760Sjairo.balart@metempsy.com    if (pkt->isFlush()) {
53813760Sjairo.balart@metempsy.com        accessPhysMem = false;
53913760Sjairo.balart@metempsy.com    }
54013760Sjairo.balart@metempsy.com
54113760Sjairo.balart@metempsy.com    DPRINTF(RubyPort, "Hit callback needs response %d\n", needsResponse);
54213760Sjairo.balart@metempsy.com
54313760Sjairo.balart@metempsy.com    if (accessPhysMem) {
54413760Sjairo.balart@metempsy.com        ruby_port->physMemPort->sendAtomic(pkt);
54513760Sjairo.balart@metempsy.com    } else if (needsResponse) {
54613760Sjairo.balart@metempsy.com        pkt->makeResponse();
54713760Sjairo.balart@metempsy.com    }
54813760Sjairo.balart@metempsy.com
54913760Sjairo.balart@metempsy.com    // turn packet around to go back to requester if response expected
55013760Sjairo.balart@metempsy.com    if (needsResponse) {
55113760Sjairo.balart@metempsy.com        DPRINTF(RubyPort, "Sending packet back over port\n");
55213760Sjairo.balart@metempsy.com        sendTiming(pkt);
55313760Sjairo.balart@metempsy.com    } else {
55413760Sjairo.balart@metempsy.com        delete pkt;
55513760Sjairo.balart@metempsy.com    }
55613760Sjairo.balart@metempsy.com    DPRINTF(RubyPort, "Hit callback done!\n");
55713760Sjairo.balart@metempsy.com}
55813760Sjairo.balart@metempsy.com
55913760Sjairo.balart@metempsy.combool
56013531Sjairo.balart@metempsy.comRubyPort::M5Port::sendTiming(PacketPtr pkt)
56113760Sjairo.balart@metempsy.com{
56213760Sjairo.balart@metempsy.com    //minimum latency, must be > 0
56313531Sjairo.balart@metempsy.com    schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock()));
56413531Sjairo.balart@metempsy.com    return true;
56513531Sjairo.balart@metempsy.com}
56613760Sjairo.balart@metempsy.com
56713760Sjairo.balart@metempsy.combool
56813760Sjairo.balart@metempsy.comRubyPort::PioPort::sendTiming(PacketPtr pkt)
56913760Sjairo.balart@metempsy.com{
57013760Sjairo.balart@metempsy.com    //minimum latency, must be > 0
57113760Sjairo.balart@metempsy.com    schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock()));
57213531Sjairo.balart@metempsy.com    return true;
57313531Sjairo.balart@metempsy.com}
57413760Sjairo.balart@metempsy.com
57513760Sjairo.balart@metempsy.combool
57613760Sjairo.balart@metempsy.comRubyPort::M5Port::isPhysMemAddress(Addr addr)
57713760Sjairo.balart@metempsy.com{
57813760Sjairo.balart@metempsy.com    AddrRangeList physMemAddrList;
57913760Sjairo.balart@metempsy.com    bool snoop = false;
58013760Sjairo.balart@metempsy.com    ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop);
58113760Sjairo.balart@metempsy.com    for (AddrRangeIter iter = physMemAddrList.begin();
58213531Sjairo.balart@metempsy.com         iter != physMemAddrList.end();
58313531Sjairo.balart@metempsy.com         iter++) {
58413531Sjairo.balart@metempsy.com        if (addr >= iter->start && addr <= iter->end) {
58513760Sjairo.balart@metempsy.com            DPRINTF(RubyPort, "Request found in %#llx - %#llx range\n",
58613531Sjairo.balart@metempsy.com                    iter->start, iter->end);
58713760Sjairo.balart@metempsy.com            return true;
58813760Sjairo.balart@metempsy.com        }
58913760Sjairo.balart@metempsy.com    }
59013760Sjairo.balart@metempsy.com    return false;
59113760Sjairo.balart@metempsy.com}
59213760Sjairo.balart@metempsy.com
59313760Sjairo.balart@metempsy.comunsigned
59413531Sjairo.balart@metempsy.comRubyPort::M5Port::deviceBlockSize() const
59513531Sjairo.balart@metempsy.com{
59613531Sjairo.balart@metempsy.com    return (unsigned) RubySystem::getBlockSizeBytes();
59713760Sjairo.balart@metempsy.com}
59813531Sjairo.balart@metempsy.com