diff options
author | Jason Lowe-Power <jason@lowepower.com> | 2017-10-06 14:43:09 -0700 |
---|---|---|
committer | Jason Lowe-Power <jason@lowepower.com> | 2017-12-05 02:09:25 +0000 |
commit | 46ec9df617df23d6bb00f6337e61e6d85038ec7e (patch) | |
tree | f38e06526221ce084873052a63abd468cbe335da /src/learning_gem5/part2/simple_memobj.cc | |
parent | 25daea0e6fd12b8ce3c282b49b3fd334d1871975 (diff) | |
download | gem5-46ec9df617df23d6bb00f6337e61e6d85038ec7e.tar.xz |
learning_gem5: Adds the simple MemObject code
Adding more code from Learning gem5 Part II
See http://learning.gem5.org/book/part2/memoryobject.html
Change-Id: Iaa9480c5cdbe4090364f02e81dc1d0a0ddac392a
Signed-off-by: Jason Lowe-Power <jason@lowepower.com>
Reviewed-on: https://gem5-review.googlesource.com/5022
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Diffstat (limited to 'src/learning_gem5/part2/simple_memobj.cc')
-rw-r--r-- | src/learning_gem5/part2/simple_memobj.cc | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/src/learning_gem5/part2/simple_memobj.cc b/src/learning_gem5/part2/simple_memobj.cc new file mode 100644 index 000000000..cb4d3d8db --- /dev/null +++ b/src/learning_gem5/part2/simple_memobj.cc @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2017 Jason Lowe-Power + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Jason Lowe-Power + */ + +#include "learning_gem5/part2/simple_memobj.hh" + +#include "debug/SimpleMemobj.hh" + +SimpleMemobj::SimpleMemobj(SimpleMemobjParams *params) : + MemObject(params), + instPort(params->name + ".inst_port", this), + dataPort(params->name + ".data_port", this), + memPort(params->name + ".mem_side", this), + blocked(false) +{ +} + +BaseMasterPort& +SimpleMemobj::getMasterPort(const std::string& if_name, PortID idx) +{ + panic_if(idx != InvalidPortID, "This object doesn't support vector ports"); + + // This is the name from the Python SimObject declaration (SimpleMemobj.py) + if (if_name == "mem_side") { + return memPort; + } else { + // pass it along to our super class + return MemObject::getMasterPort(if_name, idx); + } +} + +BaseSlavePort& +SimpleMemobj::getSlavePort(const std::string& if_name, PortID idx) +{ + panic_if(idx != InvalidPortID, "This object doesn't support vector ports"); + + // This is the name from the Python SimObject declaration in SimpleCache.py + if (if_name == "inst_port") { + return instPort; + } else if (if_name == "data_port") { + return dataPort; + } else { + // pass it along to our super class + return MemObject::getSlavePort(if_name, idx); + } +} + +void +SimpleMemobj::CPUSidePort::sendPacket(PacketPtr pkt) +{ + // Note: This flow control is very simple since the memobj is blocking. + + panic_if(blockedPacket != nullptr, "Should never try to send if blocked!"); + + // If we can't send the packet across the port, store it for later. + if (!sendTimingResp(pkt)) { + blockedPacket = pkt; + } +} + +AddrRangeList +SimpleMemobj::CPUSidePort::getAddrRanges() const +{ + return owner->getAddrRanges(); +} + +void +SimpleMemobj::CPUSidePort::trySendRetry() +{ + if (needRetry && blockedPacket == nullptr) { + // Only send a retry if the port is now completely free + needRetry = false; + DPRINTF(SimpleMemobj, "Sending retry req for %d\n", id); + sendRetryReq(); + } +} + +void +SimpleMemobj::CPUSidePort::recvFunctional(PacketPtr pkt) +{ + // Just forward to the memobj. + return owner->handleFunctional(pkt); +} + +bool +SimpleMemobj::CPUSidePort::recvTimingReq(PacketPtr pkt) +{ + // Just forward to the memobj. + if (!owner->handleRequest(pkt)) { + needRetry = true; + return false; + } else { + return true; + } +} + +void +SimpleMemobj::CPUSidePort::recvRespRetry() +{ + // We should have a blocked packet if this function is called. + assert(blockedPacket != nullptr); + + // Grab the blocked packet. + PacketPtr pkt = blockedPacket; + blockedPacket = nullptr; + + // Try to resend it. It's possible that it fails again. + sendPacket(pkt); +} + +void +SimpleMemobj::MemSidePort::sendPacket(PacketPtr pkt) +{ + // Note: This flow control is very simple since the memobj is blocking. + + panic_if(blockedPacket != nullptr, "Should never try to send if blocked!"); + + // If we can't send the packet across the port, store it for later. + if (!sendTimingReq(pkt)) { + blockedPacket = pkt; + } +} + +bool +SimpleMemobj::MemSidePort::recvTimingResp(PacketPtr pkt) +{ + // Just forward to the memobj. + return owner->handleResponse(pkt); +} + +void +SimpleMemobj::MemSidePort::recvReqRetry() +{ + // We should have a blocked packet if this function is called. + assert(blockedPacket != nullptr); + + // Grab the blocked packet. + PacketPtr pkt = blockedPacket; + blockedPacket = nullptr; + + // Try to resend it. It's possible that it fails again. + sendPacket(pkt); +} + +void +SimpleMemobj::MemSidePort::recvRangeChange() +{ + owner->sendRangeChange(); +} + +bool +SimpleMemobj::handleRequest(PacketPtr pkt) +{ + if (blocked) { + // There is currently an outstanding request. Stall. + return false; + } + + DPRINTF(SimpleMemobj, "Got request for addr %#x\n", pkt->getAddr()); + + // This memobj is now blocked waiting for the response to this packet. + blocked = true; + + // Simply forward to the memory port + memPort.sendPacket(pkt); + + return true; +} + +bool +SimpleMemobj::handleResponse(PacketPtr pkt) +{ + assert(blocked); + DPRINTF(SimpleMemobj, "Got response for addr %#x\n", pkt->getAddr()); + + // The packet is now done. We're about to put it in the port, no need for + // this object to continue to stall. + // We need to free the resource before sending the packet in case the CPU + // tries to send another request immediately (e.g., in the same callchain). + blocked = false; + + // Simply forward to the memory port + if (pkt->req->isInstFetch()) { + instPort.sendPacket(pkt); + } else { + dataPort.sendPacket(pkt); + } + + // For each of the cpu ports, if it needs to send a retry, it should do it + // now since this memory object may be unblocked now. + instPort.trySendRetry(); + dataPort.trySendRetry(); + + return true; +} + +void +SimpleMemobj::handleFunctional(PacketPtr pkt) +{ + // Just pass this on to the memory side to handle for now. + memPort.sendFunctional(pkt); +} + +AddrRangeList +SimpleMemobj::getAddrRanges() const +{ + DPRINTF(SimpleMemobj, "Sending new ranges\n"); + // Just use the same ranges as whatever is on the memory side. + return memPort.getAddrRanges(); +} + +void +SimpleMemobj::sendRangeChange() +{ + instPort.sendRangeChange(); + dataPort.sendRangeChange(); +} + + + +SimpleMemobj* +SimpleMemobjParams::create() +{ + return new SimpleMemobj(this); +} |