diff --git a/src/finn/analysis/fpgadataflow/post_synth_res.py b/src/finn/analysis/fpgadataflow/post_synth_res.py
index 1ad0d7c98e7ae04ad0466d25e5ace78bb7326069..79204c54cdb8233fd7b65968c25af819fce91959 100644
--- a/src/finn/analysis/fpgadataflow/post_synth_res.py
+++ b/src/finn/analysis/fpgadataflow/post_synth_res.py
@@ -81,32 +81,30 @@ def post_synth_res(model, override_synth_report_filename=None):
     else:
         restype_to_ind = restype_to_ind_default
 
+    def get_instance_stats(inst_name):
+        row = root.findall(".//*[@contents='%s']/.." % inst_name)
+        if row != []:
+            node_dict = {}
+            row = row[0].getchildren()
+            for (restype, ind) in restype_to_ind.items():
+                node_dict[restype] = int(row[ind].attrib["contents"])
+            return node_dict
+        else:
+            return None
+
+    # global (top-level) stats, including shell etc.
+    top_dict = get_instance_stats("(top)")
+    if top_dict is not None:
+        res_dict["(top)"] = top_dict
+
     for node in model.graph.node:
         if node.op_type == "StreamingDataflowPartition":
             sdp_model = ModelWrapper(getCustomOp(node).get_nodeattr("model"))
             sdp_res_dict = post_synth_res(sdp_model, synth_report_filename)
             res_dict.update(sdp_res_dict)
         elif _is_fpgadataflow_node(node):
-            row = root.findall(".//*[@contents='%s']/.." % node.name)
-            if row != []:
-                node_dict = {}
-                row = row[0].getchildren()
-                """ Expected XML structure:
-<tablerow class="" suppressoutput="0" wordwrap="0">
-    <tableheader class="" contents="Instance" halign="3" width="-1"/>
-    <tableheader class="" contents="Module" halign="3" width="-1"/>
-    <tableheader class="" contents="Total LUTs" halign="3" width="-1"/>
-    <tableheader class="" contents="Logic LUTs" halign="3" width="-1"/>
-    <tableheader class="" contents="LUTRAMs" halign="3" width="-1"/>
-    <tableheader class="" contents="SRLs" halign="3" width="-1"/>
-    <tableheader class="" contents="FFs" halign="3" width="-1"/>
-    <tableheader class="" contents="RAMB36" halign="3" width="-1"/>
-    <tableheader class="" contents="RAMB18" halign="3" width="-1"/>
-    <tableheader class="" contents="DSP48 Blocks" halign="3" width="-1"/>
-</tablerow>
-                """
-                for (restype, ind) in restype_to_ind.items():
-                    node_dict[restype] = int(row[ind].attrib["contents"])
+            node_dict = get_instance_stats(node.name)
+            if node_dict is not None:
                 res_dict[node.name] = node_dict
 
     return res_dict
diff --git a/src/finn/transformation/fpgadataflow/annotate_resources.py b/src/finn/transformation/fpgadataflow/annotate_resources.py
index 8f89ca19a75ca125ae3fe439acdbb3bbb80b34f4..d6ff058848700b50dadb7a6ed0ff6c07b7eeb4a3 100644
--- a/src/finn/transformation/fpgadataflow/annotate_resources.py
+++ b/src/finn/transformation/fpgadataflow/annotate_resources.py
@@ -100,4 +100,7 @@ class AnnotateResources(Transformation):
             if "efficiency" in k:
                 total_dict[k] = total_dict[k] / len(graph.node)
         model.set_metadata_prop("res_total_" + self.mode, str(total_dict))
+        if "(top)" in self.res_dict.keys():
+            top_dict = self.res_dict["(top)"]
+            model.set_metadata_prop("res_total_top_" + self.mode, str(top_dict))
         return (model, False)