Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 5 commits
  • 2 files changed
  • 0 commit comments
  • 1 contributor
Showing with 185 additions and 124 deletions.
  1. +146 −105 migen/fhdl/namer.py
  2. +39 −19 migen/graph/treeviz.py
251 migen/fhdl/namer.py
View
@@ -1,122 +1,163 @@
+from collections import OrderedDict
from itertools import combinations
-from collections import defaultdict
from migen.fhdl.structure import *
-from migen.fhdl.tracer import index_id
-
-def _bin(sig_iters):
- # advance by one in the trace of each signal
- status = []
- for signal, it in sig_iters:
- step, last = next(it)
- status.append((signal, it, step, last))
+
+class _Node:
+ def __init__(self):
+ self.signal_count = 0
+ self.numbers = set()
+ self.use_name = False
+ self.use_number = False
+ self.children = OrderedDict()
+
+def _display_tree(filename, tree):
+ from migen.graph.treeviz import RenderNode
- # build bins accordingly
- bins = defaultdict(lambda: defaultdict(list))
- for signal, it, (stepname, stepidx), last in status:
- if last:
- it = None
- bins[stepname][stepidx].append((signal, it))
-
- r = []
- # merge bins when all step indices differ
- for stepname, stepname_d in bins.items():
- if all(len(content) == 1 for content in stepname_d.values()):
- r.append((stepname, [(stepidx, signal, it)
- for stepidx, stepidx_d in stepname_d.items()
- for signal, it in stepidx_d]))
+ def _to_render_node(name, node):
+ children = [_to_render_node(k, v) for k, v in node.children.items()]
+ if node.use_name:
+ if node.use_number:
+ color = (0.5, 0.9, 0.8)
+ else:
+ color = (0.8, 0.5, 0.9)
else:
- for stepidx, stepidx_d in stepname_d.items():
- r.append((stepname, [(stepidx, signal, it)
- for signal, it in stepidx_d]))
-
- #for stepname, content in r:
- #print("Bin: " + stepname)
- #for stepidx, signal, it in content:
- #print(" stepidx:" + str(stepidx) + " " + str(signal) + " " + str(it))
- #print("++++++++++")
-
- return r
+ if node.use_number:
+ color = (0.9, 0.8, 0.5)
+ else:
+ color = (0.8, 0.8, 0.8)
+ label = "{0}\n{1} signals\n{2}".format(name, node.signal_count, node.numbers)
+ return RenderNode(label, children, color=color)
-def _sets_disjoint(l):
- for s1, s2 in combinations(l, 2):
- if not s1.isdisjoint(s2):
- return False
- return True
+ top = _to_render_node("top", tree)
+ top.to_svg(filename)
-# sig_iters contains a list of tuples (signal, iterator on the current trace position)
-def _r_build_pnd(sig_iters):
- bins = _bin(sig_iters)
-
- subnames = {}
- mentions = defaultdict(list)
- bins_named = []
- stepindices = {}
-
- for stepname, next_steps in bins:
- bin_content = []
- for stepidx, signal, it in next_steps:
- if it is None:
- mentions[stepname].append(signal)
+def _build_tree(signals, basic_tree=None):
+ root = _Node()
+ for signal in signals:
+ current_b = basic_tree
+ current = root
+ current.signal_count += 1
+ for name, number in signal.backtrace:
+ if basic_tree is None:
+ use_number = False
else:
- bin_content.append((signal, it))
- stepindices[signal] = stepidx
- if bin_content:
- bins_named.append((stepname, _r_build_pnd(bin_content)))
-
- name_sets = [set(sub_pnd.values()) for prefix, sub_pnd in bins_named]
- if not _sets_disjoint(name_sets):
- for prefix, sub_pnd in bins_named:
- for signal, subname in sub_pnd.items():
- subname = (prefix, subname)
- subnames[signal] = subname
- mentions[subname].append(signal)
- else:
- for prefix, sub_pnd in bins_named:
- for signal, subname in sub_pnd.items():
- subname = ("", subname)
- subnames[signal] = subname
- mentions[subname].append(signal)
-
- # Sort lists of mentions by step indices
- for v in mentions.values():
- v.sort(key=lambda x: stepindices[x])
-
- r = {}
- for stepname, next_steps in bins:
- for stepidx, signal, it in next_steps:
- if it is None:
- name = stepname
- prefix = ""
+ current_b = current_b.children[name]
+ use_number = current_b.use_number
+ if use_number:
+ key = (name, number)
else:
- prefix = subnames[signal][0]
- name = subnames[signal][1]
- mention = mentions[(prefix, name)]
- if prefix:
- if len(mention) > 1:
- r[signal] = prefix + str(index_id(mention, signal)) + "_" + name
- else:
- r[signal] = prefix + "_" + name
+ key = name
+ try:
+ current = current.children[key]
+ except KeyError:
+ new = _Node()
+ current.children[key] = new
+ current = new
+ current.numbers.add(number)
+ if use_number:
+ current.all_numbers = sorted(current_b.numbers)
+ current.signal_count += 1
+ return root
+
+def _set_use_name(node, node_name=""):
+ if not node.children:
+ node.use_name = True
+ return {(node_name, )}
+ else:
+ cnames = [(k, _set_use_name(v, k)) for k, v in node.children.items()]
+ for (c1_prefix, c1_names), (c2_prefix, c2_names) in combinations(cnames, 2):
+ if not c1_names.isdisjoint(c2_names):
+ node.children[c1_prefix].use_name = True
+ node.children[c2_prefix].use_name = True
+ r = set()
+ for c_prefix, c_names in cnames:
+ if node.children[c_prefix].use_name:
+ for c_name in c_names:
+ r.add((c_prefix, ) + c_name)
else:
- if len(mention) > 1:
- r[signal] = name + str(index_id(mention, signal))
- else:
- r[signal] = name
-
+ r |= c_names
+ return r
+
+def _name_signal(tree, signal):
+ elements = []
+ treepos = tree
+ for step_name, step_n in signal.backtrace:
+ try:
+ treepos = treepos.children[(step_name, step_n)]
+ use_number = True
+ except KeyError:
+ treepos = treepos.children[step_name]
+ use_number = False
+ if treepos.use_name:
+ elname = step_name
+ if use_number:
+ elname += str(treepos.all_numbers.index(step_n))
+ elements.append(elname)
+ return "_".join(elements)
+
+def _build_pnd(tree, signals):
+ return dict((signal, _name_signal(tree, signal)) for signal in signals)
+
+def _invert_pnd(pnd):
+ inv_pnd = dict()
+ for k, v in pnd.items():
+ inv_pnd[v] = inv_pnd.get(v, [])
+ inv_pnd[v].append(k)
+ return inv_pnd
+
+def _list_conflicting_signals(pnd):
+ inv_pnd = _invert_pnd(pnd)
+ r = set()
+ for k, v in inv_pnd.items():
+ if len(v) > 1:
+ r.update(v)
return r
-def last_flagged(seq):
- seq = iter(seq)
- a = next(seq)
- for b in seq:
- yield a, False
- a = b
- yield a, True
+def _set_use_number(tree, signals):
+ for signal in signals:
+ current = tree
+ for step_name, step_n in signal.backtrace:
+ current = current.children[step_name]
+ current.use_number = current.signal_count > len(current.numbers) and len(current.numbers) > 1
+
+_debug = False
def build_namespace(signals):
- sig_iters = [(signal, last_flagged(signal.backtrace))
- for signal in signals if signal.name_override is None]
- pnd = _r_build_pnd(sig_iters)
+ basic_tree = _build_tree(signals)
+ _set_use_name(basic_tree)
+ if _debug:
+ _display_tree("tree_basic.svg", basic_tree)
+ pnd = _build_pnd(basic_tree, signals)
+
+ # If there are conflicts, try splitting the tree by numbers
+ # on paths taken by conflicting signals.
+ conflicting_signals = _list_conflicting_signals(pnd)
+ if conflicting_signals:
+ _set_use_number(basic_tree, conflicting_signals)
+ if _debug:
+ print("namer: using split-by-number strategy")
+ _display_tree("tree_marked.svg", basic_tree)
+ numbered_tree = _build_tree(signals, basic_tree)
+ _set_use_name(numbered_tree)
+ if _debug:
+ _display_tree("tree_numbered.svg", numbered_tree)
+ pnd = _build_pnd(numbered_tree, signals)
+ else:
+ if _debug:
+ print("namer: using basic strategy")
+
+ # ...then add number suffixes by HUID
+ inv_pnd = _invert_pnd(pnd)
+ huid_suffixed = False
+ for name, signals in inv_pnd.items():
+ if len(signals) > 1:
+ huid_suffixed = True
+ for n, signal in enumerate(sorted(signals, key=lambda x: x.huid)):
+ pnd[signal] += str(n)
+ if _debug and huid_suffixed:
+ print("namer: using HUID suffixes")
+
ns = Namespace(pnd)
# register signals with name_override
for signal in signals:
58 migen/graph/treeviz.py
View
@@ -1,9 +1,11 @@
import cairo
import math
-def _cairo_draw_node(ctx, radius, color, outer_color, s):
+def _cairo_draw_node(ctx, dx, radius, color, outer_color, s):
ctx.save()
+ ctx.translate(dx, 0)
+
ctx.set_line_width(0.0)
gradient_color = cairo.RadialGradient(0, 0, 0, 0, 0, radius)
gradient_color.add_color_stop_rgb(0, *color)
@@ -12,10 +14,20 @@ def _cairo_draw_node(ctx, radius, color, outer_color, s):
ctx.arc(0, 0, radius, 0, 2*math.pi)
ctx.fill()
- ctx.set_source_rgb(0, 0, 0)
- x_bearing, y_bearing, textw, texth, x_advance, y_advance = ctx.text_extents(s)
- ctx.translate(-textw/2, texth/2)
- ctx.show_text(s)
+ lines = s.split("\n")
+ textws = []
+ texths = []
+ for line in lines:
+ x_bearing, y_bearing, w, h, x_advance, y_advance = ctx.text_extents(line)
+ textws.append(w)
+ texths.append(h + 2)
+ ctx.translate(0, -sum(texths[1:])/2)
+ for line, w, h in zip(lines, textws, texths):
+ ctx.translate(-w/2, h/2)
+ ctx.move_to(0, 0)
+ ctx.set_source_rgb(0, 0, 0)
+ ctx.show_text(line)
+ ctx.translate(w/2, h/2)
ctx.restore()
@@ -40,36 +52,44 @@ def __init__(self, label, children=None, color=(0.8, 0.8, 0.8), radius=40):
self.radius = radius
self.pitch = self.radius*3
- def get_extents(self):
+ def get_dimensions(self):
if self.children:
- cw, ch = zip(*[c.get_extents() for c in self.children])
- w = max(cw)*len(self.children)
- h = self.pitch + max(ch)
+ cws, chs, cdxs = zip(*[c.get_dimensions() for c in self.children])
+ w = sum(cws)
+ h = self.pitch + max(chs)
+ dx = cws[0]/4 - cws[-1]/4
else:
w = h = self.pitch
- return w, h
+ dx = 0
+ return w, h, dx
def render(self, ctx):
- _cairo_draw_node(ctx, self.radius, self.color, self.outer_color, self.label)
if self.children:
- cpitch = max([c.get_extents()[0] for c in self.children])
- first_child_x = -(cpitch*(len(self.children) - 1))/2
+ cws, chs, cdxs = zip(*[c.get_dimensions() for c in self.children])
+ first_child_x = -sum(cws)/2
ctx.save()
ctx.translate(first_child_x, self.pitch)
- for c in self.children:
+ for c, w in zip(self.children, cws):
+ ctx.translate(w/2, 0)
c.render(ctx)
- ctx.translate(cpitch, 0)
+ ctx.translate(w/2, 0)
ctx.restore()
+ dx = cws[0]/4 - cws[-1]/4
+
current_x = first_child_x
- for c in self.children:
+ for c, w, cdx in zip(self.children, cws, cdxs):
current_y = self.pitch - c.radius
- _cairo_draw_connection(ctx, 0, self.radius, self.outer_color, current_x, current_y, c.outer_color)
- current_x += cpitch
+ current_x += w/2
+ _cairo_draw_connection(ctx, dx, self.radius, self.outer_color, current_x+cdx, current_y, c.outer_color)
+ current_x += w/2
+ else:
+ dx = 0
+ _cairo_draw_node(ctx, dx, self.radius, self.color, self.outer_color, self.label)
def to_svg(self, name):
- w, h = self.get_extents()
+ w, h, dx = self.get_dimensions()
surface = cairo.SVGSurface(name, w, h)
ctx = cairo.Context(surface)
ctx.translate(w/2, self.pitch/2)

No commit comments for this range

Something went wrong with that request. Please try again.