simple_memobj.cc revision 12338
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 MemObject(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 44BaseMasterPort& 45SimpleMemobj::getMasterPort(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 { 53 // pass it along to our super class 54 return MemObject::getMasterPort(if_name, idx); 55 } 56} 57 58BaseSlavePort& 59SimpleMemobj::getSlavePort(const std::string& if_name, PortID idx) 60{ 61 panic_if(idx != InvalidPortID, "This object doesn't support vector ports"); 62 63 // This is the name from the Python SimObject declaration in SimpleCache.py 64 if (if_name == "inst_port") { 65 return instPort; 66 } else if (if_name == "data_port") { 67 return dataPort; 68 } else { 69 // pass it along to our super class 70 return MemObject::getSlavePort(if_name, idx); 71 } 72} 73 74void 75SimpleMemobj::CPUSidePort::sendPacket(PacketPtr pkt) 76{ 77 // Note: This flow control is very simple since the memobj is blocking. 78 79 panic_if(blockedPacket != nullptr, "Should never try to send if blocked!"); 80 81 // If we can't send the packet across the port, store it for later. 82 if (!sendTimingResp(pkt)) { 83 blockedPacket = pkt; 84 } 85} 86 87AddrRangeList 88SimpleMemobj::CPUSidePort::getAddrRanges() const 89{ 90 return owner->getAddrRanges(); 91} 92 93void 94SimpleMemobj::CPUSidePort::trySendRetry() 95{ 96 if (needRetry && blockedPacket == nullptr) { 97 // Only send a retry if the port is now completely free 98 needRetry = false; 99 DPRINTF(SimpleMemobj, "Sending retry req for %d\n", id); 100 sendRetryReq(); 101 } 102} 103 104void 105SimpleMemobj::CPUSidePort::recvFunctional(PacketPtr pkt) 106{ 107 // Just forward to the memobj. 108 return owner->handleFunctional(pkt); 109} 110 111bool 112SimpleMemobj::CPUSidePort::recvTimingReq(PacketPtr pkt) 113{ 114 // Just forward to the memobj. 115 if (!owner->handleRequest(pkt)) { 116 needRetry = true; 117 return false; 118 } else { 119 return true; 120 } 121} 122 123void 124SimpleMemobj::CPUSidePort::recvRespRetry() 125{ 126 // We should have a blocked packet if this function is called. 127 assert(blockedPacket != nullptr); 128 129 // Grab the blocked packet. 130 PacketPtr pkt = blockedPacket; 131 blockedPacket = nullptr; 132 133 // Try to resend it. It's possible that it fails again. 134 sendPacket(pkt); 135} 136 137void 138SimpleMemobj::MemSidePort::sendPacket(PacketPtr pkt) 139{ 140 // Note: This flow control is very simple since the memobj is blocking. 141 142 panic_if(blockedPacket != nullptr, "Should never try to send if blocked!"); 143 144 // If we can't send the packet across the port, store it for later. 145 if (!sendTimingReq(pkt)) { 146 blockedPacket = pkt; 147 } 148} 149 150bool 151SimpleMemobj::MemSidePort::recvTimingResp(PacketPtr pkt) 152{ 153 // Just forward to the memobj. 154 return owner->handleResponse(pkt); 155} 156 157void 158SimpleMemobj::MemSidePort::recvReqRetry() 159{ 160 // We should have a blocked packet if this function is called. 161 assert(blockedPacket != nullptr); 162 163 // Grab the blocked packet. 164 PacketPtr pkt = blockedPacket; 165 blockedPacket = nullptr; 166 167 // Try to resend it. It's possible that it fails again. 168 sendPacket(pkt); 169} 170 171void 172SimpleMemobj::MemSidePort::recvRangeChange() 173{ 174 owner->sendRangeChange(); 175} 176 177bool 178SimpleMemobj::handleRequest(PacketPtr pkt) 179{ 180 if (blocked) { 181 // There is currently an outstanding request. Stall. 182 return false; 183 } 184 185 DPRINTF(SimpleMemobj, "Got request for addr %#x\n", pkt->getAddr()); 186 187 // This memobj is now blocked waiting for the response to this packet. 188 blocked = true; 189 190 // Simply forward to the memory port 191 memPort.sendPacket(pkt); 192 193 return true; 194} 195 196bool 197SimpleMemobj::handleResponse(PacketPtr pkt) 198{ 199 assert(blocked); 200 DPRINTF(SimpleMemobj, "Got response for addr %#x\n", pkt->getAddr()); 201 202 // The packet is now done. We're about to put it in the port, no need for 203 // this object to continue to stall. 204 // We need to free the resource before sending the packet in case the CPU 205 // tries to send another request immediately (e.g., in the same callchain). 206 blocked = false; 207 208 // Simply forward to the memory port 209 if (pkt->req->isInstFetch()) { 210 instPort.sendPacket(pkt); 211 } else { 212 dataPort.sendPacket(pkt); 213 } 214 215 // For each of the cpu ports, if it needs to send a retry, it should do it 216 // now since this memory object may be unblocked now. 217 instPort.trySendRetry(); 218 dataPort.trySendRetry(); 219 220 return true; 221} 222 223void 224SimpleMemobj::handleFunctional(PacketPtr pkt) 225{ 226 // Just pass this on to the memory side to handle for now. 227 memPort.sendFunctional(pkt); 228} 229 230AddrRangeList 231SimpleMemobj::getAddrRanges() const 232{ 233 DPRINTF(SimpleMemobj, "Sending new ranges\n"); 234 // Just use the same ranges as whatever is on the memory side. 235 return memPort.getAddrRanges(); 236} 237 238void 239SimpleMemobj::sendRangeChange() 240{ 241 instPort.sendRangeChange(); 242 dataPort.sendRangeChange(); 243} 244 245 246 247SimpleMemobj* 248SimpleMemobjParams::create() 249{ 250 return new SimpleMemobj(this); 251} 252