From: Mahyar Samani Date: Mon, 27 Jul 2020 15:26:04 +0000 (+0000) Subject: mem,ext: Integrating DRAMSim3 with gem5 X-Git-Tag: v20.1.0.0~160 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=dde093b283d1800d4856a252d58e29a010ecc74a;p=gem5.git mem,ext: Integrating DRAMSim3 with gem5 Adding DRAMSim3 source code to the gem5 source code, the original code was taken from umd-memsys github at https://github.com/umd-memsys/ Change-Id: I32c982206f33b0acf2121f322d15baa064c412c4 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/31757 Reviewed-by: Ayaz Akram Reviewed-by: Jason Lowe-Power Maintainer: Jason Lowe-Power Tested-by: kokoro --- diff --git a/ext/dramsim3/README b/ext/dramsim3/README new file mode 100644 index 000000000..f3ee0a44f --- /dev/null +++ b/ext/dramsim3/README @@ -0,0 +1,14 @@ +Follow these steps to get DRAMSim3 as part of gem5 + +1. Download DRAMSim3 + 1.1 Go to ext/dramsim3 (this directory) + 1.2 Clone DRAMSim3: git clone git@github.com:umd-memsys/DRAMSim3.git DRAMsim3 + 1.3 cd DRAMSim3 && mkdir build + 1.4 cd build + 1.5 cmake .. + 1.6 make + +2. Compile gem5 + 2.1 cd gem5 + 2.2 Business as usual + diff --git a/ext/dramsim3/SConscript b/ext/dramsim3/SConscript new file mode 100644 index 000000000..9e5a3a1a2 --- /dev/null +++ b/ext/dramsim3/SConscript @@ -0,0 +1,69 @@ +# -*- mode:python -*- + +# Copyright (c) 2013 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. +# + +import os + +Import('main') + +thermal = False + +# See if we got a cloned DRAMSim3 repo as a subdirectory and set the +# HAVE_DRAMSIM flag accordingly +if not os.path.exists(Dir('.').srcnode().abspath + '/DRAMsim3'): + main['HAVE_DRAMSIM3'] = False + Return() + +# We have got the folder, so add the library and build the wrappers +main['HAVE_DRAMSIM3'] = True + + +dramsim_path = os.path.join(Dir('#').abspath, 'ext/dramsim3/DRAMsim3/') + +if thermal: + superlu_path = os.path.join(dramsim_path, 'ext/SuperLU_MT_3.1/lib') + main.Prepend(CPPPATH=Dir('.')) + main.Append(LIBS=['dramsim3', 'superlu_mt_OPENMP', 'm', 'f77blas', + 'atlas', 'gomp'], + LIBPATH=[dramsim_path, superlu_path]) +else: + main.Prepend(CPPPATH=Dir('.')) + # a littel hacky but can get a shared library working + main.Append(LIBS=['dramsim3', 'gomp'], + LIBPATH=[dramsim_path], # compile-time lookup + RPATH=[dramsim_path], # runtime lookup + CPPPATH=[dramsim_path+'/src/']) diff --git a/src/mem/DRAMsim3.py b/src/mem/DRAMsim3.py new file mode 100644 index 000000000..e710bf4a0 --- /dev/null +++ b/src/mem/DRAMsim3.py @@ -0,0 +1,54 @@ +# Copyright (c) 2013 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. +# +# Authors: Andreas Hansson + +from m5.params import * +from m5.objects.AbstractMemory import * + +# A wrapper for DRAMSim3 multi-channel memory controller +class DRAMsim3(AbstractMemory): + type = 'DRAMsim3' + cxx_header = "mem/dramsim3.hh" + + # A single port for now + port = ResponsePort("port for receiving requests from" + "the CPU or other requestor") + + configFile = Param.String("ext/dramsim3/DRAMsim3/configs/" + "DDR4_8Gb_x8_2400.ini", + "The configuration file to use with DRAMSim3") + filePath = Param.String("ext/dramsim3/DRAMsim3/", + "Directory to prepend to file names") diff --git a/src/mem/SConscript b/src/mem/SConscript index 91cae3790..07e197b9e 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -91,6 +91,11 @@ if env['HAVE_DRAMSIM']: Source('dramsim2_wrapper.cc') Source('dramsim2.cc') +if env['HAVE_DRAMSIM3']: + SimObject('DRAMsim3.py') + Source('dramsim3_wrapper.cc') + Source('dramsim3.cc') + SimObject('MemChecker.py') Source('mem_checker.cc') Source('mem_checker_monitor.cc') @@ -115,6 +120,7 @@ DebugFlag('MemoryAccess') DebugFlag('PacketQueue') DebugFlag('StackDist') DebugFlag("DRAMSim2") +DebugFlag("DRAMsim3") DebugFlag('HMCController') DebugFlag('SerialLink') DebugFlag('TokenPort') diff --git a/src/mem/dramsim3.cc b/src/mem/dramsim3.cc new file mode 100644 index 000000000..fc2eaca21 --- /dev/null +++ b/src/mem/dramsim3.cc @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2013 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. + * + * Authors: Andreas Hansson + */ + +#include "mem/dramsim3.hh" + +#include "base/callback.hh" +#include "base/trace.hh" +#include "debug/DRAMsim3.hh" +#include "debug/Drain.hh" +#include "sim/system.hh" + +DRAMsim3::DRAMsim3(const Params* p) : + AbstractMemory(p), + port(name() + ".port", *this), + read_cb(std::bind(&DRAMsim3::readComplete, + this, 0, std::placeholders::_1)), + write_cb(std::bind(&DRAMsim3::writeComplete, + this, 0, std::placeholders::_1)), + wrapper(p->configFile, p->filePath, read_cb, write_cb), + retryReq(false), retryResp(false), startTick(0), + nbrOutstandingReads(0), nbrOutstandingWrites(0), + sendResponseEvent([this]{ sendResponse(); }, name()), + tickEvent([this]{ tick(); }, name()) +{ + DPRINTF(DRAMsim3, + "Instantiated DRAMsim3 with clock %d ns and queue size %d\n", + wrapper.clockPeriod(), wrapper.queueSize()); + + // Register a callback to compensate for the destructor not + // being called. The callback prints the DRAMsim3 stats. + registerExitCallback([this]() { wrapper.printStats(); }); +} + +void +DRAMsim3::init() +{ + AbstractMemory::init(); + + if (!port.isConnected()) { + fatal("DRAMsim3 %s is unconnected!\n", name()); + } else { + port.sendRangeChange(); + } + + if (system()->cacheLineSize() != wrapper.burstSize()) + fatal("DRAMsim3 burst size %d does not match cache line size %d\n", + wrapper.burstSize(), system()->cacheLineSize()); +} + +void +DRAMsim3::startup() +{ + startTick = curTick(); + + // kick off the clock ticks + schedule(tickEvent, clockEdge()); +} + +void +DRAMsim3::resetStats() { + wrapper.resetStats(); +} + +void +DRAMsim3::sendResponse() +{ + assert(!retryResp); + assert(!responseQueue.empty()); + + DPRINTF(DRAMsim3, "Attempting to send response\n"); + + bool success = port.sendTimingResp(responseQueue.front()); + if (success) { + responseQueue.pop_front(); + + DPRINTF(DRAMsim3, "Have %d read, %d write, %d responses outstanding\n", + nbrOutstandingReads, nbrOutstandingWrites, + responseQueue.size()); + + if (!responseQueue.empty() && !sendResponseEvent.scheduled()) + schedule(sendResponseEvent, curTick()); + + if (nbrOutstanding() == 0) + signalDrainDone(); + } else { + retryResp = true; + + DPRINTF(DRAMsim3, "Waiting for response retry\n"); + + assert(!sendResponseEvent.scheduled()); + } +} + +unsigned int +DRAMsim3::nbrOutstanding() const +{ + return nbrOutstandingReads + nbrOutstandingWrites + responseQueue.size(); +} + +void +DRAMsim3::tick() +{ + // Only tick when it's timing mode + if (system()->isTimingMode()) { + wrapper.tick(); + + // is the connected port waiting for a retry, if so check the + // state and send a retry if conditions have changed + if (retryReq && nbrOutstanding() < wrapper.queueSize()) { + retryReq = false; + port.sendRetryReq(); + } + } + + schedule(tickEvent, curTick() + wrapper.clockPeriod() * SimClock::Int::ns); +} + +Tick +DRAMsim3::recvAtomic(PacketPtr pkt) +{ + access(pkt); + + // 50 ns is just an arbitrary value at this point + return pkt->cacheResponding() ? 0 : 50000; +} + +void +DRAMsim3::recvFunctional(PacketPtr pkt) +{ + pkt->pushLabel(name()); + + functionalAccess(pkt); + + // potentially update the packets in our response queue as well + for (auto i = responseQueue.begin(); i != responseQueue.end(); ++i) + pkt->trySatisfyFunctional(*i); + + pkt->popLabel(); +} + +bool +DRAMsim3::recvTimingReq(PacketPtr pkt) +{ + // if a cache is responding, sink the packet without further action + if (pkt->cacheResponding()) { + pendingDelete.reset(pkt); + return true; + } + + // we should not get a new request after committing to retry the + // current one, but unfortunately the CPU violates this rule, so + // simply ignore it for now + if (retryReq) + return false; + + // if we cannot accept we need to send a retry once progress can + // be made + bool can_accept = nbrOutstanding() < wrapper.queueSize(); + + // keep track of the transaction + if (pkt->isRead()) { + if (can_accept) { + outstandingReads[pkt->getAddr()].push(pkt); + + // we count a transaction as outstanding until it has left the + // queue in the controller, and the response has been sent + // back, note that this will differ for reads and writes + ++nbrOutstandingReads; + } + } else if (pkt->isWrite()) { + if (can_accept) { + outstandingWrites[pkt->getAddr()].push(pkt); + + ++nbrOutstandingWrites; + + // perform the access for writes + accessAndRespond(pkt); + } + } else { + // keep it simple and just respond if necessary + accessAndRespond(pkt); + return true; + } + + if (can_accept) { + // we should never have a situation when we think there is space, + // and there isn't + assert(wrapper.canAccept(pkt->getAddr(), pkt->isWrite())); + + DPRINTF(DRAMsim3, "Enqueueing address %lld\n", pkt->getAddr()); + + // @todo what about the granularity here, implicit assumption that + // a transaction matches the burst size of the memory (which we + // cannot determine without parsing the ini file ourselves) + wrapper.enqueue(pkt->getAddr(), pkt->isWrite()); + + return true; + } else { + retryReq = true; + return false; + } +} + +void +DRAMsim3::recvRespRetry() +{ + DPRINTF(DRAMsim3, "Retrying\n"); + + assert(retryResp); + retryResp = false; + sendResponse(); +} + +void +DRAMsim3::accessAndRespond(PacketPtr pkt) +{ + DPRINTF(DRAMsim3, "Access for address %lld\n", pkt->getAddr()); + + bool needsResponse = pkt->needsResponse(); + + // do the actual memory access which also turns the packet into a + // response + access(pkt); + + // turn packet around to go back to requester if response expected + if (needsResponse) { + // access already turned the packet into a response + assert(pkt->isResponse()); + // Here we pay for xbar additional delay and to process the payload + // of the packet. + Tick time = curTick() + pkt->headerDelay + pkt->payloadDelay; + // Reset the timings of the packet + pkt->headerDelay = pkt->payloadDelay = 0; + + DPRINTF(DRAMsim3, "Queuing response for address %lld\n", + pkt->getAddr()); + + // queue it to be sent back + responseQueue.push_back(pkt); + + // if we are not already waiting for a retry, or are scheduled + // to send a response, schedule an event + if (!retryResp && !sendResponseEvent.scheduled()) + schedule(sendResponseEvent, time); + } else { + // queue the packet for deletion + pendingDelete.reset(pkt); + } +} + +void DRAMsim3::readComplete(unsigned id, uint64_t addr) +{ + + DPRINTF(DRAMsim3, "Read to address %lld complete\n", addr); + + // get the outstanding reads for the address in question + auto p = outstandingReads.find(addr); + assert(p != outstandingReads.end()); + + // first in first out, which is not necessarily true, but it is + // the best we can do at this point + PacketPtr pkt = p->second.front(); + p->second.pop(); + + if (p->second.empty()) + outstandingReads.erase(p); + + // no need to check for drain here as the next call will add a + // response to the response queue straight away + assert(nbrOutstandingReads != 0); + --nbrOutstandingReads; + + // perform the actual memory access + accessAndRespond(pkt); +} + +void DRAMsim3::writeComplete(unsigned id, uint64_t addr) +{ + + DPRINTF(DRAMsim3, "Write to address %lld complete\n", addr); + + // get the outstanding reads for the address in question + auto p = outstandingWrites.find(addr); + assert(p != outstandingWrites.end()); + + // we have already responded, and this is only to keep track of + // what is outstanding + p->second.pop(); + if (p->second.empty()) + outstandingWrites.erase(p); + + assert(nbrOutstandingWrites != 0); + --nbrOutstandingWrites; + + if (nbrOutstanding() == 0) + signalDrainDone(); +} + +Port& +DRAMsim3::getPort(const std::string &if_name, PortID idx) +{ + if (if_name != "port") { + return ClockedObject::getPort(if_name, idx); + } else { + return port; + } +} + +DrainState +DRAMsim3::drain() +{ + // check our outstanding reads and writes and if any they need to + // drain + return nbrOutstanding() != 0 ? DrainState::Draining : DrainState::Drained; +} + +DRAMsim3::MemoryPort::MemoryPort(const std::string& _name, + DRAMsim3& _memory) + : SlavePort(_name, &_memory), memory(_memory) +{ } + +AddrRangeList +DRAMsim3::MemoryPort::getAddrRanges() const +{ + AddrRangeList ranges; + ranges.push_back(memory.getAddrRange()); + return ranges; +} + +Tick +DRAMsim3::MemoryPort::recvAtomic(PacketPtr pkt) +{ + return memory.recvAtomic(pkt); +} + +void +DRAMsim3::MemoryPort::recvFunctional(PacketPtr pkt) +{ + memory.recvFunctional(pkt); +} + +bool +DRAMsim3::MemoryPort::recvTimingReq(PacketPtr pkt) +{ + // pass it to the memory controller + return memory.recvTimingReq(pkt); +} + +void +DRAMsim3::MemoryPort::recvRespRetry() +{ + memory.recvRespRetry(); +} + +DRAMsim3* +DRAMsim3Params::create() +{ + return new DRAMsim3(this); +} diff --git a/src/mem/dramsim3.hh b/src/mem/dramsim3.hh new file mode 100644 index 000000000..1b4a8a6f5 --- /dev/null +++ b/src/mem/dramsim3.hh @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2013 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. + * + */ + +/** + * @file + * DRAMsim3 + */ +#ifndef __MEM_DRAMSIM3_HH__ +#define __MEM_DRAMSIM3_HH__ + +#include +#include +#include + +#include "mem/abstract_mem.hh" +#include "mem/dramsim3_wrapper.hh" +#include "mem/qport.hh" +#include "params/DRAMsim3.hh" + +class DRAMsim3 : public AbstractMemory +{ + private: + + /** + * The memory port has to deal with its own flow control to avoid + * having unbounded storage that is implicitly created in the port + * itself. + */ + class MemoryPort : public SlavePort + { + + private: + + DRAMsim3& memory; + + public: + + MemoryPort(const std::string& _name, DRAMsim3& _memory); + + protected: + + Tick recvAtomic(PacketPtr pkt); + + void recvFunctional(PacketPtr pkt); + + bool recvTimingReq(PacketPtr pkt); + + void recvRespRetry(); + + AddrRangeList getAddrRanges() const; + + }; + + MemoryPort port; + + /** + * Callback functions + */ + std::function read_cb; + std::function write_cb; + + /** + * The actual DRAMsim3 wrapper + */ + DRAMsim3Wrapper wrapper; + + /** + * Is the connected port waiting for a retry from us + */ + bool retryReq; + + /** + * Are we waiting for a retry for sending a response. + */ + bool retryResp; + + /** + * Keep track of when the wrapper is started. + */ + Tick startTick; + + /** + * Keep track of what packets are outstanding per + * address, and do so separately for reads and writes. This is + * done so that we can return the right packet on completion from + * DRAMSim. + */ + std::unordered_map > outstandingReads; + std::unordered_map > outstandingWrites; + + /** + * Count the number of outstanding transactions so that we can + * block any further requests until there is space in DRAMsim3 and + * the sending queue we need to buffer the response packets. + */ + unsigned int nbrOutstandingReads; + unsigned int nbrOutstandingWrites; + + /** + * Queue to hold response packets until we can send them + * back. This is needed as DRAMsim3 unconditionally passes + * responses back without any flow control. + */ + std::deque responseQueue; + + + unsigned int nbrOutstanding() const; + + /** + * When a packet is ready, use the "access()" method in + * AbstractMemory to actually create the response packet, and send + * it back to the outside world requestor. + * + * @param pkt The packet from the outside world + */ + void accessAndRespond(PacketPtr pkt); + + void sendResponse(); + + /** + * Event to schedule sending of responses + */ + EventFunctionWrapper sendResponseEvent; + + /** + * Progress the controller one clock cycle. + */ + void tick(); + + /** + * Event to schedule clock ticks + */ + EventFunctionWrapper tickEvent; + + /** + * Upstream caches need this packet until true is returned, so + * hold it for deletion until a subsequent call + */ + std::unique_ptr pendingDelete; + + public: + + typedef DRAMsim3Params Params; + DRAMsim3(const Params *p); + + /** + * Read completion callback. + * + * @param id Channel id of the responder + * @param addr Address of the request + * @param cycle Internal cycle count of DRAMsim3 + */ + void readComplete(unsigned id, uint64_t addr); + + /** + * Write completion callback. + * + * @param id Channel id of the responder + * @param addr Address of the request + * @param cycle Internal cycle count of DRAMsim3 + */ + void writeComplete(unsigned id, uint64_t addr); + + DrainState drain() override; + + virtual Port& getPort(const std::string& if_name, + PortID idx = InvalidPortID) override; + + void init() override; + void startup() override; + + void resetStats() override; + + protected: + + Tick recvAtomic(PacketPtr pkt); + void recvFunctional(PacketPtr pkt); + bool recvTimingReq(PacketPtr pkt); + void recvRespRetry(); + +}; + +#endif // __MEM_DRAMSIM3_HH__ diff --git a/src/mem/dramsim3_wrapper.cc b/src/mem/dramsim3_wrapper.cc new file mode 100644 index 000000000..07754bc6a --- /dev/null +++ b/src/mem/dramsim3_wrapper.cc @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2013 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. + * + */ + +#include + +/** + * When building the debug binary, we need to undo the command-line + * definition of DEBUG not to clash with DRAMsim3 print macros that + * are included for no obvious reason. + */ +#ifdef DEBUG +#undef DEBUG +#endif + +#include "mem/dramsim3_wrapper.hh" + +#include + +#include "DRAMsim3/src/dramsim3.h" +#include "base/compiler.hh" +#include "base/logging.hh" + +DRAMsim3Wrapper::DRAMsim3Wrapper(const std::string& config_file, + const std::string& working_dir, + std::function read_cb, + std::function write_cb) : + dramsim(dramsim3::GetMemorySystem(config_file, working_dir, + read_cb, write_cb)), + _clockPeriod(0.0), _queueSize(0), _burstSize(0) +{ + // there is no way of getting DRAMsim3 to tell us what frequency + // it is assuming, so we have to extract it ourselves + _clockPeriod = dramsim->GetTCK(); + + if (!_clockPeriod) + fatal("DRAMsim3 wrapper failed to get clock\n"); + + // we also need to know what transaction queue size DRAMsim3 is + // using so we can stall when responses are blocked + _queueSize = dramsim->GetQueueSize(); + + if (!_queueSize) + fatal("DRAMsim3 wrapper failed to get queue size\n"); + + + // finally, get the data bus bits and burst length so we can add a + // sanity check for the burst size + unsigned int dataBusBits = dramsim->GetBusBits(); + unsigned int burstLength = dramsim->GetBurstLength(); + + if (!dataBusBits || !burstLength) + fatal("DRAMsim3 wrapper failed to get burst size\n"); + + _burstSize = dataBusBits * burstLength / 8; +} + +DRAMsim3Wrapper::~DRAMsim3Wrapper() +{ + delete dramsim; +} + + +void +DRAMsim3Wrapper::printStats() +{ + dramsim->PrintStats(); +} + +void +DRAMsim3Wrapper::resetStats() +{ + dramsim->ResetStats(); +} + +void +DRAMsim3Wrapper::setCallbacks(std::function read_complete, + std::function write_complete) +{ + dramsim->RegisterCallbacks(read_complete, write_complete); +} + +bool +DRAMsim3Wrapper::canAccept(uint64_t addr, bool is_write) const +{ + return dramsim->WillAcceptTransaction(addr, is_write); +} + +void +DRAMsim3Wrapper::enqueue(uint64_t addr, bool is_write) +{ + bool success M5_VAR_USED = dramsim->AddTransaction(addr, is_write); + assert(success); +} + +double +DRAMsim3Wrapper::clockPeriod() const +{ + return _clockPeriod; +} + +unsigned int +DRAMsim3Wrapper::queueSize() const +{ + return _queueSize; +} + +unsigned int +DRAMsim3Wrapper::burstSize() const +{ + return _burstSize; +} + +void +DRAMsim3Wrapper::tick() +{ + dramsim->ClockTick(); +} + diff --git a/src/mem/dramsim3_wrapper.hh b/src/mem/dramsim3_wrapper.hh new file mode 100644 index 000000000..0c4f6d02e --- /dev/null +++ b/src/mem/dramsim3_wrapper.hh @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2013 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. + * + */ + +/** + * @file + * DRAMsim3Wrapper declaration + */ + +#ifndef __MEM_DRAMSIM3_WRAPPER_HH__ +#define __MEM_DRAMSIM3_WRAPPER_HH__ + +#include +#include + +/** + * Forward declaration to avoid includes + */ +namespace dramsim3 { + +class MemorySystem; + +} + +/** + * Wrapper class to avoid having DRAMsim3 names like ClockDomain etc + * clashing with the normal gem5 world. Many of the DRAMsim3 headers + * do not make use of namespaces, and quite a few also open up + * std. The only thing that needs to be exposed externally are the + * callbacks. This wrapper effectively avoids clashes by not including + * any of the conventional gem5 headers (e.g. Packet or SimObject). + */ +class DRAMsim3Wrapper +{ + + private: + + dramsim3::MemorySystem* dramsim; + + double _clockPeriod; + + unsigned int _queueSize; + + unsigned int _burstSize; + + template + T extractConfig(const std::string& field_name, + const std::string& file_name) const; + + public: + + /** + * Create an instance of the DRAMsim3 multi-channel memory + * controller using a specific config and system description. + * + * @param config_file Memory config file + * @param working_dir Path pre-pended to config files + */ + DRAMsim3Wrapper(const std::string& config_file, + const std::string& working_dir, + std::function read_cb, + std::function write_cb); + ~DRAMsim3Wrapper(); + + /** + * Print the stats gathered in DRAMsim3. + */ + void printStats(); + + /** + * Reset stats (useful for fastforwarding switch) + */ + void resetStats(); + + /** + * Set the callbacks to use for read and write completion. + * + * @param read_callback Callback used for read completions + * @param write_callback Callback used for write completions + */ + void setCallbacks(std::function read_complete, + std::function write_complete); + + /** + * Determine if the controller can accept a new packet or not. + * + * @return true if the controller can accept transactions + */ + bool canAccept(uint64_t addr, bool is_write) const; + + /** + * Enqueue a packet. This assumes that canAccept has returned true. + * + * @param pkt Packet to turn into a DRAMsim3 transaction + */ + void enqueue(uint64_t addr, bool is_write); + + /** + * Get the internal clock period used by DRAMsim3, specified in + * ns. + * + * @return The clock period of the DRAM interface in ns + */ + double clockPeriod() const; + + /** + * Get the transaction queue size used by DRAMsim3. + * + * @return The queue size counted in number of transactions + */ + unsigned int queueSize() const; + + /** + * Get the burst size in bytes used by DRAMsim3. + * + * @return The burst size in bytes (data width * burst length) + */ + unsigned int burstSize() const; + + /** + * Progress the memory controller one cycle + */ + void tick(); +}; + +#endif //__MEM_DRAMSIM3_WRAPPER_HH__