fix substitute for inputs with fo, dot graph
This commit is contained in:
1 parent
08d9f5a9bf
commit
5e573b0408
1 file changed
+54
-7
+54
-7
@@ -13,6 +13,8 @@ Circuit graphs also define an ordering of inputs, outputs and other nodes to eas
|
|||||||
from collections import deque, defaultdict
|
from collections import deque, defaultdict
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class GrowingList(list):
|
class GrowingList(list):
|
||||||
def __setitem__(self, index, value):
|
def __setitem__(self, index, value):
|
||||||
@@ -359,7 +361,7 @@ class Circuit:
|
|||||||
of the input and output ports must match the pins of the replaced node.
|
of the input and output ports must match the pins of the replaced node.
|
||||||
"""
|
"""
|
||||||
ios = set(impl.io_nodes)
|
ios = set(impl.io_nodes)
|
||||||
impl_in_lines = [n.outs[0] for n in impl.io_nodes if len(n.ins) == 0]
|
impl_in_nodes = [n for n in impl.io_nodes if len(n.ins) == 0]
|
||||||
impl_out_lines = [n.ins[0] for n in impl.io_nodes if len(n.ins) > 0]
|
impl_out_lines = [n.ins[0] for n in impl.io_nodes if len(n.ins) > 0]
|
||||||
designated_cell = None
|
designated_cell = None
|
||||||
if len(impl_out_lines) > 0:
|
if len(impl_out_lines) > 0:
|
||||||
@@ -367,9 +369,9 @@ class Circuit:
|
|||||||
while n.kind == '__fork__' and n not in ios:
|
while n.kind == '__fork__' and n not in ios:
|
||||||
n = n.ins[0].driver
|
n = n.ins[0].driver
|
||||||
designated_cell = n
|
designated_cell = n
|
||||||
node_in_lines = list(node.ins) + [None] * (len(impl_in_lines)-len(node.ins))
|
node_in_lines = list(node.ins) + [None] * (len(impl_in_nodes)-len(node.ins))
|
||||||
node_out_lines = list(node.outs) + [None] * (len(impl_out_lines)-len(node.outs))
|
node_out_lines = list(node.outs) + [None] * (len(impl_out_lines)-len(node.outs))
|
||||||
assert len(node_in_lines) == len(impl_in_lines)
|
assert len(node_in_lines) == len(impl_in_nodes)
|
||||||
assert len(node_out_lines) == len(impl_out_lines)
|
assert len(node_out_lines) == len(impl_out_lines)
|
||||||
node_map = dict()
|
node_map = dict()
|
||||||
if designated_cell is not None:
|
if designated_cell is not None:
|
||||||
@@ -386,13 +388,20 @@ class Circuit:
|
|||||||
node_map[n] = Node(self, f'{node.name}~{n.name}', n.kind)
|
node_map[n] = Node(self, f'{node.name}~{n.name}', n.kind)
|
||||||
elif len(n.outs) > 0 and len(n.ins) > 0: # output is also read by impl. circuit, need to add a fork.
|
elif len(n.outs) > 0 and len(n.ins) > 0: # output is also read by impl. circuit, need to add a fork.
|
||||||
node_map[n] = Node(self, f'{node.name}~{n.name}')
|
node_map[n] = Node(self, f'{node.name}~{n.name}')
|
||||||
|
elif len(n.ins) == 0 and len(n.outs) > 1: # input is read by multiple nodes, need to add fork.
|
||||||
|
node_map[n] = Node(self, f'{node.name}~{n.name}')
|
||||||
for l in impl.lines: # add all internal lines to main circuit
|
for l in impl.lines: # add all internal lines to main circuit
|
||||||
if l.reader in node_map and l.driver in node_map:
|
if l.reader in node_map and l.driver in node_map:
|
||||||
Line(self, (node_map[l.driver], l.driver_pin), (node_map[l.reader], l.reader_pin))
|
Line(self, (node_map[l.driver], l.driver_pin), (node_map[l.reader], l.reader_pin))
|
||||||
for l, ll in zip(impl_in_lines, node_in_lines): # connect inputs
|
for inn, ll in zip(impl_in_nodes, node_in_lines): # connect inputs
|
||||||
if ll is None: continue
|
if ll is None: continue
|
||||||
ll.reader = node_map[l.reader]
|
if len(inn.outs) == 1:
|
||||||
ll.reader_pin = l.reader_pin
|
l = inn.outs[0]
|
||||||
|
ll.reader = node_map[l.reader]
|
||||||
|
ll.reader_pin = l.reader_pin
|
||||||
|
else:
|
||||||
|
ll.reader = node_map[inn] # connect to existing fork
|
||||||
|
ll.reader_pin = 0
|
||||||
ll.reader.ins[ll.reader_pin] = ll
|
ll.reader.ins[ll.reader_pin] = ll
|
||||||
for l, ll in zip(impl_out_lines, node_out_lines): # connect outputs
|
for l, ll in zip(impl_out_lines, node_out_lines): # connect outputs
|
||||||
if ll is None:
|
if ll is None:
|
||||||
@@ -467,7 +476,7 @@ class Circuit:
|
|||||||
Nodes without input lines and nodes whose :py:attr:`Node.kind` contains the
|
Nodes without input lines and nodes whose :py:attr:`Node.kind` contains the
|
||||||
substrings 'dff' or 'latch' are yielded first.
|
substrings 'dff' or 'latch' are yielded first.
|
||||||
"""
|
"""
|
||||||
visit_count = [0] * len(self.nodes)
|
visit_count = np.zeros(len(self.nodes), dtype=np.uint32)
|
||||||
queue = deque(n for n in self.nodes if len(n.ins) == 0 or 'dff' in n.kind.lower() or 'latch' in n.kind.lower())
|
queue = deque(n for n in self.nodes if len(n.ins) == 0 or 'dff' in n.kind.lower() or 'latch' in n.kind.lower())
|
||||||
while len(queue) > 0:
|
while len(queue) > 0:
|
||||||
n = queue.popleft()
|
n = queue.popleft()
|
||||||
@@ -479,6 +488,16 @@ class Circuit:
|
|||||||
queue.append(succ)
|
queue.append(succ)
|
||||||
yield n
|
yield n
|
||||||
|
|
||||||
|
def topological_order_with_level(self):
|
||||||
|
level = np.zeros(len(self.nodes), dtype=np.int32) - 1
|
||||||
|
for n in self.topological_order():
|
||||||
|
if len(n.ins) == 0 or 'dff' in n.kind.lower() or 'latch' in n.kind.lower():
|
||||||
|
l = 0
|
||||||
|
else:
|
||||||
|
l = level[[l.driver.index for l in n.ins if l is not None]].max() + 1
|
||||||
|
level[n] = l
|
||||||
|
yield n, l
|
||||||
|
|
||||||
def topological_line_order(self):
|
def topological_line_order(self):
|
||||||
"""Generator function to iterate over all lines in topological order.
|
"""Generator function to iterate over all lines in topological order.
|
||||||
"""
|
"""
|
||||||
@@ -540,3 +559,31 @@ class Circuit:
|
|||||||
queue.extend(preds)
|
queue.extend(preds)
|
||||||
region.append(n)
|
region.append(n)
|
||||||
yield stem, region
|
yield stem, region
|
||||||
|
|
||||||
|
def dot(self, format='svg'):
|
||||||
|
from graphviz import Digraph
|
||||||
|
dot = Digraph(format=format, graph_attr={'rankdir': 'LR', 'splines': 'true'})
|
||||||
|
|
||||||
|
node_level = np.zeros(len(self.nodes), dtype=np.uint32)
|
||||||
|
level_nodes = defaultdict(list)
|
||||||
|
for n, lv in self.topological_order_with_level():
|
||||||
|
level_nodes[lv].append(n)
|
||||||
|
node_level[n] = lv
|
||||||
|
|
||||||
|
for lv in level_nodes:
|
||||||
|
with dot.subgraph() as s:
|
||||||
|
s.attr(rank='same')
|
||||||
|
for n in level_nodes[lv]:
|
||||||
|
ins = '|'.join([f'<i{i}>{i}' for i in range(len(n.ins))])
|
||||||
|
outs = '|'.join([f'<o{i}>{i}' for i in range(len(n.outs))])
|
||||||
|
s.node(name=str(n.index), label = f'{{{{{ins}}}|{n.index}\n{n.kind}\n{n.name}|{{{outs}}}}}', shape='record')
|
||||||
|
|
||||||
|
for l in self.lines:
|
||||||
|
driver, reader = f'{l.driver.index}:o{l.driver_pin}', f'{l.reader.index}:i{l.reader_pin}'
|
||||||
|
if node_level[l.driver] >= node_level[l.reader]:
|
||||||
|
dot.edge(driver, reader, style='dotted', label=str(l.index))
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
dot.edge(driver, reader, label=str(l.index))
|
||||||
|
|
||||||
|
return dot
|
||||||
Reference in new issue
Block a user