ruby: connect two controllers using only message buffers
authorNilay Vaish <nilay@cs.wisc.edu>
Fri, 22 Mar 2013 20:53:23 +0000 (15:53 -0500)
committerNilay Vaish <nilay@cs.wisc.edu>
Fri, 22 Mar 2013 20:53:23 +0000 (15:53 -0500)
This patch modifies ruby so that two controllers can be connected to each
other with only message buffers in between. Before this patch, all the
controllers had to be connected to the network  for them to communicate
with each other. With this patch, one can have protocols where a controller
is not connected to the network, but communicates with another controller
through a message buffer.

src/mem/ruby/slicc_interface/AbstractController.cc
src/mem/ruby/slicc_interface/AbstractController.hh
src/mem/ruby/slicc_interface/Controller.py
src/mem/slicc/ast/ObjDeclAST.py
src/mem/slicc/symbols/StateMachine.py

index 9a0ee2b2b1563648b569944eafbc33f3f5580b87..1615f8c1d09dcbb401440a2aa77b04aff8265f3d 100644 (file)
@@ -79,3 +79,10 @@ AbstractController::profileMsgDelay(uint32_t virtualNetwork, Cycles delay)
     m_delayHistogram.add(delay);
     m_delayVCHistogram[virtualNetwork].add(delay);
 }
+
+void
+AbstractController::connectWithPeer(AbstractController *c)
+{
+    getQueuesFromPeer(c);
+    c->getQueuesFromPeer(this);
+}
index ba0c4b683f62b5f79f1926fb7b37464be66b9bf1..81ef3c52bc29554acaaf09c828c01146cdb97255 100644 (file)
@@ -97,12 +97,25 @@ class AbstractController : public ClockedObject, public Consumer
     Histogram& getDelayVCHist(uint32_t index)
     { return m_delayVCHistogram[index]; }
 
+    MessageBuffer *getPeerQueue(uint32_t pid)
+    {
+        std::map<uint32_t, MessageBuffer *>::iterator it =
+                                        peerQueueMap.find(pid);
+        assert(it != peerQueueMap.end());
+        return (*it).second;
+    }
+
   protected:
     //! Profiles original cache requests including PUTs
     void profileRequest(const std::string &request);
     //! Profiles the delay associated with messages.
     void profileMsgDelay(uint32_t virtualNetwork, Cycles delay);
 
+    //! Function for connecting peer controllers
+    void connectWithPeer(AbstractController *);
+    virtual void getQueuesFromPeer(AbstractController *)
+    { fatal("getQueuesFromPeer() should be called only if implemented!"); }
+
   protected:
     int m_transitions_per_cycle;
     int m_buffer_size;
@@ -120,6 +133,9 @@ class AbstractController : public ClockedObject, public Consumer
     int m_cur_in_port_rank;
     int m_number_of_TBEs;
 
+    //! Map from physical network number to the Message Buffer.
+    std::map<uint32_t, MessageBuffer*> peerQueueMap;
+
     //! Counter for the number of cycles when the transitions carried out
     //! were equal to the maximum allowed
     uint64_t m_fully_busy_cycles;
index 5c2fd9b71fea044f342492de1913e7d35ffebe10..f8242322e66812dc35226c1c130939c322a0b5a4 100644 (file)
@@ -42,4 +42,6 @@ class RubyController(ClockedObject):
     buffer_size = Param.Int(0, "max buffer size 0 means infinite")
     recycle_latency = Param.Cycles(10, "")
     number_of_TBEs = Param.Int(256, "")
-    ruby_system = Param.RubySystem("");
+    ruby_system = Param.RubySystem("")
+
+    peer = Param.RubyController(NULL, "")
index 4509b4527641cf2b6d8121cf4fbbe0a0108dcad6..6469bc25a46753b97f1df21007d724326a6353ee 100644 (file)
@@ -41,7 +41,8 @@ class ObjDeclAST(DeclAST):
     def generate(self):
         machineComponentSym = False
 
