Esempio n. 1
0
 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))