+
+ self.intermediate_terms = intermediate_terms
+ self._intermediate_terms = _intermediate_terms
+
+
+class AddReduce(Elaboratable):
+ """Recursively Add list of numbers together.
+
+ :attribute inputs: input ``Signal``s to be summed. Modification not
+ supported, except for by ``Signal.eq``.
+ :attribute register_levels: List of nesting levels that should have
+ pipeline registers.
+ :attribute output: output sum.
+ :attribute partition_points: the input partition points. Modification not
+ supported, except for by ``Signal.eq``.
+ """
+
+ def __init__(self, inputs, output_width, register_levels, partition_points,
+ part_ops):
+ """Create an ``AddReduce``.
+
+ :param inputs: input ``Signal``s to be summed.
+ :param output_width: bit-width of ``output``.
+ :param register_levels: List of nesting levels that should have
+ pipeline registers.
+ :param partition_points: the input partition points.
+ """
+ self.inputs = inputs
+ self.part_ops = part_ops
+ self.out_part_ops = [Signal(2, name=f"out_part_ops_{i}")
+ for i in range(len(part_ops))]
+ self.output = Signal(output_width)
+ self.output_width = output_width
+ self.register_levels = register_levels
+ self.partition_points = partition_points
+
+ self.create_levels()
+
+ @staticmethod
+ def get_max_level(input_count):
+ return AddReduceSingle.get_max_level(input_count)
+
+ @staticmethod
+ def next_register_levels(register_levels):
+ """``Iterable`` of ``register_levels`` for next recursive level."""
+ for level in register_levels:
+ if level > 0:
+ yield level - 1
+
+ def create_levels(self):
+ """creates reduction levels"""
+
+ mods = []
+ next_levels = self.register_levels
+ partition_points = self.partition_points
+ inputs = self.inputs
+ part_ops = self.part_ops
+ while True:
+ next_level = AddReduceSingle(inputs, self.output_width, next_levels,
+ partition_points, part_ops)
+ mods.append(next_level)
+ if len(next_level.groups) == 0:
+ break
+ next_levels = list(AddReduce.next_register_levels(next_levels))
+ partition_points = next_level._reg_partition_points
+ inputs = next_level.intermediate_terms
+ part_ops = next_level.out_part_ops
+
+ self.levels = mods
+
+ def elaborate(self, platform):
+ """Elaborate this module."""
+ m = Module()
+
+ for i, next_level in enumerate(self.levels):
+ setattr(m.submodules, "next_level%d" % i, next_level)
+
+ # output comes from last module