summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgignore1
-rwxr-xr-xSConstruct4
-rw-r--r--configs/common/MemConfig.py1
-rw-r--r--ext/dramsim2/README11
-rw-r--r--ext/dramsim2/SConscript86
-rw-r--r--src/mem/DRAMSim2.py56
-rw-r--r--src/mem/SConscript7
-rw-r--r--src/mem/dramsim2.cc410
-rw-r--r--src/mem/dramsim2.hh210
-rw-r--r--src/mem/dramsim2_wrapper.cc199
-rw-r--r--src/mem/dramsim2_wrapper.hh163
11 files changed, 1148 insertions, 0 deletions
diff --git a/.hgignore b/.hgignore
index 9e4aee18a..9f3ff247c 100644
--- a/.hgignore
+++ b/.hgignore
@@ -9,3 +9,4 @@ cscope.out
.*.swp
m5out
src/doxygen
+ext/dramsim2/DRAMSim2
diff --git a/SConstruct b/SConstruct
index cdd44a871..27f44f893 100755
--- a/SConstruct
+++ b/SConstruct
@@ -1154,6 +1154,10 @@ main.SConscript('ext/libfdt/SConscript',
main.SConscript('ext/fputils/SConscript',
variant_dir = joinpath(build_root, 'fputils'))
+# DRAMSim2 build is shared across all configs in the build root.
+main.SConscript('ext/dramsim2/SConscript',
+ variant_dir = joinpath(build_root, 'dramsim2'))
+
###################################################
#
# This function is used to set up a directory with switching headers
diff --git a/configs/common/MemConfig.py b/configs/common/MemConfig.py
index 456ff4e1d..b49995369 100644
--- a/configs/common/MemConfig.py
+++ b/configs/common/MemConfig.py
@@ -54,6 +54,7 @@ _mem_aliases_all = [
("lpddr2_s4_1066_x32", "LPDDR2_S4_1066_x32"),
("lpddr3_1600_x32", "LPDDR3_1600_x32"),
("wio_200_x128", "WideIO_200_x128"),
+ ("dramsim2", "DRAMSim2")
]
# Filtered list of aliases. Only aliases for existing memory
diff --git a/ext/dramsim2/README b/ext/dramsim2/README
new file mode 100644
index 000000000..f83e3f0bd
--- /dev/null
+++ b/ext/dramsim2/README
@@ -0,0 +1,11 @@
+Follow these steps to get DRAMSim2 as part of gem5
+
+1. Download DRAMSim2
+ 1.1 Go to ext/dramsim2 (this directory)
+ 1.2 Clone DRAMSim2: git clone git://github.com/dramninjasUMD/DRAMSim2.git
+
+2. Compile gem5
+ 2.1 Business as usual
+
+3. Run gem5 with DRAMSim2
+ 3.1 Use --mem-type=dramsim2 and set the device and system configuration
diff --git a/ext/dramsim2/SConscript b/ext/dramsim2/SConscript
new file mode 100644
index 000000000..23ba55e52
--- /dev/null
+++ b/ext/dramsim2/SConscript
@@ -0,0 +1,86 @@
+# -*- 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.
+#
+# Authors: Andreas Hansson
+
+import os
+
+Import('main')
+
+# See if we got a cloned DRAMSim2 repo as a subdirectory and set the
+# HAVE_DRAMSIM flag accordingly
+if not os.path.exists(Dir('.').srcnode().abspath + '/DRAMSim2'):
+ main['HAVE_DRAMSIM'] = False
+ Return()
+
+# We have got the folder, so add the library and build the wrappers
+main['HAVE_DRAMSIM'] = True
+
+# Add the appropriate files. We leave out the trace driven simulator
+dram_files = []
+
+def DRAMFile(filename):
+ dram_files.append(File('DRAMSim2/' + filename))
+
+DRAMFile('AddressMapping.cpp')
+DRAMFile('Bank.cpp')
+DRAMFile('BankState.cpp')
+DRAMFile('BusPacket.cpp')
+DRAMFile('ClockDomain.cpp')
+DRAMFile('CommandQueue.cpp')
+DRAMFile('IniReader.cpp')
+DRAMFile('MemoryController.cpp')
+DRAMFile('MemorySystem.cpp')
+DRAMFile('MultiChannelMemorySystem.cpp')
+DRAMFile('Rank.cpp')
+DRAMFile('SimulatorObject.cpp')
+DRAMFile('Transaction.cpp')
+
+# DRAMSim2 violates some of the warning flags used by gem5, so
+# we explicitly disable them here
+dramenv = main.Clone()
+dramenv.Append(CCFLAGS=['-Wno-unused-value'])
+
+# Tell DRAMSim2 to not store any data as this is already covered by
+# the wrapper
+dramenv.Append(CCFLAGS=['-DNO_STORAGE'])
+
+dramenv.Library('dramsim2', [main.SharedObject(f) for f in dram_files])
+
+main.Prepend(CPPPATH=Dir('.'))
+main.Append(LIBS=['dramsim2'])
+main.Prepend(LIBPATH=[Dir('.')])
diff --git a/src/mem/DRAMSim2.py b/src/mem/DRAMSim2.py
new file mode 100644
index 000000000..9352e8b12
--- /dev/null
+++ b/src/mem/DRAMSim2.py
@@ -0,0 +1,56 @@
+# 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 AbstractMemory import *
+
+# A wrapper for DRAMSim2 multi-channel memory controller
+class DRAMSim2(AbstractMemory):
+ type = 'DRAMSim2'
+ cxx_header = "mem/dramsim2.hh"
+
+ # A single port for now
+ port = SlavePort("Slave port")
+
+ deviceConfigFile = Param.String("ini/DDR3_micron_32M_8B_x8_sg15.ini",
+ "Device configuration file")
+ systemConfigFile = Param.String("system.ini.example",
+ "Memory organisation configuration file")
+ filePath = Param.String("ext/dramsim2/DRAMSim2/",
+ "Directory to prepend to file names")
+ traceFile = Param.String("", "Output file for trace generation")
+ enableDebug = Param.Bool(False, "Enable DRAMSim2 debug output")
diff --git a/src/mem/SConscript b/src/mem/SConscript
index 90b49067e..9096fad5c 100644
--- a/src/mem/SConscript
+++ b/src/mem/SConscript
@@ -66,6 +66,11 @@ if env['TARGET_ISA'] != 'null':
Source('se_translating_port_proxy.cc')
Source('page_table.cc')
+ if env['HAVE_DRAMSIM']:
+ SimObject('DRAMSim2.py')
+ Source('dramsim2_wrapper.cc')
+ Source('dramsim2.cc')
+
DebugFlag('BaseBus')
DebugFlag('BusAddrRanges')
DebugFlag('CoherentBus')
@@ -81,6 +86,8 @@ DebugFlag('MMU')
DebugFlag('MemoryAccess')
DebugFlag('PacketQueue')
+DebugFlag("DRAMSim2")
+
DebugFlag('ProtocolTrace')
DebugFlag('RubyCache')
DebugFlag('RubyCacheTrace')
diff --git a/src/mem/dramsim2.cc b/src/mem/dramsim2.cc
new file mode 100644
index 000000000..cbba2767e
--- /dev/null
+++ b/src/mem/dramsim2.cc
@@ -0,0 +1,410 @@
+/*
+ * 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 "DRAMSim2/Callback.h"
+#include "base/callback.hh"
+#include "base/trace.hh"
+#include "debug/DRAMSim2.hh"
+#include "debug/Drain.hh"
+#include "mem/dramsim2.hh"
+#include "sim/system.hh"
+
+DRAMSim2::DRAMSim2(const Params* p) :
+ AbstractMemory(p),
+ port(name() + ".port", *this),
+ wrapper(p->deviceConfigFile, p->systemConfigFile, p->filePath,
+ p->traceFile, p->range.size() / 1024 / 1024, p->enableDebug),
+ retryReq(false), retryResp(false),
+ nbrOutstandingReads(0), nbrOutstandingWrites(0),
+ drainManager(NULL),
+ sendResponseEvent(this), tickEvent(this)
+{
+ DPRINTF(DRAMSim2,
+ "Instantiated DRAMSim2 with clock %d ns and queue size %d\n",
+ wrapper.clockPeriod(), wrapper.queueSize());
+
+ DRAMSim::TransactionCompleteCB* read_cb =
+ new DRAMSim::Callback<DRAMSim2, void, unsigned, uint64_t, uint64_t>(
+ this, &DRAMSim2::readComplete);
+ DRAMSim::TransactionCompleteCB* write_cb =
+ new DRAMSim::Callback<DRAMSim2, void, unsigned, uint64_t, uint64_t>(
+ this, &DRAMSim2::writeComplete);
+ wrapper.setCallbacks(read_cb, write_cb);
+
+ // Register a callback to compensate for the destructor not
+ // being called. The callback prints the DRAMSim2 stats.
+ Callback* cb = new MakeCallback<DRAMSim2Wrapper,
+ &DRAMSim2Wrapper::printStats>(wrapper);
+ registerExitCallback(cb);
+}
+
+void
+DRAMSim2::init()
+{
+ if (!port.isConnected()) {
+ fatal("DRAMSim2 %s is unconnected!\n", name());
+ } else {
+ port.sendRangeChange();
+ }
+
+ if (system()->cacheLineSize() != wrapper.burstSize())
+ fatal("DRAMSim2 burst size %d does not match cache line size %d\n",
+ wrapper.burstSize(), system()->cacheLineSize());
+}
+
+void
+DRAMSim2::startup()
+{
+ // kick off the clock ticks
+ schedule(tickEvent, clockEdge());
+}
+
+void
+DRAMSim2::sendResponse()
+{
+ assert(!retryResp);
+ assert(!responseQueue.empty());
+
+ DPRINTF(DRAMSim2, "Attempting to send response\n");
+
+ bool success = port.sendTimingResp(responseQueue.front());
+ if (success) {
+ responseQueue.pop_front();
+
+ DPRINTF(DRAMSim2, "Have %d read, %d write, %d responses outstanding\n",
+ nbrOutstandingReads, nbrOutstandingWrites,
+ responseQueue.size());
+
+ if (!responseQueue.empty() && !sendResponseEvent.scheduled())
+ schedule(sendResponseEvent, curTick());
+
+ // check if we were asked to drain and if we are now done
+ if (drainManager && nbrOutstanding() == 0) {
+ drainManager->signalDrainDone();
+ drainManager = NULL;
+ }
+ } else {
+ retryResp = true;
+
+ DPRINTF(DRAMSim2, "Waiting for response retry\n");
+
+ assert(!sendResponseEvent.scheduled());
+ }
+}
+
+unsigned int
+DRAMSim2::nbrOutstanding() const
+{
+ return nbrOutstandingReads + nbrOutstandingWrites + responseQueue.size();
+}
+
+void
+DRAMSim2::tick()
+{
+ 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.sendRetry();
+ }
+
+ schedule(tickEvent, curTick() + wrapper.clockPeriod() * SimClock::Int::ns);
+}
+
+Tick
+DRAMSim2::recvAtomic(PacketPtr pkt)
+{
+ access(pkt);
+
+ // 50 ns is just an arbitrary value at this point
+ return pkt->memInhibitAsserted() ? 0 : 50000;
+}
+
+void
+DRAMSim2::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->checkFunctional(*i);
+
+ pkt->popLabel();
+}
+
+bool
+DRAMSim2::recvTimingReq(PacketPtr pkt)
+{
+ // we should never see a new request while in retry
+ assert(!retryReq);
+
+ // @todo temporary hack to deal with memory corruption issues until
+ // 4-phase transactions are complete
+ for (int x = 0; x < pendingDelete.size(); x++)
+ delete pendingDelete[x];
+ pendingDelete.clear();
+
+ if (pkt->memInhibitAsserted()) {
+ // snooper will supply based on copy of packet
+ // still target's responsibility to delete packet
+ pendingDelete.push_back(pkt);
+ return true;
+ }
+
+ // 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());
+
+ DPRINTF(DRAMSim2, "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->isWrite(), pkt->getAddr());
+
+ return true;
+ } else {
+ retryReq = true;
+ return false;
+ }
+}
+
+void
+DRAMSim2::recvRetry()
+{
+ DPRINTF(DRAMSim2, "Retrying\n");
+
+ assert(retryResp);
+ retryResp = false;
+ sendResponse();
+}
+
+void
+DRAMSim2::accessAndRespond(PacketPtr pkt)
+{
+ DPRINTF(DRAMSim2, "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());
+
+ // @todo someone should pay for this
+ pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+
+ DPRINTF(DRAMSim2, "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, curTick());
+ } else {
+ // @todo the packet is going to be deleted, and the DRAMPacket
+ // is still having a pointer to it
+ pendingDelete.push_back(pkt);
+ }
+}
+
+void DRAMSim2::readComplete(unsigned id, uint64_t addr, uint64_t cycle)
+{
+ assert(cycle == divCeil(curTick(),
+ wrapper.clockPeriod() * SimClock::Int::ns));
+
+ DPRINTF(DRAMSim2, "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 DRAMSim2::writeComplete(unsigned id, uint64_t addr, uint64_t cycle)
+{
+ assert(cycle == divCeil(curTick(),
+ wrapper.clockPeriod() * SimClock::Int::ns));
+
+ DPRINTF(DRAMSim2, "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;
+
+ // check if we were asked to drain and if we are now done
+ if (drainManager && nbrOutstanding() == 0) {
+ drainManager->signalDrainDone();
+ drainManager = NULL;
+ }
+}
+
+BaseSlavePort&
+DRAMSim2::getSlavePort(const std::string &if_name, PortID idx)
+{
+ if (if_name != "port") {
+ return MemObject::getSlavePort(if_name, idx);
+ } else {
+ return port;
+ }
+}
+
+unsigned int
+DRAMSim2::drain(DrainManager* dm)
+{
+ // check our outstanding reads and writes and if any they need to
+ // drain
+ if (nbrOutstanding() != 0) {
+ setDrainState(Drainable::Draining);
+ drainManager = dm;
+ return 1;
+ } else {
+ setDrainState(Drainable::Drained);
+ return 0;
+ }
+}
+
+DRAMSim2::MemoryPort::MemoryPort(const std::string& _name,
+ DRAMSim2& _memory)
+ : SlavePort(_name, &_memory), memory(_memory)
+{ }
+
+AddrRangeList
+DRAMSim2::MemoryPort::getAddrRanges() const
+{
+ AddrRangeList ranges;
+ ranges.push_back(memory.getAddrRange());
+ return ranges;
+}
+
+Tick
+DRAMSim2::MemoryPort::recvAtomic(PacketPtr pkt)
+{
+ return memory.recvAtomic(pkt);
+}
+
+void
+DRAMSim2::MemoryPort::recvFunctional(PacketPtr pkt)
+{
+ memory.recvFunctional(pkt);
+}
+
+bool
+DRAMSim2::MemoryPort::recvTimingReq(PacketPtr pkt)
+{
+ // pass it to the memory controller
+ return memory.recvTimingReq(pkt);
+}
+
+void
+DRAMSim2::MemoryPort::recvRetry()
+{
+ memory.recvRetry();
+}
+
+DRAMSim2*
+DRAMSim2Params::create()
+{
+ return new DRAMSim2(this);
+}
diff --git a/src/mem/dramsim2.hh b/src/mem/dramsim2.hh
new file mode 100644
index 000000000..c61b84cbe
--- /dev/null
+++ b/src/mem/dramsim2.hh
@@ -0,0 +1,210 @@
+/*
+ * 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
+ */
+
+/**
+ * @file
+ * DRAMSim2
+ */
+#ifndef __MEM_DRAMSIM2_HH__
+#define __MEM_DRAMSIM2_HH__
+
+#include <queue>
+
+#include "base/hashmap.hh"
+#include "mem/abstract_mem.hh"
+#include "mem/dramsim2_wrapper.hh"
+#include "mem/qport.hh"
+#include "params/DRAMSim2.hh"
+
+class DRAMSim2 : 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:
+
+ DRAMSim2& memory;
+
+ public:
+
+ MemoryPort(const std::string& _name, DRAMSim2& _memory);
+
+ protected:
+
+ Tick recvAtomic(PacketPtr pkt);
+
+ void recvFunctional(PacketPtr pkt);
+
+ bool recvTimingReq(PacketPtr pkt);
+
+ void recvRetry();
+
+ AddrRangeList getAddrRanges() const;
+
+ };
+
+ MemoryPort port;
+
+ /**
+ * The actual DRAMSim2 wrapper
+ */
+ DRAMSim2Wrapper 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 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.
+ */
+ m5::hash_map<Addr, std::queue<PacketPtr> > outstandingReads;
+ m5::hash_map<Addr, std::queue<PacketPtr> > outstandingWrites;
+
+ /**
+ * Count the number of outstanding transactions so that we can
+ * block any further requests until there is space in DRAMSim2 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 DRAMSim2 unconditionally passes
+ * responses back without any flow control.
+ */
+ std::deque<PacketPtr> responseQueue;
+
+ /**
+ * If we need to drain, keep the drain manager around until we're
+ * done here.
+ */
+ DrainManager *drainManager;
+
+ 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
+ */
+ EventWrapper<DRAMSim2, &DRAMSim2::sendResponse> sendResponseEvent;
+
+ /**
+ * Progress the controller one clock cycle.
+ */
+ void tick();
+
+ /**
+ * Event to schedule clock ticks
+ */
+ EventWrapper<DRAMSim2, &DRAMSim2::tick> tickEvent;
+
+ /** @todo this is a temporary workaround until the 4-phase code is
+ * committed. upstream caches needs this packet until true is returned, so
+ * hold onto it for deletion until a subsequent call
+ */
+ std::vector<PacketPtr> pendingDelete;
+
+ public:
+
+ typedef DRAMSim2Params Params;
+ DRAMSim2(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 DRAMSim2
+ */
+ void readComplete(unsigned id, uint64_t addr, uint64_t cycle);
+
+ /**
+ * Write completion callback.
+ *
+ * @param id Channel id of the responder
+ * @param addr Address of the request
+ * @param cycle Internal cycle count of DRAMSim2
+ */
+ void writeComplete(unsigned id, uint64_t addr, uint64_t cycle);
+
+ unsigned int drain(DrainManager* dm);
+
+ virtual BaseSlavePort& getSlavePort(const std::string& if_name,
+ PortID idx = InvalidPortID);
+
+ virtual void init();
+ virtual void startup();
+
+ protected:
+
+ Tick recvAtomic(PacketPtr pkt);
+ void recvFunctional(PacketPtr pkt);
+ bool recvTimingReq(PacketPtr pkt);
+ void recvRetry();
+
+};
+
+#endif // __MEM_DRAMSIM2_HH__
diff --git a/src/mem/dramsim2_wrapper.cc b/src/mem/dramsim2_wrapper.cc
new file mode 100644
index 000000000..34a7ad5d5
--- /dev/null
+++ b/src/mem/dramsim2_wrapper.cc
@@ -0,0 +1,199 @@
+/*
+ * 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 <cassert>
+
+/**
+ * When building the debug binary, we need to undo the command-line
+ * definition of DEBUG not to clash with DRAMSim2 print macros that
+ * are included for no obvious reason.
+ */
+#ifdef DEBUG
+#undef DEBUG
+#endif
+
+#include <fstream>
+
+#include "DRAMSim2/MultiChannelMemorySystem.h"
+#include "base/compiler.hh"
+#include "base/misc.hh"
+#include "mem/dramsim2_wrapper.hh"
+
+/**
+ * DRAMSim2 requires SHOW_SIM_OUTPUT to be defined (declared extern in
+ * the DRAMSim2 print macros), otherwise we get linking errors due to
+ * undefined references
+ */
+int SHOW_SIM_OUTPUT = 0;
+
+DRAMSim2Wrapper::DRAMSim2Wrapper(const std::string& config_file,
+ const std::string& system_file,
+ const std::string& working_dir,
+ const std::string& trace_file,
+ unsigned int memory_size_mb,
+ bool enable_debug) :
+ dramsim(new DRAMSim::MultiChannelMemorySystem(config_file, system_file,
+ working_dir, trace_file,
+ memory_size_mb, NULL, NULL)),
+ _clockPeriod(0.0), _queueSize(0), _burstSize(0)
+{
+ // tell DRAMSim2 to ignore its internal notion of a CPU frequency
+ dramsim->setCPUClockSpeed(0);
+
+ // switch on debug output if requested
+ if (enable_debug)
+ SHOW_SIM_OUTPUT = 1;
+
+ // there is no way of getting DRAMSim2 to tell us what frequency
+ // it is assuming, so we have to extract it ourselves
+ _clockPeriod = extractConfig<double>("tCK=",
+ working_dir + '/' + config_file);
+
+ if (!_clockPeriod)
+ fatal("DRAMSim2 wrapper failed to get clock\n");
+
+ // we also need to know what transaction queue size DRAMSim2 is
+ // using so we can stall when responses are blocked
+ _queueSize = extractConfig<unsigned int>("TRANS_QUEUE_DEPTH=",
+ working_dir + '/' + system_file);
+
+ if (!_queueSize)
+ fatal("DRAMSim2 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 =
+ extractConfig<unsigned int>("JEDEC_DATA_BUS_BITS=",
+ working_dir + '/' + system_file);
+ unsigned int burstLength =
+ extractConfig<unsigned int>("BL=", working_dir + '/' + config_file);
+
+ if (!dataBusBits || !burstLength)
+ fatal("DRAMSim22 wrapper failed to get burst size\n");
+
+ _burstSize = dataBusBits * burstLength / 8;
+}
+
+DRAMSim2Wrapper::~DRAMSim2Wrapper()
+{
+ delete dramsim;
+}
+
+template <typename T>
+T
+DRAMSim2Wrapper::extractConfig(const std::string& field_name,
+ const std::string& file_name) const
+{
+ std::ifstream file_stream(file_name.c_str(), ios::in);
+
+ if (!file_stream.good())
+ fatal("DRAMSim2 wrapper could not open %s for reading\n", file_name);
+
+ bool found = false;
+ T res;
+ std::string line;
+ while (!found && file_stream) {
+ getline(file_stream, line);
+ if (line.substr(0, field_name.size()) == field_name) {
+ found = true;
+ istringstream iss(line.substr(field_name.size()));
+ iss >> res;
+ }
+ }
+
+ file_stream.close();
+
+ if (!found)
+ fatal("DRAMSim2 wrapper could not find %s in %s\n", field_name,
+ file_name);
+
+ return res;
+}
+
+void
+DRAMSim2Wrapper::printStats()
+{
+ dramsim->printStats(true);
+}
+
+void
+DRAMSim2Wrapper::setCallbacks(DRAMSim::TransactionCompleteCB* read_callback,
+ DRAMSim::TransactionCompleteCB* write_callback)
+{
+ // simply pass it on, for now we ignore the power callback
+ dramsim->RegisterCallbacks(read_callback, write_callback, NULL);
+}
+
+bool
+DRAMSim2Wrapper::canAccept() const
+{
+ return dramsim->willAcceptTransaction();
+}
+
+void
+DRAMSim2Wrapper::enqueue(bool is_write, uint64_t addr)
+{
+ bool success M5_VAR_USED = dramsim->addTransaction(is_write, addr);
+ assert(success);
+}
+
+double
+DRAMSim2Wrapper::clockPeriod() const
+{
+ return _clockPeriod;
+}
+
+unsigned int
+DRAMSim2Wrapper::queueSize() const
+{
+ return _queueSize;
+}
+
+unsigned int
+DRAMSim2Wrapper::burstSize() const
+{
+ return _burstSize;
+}
+
+void
+DRAMSim2Wrapper::tick()
+{
+ dramsim->update();
+}
diff --git a/src/mem/dramsim2_wrapper.hh b/src/mem/dramsim2_wrapper.hh
new file mode 100644
index 000000000..94ae25a8b
--- /dev/null
+++ b/src/mem/dramsim2_wrapper.hh
@@ -0,0 +1,163 @@
+/*
+ * 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
+ */
+
+/**
+ * @file
+ * DRAMSim2Wrapper declaration
+ */
+
+#ifndef __MEM_DRAMSIM2_WRAPPER_HH__
+#define __MEM_DRAMSIM2_WRAPPER_HH__
+
+#include <string>
+
+#include "DRAMSim2/Callback.h"
+
+/**
+ * Forward declaration to avoid includes
+ */
+namespace DRAMSim {
+
+class MultiChannelMemorySystem;
+
+}
+
+/**
+ * Wrapper class to avoid having DRAMSim2 names like ClockDomain etc
+ * clashing with the normal gem5 world. Many of the DRAMSim2 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 DRAMSim2Wrapper
+{
+
+ private:
+
+ DRAMSim::MultiChannelMemorySystem* dramsim;
+
+ double _clockPeriod;
+
+ unsigned int _queueSize;
+
+ unsigned int _burstSize;
+
+ template <typename T>
+ T extractConfig(const std::string& field_name,
+ const std::string& file_name) const;
+
+ public:
+
+ /**
+ * Create an instance of the DRAMSim2 multi-channel memory
+ * controller using a specific config and system description.
+ *
+ * @param config_file Memory config file
+ * @param system_file Controller config file
+ * @param working_dir Path pre-pended to config files
+ * @param trace_file Output trace file
+ * @param memory_size_mb Total memory size in MByte
+ * @param enable_debug Enable debug output
+ */
+ DRAMSim2Wrapper(const std::string& config_file,
+ const std::string& system_file,
+ const std::string& working_dir,
+ const std::string& trace_file,
+ unsigned int memory_size_mb,
+ bool enable_debug);
+ ~DRAMSim2Wrapper();
+
+ /**
+ * Print the stats gathered in DRAMsim2.
+ */
+ void printStats();
+
+ /**
+ * 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(DRAMSim::TransactionCompleteCB* read_callback,
+ DRAMSim::TransactionCompleteCB* write_callback);
+
+ /**
+ * Determine if the controller can accept a new packet or not.
+ *
+ * @return true if the controller can accept transactions
+ */
+ bool canAccept() const;
+
+ /**
+ * Enqueue a packet. This assumes that canAccept has returned true.
+ *
+ * @param pkt Packet to turn into a DRAMSim2 transaction
+ */
+ void enqueue(bool is_write, uint64_t addr);
+
+ /**
+ * Get the internal clock period used by DRAMSim2, specified in
+ * ns.
+ *
+ * @return The clock period of the DRAM interface in ns
+ */
+ double clockPeriod() const;
+
+ /**
+ * Get the transaction queue size used by DRAMSim2.
+ *
+ * @return The queue size counted in number of transactions
+ */
+ unsigned int queueSize() const;
+
+ /**
+ * Get the burst size in bytes used by DRAMSim2.
+ *
+ * @return The burst size in bytes (data width * burst length)
+ */
+ unsigned int burstSize() const;
+
+ /**
+ * Progress the memory controller one cycle
+ */
+ void tick();
+};
+
+#endif //__MEM_DRAMSIM2_WRAPPER_HH__