summaryrefslogtreecommitdiff
path: root/src/mem/ruby
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem/ruby')
-rw-r--r--src/mem/ruby/SConscript1
-rw-r--r--src/mem/ruby/slicc_interface/AbstractCacheEntry.hh12
-rw-r--r--src/mem/ruby/slicc_interface/AbstractEntry.cc38
-rw-r--r--src/mem/ruby/slicc_interface/AbstractEntry.hh73
-rw-r--r--src/mem/ruby/slicc_interface/SConscript1
-rw-r--r--src/mem/ruby/system/Cache.py1
-rw-r--r--src/mem/ruby/system/CacheMemory.cc35
-rw-r--r--src/mem/ruby/system/CacheMemory.hh7
-rw-r--r--src/mem/ruby/system/DirectoryMemory.cc3
-rw-r--r--src/mem/ruby/system/DirectoryMemory.hh3
-rw-r--r--src/mem/ruby/system/DirectoryMemory.py1
-rw-r--r--src/mem/ruby/system/RubyPort.cc275
-rw-r--r--src/mem/ruby/system/RubyPort.hh90
-rw-r--r--src/mem/ruby/system/Sequencer.hh3
-rw-r--r--src/mem/ruby/system/Sequencer.py3
15 files changed, 486 insertions, 60 deletions
diff --git a/src/mem/ruby/SConscript b/src/mem/ruby/SConscript
index 66b091e22..1f7509df4 100644
--- a/src/mem/ruby/SConscript
+++ b/src/mem/ruby/SConscript
@@ -87,6 +87,7 @@ def MakeInclude(source):
target = generated_dir.File(basename(source))
env.Command(target, source, MakeIncludeAction)
+MakeInclude('slicc_interface/AbstractEntry.hh')
MakeInclude('slicc_interface/AbstractCacheEntry.hh')
MakeInclude('slicc_interface/AbstractProtocol.hh')
MakeInclude('slicc_interface/Message.hh')
diff --git a/src/mem/ruby/slicc_interface/AbstractCacheEntry.hh b/src/mem/ruby/slicc_interface/AbstractCacheEntry.hh
index be1f14b05..b98e1fa07 100644
--- a/src/mem/ruby/slicc_interface/AbstractCacheEntry.hh
+++ b/src/mem/ruby/slicc_interface/AbstractCacheEntry.hh
@@ -40,10 +40,11 @@
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/common/Address.hh"
#include "mem/protocol/AccessPermission.hh"
+#include "mem/ruby/slicc_interface/AbstractEntry.hh"
class DataBlock;
-class AbstractCacheEntry {
+class AbstractCacheEntry : public AbstractEntry {
public:
// Constructors
AbstractCacheEntry();
@@ -51,15 +52,6 @@ public:
// Destructor, prevent it from instantiation
virtual ~AbstractCacheEntry() = 0;
- // Public Methods
-
- // The methods below are those called by ruby runtime, add when it is
- // absolutely necessary and should all be virtual function.
- virtual DataBlock& getDataBlk() = 0;
-
-
- virtual void print(ostream& out) const = 0;
-
// Data Members (m_ prefix)
Address m_Address; // Address of this block, required by CacheMemory
Time m_LastRef; // Last time this block was referenced, required by CacheMemory
diff --git a/src/mem/ruby/slicc_interface/AbstractEntry.cc b/src/mem/ruby/slicc_interface/AbstractEntry.cc
new file mode 100644
index 000000000..914d4a37e
--- /dev/null
+++ b/src/mem/ruby/slicc_interface/AbstractEntry.cc
@@ -0,0 +1,38 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * 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 "mem/ruby/slicc_interface/AbstractEntry.hh"
+
+// Must define constructor and destructor in subclasses
+AbstractEntry::AbstractEntry() {
+}
+
+AbstractEntry::~AbstractEntry() {
+}
+
diff --git a/src/mem/ruby/slicc_interface/AbstractEntry.hh b/src/mem/ruby/slicc_interface/AbstractEntry.hh
new file mode 100644
index 000000000..8e1968d62
--- /dev/null
+++ b/src/mem/ruby/slicc_interface/AbstractEntry.hh
@@ -0,0 +1,73 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef AbstractEntry_H
+#define AbstractEntry_H
+
+#include "mem/ruby/common/Global.hh"
+#include "mem/ruby/common/Address.hh"
+#include "mem/protocol/AccessPermission.hh"
+
+class DataBlock;
+
+class AbstractEntry {
+public:
+ // Constructors
+ AbstractEntry();
+
+ // Destructor, prevent it from instantiation
+ virtual ~AbstractEntry() = 0;
+
+ // Public Methods
+
+ // The methods below are those called by ruby runtime, add when it is
+ // absolutely necessary and should all be virtual function.
+ virtual DataBlock& getDataBlk() = 0;
+
+
+ virtual void print(ostream& out) const = 0;
+
+};
+
+// Output operator declaration
+ostream& operator<<(ostream& out, const AbstractEntry& obj);
+
+// ******************* Definitions *******************
+
+// Output operator definition
+extern inline
+ostream& operator<<(ostream& out, const AbstractEntry& obj)
+{
+ obj.print(out);
+ out << flush;
+ return out;
+}
+
+#endif //AbstractEntry_H
+
diff --git a/src/mem/ruby/slicc_interface/SConscript b/src/mem/ruby/slicc_interface/SConscript
index 98f4b4fa2..111859559 100644
--- a/src/mem/ruby/slicc_interface/SConscript
+++ b/src/mem/ruby/slicc_interface/SConscript
@@ -35,6 +35,7 @@ if not env['RUBY']:
SimObject('Controller.py')
+Source('AbstractEntry.cc')
Source('AbstractCacheEntry.cc')
Source('RubySlicc_Profiler_interface.cc')
Source('RubySlicc_ComponentMapping.cc')
diff --git a/src/mem/ruby/system/Cache.py b/src/mem/ruby/system/Cache.py
index 250d8e888..209d6f6e2 100644
--- a/src/mem/ruby/system/Cache.py
+++ b/src/mem/ruby/system/Cache.py
@@ -9,4 +9,3 @@ class RubyCache(SimObject):
latency = Param.Int("");
assoc = Param.Int("");
replacement_policy = Param.String("PSEUDO_LRU", "");
- controller = Param.RubyController("");
diff --git a/src/mem/ruby/system/CacheMemory.cc b/src/mem/ruby/system/CacheMemory.cc
index 43a0e13e9..11dd8ca96 100644
--- a/src/mem/ruby/system/CacheMemory.cc
+++ b/src/mem/ruby/system/CacheMemory.cc
@@ -31,9 +31,6 @@
int CacheMemory::m_num_last_level_caches = 0;
MachineType CacheMemory::m_last_level_machine_type = MachineType_FIRST;
-// Output operator declaration
-//ostream& operator<<(ostream& out, const CacheMemory<ENTRY>& obj);
-
// ******************* Definitions *******************
// Output operator definition
@@ -56,29 +53,27 @@ RubyCacheParams::create()
CacheMemory::CacheMemory(const Params *p)
: SimObject(p)
{
- int cache_size = p->size;
+ m_cache_size = p->size;
m_latency = p->latency;
m_cache_assoc = p->assoc;
- string policy = p->replacement_policy;
- m_controller = p->controller;
-
- int num_lines = cache_size/RubySystem::getBlockSizeBytes();
- m_cache_num_sets = num_lines / m_cache_assoc;
- m_cache_num_set_bits = log_int(m_cache_num_sets);
- assert(m_cache_num_set_bits > 0);
-
- if(policy == "PSEUDO_LRU")
- m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc);
- else if (policy == "LRU")
- m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc);
- else
- assert(false);
-
+ m_policy = p->replacement_policy;
}
void CacheMemory::init()
{
+ m_cache_num_sets = (m_cache_size / m_cache_assoc) / RubySystem::getBlockSizeBytes();
+ assert(m_cache_num_sets > 1);
+ m_cache_num_set_bits = log_int(m_cache_num_sets);
+ assert(m_cache_num_set_bits > 0);
+
+ if(m_policy == "PSEUDO_LRU")
+ m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc);
+ else if (m_policy == "LRU")
+ m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc);
+ else
+ assert(false);
+
m_num_last_level_caches =
MachineType_base_count(MachineType_FIRST);
#if 0
@@ -126,8 +121,6 @@ CacheMemory::numberOfLastLevelCaches()
void CacheMemory::printConfig(ostream& out)
{
out << "Cache config: " << m_cache_name << endl;
- if (m_controller != NULL)
- out << " controller: " << m_controller->getName() << endl;
out << " cache_associativity: " << m_cache_assoc << endl;
out << " num_cache_sets_bits: " << m_cache_num_set_bits << endl;
const int cache_num_sets = 1 << m_cache_num_set_bits;
diff --git a/src/mem/ruby/system/CacheMemory.hh b/src/mem/ruby/system/CacheMemory.hh
index fac076da9..f70427f2d 100644
--- a/src/mem/ruby/system/CacheMemory.hh
+++ b/src/mem/ruby/system/CacheMemory.hh
@@ -72,10 +72,6 @@ public:
// Destructor
~CacheMemory();
- // factory
- // static CacheMemory* createCache(int level, int num, char split_type, AbstractCacheEntry* (*entry_factory)());
- // static CacheMemory* getCache(int cache_id);
-
// Public Methods
void printConfig(ostream& out);
@@ -155,7 +151,6 @@ private:
private:
const string m_cache_name;
- AbstractController* m_controller;
int m_latency;
// Data Members (m_prefix)
@@ -172,6 +167,8 @@ private:
CacheProfiler* m_profiler_ptr;
+ int m_cache_size;
+ string m_policy;
int m_cache_num_sets;
int m_cache_num_set_bits;
int m_cache_assoc;
diff --git a/src/mem/ruby/system/DirectoryMemory.cc b/src/mem/ruby/system/DirectoryMemory.cc
index b0b33b048..e4801594c 100644
--- a/src/mem/ruby/system/DirectoryMemory.cc
+++ b/src/mem/ruby/system/DirectoryMemory.cc
@@ -39,7 +39,6 @@
#include "mem/ruby/system/System.hh"
#include "mem/ruby/system/DirectoryMemory.hh"
#include "mem/ruby/slicc_interface/RubySlicc_Util.hh"
-#include "mem/ruby/slicc_interface/AbstractController.hh"
#include "mem/gems_common/util.hh"
int DirectoryMemory::m_num_directories = 0;
@@ -52,7 +51,6 @@ DirectoryMemory::DirectoryMemory(const Params *p)
m_version = p->version;
m_size_bytes = p->size_mb * static_cast<uint64>(1<<20);
m_size_bits = log_int(m_size_bytes);
- m_controller = p->controller;
}
void DirectoryMemory::init()
@@ -85,7 +83,6 @@ DirectoryMemory::~DirectoryMemory()
void DirectoryMemory::printConfig(ostream& out) const
{
out << "DirectoryMemory module config: " << m_name << endl;
- out << " controller: " << m_controller->getName() << endl;
out << " version: " << m_version << endl;
out << " memory_bits: " << m_size_bits << endl;
out << " memory_size_bytes: " << m_size_bytes << endl;
diff --git a/src/mem/ruby/system/DirectoryMemory.hh b/src/mem/ruby/system/DirectoryMemory.hh
index 1575187b0..0f4368b2c 100644
--- a/src/mem/ruby/system/DirectoryMemory.hh
+++ b/src/mem/ruby/system/DirectoryMemory.hh
@@ -46,8 +46,6 @@
#include "sim/sim_object.hh"
#include "params/RubyDirectoryMemory.hh"
-class AbstractController;
-
class DirectoryMemory : public SimObject {
public:
// Constructors
@@ -83,7 +81,6 @@ private:
private:
const string m_name;
- AbstractController* m_controller;
// Data Members (m_ prefix)
Directory_Entry **m_entries;
// int m_size; // # of memory module blocks this directory is responsible for
diff --git a/src/mem/ruby/system/DirectoryMemory.py b/src/mem/ruby/system/DirectoryMemory.py
index 55c2d82bd..e3becc4fc 100644
--- a/src/mem/ruby/system/DirectoryMemory.py
+++ b/src/mem/ruby/system/DirectoryMemory.py
@@ -7,4 +7,3 @@ class RubyDirectoryMemory(SimObject):
cxx_class = 'DirectoryMemory'
version = Param.Int(0, "")
size_mb = Param.Int(1024, "")
- controller = Param.RubyController(Parent.any, "")
diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc
index b83ba43e3..d8fb6b470 100644
--- a/src/mem/ruby/system/RubyPort.cc
+++ b/src/mem/ruby/system/RubyPort.cc
@@ -31,27 +31,290 @@
#include "mem/ruby/system/RubyPort.hh"
#include "mem/ruby/slicc_interface/AbstractController.hh"
-//void (*RubyPort::m_hit_callback)(int64_t) = NULL;
uint16_t RubyPort::m_num_ports = 0;
+RubyPort::RequestMap RubyPort::pending_cpu_requests;
+
RubyPort::RubyPort(const Params *p)
- : MemObject(p)
+ : MemObject(p),
+ funcMemPort(csprintf("%s-funcmem_port", name()), this)
{
m_version = p->version;
assert(m_version != -1);
- m_controller = p->controller;
- assert(m_controller != NULL);
- m_mandatory_q_ptr = m_controller->getMandatoryQueue();
+ m_controller = NULL;
+ m_mandatory_q_ptr = NULL;
m_port_id = m_num_ports++;
m_request_cnt = 0;
- m_hit_callback = NULL;
+ m_hit_callback = ruby_hit_callback;
+ pio_port = NULL;
assert(m_num_ports <= 2048); // see below for reason
}
+void RubyPort::init()
+{
+ assert(m_controller != NULL);
+ m_mandatory_q_ptr = m_controller->getMandatoryQueue();
+}
+
Port *
RubyPort::getPort(const std::string &if_name, int idx)
{
+ if (if_name == "port") {
+ return new M5Port(csprintf("%s-port%d", name(), idx), this);
+ } else if (if_name == "pio_port") {
+ //
+ // ensure there is only one pio port
+ //
+ assert(pio_port == NULL);
+
+ pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx),
+ this);
+
+ return pio_port;
+ } else if (if_name == "funcmem_port") {
+ return &funcMemPort;
+ }
return NULL;
}
+
+RubyPort::PioPort::PioPort(const std::string &_name,
+ RubyPort *_port)
+ : SimpleTimingPort(_name, _port)
+{
+ DPRINTF(Ruby, "creating port to ruby sequencer to cpu %s\n", _name);
+ ruby_port = _port;
+}
+
+RubyPort::M5Port::M5Port(const std::string &_name,
+ RubyPort *_port)
+ : SimpleTimingPort(_name, _port)
+{
+ DPRINTF(Ruby, "creating port from ruby sequcner to cpu %s\n", _name);
+ ruby_port = _port;
+}
+
+Tick
+RubyPort::PioPort::recvAtomic(PacketPtr pkt)
+{
+ panic("RubyPort::PioPort::recvAtomic() not implemented!\n");
+ return 0;
+}
+
+
+Tick
+RubyPort::M5Port::recvAtomic(PacketPtr pkt)
+{
+ panic("RubyPort::M5Port::recvAtomic() not implemented!\n");
+ return 0;
+}
+
+
+bool
+RubyPort::PioPort::recvTiming(PacketPtr pkt)
+{
+ //
+ // In FS mode, ruby memory will receive pio responses from devices and
+ // it must forward these responses back to the particular CPU.
+ //
+ DPRINTF(MemoryAccess,
+ "Pio response for address %#x\n",
+ pkt->getAddr());
+
+ assert(pkt->isResponse());
+
+ //
+ // First we must retrieve the request port from the sender State
+ //
+ RubyPort::SenderState *senderState =
+ safe_cast<RubyPort::SenderState *>(pkt->senderState);
+ M5Port *port = senderState->port;
+ assert(port != NULL);
+
+ // pop the sender state from the packet
+ pkt->senderState = senderState->saved;
+ delete senderState;
+
+ port->sendTiming(pkt);
+
+ return true;
+}
+
+bool
+RubyPort::M5Port::recvTiming(PacketPtr pkt)
+{
+ DPRINTF(MemoryAccess,
+ "Timing access caught for address %#x\n",
+ pkt->getAddr());
+
+ //dsm: based on SimpleTimingPort::recvTiming(pkt);
+
+ //
+ // After checking for pio responses, the remainder of packets
+ // received by ruby should only be M5 requests, which should never
+ // get nacked. There used to be code to hanldle nacks here, but
+ // I'm pretty sure it didn't work correctly with the drain code,
+ // so that would need to be fixed if we ever added it back.
+ //
+ assert(pkt->isRequest());
+
+ if (pkt->memInhibitAsserted()) {
+ warn("memInhibitAsserted???");
+ // snooper will supply based on copy of packet
+ // still target's responsibility to delete packet
+ delete pkt;
+ return true;
+ }
+
+ //
+ // Check for pio requests and directly send them to the dedicated
+ // pio port.
+ //
+ if (!isPhysMemAddress(pkt->getAddr())) {
+ assert(ruby_port->pio_port != NULL);
+
+ //
+ // Save the port in the sender state object to be used later to
+ // route the response
+ //
+ pkt->senderState = new SenderState(this, pkt->senderState);
+
+ return ruby_port->pio_port->sendTiming(pkt);
+ }
+
+ //
+ // For DMA and CPU requests, translate them to ruby requests before
+ // sending them to our assigned ruby port.
+ //
+ RubyRequestType type = RubyRequestType_NULL;
+ Addr pc = 0;
+ if (pkt->isRead()) {
+ if (pkt->req->isInstFetch()) {
+ type = RubyRequestType_IFETCH;
+ pc = pkt->req->getPC();
+ } else {
+ type = RubyRequestType_LD;
+ }
+ } else if (pkt->isWrite()) {
+ type = RubyRequestType_ST;
+ } else if (pkt->isReadWrite()) {
+ type = RubyRequestType_RMW_Write;
+ }
+
+ RubyRequest ruby_request(pkt->getAddr(), pkt->getPtr<uint8_t>(),
+ pkt->getSize(), pc, type,
+ RubyAccessMode_Supervisor);
+
+ // Submit the ruby request
+ int64_t req_id = ruby_port->makeRequest(ruby_request);
+ if (req_id == -1) {
+ return false;
+ }
+
+ // Save the request for the callback
+ RubyPort::pending_cpu_requests[req_id] = new RequestCookie(pkt, this);
+
+ return true;
+}
+
+void
+RubyPort::ruby_hit_callback(int64_t req_id)
+{
+ //
+ // Note: This single fuction can be called by cpu and dma ports,
+ // as well as the functional port.
+ //
+ RequestMap::iterator i = pending_cpu_requests.find(req_id);
+ if (i == pending_cpu_requests.end())
+ panic("could not find pending request %d\n", req_id);
+
+ RequestCookie *cookie = i->second;
+ pending_cpu_requests.erase(i);
+
+ Packet *pkt = cookie->pkt;
+ M5Port *port = cookie->m5Port;
+ delete cookie;
+
+ port->hitCallback(pkt);
+}
+
+void
+RubyPort::M5Port::hitCallback(PacketPtr pkt)
+{
+
+ bool needsResponse = pkt->needsResponse();
+
+ DPRINTF(MemoryAccess, "Hit callback needs response %d\n",
+ needsResponse);
+
+ ruby_port->funcMemPort.sendFunctional(pkt);
+
+ // turn packet around to go back to requester if response expected
+ if (needsResponse) {
+ // recvAtomic() should already have turned packet into
+ // atomic response
+ assert(pkt->isResponse());
+ DPRINTF(MemoryAccess, "Sending packet back over port\n");
+ sendTiming(pkt);
+ } else {
+ delete pkt;
+ }
+ DPRINTF(MemoryAccess, "Hit callback done!\n");
+}
+
+bool
+RubyPort::M5Port::sendTiming(PacketPtr pkt)
+{
+ schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0
+ return true;
+}
+
+bool
+RubyPort::PioPort::sendTiming(PacketPtr pkt)
+{
+ schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0
+ return true;
+}
+
+bool
+RubyPort::M5Port::isPhysMemAddress(Addr addr)
+{
+ AddrRangeList physMemAddrList;
+ bool snoop = false;
+ ruby_port->funcMemPort.getPeerAddressRanges(physMemAddrList, snoop);
+ for(AddrRangeIter iter = physMemAddrList.begin();
+ iter != physMemAddrList.end();
+ iter++) {
+ if (addr >= iter->start && addr <= iter->end) {
+ DPRINTF(MemoryAccess, "Request found in %#llx - %#llx range\n",
+ iter->start, iter->end);
+ return true;
+ }
+ }
+ assert(isPioAddress(addr));
+ return false;
+}
+
+bool
+RubyPort::M5Port::isPioAddress(Addr addr)
+{
+ AddrRangeList pioAddrList;
+ bool snoop = false;
+ if (ruby_port->pio_port == NULL) {
+ return false;
+ }
+
+ ruby_port->pio_port->getPeerAddressRanges(pioAddrList, snoop);
+ for(AddrRangeIter iter = pioAddrList.begin();
+ iter != pioAddrList.end();
+ iter++) {
+ if (addr >= iter->start && addr <= iter->end) {
+ DPRINTF(MemoryAccess, "Pio request found in %#llx - %#llx range\n",
+ iter->start, iter->end);
+ return true;
+ }
+ }
+ return false;
+}
+
diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh
index 20557669a..a03c4dce2 100644
--- a/src/mem/ruby/system/RubyPort.hh
+++ b/src/mem/ruby/system/RubyPort.hh
@@ -46,18 +46,81 @@ class AbstractController;
class RubyPort : public MemObject {
public:
+
+ class M5Port : public SimpleTimingPort
+ {
+
+ RubyPort *ruby_port;
+
+ public:
+ M5Port(const std::string &_name,
+ RubyPort *_port);
+ bool sendTiming(PacketPtr pkt);
+ void hitCallback(PacketPtr pkt);
+
+ protected:
+ virtual bool recvTiming(PacketPtr pkt);
+ virtual Tick recvAtomic(PacketPtr pkt);
+
+ private:
+ bool isPioAddress(Addr addr);
+ bool isPhysMemAddress(Addr addr);
+ };
+
+ friend class M5Port;
+
+ class PioPort : public SimpleTimingPort
+ {
+
+ RubyPort *ruby_port;
+
+ public:
+ PioPort(const std::string &_name,
+ RubyPort *_port);
+ bool sendTiming(PacketPtr pkt);
+
+ protected:
+ virtual bool recvTiming(PacketPtr pkt);
+ virtual Tick recvAtomic(PacketPtr pkt);
+ };
+
+ friend class PioPort;
+
+ struct SenderState : public Packet::SenderState
+ {
+ M5Port* port;
+ Packet::SenderState *saved;
+
+ SenderState(M5Port* _port,
+ Packet::SenderState *sender_state = NULL)
+ : port(_port), saved(sender_state)
+ {}
+ };
+
typedef RubyPortParams Params;
RubyPort(const Params *p);
- virtual ~RubyPort() {}
+ virtual ~RubyPort() {}
+
+ void init();
Port *getPort(const std::string &if_name, int idx);
- virtual int64_t makeRequest(const RubyRequest & request) = 0;
+ virtual int64_t makeRequest(const RubyRequest & request) = 0;
- void registerHitCallback(void (*hit_callback)(int64_t request_id)) {
- assert(m_hit_callback == NULL); // can't assign hit_callback twice
- m_hit_callback = hit_callback;
- }
+ void registerHitCallback(void (*hit_callback)(int64_t request_id)) {
+ //
+ // Can't assign hit_callback twice and by default it is set to the
+ // RubyPort's default callback function.
+ //
+ assert(m_hit_callback == ruby_hit_callback);
+ m_hit_callback = hit_callback;
+ }
+
+ //
+ // Called by the controller to give the sequencer a pointer.
+ // A pointer to the controller is needed for atomic support.
+ //
+ void setController(AbstractController* _cntrl) { m_controller = _cntrl; }
protected:
const string m_name;
@@ -87,11 +150,26 @@ protected:
int m_version;
AbstractController* m_controller;
MessageBuffer* m_mandatory_q_ptr;
+ PioPort* pio_port;
private:
static uint16_t m_num_ports;
uint16_t m_port_id;
uint64_t m_request_cnt;
+
+ struct RequestCookie {
+ Packet *pkt;
+ M5Port *m5Port;
+ RequestCookie(Packet *p, M5Port *m5p)
+ : pkt(p), m5Port(m5p)
+ {}
+ };
+
+ typedef std::map<int64_t, RequestCookie*> RequestMap;
+ static RequestMap pending_cpu_requests;
+ static void ruby_hit_callback(int64_t req_id);
+
+ FunctionalPort funcMemPort;
};
#endif
diff --git a/src/mem/ruby/system/Sequencer.hh b/src/mem/ruby/system/Sequencer.hh
index d2dc5bbb3..974b251f0 100644
--- a/src/mem/ruby/system/Sequencer.hh
+++ b/src/mem/ruby/system/Sequencer.hh
@@ -118,9 +118,6 @@ private:
CacheMemory* m_dataCache_ptr;
CacheMemory* m_instCache_ptr;
- // indicates what processor on the chip this sequencer is associated with
- int m_controller_type;
-
Map<Address, SequencerRequest*> m_writeRequestTable;
Map<Address, SequencerRequest*> m_readRequestTable;
// Global outstanding request count, across all request tables
diff --git a/src/mem/ruby/system/Sequencer.py b/src/mem/ruby/system/Sequencer.py
index add5a06a1..1333204a2 100644
--- a/src/mem/ruby/system/Sequencer.py
+++ b/src/mem/ruby/system/Sequencer.py
@@ -1,12 +1,13 @@
from m5.params import *
+from m5.proxy import *
from MemObject import MemObject
class RubyPort(MemObject):
type = 'RubyPort'
abstract = True
port = VectorPort("M5 port")
- controller = Param.RubyController("")
version = Param.Int(0, "")
+ pio_port = Port("Ruby_pio_port")
class RubySequencer(RubyPort):
type = 'RubySequencer'