summaryrefslogtreecommitdiff
path: root/src/mem/ruby/network
diff options
context:
space:
mode:
authorNilay Vaish <nilay@cs.wisc.edu>2014-09-01 16:55:40 -0500
committerNilay Vaish <nilay@cs.wisc.edu>2014-09-01 16:55:40 -0500
commit82d136285dac52a97384961a814d5a0dda4a6482 (patch)
tree7e5a7cb87120591f8d87e73cfad4f9d5a300ee67 /src/mem/ruby/network
parent01f792a3675983411ff77b54cbee7ffee2a3d5d5 (diff)
downloadgem5-82d136285dac52a97384961a814d5a0dda4a6482.tar.xz
ruby: move files from ruby/system to ruby/structures
The directory ruby/system is crowded and unorganized. Hence, the files the hold actual physical structures, are being moved to the directory ruby/structures. This includes Cache Memory, Directory Memory, Memory Controller, Wire Buffer, TBE Table, Perfect Cache Memory, Timer Table, Bank Array. The directory ruby/systems has the glue code that holds these structures together. --HG-- rename : src/mem/ruby/system/MachineID.hh => src/mem/ruby/common/MachineID.hh rename : src/mem/ruby/buffers/MessageBuffer.cc => src/mem/ruby/network/MessageBuffer.cc rename : src/mem/ruby/buffers/MessageBuffer.hh => src/mem/ruby/network/MessageBuffer.hh rename : src/mem/ruby/buffers/MessageBufferNode.cc => src/mem/ruby/network/MessageBufferNode.cc rename : src/mem/ruby/buffers/MessageBufferNode.hh => src/mem/ruby/network/MessageBufferNode.hh rename : src/mem/ruby/system/AbstractReplacementPolicy.hh => src/mem/ruby/structures/AbstractReplacementPolicy.hh rename : src/mem/ruby/system/BankedArray.cc => src/mem/ruby/structures/BankedArray.cc rename : src/mem/ruby/system/BankedArray.hh => src/mem/ruby/structures/BankedArray.hh rename : src/mem/ruby/system/Cache.py => src/mem/ruby/structures/Cache.py rename : src/mem/ruby/system/CacheMemory.cc => src/mem/ruby/structures/CacheMemory.cc rename : src/mem/ruby/system/CacheMemory.hh => src/mem/ruby/structures/CacheMemory.hh rename : src/mem/ruby/system/DirectoryMemory.cc => src/mem/ruby/structures/DirectoryMemory.cc rename : src/mem/ruby/system/DirectoryMemory.hh => src/mem/ruby/structures/DirectoryMemory.hh rename : src/mem/ruby/system/DirectoryMemory.py => src/mem/ruby/structures/DirectoryMemory.py rename : src/mem/ruby/system/LRUPolicy.hh => src/mem/ruby/structures/LRUPolicy.hh rename : src/mem/ruby/system/MemoryControl.cc => src/mem/ruby/structures/MemoryControl.cc rename : src/mem/ruby/system/MemoryControl.hh => src/mem/ruby/structures/MemoryControl.hh rename : src/mem/ruby/system/MemoryControl.py => src/mem/ruby/structures/MemoryControl.py rename : src/mem/ruby/system/MemoryNode.cc => src/mem/ruby/structures/MemoryNode.cc rename : src/mem/ruby/system/MemoryNode.hh => src/mem/ruby/structures/MemoryNode.hh rename : src/mem/ruby/system/MemoryVector.hh => src/mem/ruby/structures/MemoryVector.hh rename : src/mem/ruby/system/PerfectCacheMemory.hh => src/mem/ruby/structures/PerfectCacheMemory.hh rename : src/mem/ruby/system/PersistentTable.cc => src/mem/ruby/structures/PersistentTable.cc rename : src/mem/ruby/system/PersistentTable.hh => src/mem/ruby/structures/PersistentTable.hh rename : src/mem/ruby/system/PseudoLRUPolicy.hh => src/mem/ruby/structures/PseudoLRUPolicy.hh rename : src/mem/ruby/system/RubyMemoryControl.cc => src/mem/ruby/structures/RubyMemoryControl.cc rename : src/mem/ruby/system/RubyMemoryControl.hh => src/mem/ruby/structures/RubyMemoryControl.hh rename : src/mem/ruby/system/RubyMemoryControl.py => src/mem/ruby/structures/RubyMemoryControl.py rename : src/mem/ruby/system/SparseMemory.cc => src/mem/ruby/structures/SparseMemory.cc rename : src/mem/ruby/system/SparseMemory.hh => src/mem/ruby/structures/SparseMemory.hh rename : src/mem/ruby/system/TBETable.hh => src/mem/ruby/structures/TBETable.hh rename : src/mem/ruby/system/TimerTable.cc => src/mem/ruby/structures/TimerTable.cc rename : src/mem/ruby/system/TimerTable.hh => src/mem/ruby/structures/TimerTable.hh rename : src/mem/ruby/system/WireBuffer.cc => src/mem/ruby/structures/WireBuffer.cc rename : src/mem/ruby/system/WireBuffer.hh => src/mem/ruby/structures/WireBuffer.hh rename : src/mem/ruby/system/WireBuffer.py => src/mem/ruby/structures/WireBuffer.py rename : src/mem/ruby/recorder/CacheRecorder.cc => src/mem/ruby/system/CacheRecorder.cc rename : src/mem/ruby/recorder/CacheRecorder.hh => src/mem/ruby/system/CacheRecorder.hh
Diffstat (limited to 'src/mem/ruby/network')
-rw-r--r--src/mem/ruby/network/MessageBuffer.cc422
-rw-r--r--src/mem/ruby/network/MessageBuffer.hh215
-rw-r--r--src/mem/ruby/network/MessageBufferNode.cc39
-rw-r--r--src/mem/ruby/network/MessageBufferNode.hh75
-rw-r--r--src/mem/ruby/network/SConscript2
-rw-r--r--src/mem/ruby/network/garnet/BaseGarnetNetwork.cc2
-rw-r--r--src/mem/ruby/network/garnet/fixed-pipeline/NetworkInterface_d.cc2
-rw-r--r--src/mem/ruby/network/garnet/flexible-pipeline/NetworkInterface.cc2
-rw-r--r--src/mem/ruby/network/simple/PerfectSwitch.cc2
-rw-r--r--src/mem/ruby/network/simple/SimpleNetwork.cc2
-rw-r--r--src/mem/ruby/network/simple/Switch.cc2
-rw-r--r--src/mem/ruby/network/simple/Throttle.cc2
12 files changed, 760 insertions, 7 deletions
diff --git a/src/mem/ruby/network/MessageBuffer.cc b/src/mem/ruby/network/MessageBuffer.cc
new file mode 100644
index 000000000..1961765c5
--- /dev/null
+++ b/src/mem/ruby/network/MessageBuffer.cc
@@ -0,0 +1,422 @@
+/*
+ * 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 <cassert>
+
+#include "base/cprintf.hh"
+#include "base/misc.hh"
+#include "base/stl_helpers.hh"
+#include "debug/RubyQueue.hh"
+#include "mem/ruby/network/MessageBuffer.hh"
+#include "mem/ruby/system/System.hh"
+
+using namespace std;
+using m5::stl_helpers::operator<<;
+
+MessageBuffer::MessageBuffer(const string &name)
+ : m_time_last_time_size_checked(0), m_time_last_time_enqueue(0),
+ m_time_last_time_pop(0), m_last_arrival_time(0)
+{
+ m_msg_counter = 0;
+ m_consumer = NULL;
+ m_sender = NULL;
+ m_receiver = NULL;
+
+ m_ordering_set = false;
+ m_strict_fifo = true;
+ m_max_size = 0;
+ m_randomization = true;
+ m_size_last_time_size_checked = 0;
+ m_size_at_cycle_start = 0;
+ m_msgs_this_cycle = 0;
+ m_not_avail_count = 0;
+ m_priority_rank = 0;
+ m_name = name;
+
+ m_stall_msg_map.clear();
+ m_input_link_id = 0;
+ m_vnet_id = 0;
+}
+
+unsigned int
+MessageBuffer::getSize()
+{
+ if (m_time_last_time_size_checked != m_receiver->curCycle()) {
+ m_time_last_time_size_checked = m_receiver->curCycle();
+ m_size_last_time_size_checked = m_prio_heap.size();
+ }
+
+ return m_size_last_time_size_checked;
+}
+
+bool
+MessageBuffer::areNSlotsAvailable(unsigned int n)
+{
+
+ // fast path when message buffers have infinite size
+ if (m_max_size == 0) {
+ return true;
+ }
+
+ // determine the correct size for the current cycle
+ // pop operations shouldn't effect the network's visible size
+ // until next cycle, but enqueue operations effect the visible
+ // size immediately
+ unsigned int current_size = 0;
+
+ if (m_time_last_time_pop < m_sender->clockEdge()) {
+ // no pops this cycle - heap size is correct
+ current_size = m_prio_heap.size();
+ } else {
+ if (m_time_last_time_enqueue < m_sender->curCycle()) {
+ // no enqueues this cycle - m_size_at_cycle_start is correct
+ current_size = m_size_at_cycle_start;
+ } else {
+ // both pops and enqueues occured this cycle - add new
+ // enqueued msgs to m_size_at_cycle_start
+ current_size = m_size_at_cycle_start + m_msgs_this_cycle;
+ }
+ }
+
+ // now compare the new size with our max size
+ if (current_size + n <= m_max_size) {
+ return true;
+ } else {
+ DPRINTF(RubyQueue, "n: %d, current_size: %d, heap size: %d, "
+ "m_max_size: %d\n",
+ n, current_size, m_prio_heap.size(), m_max_size);
+ m_not_avail_count++;
+ return false;
+ }
+}
+
+const Message*
+MessageBuffer::peek() const
+{
+ DPRINTF(RubyQueue, "Peeking at head of queue.\n");
+ assert(isReady());
+
+ const Message* msg_ptr = m_prio_heap.front().m_msgptr.get();
+ assert(msg_ptr);
+
+ DPRINTF(RubyQueue, "Message: %s\n", (*msg_ptr));
+ return msg_ptr;
+}
+
+// FIXME - move me somewhere else
+Cycles
+random_time()
+{
+ Cycles time(1);
+ time += Cycles(random() & 0x3); // [0...3]
+ if ((random() & 0x7) == 0) { // 1 in 8 chance
+ time += Cycles(100 + (random() % 0xf)); // 100 + [1...15]
+ }
+ return time;
+}
+
+void
+MessageBuffer::enqueue(MsgPtr message, Cycles delta)
+{
+ m_msg_counter++;
+
+ // record current time incase we have a pop that also adjusts my size
+ if (m_time_last_time_enqueue < m_sender->curCycle()) {
+ m_msgs_this_cycle = 0; // first msg this cycle
+ m_time_last_time_enqueue = m_sender->curCycle();
+ }
+ m_msgs_this_cycle++;
+
+ assert(m_ordering_set);
+
+ // Calculate the arrival time of the message, that is, the first
+ // cycle the message can be dequeued.
+ assert(delta > 0);
+ Tick current_time = m_sender->clockEdge();
+ Tick arrival_time = 0;
+
+ if (!RubySystem::getRandomization() || !m_randomization) {
+ // No randomization
+ arrival_time = current_time + delta * m_sender->clockPeriod();
+ } else {
+ // Randomization - ignore delta
+ if (m_strict_fifo) {
+ if (m_last_arrival_time < current_time) {
+ m_last_arrival_time = current_time;
+ }
+ arrival_time = m_last_arrival_time +
+ random_time() * m_sender->clockPeriod();
+ } else {
+ arrival_time = current_time +
+ random_time() * m_sender->clockPeriod();
+ }
+ }
+
+ // Check the arrival time
+ assert(arrival_time > current_time);
+ if (m_strict_fifo) {
+ if (arrival_time < m_last_arrival_time) {
+ panic("FIFO ordering violated: %s name: %s current time: %d "
+ "delta: %d arrival_time: %d last arrival_time: %d\n",
+ *this, m_name, current_time,
+ delta * m_sender->clockPeriod(),
+ arrival_time, m_last_arrival_time);
+ }
+ }
+
+ // If running a cache trace, don't worry about the last arrival checks
+ if (!g_system_ptr->m_warmup_enabled) {
+ m_last_arrival_time = arrival_time;
+ }
+
+ // compute the delay cycles and set enqueue time
+ Message* msg_ptr = message.get();
+ assert(msg_ptr != NULL);
+
+ assert(m_sender->clockEdge() >= msg_ptr->getLastEnqueueTime() &&
+ "ensure we aren't dequeued early");
+
+ msg_ptr->updateDelayedTicks(m_sender->clockEdge());
+ msg_ptr->setLastEnqueueTime(arrival_time);
+
+ // Insert the message into the priority heap
+ MessageBufferNode thisNode(arrival_time, m_msg_counter, message);
+ m_prio_heap.push_back(thisNode);
+ push_heap(m_prio_heap.begin(), m_prio_heap.end(),
+ greater<MessageBufferNode>());
+
+ DPRINTF(RubyQueue, "Enqueue arrival_time: %lld, Message: %s\n",
+ arrival_time, *(message.get()));
+
+ // Schedule the wakeup
+ assert(m_consumer != NULL);
+ m_consumer->scheduleEventAbsolute(arrival_time);
+ m_consumer->storeEventInfo(m_vnet_id);
+}
+
+Cycles
+MessageBuffer::dequeue()
+{
+ DPRINTF(RubyQueue, "Popping\n");
+ assert(isReady());
+
+ // get MsgPtr of the message about to be dequeued
+ MsgPtr message = m_prio_heap.front().m_msgptr;
+
+ // get the delay cycles
+ message->updateDelayedTicks(m_receiver->clockEdge());
+ Cycles delayCycles =
+ m_receiver->ticksToCycles(message->getDelayedTicks());
+
+ // record previous size and time so the current buffer size isn't
+ // adjusted until next cycle
+ if (m_time_last_time_pop < m_receiver->clockEdge()) {
+ m_size_at_cycle_start = m_prio_heap.size();
+ m_time_last_time_pop = m_receiver->clockEdge();
+ }
+
+ pop_heap(m_prio_heap.begin(), m_prio_heap.end(),
+ greater<MessageBufferNode>());
+ m_prio_heap.pop_back();
+
+ return delayCycles;
+}
+
+void
+MessageBuffer::clear()
+{
+ m_prio_heap.clear();
+
+ m_msg_counter = 0;
+ m_time_last_time_enqueue = Cycles(0);
+ m_time_last_time_pop = 0;
+ m_size_at_cycle_start = 0;
+ m_msgs_this_cycle = 0;
+}
+
+void
+MessageBuffer::recycle()
+{
+ DPRINTF(RubyQueue, "Recycling.\n");
+ assert(isReady());
+ MessageBufferNode node = m_prio_heap.front();
+ pop_heap(m_prio_heap.begin(), m_prio_heap.end(),
+ greater<MessageBufferNode>());
+
+ node.m_time = m_receiver->clockEdge(m_recycle_latency);
+ m_prio_heap.back() = node;
+ push_heap(m_prio_heap.begin(), m_prio_heap.end(),
+ greater<MessageBufferNode>());
+ m_consumer->
+ scheduleEventAbsolute(m_receiver->clockEdge(m_recycle_latency));
+}
+
+void
+MessageBuffer::reanalyzeList(list<MsgPtr> &lt, Tick nextTick)
+{
+ while(!lt.empty()) {
+ m_msg_counter++;
+ MessageBufferNode msgNode(nextTick, m_msg_counter, lt.front());
+
+ m_prio_heap.push_back(msgNode);
+ push_heap(m_prio_heap.begin(), m_prio_heap.end(),
+ greater<MessageBufferNode>());
+
+ m_consumer->scheduleEventAbsolute(nextTick);
+ lt.pop_front();
+ }
+}
+
+void
+MessageBuffer::reanalyzeMessages(const Address& addr)
+{
+ DPRINTF(RubyQueue, "ReanalyzeMessages\n");
+ assert(m_stall_msg_map.count(addr) > 0);
+ Tick nextTick = m_receiver->clockEdge(Cycles(1));
+
+ //
+ // Put all stalled messages associated with this address back on the
+ // prio heap
+ //
+ reanalyzeList(m_stall_msg_map[addr], nextTick);
+ m_stall_msg_map.erase(addr);
+}
+
+void
+MessageBuffer::reanalyzeAllMessages()
+{
+ DPRINTF(RubyQueue, "ReanalyzeAllMessages\n");
+ Tick nextTick = m_receiver->clockEdge(Cycles(1));
+
+ //
+ // Put all stalled messages associated with this address back on the
+ // prio heap
+ //
+ for (StallMsgMapType::iterator map_iter = m_stall_msg_map.begin();
+ map_iter != m_stall_msg_map.end(); ++map_iter) {
+ reanalyzeList(map_iter->second, nextTick);
+ }
+ m_stall_msg_map.clear();
+}
+
+void
+MessageBuffer::stallMessage(const Address& addr)
+{
+ DPRINTF(RubyQueue, "Stalling due to %s\n", addr);
+ assert(isReady());
+ assert(addr.getOffset() == 0);
+ MsgPtr message = m_prio_heap.front().m_msgptr;
+
+ dequeue();
+
+ //
+ // Note: no event is scheduled to analyze the map at a later time.
+ // Instead the controller is responsible to call reanalyzeMessages when
+ // these addresses change state.
+ //
+ (m_stall_msg_map[addr]).push_back(message);
+}
+
+void
+MessageBuffer::print(ostream& out) const
+{
+ ccprintf(out, "[MessageBuffer: ");
+ if (m_consumer != NULL) {
+ ccprintf(out, " consumer-yes ");
+ }
+
+ vector<MessageBufferNode> copy(m_prio_heap);
+ sort_heap(copy.begin(), copy.end(), greater<MessageBufferNode>());
+ ccprintf(out, "%s] %s", copy, m_name);
+}
+
+bool
+MessageBuffer::isReady() const
+{
+ return ((m_prio_heap.size() > 0) &&
+ (m_prio_heap.front().m_time <= m_receiver->clockEdge()));
+}
+
+bool
+MessageBuffer::functionalRead(Packet *pkt)
+{
+ // Check the priority heap and read any messages that may
+ // correspond to the address in the packet.
+ for (unsigned int i = 0; i < m_prio_heap.size(); ++i) {
+ Message *msg = m_prio_heap[i].m_msgptr.get();
+ if (msg->functionalRead(pkt)) return true;
+ }
+
+ // Read the messages in the stall queue that correspond
+ // to the address in the packet.
+ for (StallMsgMapType::iterator map_iter = m_stall_msg_map.begin();
+ map_iter != m_stall_msg_map.end();
+ ++map_iter) {
+
+ for (std::list<MsgPtr>::iterator it = (map_iter->second).begin();
+ it != (map_iter->second).end(); ++it) {
+
+ Message *msg = (*it).get();
+ if (msg->functionalRead(pkt)) return true;
+ }
+ }
+ return false;
+}
+
+uint32_t
+MessageBuffer::functionalWrite(Packet *pkt)
+{
+ uint32_t num_functional_writes = 0;
+
+ // Check the priority heap and write any messages that may
+ // correspond to the address in the packet.
+ for (unsigned int i = 0; i < m_prio_heap.size(); ++i) {
+ Message *msg = m_prio_heap[i].m_msgptr.get();
+ if (msg->functionalWrite(pkt)) {
+ num_functional_writes++;
+ }
+ }
+
+ // Check the stall queue and write any messages that may
+ // correspond to the address in the packet.
+ for (StallMsgMapType::iterator map_iter = m_stall_msg_map.begin();
+ map_iter != m_stall_msg_map.end();
+ ++map_iter) {
+
+ for (std::list<MsgPtr>::iterator it = (map_iter->second).begin();
+ it != (map_iter->second).end(); ++it) {
+
+ Message *msg = (*it).get();
+ if (msg->functionalWrite(pkt)) {
+ num_functional_writes++;
+ }
+ }
+ }
+
+ return num_functional_writes;
+}
diff --git a/src/mem/ruby/network/MessageBuffer.hh b/src/mem/ruby/network/MessageBuffer.hh
new file mode 100644
index 000000000..6d51eade9
--- /dev/null
+++ b/src/mem/ruby/network/MessageBuffer.hh
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+
+/*
+ * Unordered buffer of messages that can be inserted such
+ * that they can be dequeued after a given delta time has expired.
+ */
+
+#ifndef __MEM_RUBY_BUFFERS_MESSAGEBUFFER_HH__
+#define __MEM_RUBY_BUFFERS_MESSAGEBUFFER_HH__
+
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "mem/ruby/common/Address.hh"
+#include "mem/ruby/common/Consumer.hh"
+#include "mem/ruby/network/MessageBufferNode.hh"
+#include "mem/ruby/slicc_interface/Message.hh"
+#include "mem/packet.hh"
+
+class MessageBuffer
+{
+ public:
+ MessageBuffer(const std::string &name = "");
+
+ std::string name() const { return m_name; }
+
+ void setRecycleLatency(Cycles recycle_latency)
+ { m_recycle_latency = recycle_latency; }
+
+ void reanalyzeMessages(const Address& addr);
+ void reanalyzeAllMessages();
+ void stallMessage(const Address& addr);
+
+ // TRUE if head of queue timestamp <= SystemTime
+ bool isReady() const;
+
+ void
+ delayHead()
+ {
+ MessageBufferNode node = m_prio_heap.front();
+ std::pop_heap(m_prio_heap.begin(), m_prio_heap.end(),
+ std::greater<MessageBufferNode>());
+ m_prio_heap.pop_back();
+ enqueue(node.m_msgptr, Cycles(1));
+ }
+
+ bool areNSlotsAvailable(unsigned int n);
+ int getPriority() { return m_priority_rank; }
+ void setPriority(int rank) { m_priority_rank = rank; }
+ void setConsumer(Consumer* consumer)
+ {
+ if (m_consumer != NULL) {
+ fatal("Trying to connect %s to MessageBuffer %s. \
+ \n%s already connected. Check the cntrl_id's.\n",
+ *consumer, *this, *m_consumer);
+ }
+ m_consumer = consumer;
+ }
+
+ void setSender(ClockedObject* obj)
+ {
+ assert(m_sender == NULL || m_sender == obj);
+ m_sender = obj;
+ }
+
+ void setReceiver(ClockedObject* obj)
+ {
+ assert(m_receiver == NULL || m_receiver == obj);
+ m_receiver = obj;
+ }
+
+ void setDescription(const std::string& name) { m_name = name; }
+ std::string getDescription() { return m_name;}
+
+ Consumer* getConsumer() { return m_consumer; }
+
+ //! Function for extracting the message at the head of the
+ //! message queue. The function assumes that the queue is nonempty.
+ const Message* peek() const;
+
+ const MsgPtr&
+ peekMsgPtr() const
+ {
+ assert(isReady());
+ return m_prio_heap.front().m_msgptr;
+ }
+
+ void enqueue(MsgPtr message) { enqueue(message, Cycles(1)); }
+ void enqueue(MsgPtr message, Cycles delta);
+
+ //! Updates the delay cycles of the message at the head of the queue,
+ //! removes it from the queue and returns its total delay.
+ Cycles dequeue();
+
+ void recycle();
+ bool isEmpty() const { return m_prio_heap.size() == 0; }
+
+ void
+ setOrdering(bool order)
+ {
+ m_strict_fifo = order;
+ m_ordering_set = true;
+ }
+
+ void resize(unsigned int size) { m_max_size = size; }
+ unsigned int getSize();
+ void setRandomization(bool random_flag) { m_randomization = random_flag; }
+
+ void clear();
+ void print(std::ostream& out) const;
+ void clearStats() { m_not_avail_count = 0; m_msg_counter = 0; }
+
+ void setIncomingLink(int link_id) { m_input_link_id = link_id; }
+ void setVnet(int net) { m_vnet_id = net; }
+
+ // Function for figuring out if any of the messages in the buffer can
+ // satisfy the read request for the address in the packet.
+ // Return value, if true, indicates that the request was fulfilled.
+ bool functionalRead(Packet *pkt);
+
+ // Function for figuring out if any of the messages in the buffer need
+ // to be updated with the data from the packet.
+ // Return value indicates the number of messages that were updated.
+ // This required for debugging the code.
+ uint32_t functionalWrite(Packet *pkt);
+
+ private:
+ void reanalyzeList(std::list<MsgPtr> &, Tick);
+
+ private:
+ //added by SS
+ Cycles m_recycle_latency;
+
+ // Data Members (m_ prefix)
+ //! The two ends of the buffer.
+ ClockedObject* m_sender;
+ ClockedObject* m_receiver;
+
+ //! Consumer to signal a wakeup(), can be NULL
+ Consumer* m_consumer;
+ std::vector<MessageBufferNode> m_prio_heap;
+
+ // use a std::map for the stalled messages as this container is
+ // sorted and ensures a well-defined iteration order
+ typedef std::map< Address, std::list<MsgPtr> > StallMsgMapType;
+
+ StallMsgMapType m_stall_msg_map;
+ std::string m_name;
+
+ unsigned int m_max_size;
+ Cycles m_time_last_time_size_checked;
+ unsigned int m_size_last_time_size_checked;
+
+ // variables used so enqueues appear to happen imediately, while
+ // pop happen the next cycle
+ Cycles m_time_last_time_enqueue;
+ Tick m_time_last_time_pop;
+ Tick m_last_arrival_time;
+
+ unsigned int m_size_at_cycle_start;
+ unsigned int m_msgs_this_cycle;
+
+ int m_not_avail_count; // count the # of times I didn't have N
+ // slots available
+ uint64 m_msg_counter;
+ int m_priority_rank;
+ bool m_strict_fifo;
+ bool m_ordering_set;
+ bool m_randomization;
+
+ int m_input_link_id;
+ int m_vnet_id;
+};
+
+Cycles random_time();
+
+inline std::ostream&
+operator<<(std::ostream& out, const MessageBuffer& obj)
+{
+ obj.print(out);
+ out << std::flush;
+ return out;
+}
+
+#endif // __MEM_RUBY_BUFFERS_MESSAGEBUFFER_HH__
diff --git a/src/mem/ruby/network/MessageBufferNode.cc b/src/mem/ruby/network/MessageBufferNode.cc
new file mode 100644
index 000000000..2e682b096
--- /dev/null
+++ b/src/mem/ruby/network/MessageBufferNode.cc
@@ -0,0 +1,39 @@
+/*
+ * 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/network/MessageBufferNode.hh"
+
+void
+MessageBufferNode::print(std::ostream& out) const
+{
+ out << "[";
+ out << m_time << ", ";
+ out << m_msg_counter << ", ";
+ out << *m_msgptr << "; ";
+ out << "]";
+}
diff --git a/src/mem/ruby/network/MessageBufferNode.hh b/src/mem/ruby/network/MessageBufferNode.hh
new file mode 100644
index 000000000..16aec8a1b
--- /dev/null
+++ b/src/mem/ruby/network/MessageBufferNode.hh
@@ -0,0 +1,75 @@
+/*
+ * 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 __MEM_RUBY_BUFFERS_MESSAGEBUFFERNODE_HH__
+#define __MEM_RUBY_BUFFERS_MESSAGEBUFFERNODE_HH__
+
+#include <iostream>
+
+#include "mem/ruby/slicc_interface/Message.hh"
+
+class MessageBufferNode
+{
+ public:
+ MessageBufferNode()
+ : m_time(0), m_msg_counter(0)
+ {}
+
+ MessageBufferNode(const Tick time, uint64_t counter,
+ const MsgPtr& msgptr)
+ : m_time(time), m_msg_counter(counter), m_msgptr(msgptr)
+ {}
+
+ void print(std::ostream& out) const;
+
+ public:
+ Tick m_time;
+ uint64_t m_msg_counter; // FIXME, should this be a 64-bit value?
+ MsgPtr m_msgptr;
+};
+
+inline bool
+operator>(const MessageBufferNode& n1, const MessageBufferNode& n2)
+{
+ if (n1.m_time == n2.m_time) {
+ assert(n1.m_msg_counter != n2.m_msg_counter);
+ return n1.m_msg_counter > n2.m_msg_counter;
+ } else {
+ return n1.m_time > n2.m_time;
+ }
+}
+
+inline std::ostream&
+operator<<(std::ostream& out, const MessageBufferNode& obj)
+{
+ obj.print(out);
+ out << std::flush;
+ return out;
+}
+
+#endif // __MEM_RUBY_BUFFERS_MESSAGEBUFFERNODE_HH__
diff --git a/src/mem/ruby/network/SConscript b/src/mem/ruby/network/SConscript
index c4abba716..1b0b1c94b 100644
--- a/src/mem/ruby/network/SConscript
+++ b/src/mem/ruby/network/SConscript
@@ -39,5 +39,7 @@ SimObject('Network.py')
Source('BasicLink.cc')
Source('BasicRouter.cc')
+Source('MessageBuffer.cc')
+Source('MessageBufferNode.cc')
Source('Network.cc')
Source('Topology.cc')
diff --git a/src/mem/ruby/network/garnet/BaseGarnetNetwork.cc b/src/mem/ruby/network/garnet/BaseGarnetNetwork.cc
index f237c4dcc..01f1b80ed 100644
--- a/src/mem/ruby/network/garnet/BaseGarnetNetwork.cc
+++ b/src/mem/ruby/network/garnet/BaseGarnetNetwork.cc
@@ -28,8 +28,8 @@
* Authors: Niket Agarwal
*/
-#include "mem/ruby/buffers/MessageBuffer.hh"
#include "mem/ruby/network/garnet/BaseGarnetNetwork.hh"
+#include "mem/ruby/network/MessageBuffer.hh"
using namespace std;
diff --git a/src/mem/ruby/network/garnet/fixed-pipeline/NetworkInterface_d.cc b/src/mem/ruby/network/garnet/fixed-pipeline/NetworkInterface_d.cc
index 3e4088038..5f9493806 100644
--- a/src/mem/ruby/network/garnet/fixed-pipeline/NetworkInterface_d.cc
+++ b/src/mem/ruby/network/garnet/fixed-pipeline/NetworkInterface_d.cc
@@ -34,7 +34,7 @@
#include "base/cast.hh"
#include "base/stl_helpers.hh"
#include "debug/RubyNetwork.hh"
-#include "mem/ruby/buffers/MessageBuffer.hh"
+#include "mem/ruby/network/MessageBuffer.hh"
#include "mem/ruby/network/garnet/fixed-pipeline/NetworkInterface_d.hh"
#include "mem/ruby/network/garnet/fixed-pipeline/flitBuffer_d.hh"
#include "mem/ruby/slicc_interface/NetworkMessage.hh"
diff --git a/src/mem/ruby/network/garnet/flexible-pipeline/NetworkInterface.cc b/src/mem/ruby/network/garnet/flexible-pipeline/NetworkInterface.cc
index ba32abd44..13bbe2b08 100644
--- a/src/mem/ruby/network/garnet/flexible-pipeline/NetworkInterface.cc
+++ b/src/mem/ruby/network/garnet/flexible-pipeline/NetworkInterface.cc
@@ -34,7 +34,7 @@
#include "base/cast.hh"
#include "base/stl_helpers.hh"
#include "debug/RubyNetwork.hh"
-#include "mem/ruby/buffers/MessageBuffer.hh"
+#include "mem/ruby/network/MessageBuffer.hh"
#include "mem/ruby/network/garnet/flexible-pipeline/NetworkInterface.hh"
#include "mem/ruby/network/garnet/flexible-pipeline/flitBuffer.hh"
#include "mem/ruby/slicc_interface/NetworkMessage.hh"
diff --git a/src/mem/ruby/network/simple/PerfectSwitch.cc b/src/mem/ruby/network/simple/PerfectSwitch.cc
index cf2430e36..0c6111c48 100644
--- a/src/mem/ruby/network/simple/PerfectSwitch.cc
+++ b/src/mem/ruby/network/simple/PerfectSwitch.cc
@@ -30,7 +30,7 @@
#include "base/cast.hh"
#include "debug/RubyNetwork.hh"
-#include "mem/ruby/buffers/MessageBuffer.hh"
+#include "mem/ruby/network/MessageBuffer.hh"
#include "mem/ruby/network/simple/PerfectSwitch.hh"
#include "mem/ruby/network/simple/SimpleNetwork.hh"
#include "mem/ruby/network/simple/Switch.hh"
diff --git a/src/mem/ruby/network/simple/SimpleNetwork.cc b/src/mem/ruby/network/simple/SimpleNetwork.cc
index 05b729183..9eca157f6 100644
--- a/src/mem/ruby/network/simple/SimpleNetwork.cc
+++ b/src/mem/ruby/network/simple/SimpleNetwork.cc
@@ -31,8 +31,8 @@
#include "base/cast.hh"
#include "base/stl_helpers.hh"
-#include "mem/ruby/buffers/MessageBuffer.hh"
#include "mem/ruby/common/NetDest.hh"
+#include "mem/ruby/network/MessageBuffer.hh"
#include "mem/ruby/network/simple/SimpleLink.hh"
#include "mem/ruby/network/simple/SimpleNetwork.hh"
#include "mem/ruby/network/simple/Switch.hh"
diff --git a/src/mem/ruby/network/simple/Switch.cc b/src/mem/ruby/network/simple/Switch.cc
index 1e153be76..6e116d82c 100644
--- a/src/mem/ruby/network/simple/Switch.cc
+++ b/src/mem/ruby/network/simple/Switch.cc
@@ -30,7 +30,7 @@
#include "base/cast.hh"
#include "base/stl_helpers.hh"
-#include "mem/ruby/buffers/MessageBuffer.hh"
+#include "mem/ruby/network/MessageBuffer.hh"
#include "mem/ruby/network/simple/PerfectSwitch.hh"
#include "mem/ruby/network/simple/SimpleNetwork.hh"
#include "mem/ruby/network/simple/Switch.hh"
diff --git a/src/mem/ruby/network/simple/Throttle.cc b/src/mem/ruby/network/simple/Throttle.cc
index da7b1732b..40958a6da 100644
--- a/src/mem/ruby/network/simple/Throttle.cc
+++ b/src/mem/ruby/network/simple/Throttle.cc
@@ -31,8 +31,8 @@
#include "base/cast.hh"
#include "base/cprintf.hh"
#include "debug/RubyNetwork.hh"
-#include "mem/ruby/buffers/MessageBuffer.hh"
#include "mem/ruby/network/simple/Throttle.hh"
+#include "mem/ruby/network/MessageBuffer.hh"
#include "mem/ruby/network/Network.hh"
#include "mem/ruby/slicc_interface/NetworkMessage.hh"
#include "mem/ruby/system/System.hh"