1// Copyright (c) 2015 ARM Limited 2// All rights reserved. 3// 4// The license below extends only to copyright in the software and shall 5// not be construed as granting a license to any other intellectual 6// property including but not limited to intellectual property relating 7// to a hardware implementation of the functionality of the software 8// licensed hereunder. You may use the software subject to the license 9// terms below provided that you ensure that this notice is replicated 10// unmodified and in its entirety in all distributions of the software, 11// modified or unmodified, in source code or in binary form. 12// 13// Redistribution and use in source and binary forms, with or without 14// modification, are permitted provided that the following conditions are 15// met: redistributions of source code must retain the above copyright 16// notice, this list of conditions and the following disclaimer; 17// redistributions in binary form must reproduce the above copyright 18// notice, this list of conditions and the following disclaimer in the 19// documentation and/or other materials provided with the distribution; 20// neither the name of the copyright holders nor the names of its 21// contributors may be used to endorse or promote products derived from 22// this software without specific prior written permission. 23// 24// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 36// Copyright 2009-2014 Sandia Coporation. Under the terms 37// of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. 38// Government retains certain rights in this software. 39// 40// Copyright (c) 2009-2014, Sandia Corporation 41// All rights reserved. 42// 43// For license information, see the LICENSE file in the current directory. 44 45#include "gem5.hh" 46 47#ifdef fatal // gem5 sets this 48#undef fatal 49#endif 50 51using namespace SST; 52using namespace SST::gem5; 53using namespace SST::MemHierarchy; 54 55ExtSlave::ExtSlave(gem5Component *g5c, Output &out, 56 ::ExternalSlave& port, std::string &name) : 57 Port(name, port), 58 comp(g5c), out(out), simPhase(CONSTRUCTION), initPackets(NULL), 59 link(comp->configureLink(name, new Event::Handler<ExtSlave>(this, 60 &ExtSlave::handleEvent))) 61{ 62 if (!link) { 63 out.fatal(CALL_INFO, 1, "Failed to configure link %s\n", name.c_str()); 64 } 65} 66 67void ExtSlave::init(unsigned phase) 68{ 69 simPhase = INIT; 70 if (initPackets) { 71 while (!initPackets->empty()) { 72 link->sendInitData(initPackets->front()); 73 initPackets->pop_front(); 74 } 75 delete initPackets; 76 initPackets = NULL; 77 } 78} 79 80void 81ExtSlave::recvFunctional(PacketPtr pkt) 82{ 83 if (simPhase == CONSTRUCTION) { 84 if (initPackets == NULL) { 85 initPackets = new std::list<MemEvent*>; 86 } 87 ::MemCmd::Command pktCmd = (::MemCmd::Command)pkt->cmd.toInt(); 88 assert(pktCmd == ::MemCmd::WriteReq); 89 Addr a = pkt->getAddr(); 90 MemEvent* ev = new MemEvent(comp, a, a, GetX); 91 ev->setPayload(pkt->getSize(), pkt->getPtr<uint8_t>()); 92 initPackets->push_back(ev); 93 } else { 94 panic("Functional accesses not allowed after construction phase"); 95 } 96} 97 98bool 99ExtSlave::recvTimingReq(PacketPtr pkt) 100{ 101 Command cmd; 102 switch ((::MemCmd::Command)pkt->cmd.toInt()) { 103 case ::MemCmd::HardPFReq: 104 case ::MemCmd::SoftPFReq: 105 case ::MemCmd::LoadLockedReq: 106 case ::MemCmd::ReadExReq: 107 case ::MemCmd::ReadReq: cmd = GetS; break; 108 case ::MemCmd::StoreCondReq: 109 case ::MemCmd::WriteReq: cmd = GetX; break; 110 default: 111 out.fatal(CALL_INFO, 1, "Don't know how to convert gem5 packet " 112 "command %s to SST\n", pkt->cmd.toString().c_str()); 113 } 114 115 auto ev = new MemEvent(comp, pkt->getAddr(), pkt->getAddr(), cmd); 116 ev->setPayload(pkt->getSize(), pkt->getPtr<uint8_t>()); 117 if ((::MemCmd::Command)pkt->cmd.toInt() == ::MemCmd::LoadLockedReq) 118 ev->setLoadLink(); 119 else if ((::MemCmd::Command)pkt->cmd.toInt() == ::MemCmd::StoreCondReq) 120 ev->setStoreConditional(); 121 122 if (pkt->req->isLockedRMW()) ev->setFlag(MemEvent::F_LOCKED); 123 if (pkt->req->isUncacheable()) ev->setFlag(MemEvent::F_NONCACHEABLE); 124 if (pkt->req->hasContextId()) ev->setGroupId(pkt->req->contextId()); 125// Prefetches not working with SST; it maybe be dropping them, treating them 126// as not deserving of responses, or something else -- not sure yet. 127// ev->setPrefetchFlag(pkt->req->isPrefetch()); 128 129 if (simPhase == INIT) { 130 link->sendInitData(ev); 131 delete pkt; 132 } else { 133 if (pkt->needsResponse()) { 134 PacketMap[ev->getID()] = pkt; 135 } 136 link->send(ev); 137 } 138 return true; 139} 140 141 142void 143ExtSlave::handleEvent(Event* ev) 144{ 145 MemEvent* event = dynamic_cast<MemEvent*>(ev); 146 if (!event) { 147 out.fatal(CALL_INFO, 1, "ExtSlave handleEvent received non-MemEvent\n"); 148 delete ev; 149 return; 150 } 151 Event::id_type id = event->getID(); 152 153 PacketMap_t::iterator mi = PacketMap.find(id); 154 if (mi != PacketMap.end()) { // replying to prior request 155 PacketPtr pkt = mi->second; 156 PacketMap.erase(mi); 157 158 pkt->makeResponse(); // Convert to a response packet 159 pkt->setData(event->getPayload().data()); 160 161 // Resolve the success of Store Conditionals 162 if (pkt->isLLSC() && pkt->isWrite()) { 163 pkt->req->setExtraData(event->isAtomic()); 164 } 165 166 // Clear out bus delay notifications 167 pkt->headerDelay = pkt->payloadDelay = 0; 168 169 if (blocked() || !sendTimingResp(pkt)) { 170 respQ.push_back(pkt); 171 } 172 } else { // we can handle unexpected invalidates, but nothing else. 173 Command cmd = event->getCmd(); 174 assert(cmd == Inv); 175 176 // make Req/Pkt for Snoop/no response needed 177 // presently no consideration for masterId, packet type, flags... 178 RequestPtr req = std::make_shared<Request>( 179 event->getAddr(), event->getSize(), 0, 0); 180 181 auto pkt = new Packet(req, ::MemCmd::InvalidateReq); 182 183 // Clear out bus delay notifications 184 pkt->headerDelay = pkt->payloadDelay = 0; 185 186 sendTimingSnoopReq(pkt); 187 } 188 delete event; 189} 190 191void 192ExtSlave::recvRespRetry() 193{ 194 while (blocked() && sendTimingResp(respQ.front())) { 195 respQ.pop_front(); 196 } 197} 198