Merge pull request #26 from antmicro/net_attr_fix

Reworked net attribute retrieval
diff --git a/tests/net_attr/README.rst b/tests/net_attr/README.rst
new file mode 100644
index 0000000..d0d98ed
--- /dev/null
+++ b/tests/net_attr/README.rst
@@ -0,0 +1,4 @@
+Test for handling nets consisting of multiple wires
++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+This test verifies correct handling of nets that pass through multiple wires. In such cases Yosys assigns multiple names to that net.
\ No newline at end of file
diff --git a/tests/net_attr/child/child.model.xml b/tests/net_attr/child/child.model.xml
new file mode 100644
index 0000000..90cfeb8
--- /dev/null
+++ b/tests/net_attr/child/child.model.xml
@@ -0,0 +1,10 @@
+<models xmlns:xi="http://www.w3.org/2001/XInclude">
+  <model name="CHILD">
+    <input_ports>
+      <port name="I"/>
+    </input_ports>
+    <output_ports>
+      <port name="O"/>
+    </output_ports>
+  </model>
+</models>
diff --git a/tests/net_attr/child/child.pb_type.xml b/tests/net_attr/child/child.pb_type.xml
new file mode 100644
index 0000000..0cba455
--- /dev/null
+++ b/tests/net_attr/child/child.pb_type.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<pb_type xmlns:xi="http://www.w3.org/2001/XInclude" name="CHILD" num_pb="1">
+  <blif_model>.subckt CHILD</blif_model>
+  <input name="I" num_pins="1"/>
+  <output name="O" num_pins="1"/>
+</pb_type>
diff --git a/tests/net_attr/child/child.sim.v b/tests/net_attr/child/child.sim.v
new file mode 100644
index 0000000..e09db94
--- /dev/null
+++ b/tests/net_attr/child/child.sim.v
@@ -0,0 +1,6 @@
+module CHILD(
+    input  wire I,
+    output wire O
+);
+
+endmodule
diff --git a/tests/net_attr/golden.model.xml b/tests/net_attr/golden.model.xml
new file mode 100644
index 0000000..0d2461a
--- /dev/null
+++ b/tests/net_attr/golden.model.xml
@@ -0,0 +1,3 @@
+<models xmlns:xi="http://www.w3.org/2001/XInclude">
+  <xi:include href="./child/child.model.xml" xpointer="xpointer(models/child::node())"/>
+</models>
diff --git a/tests/net_attr/golden.pb_type.xml b/tests/net_attr/golden.pb_type.xml
new file mode 100644
index 0000000..354b299
--- /dev/null
+++ b/tests/net_attr/golden.pb_type.xml
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='utf-8'?>
+<pb_type xmlns:xi="http://www.w3.org/2001/XInclude" name="PARENT" num_pb="1">
+  <input name="I" num_pins="1"/>
+  <output name="O" num_pins="1"/>
+  <pb_type name="child" num_pb="1">
+    <!--old_name CHILD-->
+    <xi:include href="./child/child.pb_type.xml" xpointer="xpointer(pb_type/child::node())"/>
+  </pb_type>
+  <interconnect>
+    <direct>
+      <port name="I" type="input"/>
+      <port from="child" name="I" type="output"/>
+    </direct>
+    <direct>
+      <port from="child" name="O" type="input"/>
+      <port name="O" type="output"/>
+    </direct>
+  </interconnect>
+</pb_type>
diff --git a/tests/net_attr/parent.sim.v b/tests/net_attr/parent.sim.v
new file mode 100644
index 0000000..599456a
--- /dev/null
+++ b/tests/net_attr/parent.sim.v
@@ -0,0 +1,15 @@
+`include "./child/child.sim.v"
+
+module PARENT(
+    input  wire I,
+    output wire O
+);
+
+    wire hop1 = I;
+
+    CHILD child (
+    .I(hop1),
+    .O(O)
+    );
+
+endmodule
diff --git a/v2x/vlog_to_pbtype.py b/v2x/vlog_to_pbtype.py
index cef2102..f981113 100755
--- a/v2x/vlog_to_pbtype.py
+++ b/v2x/vlog_to_pbtype.py
@@ -212,7 +212,7 @@
         smod = yj.module(sink_type)
         potential_attrs.append(filter_src(smod.port_attrs(sink_pin)))
 
-    net_attrs = filter_src(mod.net_attrs(mod.net_name(netid)))
+    net_attrs = filter_src(mod.net_attrs_by_netid(netid))
     copy_attrs(net_attrs, potential_attrs)
     return net_attrs
 
diff --git a/v2x/yosys/json.py b/v2x/yosys/json.py
index 7278773..93a32da 100755
--- a/v2x/yosys/json.py
+++ b/v2x/yosys/json.py
@@ -273,10 +273,49 @@
         for n, props in self.data["netnames"].items():
             if netid in props['bits']:
                 names.append(n)
+        # FIXME: This fails when there are two wires with different names
+        # connected to the same netid (yes, that's possible). Which name
+        # should be returned in that case ?
         if len(names) != 1:
             raise KeyError("Net id {} not found".format(netid))
         return names[0]
 
+    def net_attrs_by_netid(self, netid):
+        """
+        Returns attributes of a given netid. Raises RuntimeError if the same
+        attribute is defined for two or more wires belonging to the same net.
+        The attribute 'src' is an exception, 'src' strings are concatenated
+        when defined for more than one wire.
+
+        Returns dict:
+        -------
+        netid : int
+        """
+
+        attributes = {}
+
+        for name, data in self.data["netnames"].items():
+            if netid in data['bits']:
+
+                # Join attributes
+                for attr, value in data['attributes'].items():
+
+                    # Allow multiple definitions of the same attribute only
+                    # for the 'src'. Otherwise raise an exception
+                    if attr in attributes and attr != 'src':
+                        raise RuntimeError(
+                            "Conflicting attributes '{}' on netid {}".format(
+                                attr, netid))
+
+                    # Join 'src' attribute strings
+                    if attr in attributes and attr == 'src':
+                        attributes[attr] += ";{}".format(value)
+                    # Store the value
+                    else:
+                        attributes[attr] = value
+
+        return attributes
+
     def net_drivers(self, net):
         """Returns a list of drivers of a given net, both top level inputs.
         and cell outputs. "cell" is set to the name of the module for top level