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)
def __init__(self, parent: Module, source: Wire, delay: int): super().__init__("{}_v_buffer".format(source.name), parent) buf_out = parent.create_wire() org_post = set(source.post) for p in org_post: p.unbind() p.bind(buf_out) self._input = PinIn("v_bfr_in", self, source) self._output = PinOut("v_bfr_out", self, buf_out) self._delay = delay
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)
class Alias(UnitBlock): def __init__(self, name: str, parent: (Block, Device), org: Net, alias: Net): super().__init__(name, parent) self._input = PinIn("alias", self, alias) self._output = PinOut("org", self, org) def unbind(self): self._input.unbind() self._output.unbind() @property def wire_in(self): return self._input.connection @property def wire_out(self): return self._output.connection @property def input_pins(self): return [self._input] @property def output_pins(self): return [self._output] @property def gate_count(self): return 0 def get_delay(self, other=None): return 0 def truth_table(self, other): return 1 def to_verilog(self): return "\tassign {} = {};".format(self._output.connection.name, self._input.connection.name)
def __init__(self, name: str, parent: Device, model: Device, mapping: Dict[str, Net]): super().__init__(name, parent) self._model = model self._pins = dict() self._inputs = list() self._outputs = list() for x in model.input_labels: pin = PinIn(x, self, mapping.get(x)) self._pins[x] = pin self._inputs.append(pin) for x in model.output_labels: pin = PinOut(x, self, mapping.get(x)) self._pins[x] = pin self._outputs.append(pin)
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))
class VirtualBuffer(LogicBlock): def __init__(self, parent: Module, source: Wire, delay: int): super().__init__("{}_v_buffer".format(source.name), parent) buf_out = parent.create_wire() org_post = set(source.post) for p in org_post: p.unbind() p.bind(buf_out) self._input = PinIn("v_bfr_in", self, source) self._output = PinOut("v_bfr_out", self, buf_out) self._delay = delay @property def input_pins(self): return [self._input] @property def output_pins(self): return {self._output} def get_delay(self, other=None): return self._delay def decrease(self, margin: int = 1): if self._delay == 0: print("delay is already 0") return self._delay = self._delay - margin if self._delay == 0: source = self._input.connection self._input.unbind() to = self._output.connection self._output.unbind() to.post.pop().bind(source) self.parent.remove_net(to.name) def increase(self, margin: int = 1): self._delay = self._delay + margin @property def gate_count(self): return 2 * self._delay def to_verilog(self): return "Black box" def cell_mapping(self, library): if self._delay == 0: return buffer_model = library.get_buffer() input_wire = self._input.connection self._input.unbind() for i in range(self._delay - 1): 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 output_wire = self._output.connection self._output.unbind() self.parent.register_instance( buffer_model.instantiate("{}_bfr_after".format(output_wire.name), self.parent, [input_wire, output_wire]))
def __init__(self, name: str, parent: (Block, Device), org: Net, alias: Net): super().__init__(name, parent) self._input = PinIn("alias", self, alias) self._output = PinOut("org", self, org)
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() self._delay_est = 1 self._gate = 1 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 __hash__(self): return hash(self.name) def ideal_case(self): self._delay_est = 1 self._gate = 1 def reset_delay(self): self._before = 0 for a in self._after.keys(): self._after[a] = 0 def worst_case(self, limit=2): self._delay_est = math.ceil(math.log(len(self._outputs), limit)) self._gate = sum(limit**i for i in range(self._delay_est)) 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 _level_up(self): new_source = self.parent.create_wire() internal_wires = dict() fo = len(self._outputs) for i in range(fo): wire, delay = self._pop_out() if delay > 0: delay = delay - 1 internal_wires[wire] = delay ds = Distributor(self.parent, new_source, internal_wires) self._add_wire(new_source) return ds 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() while total > degree: basket.append(degree) total = total - degree if total != 0: basket.append(total) if len(basket) > 1: if basket[-1] == 1: basket[-2] = basket[-2] - 1 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): 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: return self 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) return child_splitter.splitter_submerge() def break_up(self, degree: int, extra_splitters: set): if self in extra_splitters: print(self.name, self.fan_out) if len(self._outputs) <= degree: extra_splitters.add(self) self.buffer_float() upper = self._input.connection.source_instance if not isinstance(upper, Distributor): return else: return upper.break_up(degree, extra_splitters) upper = self._input.connection.source_instance if not isinstance(upper, Distributor): lower = self._level_up() return lower.break_up(degree, extra_splitters) extra_splitters.add(self) 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() ds = Distributor(self.parent, sibling, internal_wires) extra_splitters.add(ds) upper._add_wire(sibling) ds.buffer_float() self.buffer_float() return upper.break_up(degree, extra_splitters) @property def source(self): return self._input.connection @property def input_pins(self): return [self._input] @property def fan_out(self): return len(self._outputs) @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 + self._delay_est + self._after.get(other) @property def max_delay(self): return self._before + self._delay_est + max(self._after.values()) @property def ideal_gate_count(self): dls = list(self._after.values()) finals = list() level = 1 while (True): count = sum(x > min(dls) for x in dls) if count <= 1: finals = dls break level = level + 1 finals.extend([x for x in dls if x == min(dls)]) dls = [x - 1 for x in dls if x > min(dls)] level = level + min(dls) dls = [x - min(dls) for x in dls] return 2 * level + self._before * 2 + 2 * sum(finals) @property def gate_count(self): return 2 * self._gate + 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))