diff --git a/migen/corelogic/record.py b/migen/corelogic/record.py index 2bbe47cf8..eadeb0a22 100644 --- a/migen/corelogic/record.py +++ b/migen/corelogic/record.py @@ -1,9 +1,8 @@ from migen.fhdl.structure import * -from migen.fhdl.structure import _make_signal_name class Record: def __init__(self, layout, name=None): - self.name = name or _make_signal_name() + self.name = name or "anonymous" self.field_order = [] for f in layout: if isinstance(f, tuple): @@ -34,7 +33,7 @@ class Record: return l def copy(self, name=None): - return Record(self.layout(), name or _make_signal_name()) + return Record(self.layout(), name) def get_alignment(self, name): return list(filter(lambda x: x[0] == name, self.field_order))[0][1] diff --git a/migen/fhdl/namer.py b/migen/fhdl/namer.py new file mode 100644 index 000000000..cdd2a9920 --- /dev/null +++ b/migen/fhdl/namer.py @@ -0,0 +1,142 @@ +import inspect +import re +from itertools import combinations + +class NoContext: + pass + +def trace_back(name=None): + l = [] + frame = inspect.currentframe().f_back.f_back + while frame is not None: + try: + obj = frame.f_locals["self"] + except KeyError: + obj = None + if obj is None or isinstance(obj, NoContext): + modules = frame.f_globals["__name__"] + modules = modules.split(".") + obj = modules[len(modules)-1] + + if name is None: + line = inspect.getframeinfo(frame).code_context[0] + m = re.match("[\t ]*([0-9A-Za-z_\.]+)[\t ]*=", line) + if m is None: + name = None + else: + names = m.group(1).split(".") + name = names[len(names)-1] + l.insert(0, (obj, name)) + name = None + frame = frame.f_back + return l + +def obj_name(obj): + if isinstance(obj, str): + return obj + else: + return obj.__class__.__name__.lower() + +class TreeNode: + def __init__(self, name): + self.name = name + self.ids = {} + self.children = [] + self.include_context = False + self.include_varname = False + +def add_to_tree(root, backtrace): + for step in backtrace: + n = obj_name(step[0]) + found = list(filter(lambda x: x.name == n, root.children)) + if found: + node = found[0] + else: + node = TreeNode(n) + root.children.append(node) + if not isinstance(step[0], str) and id(step[0]) not in node.ids: + node.ids[id(step[0])] = len(node.ids) + root = node + +def build_tree(signals): + t = TreeNode("root") + for signal in signals: + if signal.name_override is None: + add_to_tree(t, signal.backtrace) + return t + +def name_backtrace(root, backtrace): + parts = [] + for step in backtrace: + n = obj_name(step[0]) + found = list(filter(lambda x: x.name == n, root.children)) + node = found[0] + if node.include_context: + if len(node.ids) > 1: + parts.append(node.name + str(node.ids[id(step[0])])) + else: + parts.append(node.name) + if node.include_varname and step[1] is not None: + parts.append(step[1]) + return "_".join(parts) + +def _include_divergence(root, bt1, bt2): + for step1, step2 in zip(bt1, bt2): + n1, n2 = obj_name(step1[0]), obj_name(step2[0]) + node1 = list(filter(lambda x: x.name == n1, root.children)) + node2 = list(filter(lambda x: x.name == n2, root.children)) + if node1 != node2: + node1.include_context = True + node2.include_context = True + return + if not isinstance(step1[0], str) and not isinstance(step2[0], str) \ + and id(step1[0]) != id(step2[0]): + node1.include_context = True + return + if step1[1] is not None and step2[1] is not None \ + and step1[1] != step2[1]: + node1.include_varname = True + return + root = node1 + +def resolve_conflicts(root, signals): + for s1, s2 in combinations(signals, 2): + if name_backtrace(root, s1) == name_backtrace(root, s2): + _include_divergence(root, s1.backtrace, s2.backtrace) + +def build_tree_res(signals): + t = build_tree(signals) + resolve_conflicts(t, signals) + return t + +def signal_name(root, sig): + if sig.name_override is not None: + return sig.name_override + else: + return name_backtrace(root, sig.backtrace) + +class Namespace: + def __init__(self, tree): + self.counts = {} + self.sigs = {} + self.tree = tree + + def get_name(self, sig): + sig_name = signal_name(self.tree, sig) + try: + n = self.sigs[sig] + if n: + return sig_name + "_" + str(n) + else: + return sig_name + except KeyError: + try: + n = self.counts[sig_name] + except KeyError: + n = 0 + self.sigs[sig] = n + self.counts[sig_name] = n + 1 + if n: + return sig_name + "_" + str(n) + else: + return sig_name diff --git a/migen/fhdl/structure.py b/migen/fhdl/structure.py index c32ac8427..3dabbc6b6 100644 --- a/migen/fhdl/structure.py +++ b/migen/fhdl/structure.py @@ -2,6 +2,8 @@ import math import inspect import re +from migen.fhdl import namer + def bits_for(n): if isinstance(n, Constant): return n.bv.width @@ -131,61 +133,13 @@ def _cst(x): else: return x -_forbidden_prefixes = {'inst', 'source', 'sink', 'fsm'} - -def _try_class_name(frame): - while frame is not None: - try: - cl = frame.f_locals['self'] - prefix = cl.__class__.__name__.lower() - if prefix not in _forbidden_prefixes: - return prefix - except KeyError: - pass - frame = frame.f_back - return None - -def _try_module_name(frame): - modules = frame.f_globals["__name__"] - if modules != "__main__": - modules = modules.split('.') - prefix = modules[len(modules)-1] - return prefix - else: - return None - -def _make_signal_name(name=None, back=2): - frame = inspect.currentframe() - for i in range(back): - frame = frame.f_back - - if name is None: - line = inspect.getframeinfo(frame).code_context[0] - m = re.match('[\t ]*([0-9A-Za-z_\.]+)[\t ]*=', line) - if m is None: - name = "anonymous" - else: - names = m.group(1).split('.') - name = names[len(names)-1] - - prefix = _try_class_name(frame) - if prefix is None: - prefix = _try_module_name(frame) - if prefix is None: - prefix = "" - else: - prefix += "_" - - return prefix + name - class Signal(Value): - def __init__(self, bv=BV(), name=None, variable=False, reset=0, namer=None): + def __init__(self, bv=BV(), name=None, variable=False, reset=0, name_override=None): self.bv = bv self.variable = variable - self.name = name - if self.name is None: - self.name = _make_signal_name(namer) self.reset = Constant(reset, bv) + self.name_override = name_override + self.backtrace = namer.trace_back(name) def __hash__(self): return id(self) diff --git a/migen/fhdl/tools.py b/migen/fhdl/tools.py index cd94d4fa8..6ba4372dd 100644 --- a/migen/fhdl/tools.py +++ b/migen/fhdl/tools.py @@ -1,30 +1,6 @@ from migen.fhdl.structure import * from migen.fhdl.structure import _Operator, _Slice, _Assign, _StatementList -class Namespace: - def __init__(self): - self.counts = {} - self.sigs = {} - - def get_name(self, sig): - try: - n = self.sigs[sig] - if n: - return sig.name + "_" + str(n) - else: - return sig.name - except KeyError: - try: - n = self.counts[sig.name] - except KeyError: - n = 0 - self.sigs[sig] = n - self.counts[sig.name] = n + 1 - if n: - return sig.name + "_" + str(n) - else: - return sig.name - def list_signals(node): if node is None: return set() diff --git a/migen/fhdl/verilog.py b/migen/fhdl/verilog.py index 349b6d7a0..1842b20ae 100644 --- a/migen/fhdl/verilog.py +++ b/migen/fhdl/verilog.py @@ -3,6 +3,7 @@ from functools import partial from migen.fhdl.structure import * from migen.fhdl.structure import _Operator, _Slice, _Assign, _StatementList from migen.fhdl.tools import * +from migen.fhdl.namer import Namespace, build_tree_res def _printsig(ns, s): if s.bv.signed: @@ -205,15 +206,14 @@ def _printinstances(ns, i, clk, rst): r += ");\n\n" return r -def convert(f, ios=set(), name="top", clk_signal=None, rst_signal=None, ns=None): +def convert(f, ios=set(), name="top", clk_signal=None, rst_signal=None, return_ns=False): if clk_signal is None: - clk_signal = Signal(name="sys_clk") + clk_signal = Signal(name_override="sys_clk") ios.add(clk_signal) if rst_signal is None: - rst_signal = Signal(name="sys_rst") + rst_signal = Signal(name_override="sys_rst") ios.add(rst_signal) - if ns is None: - ns = Namespace() + ns = Namespace(namer.build_tree_res(list_signals(f))) ios |= f.pads @@ -225,4 +225,7 @@ def convert(f, ios=set(), name="top", clk_signal=None, rst_signal=None, ns=None) r += "endmodule\n" - return r + if return_ns: + return r, ns + else: + return r diff --git a/migen/flow/actor.py b/migen/flow/actor.py index e6024bdfb..7203083ab 100644 --- a/migen/flow/actor.py +++ b/migen/flow/actor.py @@ -1,5 +1,4 @@ from migen.fhdl.structure import * -from migen.fhdl.structure import _make_signal_name from migen.corelogic.misc import optree from migen.corelogic.record import * @@ -26,11 +25,11 @@ class Endpoint: def __init__(self, token): self.token = token if isinstance(self, Sink): - self.stb = Signal(namer="stb_i") - self.ack = Signal(namer="ack_o") + self.stb = Signal(name="stb_i") + self.ack = Signal(name="ack_o") else: - self.stb = Signal(namer="stb_o") - self.ack = Signal(namer="ack_i") + self.stb = Signal(name="stb_o") + self.ack = Signal(name="ack_i") def token_signal(self): sigs = self.token.flatten() @@ -108,7 +107,7 @@ class Actor: if isinstance(desc[2], Record): token = desc[2] else: - token = Record(desc[2], name=_make_signal_name(desc[0], 1)) + token = Record(desc[2]) ep = desc[1](token) self.endpoints[desc[0]] = ep else: