112338Sjason@lowepower.com/*
212338Sjason@lowepower.com * Copyright (c) 2017 Jason Lowe-Power
312338Sjason@lowepower.com * All rights reserved.
412338Sjason@lowepower.com *
512338Sjason@lowepower.com * Redistribution and use in source and binary forms, with or without
612338Sjason@lowepower.com * modification, are permitted provided that the following conditions are
712338Sjason@lowepower.com * met: redistributions of source code must retain the above copyright
812338Sjason@lowepower.com * notice, this list of conditions and the following disclaimer;
912338Sjason@lowepower.com * redistributions in binary form must reproduce the above copyright
1012338Sjason@lowepower.com * notice, this list of conditions and the following disclaimer in the
1112338Sjason@lowepower.com * documentation and/or other materials provided with the distribution;
1212338Sjason@lowepower.com * neither the name of the copyright holders nor the names of its
1312338Sjason@lowepower.com * contributors may be used to endorse or promote products derived from
1412338Sjason@lowepower.com * this software without specific prior written permission.
1512338Sjason@lowepower.com *
1612338Sjason@lowepower.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1712338Sjason@lowepower.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1812338Sjason@lowepower.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1912338Sjason@lowepower.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2012338Sjason@lowepower.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2112338Sjason@lowepower.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2212338Sjason@lowepower.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2312338Sjason@lowepower.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2412338Sjason@lowepower.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2512338Sjason@lowepower.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2612338Sjason@lowepower.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2712338Sjason@lowepower.com *
2812338Sjason@lowepower.com * Authors: Jason Lowe-Power
2912338Sjason@lowepower.com */
3012338Sjason@lowepower.com
3112338Sjason@lowepower.com#include "learning_gem5/part2/simple_memobj.hh"
3212338Sjason@lowepower.com
3312338Sjason@lowepower.com#include "debug/SimpleMemobj.hh"
3412338Sjason@lowepower.com
3512338Sjason@lowepower.comSimpleMemobj::SimpleMemobj(SimpleMemobjParams *params) :
3614252Sgabeblack@google.com    SimObject(params),
3712338Sjason@lowepower.com    instPort(params->name + ".inst_port", this),
3812338Sjason@lowepower.com    dataPort(params->name + ".data_port", this),
3912338Sjason@lowepower.com    memPort(params->name + ".mem_side", this),
4012338Sjason@lowepower.com    blocked(false)
4112338Sjason@lowepower.com{
4212338Sjason@lowepower.com}
4312338Sjason@lowepower.com
4413784Sgabeblack@google.comPort &
4513784Sgabeblack@google.comSimpleMemobj::getPort(const std::string &if_name, PortID idx)
4612338Sjason@lowepower.com{
4712338Sjason@lowepower.com    panic_if(idx != InvalidPortID, "This object doesn't support vector ports");
4812338Sjason@lowepower.com
4912338Sjason@lowepower.com    // This is the name from the Python SimObject declaration (SimpleMemobj.py)
5012338Sjason@lowepower.com    if (if_name == "mem_side") {
5112338Sjason@lowepower.com        return memPort;
5213784Sgabeblack@google.com    } else if (if_name == "inst_port") {
5312338Sjason@lowepower.com        return instPort;
5412338Sjason@lowepower.com    } else if (if_name == "data_port") {
5512338Sjason@lowepower.com        return dataPort;
5612338Sjason@lowepower.com    } else {
5712338Sjason@lowepower.com        // pass it along to our super class
5814252Sgabeblack@google.com        return SimObject::getPort(if_name, idx);
5912338Sjason@lowepower.com    }
6012338Sjason@lowepower.com}
6112338Sjason@lowepower.com
6212338Sjason@lowepower.comvoid
6312338Sjason@lowepower.comSimpleMemobj::CPUSidePort::sendPacket(PacketPtr pkt)
6412338Sjason@lowepower.com{
6512338Sjason@lowepower.com    // Note: This flow control is very simple since the memobj is blocking.
6612338Sjason@lowepower.com
6712338Sjason@lowepower.com    panic_if(blockedPacket != nullptr, "Should never try to send if blocked!");
6812338Sjason@lowepower.com
6912338Sjason@lowepower.com    // If we can't send the packet across the port, store it for later.
7012338Sjason@lowepower.com    if (!sendTimingResp(pkt)) {
7112338Sjason@lowepower.com        blockedPacket = pkt;
7212338Sjason@lowepower.com    }
7312338Sjason@lowepower.com}
7412338Sjason@lowepower.com
7512338Sjason@lowepower.comAddrRangeList
7612338Sjason@lowepower.comSimpleMemobj::CPUSidePort::getAddrRanges() const
7712338Sjason@lowepower.com{
7812338Sjason@lowepower.com    return owner->getAddrRanges();
7912338Sjason@lowepower.com}
8012338Sjason@lowepower.com
8112338Sjason@lowepower.comvoid
8212338Sjason@lowepower.comSimpleMemobj::CPUSidePort::trySendRetry()
8312338Sjason@lowepower.com{
8412338Sjason@lowepower.com    if (needRetry && blockedPacket == nullptr) {
8512338Sjason@lowepower.com        // Only send a retry if the port is now completely free
8612338Sjason@lowepower.com        needRetry = false;
8712338Sjason@lowepower.com        DPRINTF(SimpleMemobj, "Sending retry req for %d\n", id);
8812338Sjason@lowepower.com        sendRetryReq();
8912338Sjason@lowepower.com    }
9012338Sjason@lowepower.com}
9112338Sjason@lowepower.com
9212338Sjason@lowepower.comvoid
9312338Sjason@lowepower.comSimpleMemobj::CPUSidePort::recvFunctional(PacketPtr pkt)
9412338Sjason@lowepower.com{
9512338Sjason@lowepower.com    // Just forward to the memobj.
9612338Sjason@lowepower.com    return owner->handleFunctional(pkt);
9712338Sjason@lowepower.com}
9812338Sjason@lowepower.com
9912338Sjason@lowepower.combool
10012338Sjason@lowepower.comSimpleMemobj::CPUSidePort::recvTimingReq(PacketPtr pkt)
10112338Sjason@lowepower.com{
10212338Sjason@lowepower.com    // Just forward to the memobj.
10312338Sjason@lowepower.com    if (!owner->handleRequest(pkt)) {
10412338Sjason@lowepower.com        needRetry = true;
10512338Sjason@lowepower.com        return false;
10612338Sjason@lowepower.com    } else {
10712338Sjason@lowepower.com        return true;
10812338Sjason@lowepower.com    }
10912338Sjason@lowepower.com}
11012338Sjason@lowepower.com
11112338Sjason@lowepower.comvoid
11212338Sjason@lowepower.comSimpleMemobj::CPUSidePort::recvRespRetry()
11312338Sjason@lowepower.com{
11412338Sjason@lowepower.com    // We should have a blocked packet if this function is called.
11512338Sjason@lowepower.com    assert(blockedPacket != nullptr);
11612338Sjason@lowepower.com
11712338Sjason@lowepower.com    // Grab the blocked packet.
11812338Sjason@lowepower.com    PacketPtr pkt = blockedPacket;
11912338Sjason@lowepower.com    blockedPacket = nullptr;
12012338Sjason@lowepower.com
12112338Sjason@lowepower.com    // Try to resend it. It's possible that it fails again.
12212338Sjason@lowepower.com    sendPacket(pkt);
12312338Sjason@lowepower.com}
12412338Sjason@lowepower.com
12512338Sjason@lowepower.comvoid
12612338Sjason@lowepower.comSimpleMemobj::MemSidePort::sendPacket(PacketPtr pkt)
12712338Sjason@lowepower.com{
12812338Sjason@lowepower.com    // Note: This flow control is very simple since the memobj is blocking.
12912338Sjason@lowepower.com
13012338Sjason@lowepower.com    panic_if(blockedPacket != nullptr, "Should never try to send if blocked!");
13112338Sjason@lowepower.com
13212338Sjason@lowepower.com    // If we can't send the packet across the port, store it for later.
13312338Sjason@lowepower.com    if (!sendTimingReq(pkt)) {
13412338Sjason@lowepower.com        blockedPacket = pkt;
13512338Sjason@lowepower.com    }
13612338Sjason@lowepower.com}
13712338Sjason@lowepower.com
13812338Sjason@lowepower.combool
13912338Sjason@lowepower.comSimpleMemobj::MemSidePort::recvTimingResp(PacketPtr pkt)
14012338Sjason@lowepower.com{
14112338Sjason@lowepower.com    // Just forward to the memobj.
14212338Sjason@lowepower.com    return owner->handleResponse(pkt);
14312338Sjason@lowepower.com}
14412338Sjason@lowepower.com
14512338Sjason@lowepower.comvoid
14612338Sjason@lowepower.comSimpleMemobj::MemSidePort::recvReqRetry()
14712338Sjason@lowepower.com{
14812338Sjason@lowepower.com    // We should have a blocked packet if this function is called.
14912338Sjason@lowepower.com    assert(blockedPacket != nullptr);
15012338Sjason@lowepower.com
15112338Sjason@lowepower.com    // Grab the blocked packet.
15212338Sjason@lowepower.com    PacketPtr pkt = blockedPacket;
15312338Sjason@lowepower.com    blockedPacket = nullptr;
15412338Sjason@lowepower.com
15512338Sjason@lowepower.com    // Try to resend it. It's possible that it fails again.
15612338Sjason@lowepower.com    sendPacket(pkt);
15712338Sjason@lowepower.com}
15812338Sjason@lowepower.com
15912338Sjason@lowepower.comvoid
16012338Sjason@lowepower.comSimpleMemobj::MemSidePort::recvRangeChange()
16112338Sjason@lowepower.com{
16212338Sjason@lowepower.com    owner->sendRangeChange();
16312338Sjason@lowepower.com}
16412338Sjason@lowepower.com
16512338Sjason@lowepower.combool
16612338Sjason@lowepower.comSimpleMemobj::handleRequest(PacketPtr pkt)
16712338Sjason@lowepower.com{
16812338Sjason@lowepower.com    if (blocked) {
16912338Sjason@lowepower.com        // There is currently an outstanding request. Stall.
17012338Sjason@lowepower.com        return false;
17112338Sjason@lowepower.com    }
17212338Sjason@lowepower.com
17312338Sjason@lowepower.com    DPRINTF(SimpleMemobj, "Got request for addr %#x\n", pkt->getAddr());
17412338Sjason@lowepower.com
17512338Sjason@lowepower.com    // This memobj is now blocked waiting for the response to this packet.
17612338Sjason@lowepower.com    blocked = true;
17712338Sjason@lowepower.com
17812338Sjason@lowepower.com    // Simply forward to the memory port
17912338Sjason@lowepower.com    memPort.sendPacket(pkt);
18012338Sjason@lowepower.com
18112338Sjason@lowepower.com    return true;
18212338Sjason@lowepower.com}
18312338Sjason@lowepower.com
18412338Sjason@lowepower.combool
18512338Sjason@lowepower.comSimpleMemobj::handleResponse(PacketPtr pkt)
18612338Sjason@lowepower.com{
18712338Sjason@lowepower.com    assert(blocked);
18812338Sjason@lowepower.com    DPRINTF(SimpleMemobj, "Got response for addr %#x\n", pkt->getAddr());
18912338Sjason@lowepower.com
19012338Sjason@lowepower.com    // The packet is now done. We're about to put it in the port, no need for
19112338Sjason@lowepower.com    // this object to continue to stall.
19212338Sjason@lowepower.com    // We need to free the resource before sending the packet in case the CPU
19312338Sjason@lowepower.com    // tries to send another request immediately (e.g., in the same callchain).
19412338Sjason@lowepower.com    blocked = false;
19512338Sjason@lowepower.com
19612338Sjason@lowepower.com    // Simply forward to the memory port
19712338Sjason@lowepower.com    if (pkt->req->isInstFetch()) {
19812338Sjason@lowepower.com        instPort.sendPacket(pkt);
19912338Sjason@lowepower.com    } else {
20012338Sjason@lowepower.com        dataPort.sendPacket(pkt);
20112338Sjason@lowepower.com    }
20212338Sjason@lowepower.com
20312338Sjason@lowepower.com    // For each of the cpu ports, if it needs to send a retry, it should do it
20412338Sjason@lowepower.com    // now since this memory object may be unblocked now.
20512338Sjason@lowepower.com    instPort.trySendRetry();
20612338Sjason@lowepower.com    dataPort.trySendRetry();
20712338Sjason@lowepower.com
20812338Sjason@lowepower.com    return true;
20912338Sjason@lowepower.com}
21012338Sjason@lowepower.com
21112338Sjason@lowepower.comvoid
21212338Sjason@lowepower.comSimpleMemobj::handleFunctional(PacketPtr pkt)
21312338Sjason@lowepower.com{
21412338Sjason@lowepower.com    // Just pass this on to the memory side to handle for now.
21512338Sjason@lowepower.com    memPort.sendFunctional(pkt);
21612338Sjason@lowepower.com}
21712338Sjason@lowepower.com
21812338Sjason@lowepower.comAddrRangeList
21912338Sjason@lowepower.comSimpleMemobj::getAddrRanges() const
22012338Sjason@lowepower.com{
22112338Sjason@lowepower.com    DPRINTF(SimpleMemobj, "Sending new ranges\n");
22212338Sjason@lowepower.com    // Just use the same ranges as whatever is on the memory side.
22312338Sjason@lowepower.com    return memPort.getAddrRanges();
22412338Sjason@lowepower.com}
22512338Sjason@lowepower.com
22612338Sjason@lowepower.comvoid
22712338Sjason@lowepower.comSimpleMemobj::sendRangeChange()
22812338Sjason@lowepower.com{
22912338Sjason@lowepower.com    instPort.sendRangeChange();
23012338Sjason@lowepower.com    dataPort.sendRangeChange();
23112338Sjason@lowepower.com}
23212338Sjason@lowepower.com
23312338Sjason@lowepower.com
23412338Sjason@lowepower.com
23512338Sjason@lowepower.comSimpleMemobj*
23612338Sjason@lowepower.comSimpleMemobjParams::create()
23712338Sjason@lowepower.com{
23812338Sjason@lowepower.com    return new SimpleMemobj(this);
23912338Sjason@lowepower.com}
240