1/* 2 * Copyright (c) 2017 Jason Lowe-Power 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Jason Lowe-Power 29 */ 30 31#include "learning_gem5/part2/simple_memobj.hh" 32 33#include "debug/SimpleMemobj.hh" 34 35SimpleMemobj::SimpleMemobj(SimpleMemobjParams *params) : 36 SimObject(params), 37 instPort(params->name + ".inst_port", this), 38 dataPort(params->name + ".data_port", this), 39 memPort(params->name + ".mem_side", this), 40 blocked(false) 41{ 42} 43 44Port & 45SimpleMemobj::getPort(const std::string &if_name, PortID idx) 46{ 47 panic_if(idx != InvalidPortID, "This object doesn't support vector ports"); 48 49 // This is the name from the Python SimObject declaration (SimpleMemobj.py) 50 if (if_name == "mem_side") { 51 return memPort; 52 } else if (if_name == "inst_port") { 53 return instPort; 54 } else if (if_name == "data_port") { 55 return dataPort; 56 } else { 57 // pass it along to our super class 58 return SimObject::getPort(if_name, idx); 59 } 60} 61 62void 63SimpleMemobj::CPUSidePort::sendPacket(PacketPtr pkt) 64{ 65 // Note: This flow control is very simple since the memobj is blocking. 66 67 panic_if(blockedPacket != nullptr, "Should never try to send if blocked!"); 68 69 // If we can't send the packet across the port, store it for later. 70 if (!sendTimingResp(pkt)) { 71 blockedPacket = pkt; 72 } 73} 74 75AddrRangeList 76SimpleMemobj::CPUSidePort::getAddrRanges() const 77{ 78 return owner->getAddrRanges(); 79} 80 81void 82SimpleMemobj::CPUSidePort::trySendRetry() 83{ 84 if (needRetry && blockedPacket == nullptr) { 85 // Only send a retry if the port is now completely free 86 needRetry = false; 87 DPRINTF(SimpleMemobj, "Sending retry req for %d\n", id); 88 sendRetryReq(); 89 } 90} 91 92void 93SimpleMemobj::CPUSidePort::recvFunctional(PacketPtr pkt) 94{ 95 // Just forward to the memobj. 96 return owner->handleFunctional(pkt); 97} 98 99bool 100SimpleMemobj::CPUSidePort::recvTimingReq(PacketPtr pkt) 101{ 102 // Just forward to the memobj. 103 if (!owner->handleRequest(pkt)) { 104 needRetry = true; 105 return false; 106 } else { 107 return true; 108 } 109} 110 111void 112SimpleMemobj::CPUSidePort::recvRespRetry() 113{ 114 // We should have a blocked packet if this function is called. 115 assert(blockedPacket != nullptr); 116 117 // Grab the blocked packet. 118 PacketPtr pkt = blockedPacket; 119 blockedPacket = nullptr; 120 121 // Try to resend it. It's possible that it fails again. 122 sendPacket(pkt); 123} 124 125void 126SimpleMemobj::MemSidePort::sendPacket(PacketPtr pkt) 127{ 128 // Note: This flow control is very simple since the memobj is blocking. 129 130 panic_if(blockedPacket != nullptr, "Should never try to send if blocked!"); 131 132 // If we can't send the packet across the port, store it for later. 133 if (!sendTimingReq(pkt)) { 134 blockedPacket = pkt; 135 } 136} 137 138bool 139SimpleMemobj::MemSidePort::recvTimingResp(PacketPtr pkt) 140{ 141 // Just forward to the memobj. 142 return owner->handleResponse(pkt); 143} 144 145void 146SimpleMemobj::MemSidePort::recvReqRetry() 147{ 148 // We should have a blocked packet if this function is called. 149 assert(blockedPacket != nullptr); 150 151 // Grab the blocked packet. 152 PacketPtr pkt = blockedPacket; 153 blockedPacket = nullptr; 154 155 // Try to resend it. It's possible that it fails again. 156 sendPacket(pkt); 157} 158 159void 160SimpleMemobj::MemSidePort::recvRangeChange() 161{ 162 owner->sendRangeChange(); 163} 164 165bool 166SimpleMemobj::handleRequest(PacketPtr pkt) 167{ 168 if (blocked) { 169 // There is currently an outstanding request. Stall. 170 return false; 171 } 172 173 DPRINTF(SimpleMemobj, "Got request for addr %#x\n", pkt->getAddr()); 174 175 // This memobj is now blocked waiting for the response to this packet. 176 blocked = true; 177 178 // Simply forward to the memory port 179 memPort.sendPacket(pkt); 180 181 return true; 182} 183 184bool 185SimpleMemobj::handleResponse(PacketPtr pkt) 186{ 187 assert(blocked); 188 DPRINTF(SimpleMemobj, "Got response for addr %#x\n", pkt->getAddr()); 189 190 // The packet is now done. We're about to put it in the port, no need for 191 // this object to continue to stall. 192 // We need to free the resource before sending the packet in case the CPU 193 // tries to send another request immediately (e.g., in the same callchain). 194 blocked = false; 195 196 // Simply forward to the memory port 197 if (pkt->req->isInstFetch()) { 198 instPort.sendPacket(pkt); 199 } else { 200 dataPort.sendPacket(pkt); 201 } 202 203 // For each of the cpu ports, if it needs to send a retry, it should do it 204 // now since this memory object may be unblocked now. 205 instPort.trySendRetry(); 206 dataPort.trySendRetry(); 207 208 return true; 209} 210 211void 212SimpleMemobj::handleFunctional(PacketPtr pkt) 213{ 214 // Just pass this on to the memory side to handle for now. 215 memPort.sendFunctional(pkt); 216} 217 218AddrRangeList 219SimpleMemobj::getAddrRanges() const 220{ 221 DPRINTF(SimpleMemobj, "Sending new ranges\n"); 222 // Just use the same ranges as whatever is on the memory side. 223 return memPort.getAddrRanges(); 224} 225 226void 227SimpleMemobj::sendRangeChange() 228{ 229 instPort.sendRangeChange(); 230 dataPort.sendRangeChange(); 231} 232 233 234 235SimpleMemobj* 236SimpleMemobjParams::create() 237{ 238 return new SimpleMemobj(this); 239} 240