modnames[name] = 0
 
 
+def get_runlengths(pbit, size):
+    res = []
+    count = 1
+    # identify where the 1s are, which indicates "start of a new partition"
+    # we want a list of the lengths of all partitions
+    for i in range(size):
+        if pbit & (1<<i): # it's a 1: ends old partition, starts new
+            res.append(count) # add partition
+            count = 1 # start again
+        else:
+            count += 1
+    # end reached, add whatever is left. could have done this by creating
+    # "fake" extra bit on the partitions, but hey
+    res.append(count)
+
+    return res
+
+
 # Prototype https://bugs.libre-soc.org/show_bug.cgi?id=713#c53
 # this provides a "compatibility" layer with existing SimdSignal
 # behaviour.  the idea is that this interface defines which "combinations"
     def get_cases(self):
         return range(1 << len(self.get_mask()))
 
+    def get_num_elements(self, pbit):
+        keys = list(self.psig.partpoints.keys())
+        return len(get_runlengths(pbit, len(keys)))
+
+    def get_el_range(self, pbit, el_num):
+        """based on the element number and the current elwid/pbit (case)
+        return the range start/end of the element within its underlying signal
+        this function is not at all designed to be efficient.
+        """
+        keys = list(self.psig.partpoints.keys())
+        runs = get_runlengths(pbit, len(keys))
+        keys = [0] + keys + [len(self.psig.sig)]
+        y = 0
+        numparts = runs[0]
+        for i in range(el_num):
+            y += numparts
+            numparts = runs[i]
+        return range(keys[y], keys[y+numparts])
+
     @property
     def blanklanes(self):
         return 0