def connect_to(self, other: PinIn): if self._assignment is None: alias_wire = self.parent.create_wire() if self._source is not None: source = self._source source.unbind() source.bind(alias_wire) self._assignment = self.parent.add_alias(alias_wire.name, self.name) other.bind(self.alias)
class Distributor(LogicBlock): def __init__(self, parent: Module, source: Wire, child_wires: Dict[Wire, int] = None): super().__init__("{}_v_fanout".format(source.name), parent) self._before = 0 self._tracker = 0 self._outputs = set() self._after = dict() if child_wires is None: org_post = set(source.post) for p in org_post: p.unbind() split_out_wire = parent.create_wire() p.bind(split_out_wire) self._add_wire(split_out_wire) else: for p in child_wires.keys(): self._add_wire(p, child_wires[p]) self._input = PinIn("v_fanout_in", self, source) def _add_wire(self, other: Wire, delay: int = 0): split_out_pin = PinOut("v_fanout_out_{}".format(str(self._tracker)), self, other) self._outputs.add(split_out_pin) self._tracker = self._tracker + 1 self._after[split_out_pin.name] = delay def _create_parent_splitter(self): old_source = self._input.connection new_source = self.parent.create_wire() self._input.unbind() self._input.bind(new_source) self.name = "{}_v_fanout".format(new_source.name) upper = Distributor(self.parent, old_source) upper._add_wire(new_source) if self._before > 0: self._before = self._before - 1 return upper def _pop_out(self, pin: PinOut = None): if pin is None: pin = self._outputs.pop() else: self._outputs.remove(pin) delay = self._after[pin.name] wire = pin.connection pin.unbind() del self._after[pin.name] return wire, delay def _decompose(self, degree: int): total = len(self._outputs) basket = list() for i in range(int(total / degree)): basket.append(degree) if total % degree == 1: basket[-1] = basket[-1] - 1 elif total % degree == 0: del basket[-1] return basket def add_delay(self, other: str, margin: int): if self._after.get(other) is None: print("No such connection") return self._after[other] = self._after.get(other) + margin def buffer_float(self): mutual = min(self._after.values()) if mutual != 0: self._before = self._before + mutual for k in self._after.keys(): self._after[k] = self._after[k] - mutual if isinstance(self._input.connection.source_instance, Distributor): self._input.connection.source_instance.add_delay( self._input.connection.source.name, self._before) self._before = 0 def splitter_submerge(self, results: list): threashold = min(self._after.values()) to_next = { x for x in self._outputs if self._after.get(x.name) > threashold } if len(to_next) <= 1: results.append(self) return internal_splitter = self.parent.create_wire() self._add_wire(internal_splitter) to_next_wires = dict() for x in to_next: wire, delay = self._pop_out(x) to_next_wires[wire] = delay - 1 child_splitter = Distributor(self.parent, internal_splitter, to_next_wires) child_splitter.splitter_submerge(results) results.append(self) def break_up(self, degree: int, extra_splitters: set, dependency_list: list): if len(self._outputs) <= degree: self.buffer_float() return upper = self._input.connection.source_instance if not isinstance(upper, Distributor): upper = self._create_parent_splitter() extra_splitters.add(upper) self.buffer_float() basket = self._decompose(degree) for item in basket: internal_wires = dict() for i in range(item): wire, delay = self._pop_out() internal_wires[wire] = delay sibling = self.parent.create_wire() extra_splitters.add( Distributor(self.parent, sibling, internal_wires)) upper._add_wire(sibling) if upper not in dependency_list: upper.break_up(degree, extra_splitters, dependency_list) @property def source(self): return self._input.connection @property def input_pins(self): return [self._input] @property def fan_out(self): return len(self.output_pins) @property def output_pins(self): return self._outputs def get_delay(self, other: str): if self._after.get(other) is None: print("No such connection") return return self._before + 1 + self._after.get(other) @property def max_delay(self): return self._before + 1 + max(self._after.values()) @property def gate_count(self): return 2 + self._before * 2 + 2 * sum(x for x in self._after.values()) def to_verilog(self): return "Black box" def cell_mapping(self, library: Library): buffer_model = library.get_buffer() input_wire = self._input.connection self._input.unbind() for i in range(self._before): wire_down = self.parent.create_wire() self.parent.register_instance( buffer_model.instantiate("{}_bfr_after".format(wire_down.name), self.parent, [input_wire, wire_down])) input_wire = wire_down wires = [input_wire] for x in self._outputs: output_wire = x.connection delay = self._after[x.name] x.unbind() for i in range(delay): wire_up = self.parent.create_wire() self.parent.register_instance( buffer_model.instantiate( "{}_bfr_before".format(wire_up.name), self.parent, [wire_up, output_wire])) output_wire = wire_up wires.append(output_wire) splitter_model = library.get_splitter(self.fan_out) self.parent.register_instance( splitter_model.instantiate(self.name, self.parent, wires))