-        if "network" in self and "virtual_network" not in self:
+        if "network" in self and not ("virtual_network" in self or
+                                      "physical_network" in self) :
             self.error("Network queues require a 'virtual_network' attribute")
 
         type = self.type_ast.type
index d5965d46d7803b32e1442c762fb5e22f098e0711..3f54a1cdbff34b6ba1f22e41170cc5778ee34f2f 100644 (file)
@@ -239,9 +239,12 @@ class $py_ident(RubyController):
 ''')
 
         seen_types = set()
+        has_peer = False
         for var in self.objects:
             if var.type.ident not in seen_types and not var.type.isPrimitive:
                 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
+            if "network" in var and "physical_network" in var:
+                has_peer = True
             seen_types.add(var.type.ident)
 
         # for adding information to the protocol debug trace
@@ -331,6 +334,8 @@ static int m_num_controllers;
             if proto:
                 code('$proto')
 
+        if has_peer:
+            code('void getQueuesFromPeer(AbstractController *);')
         if self.EntryType != None:
             code('''
 
@@ -388,6 +393,7 @@ void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
         code = self.symtab.codeFormatter()
         ident = self.ident
         c_ident = "%s_Controller" % self.ident
+        has_peer = False
 
         code('''
 /** \\file $c_ident.cc
@@ -514,8 +520,21 @@ m_dma_sequencer_ptr->setController(this);
                 code('''
 m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
 m_${{var.c_ident}}_ptr->setReceiver(this);
+''')
+            else:
+                if "network" in var and "physical_network" in var and \
+                   var["network"] == "To":
+                    has_peer = True
+                    code('''
+m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
+peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr;
+m_${{var.c_ident}}_ptr->setSender(this);
 ''')
 
+        code('''
+if (p->peer != NULL)
+    connectWithPeer(p->peer);
+''')
         code.dedent()
         code('''
 }
@@ -549,10 +568,7 @@ $c_ident::init()
                         code('(*$vid) = ${{var["default"]}};')
                 else:
                     # Normal Object
-                    # added by SS
-                    if "factory" in var:
-                        code('$vid = ${{var["factory"]}};')
-                    elif var.ident.find("mandatoryQueue") < 0:
+                    if var.ident.find("mandatoryQueue") < 0:
                         th = var.get("template", "")
                         expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
                         args = ""
@@ -593,21 +609,22 @@ $c_ident::init()
                 # Network port object
                 network = var["network"]
                 ordered =  var["ordered"]
-                vnet = var["virtual_network"]
-                vnet_type = var["vnet_type"]
 
-                assert var.machine is not None
-                code('''
+                if "virtual_network" in var:
+                    vnet = var["virtual_network"]
+                    vnet_type = var["vnet_type"]
+
+                    assert var.machine is not None
+                    code('''
 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
+assert($vid != NULL);
 ''')
 
-                code('assert($vid != NULL);')
-
-                # Set the end
-                if network == "To":
-                    code('$vid->setSender(this);')
-                else:
-                    code('$vid->setReceiver(this);')
+                    # Set the end
+                    if network == "To":
+                        code('$vid->setSender(this);')
+                    else:
+                        code('$vid->setReceiver(this);')
 
                 # Set ordering
                 if "ordered" in var:
@@ -1007,6 +1024,26 @@ $c_ident::functionalWriteBuffers(PacketPtr& pkt)
 }
 ''')
 
+        # Check if this controller has a peer, if yes then write the
+        # function for connecting to the peer.
+        if has_peer:
+            code('''
+
+void
+$c_ident::getQueuesFromPeer(AbstractController *peer)
+{
+''')
+            for var in self.objects:
+                if "network" in var and "physical_network" in var and \
+                   var["network"] == "From":
+                    code('''
+m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}});
+assert(m_${{var.c_ident}}_ptr != NULL);
+m_${{var.c_ident}}_ptr->setReceiver(this);
+
+''')
+            code('}')
+
         code.write(path, "%s.cc" % c_ident)
 
     def printCWakeup(self, path, includes):