| // Copyright (c) 2015 ARM Limited |
| // All rights reserved. |
| // |
| // The license below extends only to copyright in the software and shall |
| // not be construed as granting a license to any other intellectual |
| // property including but not limited to intellectual property relating |
| // to a hardware implementation of the functionality of the software |
| // licensed hereunder. You may use the software subject to the license |
| // terms below provided that you ensure that this notice is replicated |
| // unmodified and in its entirety in all distributions of the software, |
| // modified or unmodified, in source code or in binary form. |
| // |
| // 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. |
| |
| // Copyright 2009-2014 Sandia Coporation. Under the terms |
| // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. |
| // Government retains certain rights in this software. |
| // |
| // Copyright (c) 2009-2014, Sandia Corporation |
| // All rights reserved. |
| // |
| // For license information, see the LICENSE file in the current directory. |
| |
| #include "gem5.hh" |
| |
| #ifdef fatal // gem5 sets this |
| #undef fatal |
| #endif |
| |
| #include <mem/packet.hh> |
| |
| #include <elements/memHierarchy/memNIC.h> |
| |
| using namespace SST; |
| using namespace SST::gem5; |
| using namespace SST::MemHierarchy; |
| |
| ExtMaster::ExtMaster(gem5Component *g, Output &o, ::gem5::ExternalMaster& p, |
| std::string &n) : |
| ::gem5::ExternalMaster::Port(n, p), out(o), port(p), |
| simPhase(CONSTRUCTION), gem5(g), name(n) |
| { |
| Params _p; // will be ignored |
| nic = dynamic_cast<MemNIC*>(gem5->loadModuleWithComponent("memHierarchy.memNIC", g, _p)); |
| |
| MemNIC::ComponentInfo ci; |
| ci.num_vcs = 1; |
| ci.link_port = "network"; |
| ci.link_bandwidth = "16GB/s"; |
| ci.link_inbuf_size = "1KB"; |
| ci.link_outbuf_size = "1KB"; |
| ci.network_addr = 0; // hard coded at the moment |
| ci.type = MemNIC::TypeDirectoryCtrl; |
| nic->moduleInit(ci, new Event::Handler<ExtMaster> |
| (this, &ExtMaster::handleEvent)); |
| } |
| |
| void |
| ExtMaster::init(unsigned phase) |
| { |
| simPhase = INIT; |
| |
| if (phase == 0) { |
| assert(nic); |
| for (auto range : getAddrRanges()) { |
| MemNIC::ComponentTypeInfo ti; |
| ti.rangeStart = range.start(); |
| ti.rangeEnd = range.end(); |
| ti.interleaveSize = 0; |
| ti.interleaveStep = 0; |
| nic->addTypeInfo(ti); |
| ranges.insert(range); |
| } |
| } |
| |
| nic->init(phase); |
| } |
| |
| void |
| ExtMaster::setup(void) |
| { |
| nic->setup(); |
| |
| simPhase = RUN; |
| } |
| |
| void |
| ExtMaster::finish(void) |
| { |
| nic->finish(); |
| } |
| |
| void |
| ExtMaster::clock(void) |
| { |
| nic->clock(); |
| } |
| |
| void |
| ExtMaster::handleEvent(SST::Event* event) |
| { |
| if (simPhase == CONSTRUCTION) { |
| out.fatal(CALL_INFO, 1, "received Event during Construction phase\n"); |
| } |
| |
| MemEvent *ev = dynamic_cast<MemEvent*>(event); |
| if (!ev) { |
| out.fatal(CALL_INFO, 1, "Can't handle non-MemEvent Event's\n"); |
| } |
| |
| Command cmdI = ev->getCmd(); // command in - SST |
| ::gem5::MemCmd::Command cmdO; // command out - gem5 |
| bool data = false; |
| |
| switch (cmdI) { |
| case GetS: cmdO = ::gem5::MemCmd::ReadReq; break; |
| case GetX: cmdO = ::gem5::MemCmd::WriteReq; data = true; break; |
| case GetSEx: |
| case PutS: |
| case PutM: |
| case PutE: |
| case PutX: |
| case PutXE: |
| case Inv: |
| case FetchInv: |
| case FetchInvX: |
| |
| case NACK: |
| |
| case NULLCMD: |
| case GetSResp: |
| case GetXResp: |
| case FetchResp: |
| case FetchXResp: |
| out.fatal(CALL_INFO, 1, "Don't know how to convert " |
| "SST command %s to gem5\n", |
| CommandString[cmdI]); |
| } |
| |
| ::gem5::Request::FlagsType flags = 0; |
| if (ev->queryFlag(MemEvent::F_LOCKED)) |
| flags |= ::gem5::Request::LOCKED_RMW; |
| if (ev->queryFlag(MemEvent::F_NONCACHEABLE)) |
| flags |= ::gem5::Request::UNCACHEABLE; |
| if (ev->isLoadLink()) { |
| assert(cmdI == GetS); |
| cmdO = ::gem5::MemCmd::LoadLockedReq; |
| } else if (ev->isStoreConditional()) { |
| assert(cmdI == GetX); |
| cmdO = ::gem5::MemCmd::StoreCondReq; |
| } |
| |
| auto req = std::make_shared<::gem5::Request>( |
| ev->getAddr(), ev->getSize(), flags, 0); |
| req->setContext(ev->getGroupId()); |
| |
| auto pkt = new ::gem5::Packet(req, cmdO); |
| pkt->allocate(); |
| if (data) { |
| pkt->setData(ev->getPayload().data()); |
| } |
| pkt->pushSenderState(new SenderState(ev)); |
| |
| if (blocked() || !sendTimingReq(pkt)) |
| sendQ.push_back(pkt); |
| } |
| |
| bool |
| ExtMaster::recvTimingResp(::gem5::PacketPtr pkt) { |
| if (simPhase == INIT) { |
| out.fatal(CALL_INFO, 1, "not prepared to handle INIT-phase traffic\n"); |
| } |
| |
| // get original SST packet from gem5 SenderState |
| auto senderState = dynamic_cast<SenderState*>(pkt->popSenderState()); |
| if (!senderState) |
| out.fatal(CALL_INFO, 1, "gem5 senderState corrupt\n"); |
| |
| // make (new) response packet, discard (old) original request |
| MemEvent* ev = senderState->event; |
| delete senderState; |
| |
| MemEvent* resp = ev->makeResponse(); |
| delete ev; |
| |
| // copy the payload and then destroy gem5 packet |
| resp->setPayload(pkt->getSize(), pkt->getPtr<uint8_t>()); |
| delete pkt; |
| |
| nic->send(resp); |
| return true; |
| } |
| |
| void |
| ExtMaster::recvReqRetry() { |
| while (blocked() && sendTimingReq(sendQ.front())) { |
| sendQ.pop_front(); |
| } |
| } |
| |
| void |
| ExtMaster::recvRangeChange() { |
| for (auto range : getAddrRanges()) { |
| if (ranges.find(range) == ranges.end()) { // i.e. if not found, |
| MemNIC::ComponentTypeInfo ti; // indicating a new range. |
| ti.rangeStart = range.start(); |
| ti.rangeEnd = range.end(); |
| ti.interleaveSize = 0; |
| ti.interleaveStep = 0; |
| nic->addTypeInfo(ti); |
| ranges.insert(range); |
| } |
| } |
| } |