litex/migen/fhdl/namer.py

160 lines
3.7 KiB
Python
Raw Normal View History

2012-01-16 12:09:52 -05:00
import inspect
import re
from itertools import combinations
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
2012-01-20 16:15:44 -05:00
if obj is None:
2012-01-16 12:09:52 -05:00
modules = frame.f_globals["__name__"]
modules = modules.split(".")
obj = modules[len(modules)-1]
if name is None:
code_contexts = inspect.getframeinfo(frame).code_context
if code_contexts is not None:
line = code_contexts[0]
m = re.match("[\t ]*([0-9A-Za-z_\.]+)[\t ]*=", line)
if m is not None:
names = m.group(1).split(".")
name = names[len(names)-1]
2012-01-16 12:09:52 -05:00
l.insert(0, (obj, name))
name = None
frame = frame.f_back
return l
2012-01-19 12:25:25 -05:00
class _StepNamer():
def __init__(self):
self.name_to_ids = {}
2012-01-16 12:09:52 -05:00
def context_prefix(self, obj):
2012-01-19 12:25:25 -05:00
if isinstance(obj, str):
return obj
2012-01-16 12:09:52 -05:00
else:
2012-01-19 12:25:25 -05:00
n = obj.__class__.__name__.lower()
try:
l = self.name_to_ids[n]
except KeyError:
self.name_to_ids[n] = [id(obj)]
return n + "0"
2012-01-16 12:09:52 -05:00
else:
2012-01-19 12:25:25 -05:00
try:
idx = l.index(id(obj))
except ValueError:
idx = len(l)
l.append(id(obj))
return n + str(idx)
2012-01-16 12:09:52 -05:00
def name(self, with_context_prefix, step):
if with_context_prefix or step[1] is None:
n = self.context_prefix(step[0])
if step[1] is not None:
n += "_" + step[1]
else:
n = step[1]
2012-01-19 12:25:25 -05:00
return n
2012-01-16 12:09:52 -05:00
# Returns True if we should include the context prefix
def _choose_strategy(objs):
id_with_name = {}
for obj in objs:
if not isinstance(obj, str):
n = obj.__class__.__name__.lower()
try:
existing_id = id_with_name[n]
except KeyError:
id_with_name[n] = id(obj)
else:
if existing_id != id(obj):
return True
return False
2012-01-19 12:25:25 -05:00
def _bin(sn, sig_iters):
status = []
2012-01-19 12:25:25 -05:00
for signal, it in sig_iters:
2012-01-19 12:42:43 -05:00
step, last = next(it)
status.append((signal, it, step, last))
with_context_prefix = _choose_strategy(step[0] for signal, it, step, last in status)
terminals = []
bins = {}
for signal, it, step, last in status:
step_name = sn.name(with_context_prefix, step)
2012-01-19 12:42:43 -05:00
if last:
terminals.append((step_name, signal))
2012-01-19 12:25:25 -05:00
else:
if step_name not in bins:
bins[step_name] = []
bins[step_name].append((signal, it))
return terminals, bins
2012-01-16 12:09:52 -05:00
2012-01-19 13:24:43 -05:00
def _sets_disjoint(l):
for s1, s2 in combinations(l, 2):
if not s1.isdisjoint(s2):
return False
return True
2012-01-19 12:25:25 -05:00
def _r_build_pnd(sn, sig_iters):
terminals, bins = _bin(sn, sig_iters)
bins_named = [(k, _r_build_pnd(sn, v)) for k, v in bins.items()]
name_sets = [set(sub_pnd.values()) for prefix, sub_pnd in bins_named]
r = {}
2012-01-19 13:24:43 -05:00
if not _sets_disjoint(name_sets):
2012-01-19 12:25:25 -05:00
for prefix, sub_pnd in bins_named:
for s, n in sub_pnd.items():
2012-01-19 12:42:43 -05:00
r[s] = prefix + "_" + n
2012-01-19 12:25:25 -05:00
else:
for prefix, sub_pnd in bins_named:
r.update(sub_pnd)
2012-01-19 12:42:43 -05:00
for n, s in terminals:
r[s] = n
2012-01-19 12:25:25 -05:00
return r
2012-01-19 12:42:43 -05:00
def last_flagged(seq):
seq = iter(seq)
a = next(seq)
for b in seq:
yield a, False
a = b
yield a, True
def build_namespace(signals):
2012-01-19 12:42:43 -05:00
sig_iters = [(signal, last_flagged(signal.backtrace))
for signal in signals if signal.name_override is None]
pnd = _r_build_pnd(_StepNamer(), sig_iters)
ns = Namespace(pnd)
# register signals with name_override
for signal in signals:
if signal.name_override is not None:
ns.get_name(signal)
return ns
2012-01-16 12:09:52 -05:00
class Namespace:
2012-01-19 12:25:25 -05:00
def __init__(self, pnd):
2012-01-16 12:09:52 -05:00
self.counts = {}
self.sigs = {}
2012-01-19 12:25:25 -05:00
self.pnd = pnd
2012-01-16 12:09:52 -05:00
def get_name(self, sig):
2012-01-19 12:25:25 -05:00
if sig.name_override is not None:
sig_name = sig.name_override
else:
sig_name = self.pnd[sig]
2012-01-16 12:09:52 -05:00
try:
n = self.sigs[sig]
except KeyError:
try:
n = self.counts[sig_name]
except KeyError:
n = 0
self.sigs[sig] = n
self.counts[sig_name] = n + 1
2012-01-19 12:25:25 -05:00
if n:
return sig_name + "_" + str(n)
else:
return sig_name