from migen.fhdl.structure import *
from migen.fhdl.specials import Special
-from migen.fhdl.tools import flat_iteration
+from migen.fhdl.tools import flat_iteration, rename_clock_domain
class FinalizeError(Exception):
pass
for mod_name, f in subfragments:
for cd in f.clock_domains:
if cd.name in needs_renaming:
- f.rename_clock_domain(cd.name, mod_name + "_" + cd.name)
+ rename_clock_domain(f, cd.name, mod_name + "_" + cd.name)
# sum subfragments
for mod_name, f in subfragments:
self._fragment += f
from migen.fhdl.structure import *
-from migen.fhdl.tools import list_signals, value_bits_sign
+from migen.fhdl.tools import *
from migen.fhdl.tracer import get_obj_var_name
from migen.fhdl.verilog import _printexpr as verilog_printexpr
class Special(HUID):
+ def iter_expressions(self):
+ for x in []:
+ yield x
+
def rename_clock_domain(self, old, new):
- pass
+ for obj, attr, direction in self.iter_expressions():
+ rename_clock_domain_expr(getattr(obj, attr), old, new)
+
+ def list_clock_domains(self):
+ r = set()
+ for obj, attr, direction in self.iter_expressions():
+ r |= list_clock_domains_expr(getattr(obj, attr))
+ return r
- def get_clock_domains(self):
- return set()
+ def list_ios(self, ins, outs, inouts):
+ r = set()
+ for obj, attr, direction in self.iter_expressions():
+ if (direction == SPECIAL_INPUT and ins) \
+ or (direction == SPECIAL_OUTPUT and outs) \
+ or (direction == SPECIAL_INOUT and inouts):
+ signals = list_signals(getattr(obj, attr))
+ r.update(signals)
+ return r
class Tristate(Special):
def __init__(self, target, o, oe, i=None):
self.oe = oe
self.i = i
- def list_ios(self, ins, outs, inouts):
- r = set()
- if inouts:
- r.update(list_signals(self.target))
- if ins:
- r.update(list_signals(self.o))
- r.update(list_signals(self.oe))
- if outs:
- r.update(list_signals(self.i))
- return r
+ def iter_expressions(self):
+ for attr, target_context in [
+ ("target", SPECIAL_INOUT),
+ ("o", SPECIAL_INPUT),
+ ("oe", SPECIAL_INPUT),
+ ("i", SPECIAL_OUTPUT)]:
+ yield self, attr, target_context
@staticmethod
def emit_verilog(tristate, ns, clock_domains):
self.name = name
self.value = value
- class _CR:
- def __init__(self, name_inst, domain="sys", invert=False):
- self.name_inst = name_inst
- self.domain = domain
- self.invert = invert
- class ClockPort(_CR):
- pass
- class ResetPort(_CR):
- pass
-
def get_io(self, name):
for item in self.items:
if isinstance(item, Instance._IO) and item.name == name:
return item.expr
- def rename_clock_domain(self, old, new):
- for cr in filter(lambda x: isinstance(x, Instance._CR), self.items):
- if cr.domain == old:
- cr.domain = new
-
- def get_clock_domains(self):
- return set(cr.domain
- for cr in filter(lambda x: isinstance(x, Instance._CR), self.items))
-
- def list_ios(self, ins, outs, inouts):
- subsets = [list_signals(item.expr) for item in filter(lambda x:
- (ins and isinstance(x, Instance.Input))
- or (outs and isinstance(x, Instance.Output))
- or (inouts and isinstance(x, Instance.InOut)),
- self.items)]
- if subsets:
- return set.union(*subsets)
- else:
- return set()
+ def iter_expressions(self):
+ for item in self.items:
+ if isinstance(item, Instance.Input):
+ yield item, "expr", SPECIAL_INPUT
+ elif isinstance(item, Instance.Output):
+ yield item, "expr", SPECIAL_OUTPUT
+ elif isinstance(item, Instance.InOut):
+ yield item, "expr", SPECIAL_INOUT
@staticmethod
def emit_verilog(instance, ns, clock_domains):
if isinstance(p, Instance._IO):
name_inst = p.name
name_design = verilog_printexpr(ns, p.expr)[0]
- elif isinstance(p, Instance.ClockPort):
- name_inst = p.name_inst
- name_design = ns.get_name(clock_domains[p.domain].clk)
- if p.invert:
- name_design = "~" + name_design
- elif isinstance(p, Instance.ResetPort):
- name_inst = p.name_inst
- name_design = ns.get_name(clock_domains[p.domain].rst)
- else:
- continue
- if not firstp:
- r += ",\n"
- firstp = False
- r += "\t." + name_inst + "(" + name_design + ")"
+ if not firstp:
+ r += ",\n"
+ firstp = False
+ r += "\t." + name_inst + "(" + name_design + ")"
if not firstp:
r += "\n"
r += ");\n\n"
self.ports.append(mp)
return mp
+ def iter_expressions(self):
+ for p in self.ports:
+ for attr, target_context in [
+ ("adr", SPECIAL_INPUT),
+ ("we", SPECIAL_INPUT),
+ ("dat_w", SPECIAL_INPUT),
+ ("re", SPECIAL_INPUT),
+ ("dat_r", SPECIAL_OUTPUT)]:
+ yield p, attr, target_context
+
def rename_clock_domain(self, old, new):
+ # port expressions are always signals - no need to call Special.rename_clock_domain
for port in self.ports:
if port.clock_domain == old:
port.clock_domain = new
- def get_clock_domains(self):
+ def list_clock_domains(self):
+ # port expressions are always signals - no need to call Special.list_clock_domains
return set(port.clock_domain for port in self.ports)
- def list_ios(self, ins, outs, inouts):
- s = set()
- def add(*sigs):
- for sig in sigs:
- if sig is not None:
- s.add(sig)
- for p in self.ports:
- if ins:
- add(p.adr, p.we, p.dat_w, p.re)
- if outs:
- add(p.dat_r)
- return s
-
@staticmethod
def emit_verilog(memory, ns, clock_domains):
r = ""
self.template = template
self.signals = signals
- def list_ios(self, ins, outs, inouts):
- return set()
-
@staticmethod
def emit_verilog(directive, ns, clock_domains):
name_dict = dict((k, ns.get_name(sig)) for k, sig in directive.signals.items())
def __repr__(self):
return "<Signal " + (self.backtrace[-1][0] or "anonymous") + " at " + hex(id(self)) + ">"
+class ClockSignal(Value):
+ def __init__(self, cd="sys"):
+ Value.__init__(self)
+ self.cd = cd
+
+class ResetSignal(Value):
+ def __init__(self, cd="sys"):
+ Value.__init__(self)
+ self.cd = cd
+
# statements
class _Assign:
else:
return list.__getitem__(self, key)
+(SPECIAL_INPUT, SPECIAL_OUTPUT, SPECIAL_INOUT) = range(3)
+
class Fragment:
def __init__(self, comb=None, sync=None, specials=None, clock_domains=None, sim=None):
if comb is None: comb = []
self.specials | other.specials,
self.clock_domains + other.clock_domains,
self.sim + other.sim)
-
- def rename_clock_domain(self, old, new):
- self.sync[new] = self.sync[old]
- del self.sync[old]
- for special in self.specials:
- special.rename_clock_domain(old, new)
- try:
- cd = self.clock_domains[old]
- except KeyError:
- pass
- else:
- cd.rename(new)
from migen.fhdl.structure import _Operator, _Slice, _Assign, _ArrayProxy
from migen.fhdl.visit import NodeVisitor, NodeTransformer
+def bitreverse(s):
+ length, signed = value_bits_sign(s)
+ l = [s[i] for i in reversed(range(length))]
+ return Cat(*l)
+
def flat_iteration(l):
for element in l:
if isinstance(element, collections.Iterable):
r |= special.list_ios(ins, outs, inouts)
return r
+class _ClockDomainLister(NodeVisitor):
+ def __init__(self):
+ self.clock_domains = set()
+
+ def visit_ClockSignal(self, node):
+ self.clock_domains.add(node.cd)
+
+ def visit_ResetSignal(self, node):
+ self.clock_domains.add(node.cd)
+
+ def visit_clock_domains(self, node):
+ for clockname, statements in node.items():
+ self.clock_domains.add(clockname)
+ self.visit(statements)
+
+def list_clock_domains_expr(f):
+ cdl = _ClockDomainLister()
+ cdl.visit(f)
+ return cdl.clock_domains
+
def list_clock_domains(f):
- r = set(f.sync.keys())
+ r = list_clock_domains_expr(f)
for special in f.specials:
- r |= special.get_clock_domains()
+ r |= special.list_clock_domains()
for cd in f.clock_domains:
r.add(cd.name)
return r
return bits_for(v), v < 0
elif isinstance(v, Signal):
return v.nbits, v.signed
+ elif isinstance(v, (ClockSignal, ResetSignal)):
+ return 1, False
elif isinstance(v, _Operator):
obs = list(map(value_bits_sign, v.operands))
if v.op == "+" or v.op == "-":
else:
raise TypeError
-class _ArrayLowerer(NodeTransformer):
- def __init__(self):
+# Basics are FHDL structure elements that back-ends are not required to support
+# but can be expressed in terms of other elements (lowered) before conversion.
+class _BasicLowerer(NodeTransformer):
+ def __init__(self, clock_domains):
self.comb = []
self.target_context = False
self.extra_stmts = []
+ self.clock_domains = clock_domains
def visit_Assign(self, node):
old_target_context, old_extra_stmts = self.target_context, self.extra_stmts
self.comb.append(Case(self.visit(node.key), cases).makedefault())
return array_muxed
-def lower_arrays(f):
- al = _ArrayLowerer()
- tf = al.visit(f)
- tf.comb += al.comb
- return tf
+ def visit_ClockSignal(self, node):
+ return self.clock_domains[node.cd].clk
-def bitreverse(s):
- length, signed = value_bits_sign(s)
- l = [s[i] for i in reversed(range(length))]
- return Cat(*l)
+ def visit_ResetSignal(self, node):
+ return self.clock_domains[node.cd].rst
+
+def lower_basics(f):
+ bl = _BasicLowerer(f.clock_domains)
+ f = bl.visit(f)
+ f.comb += bl.comb
+
+ for special in f.specials:
+ for obj, attr, direction in special.iter_expressions():
+ if direction != SPECIAL_INOUT:
+ # inouts are only supported by Migen when connected directly to top-level
+ # in this case, they are Signal and never need lowering
+ bl.comb = []
+ bl.target_context = direction != SPECIAL_INPUT
+ bl.extra_stmts = []
+ expr = getattr(obj, attr)
+ expr = bl.visit(expr)
+ setattr(obj, attr, expr)
+ f.comb += bl.comb + bl.extra_stmts
+
+ return f
+
+class _ClockDomainRenamer(NodeVisitor):
+ def __init__(self, old, new):
+ self.old = old
+ self.new = new
+
+ def visit_ClockSignal(self, node):
+ if node.cd == self.old:
+ node.cd = self.new
+
+ def visit_ResetSignal(self, node):
+ if node.cd == self.old:
+ node.cd = self.new
+
+def rename_clock_domain_expr(f, old, new):
+ cdr = _ClockDomainRenamer(old, new)
+ cdr.visit(f)
+
+def rename_clock_domain(f, old, new):
+ rename_clock_domain_expr(f, old, new)
+ f.sync[new] = f.sync[old]
+ del f.sync[old]
+ for special in f.specials:
+ special.rename_clock_domain(old, new)
+ try:
+ cd = f.clock_domains[old]
+ except KeyError:
+ pass
+ else:
+ cd.rename(new)
def _insert_resets(f):
newsync = dict()
for k, v in f.sync.items():
- newsync[k] = insert_reset(f.clock_domains[k].rst, v)
+ newsync[k] = insert_reset(ResetSignal(k), v)
f.sync = newsync
def _printsync(f, ns):
f = f.get_fragment()
if ios is None:
ios = set()
-
- f = lower_arrays(f) # this also copies f
- fs, lowered_specials = _lower_specials(special_overrides, f.specials)
- f += fs
+
for cd_name in list_clock_domains(f):
try:
f.clock_domains[cd_name]
cd = ClockDomain(cd_name)
f.clock_domains.append(cd)
ios |= {cd.clk, cd.rst}
+
_insert_resets(f)
+ f = lower_basics(f)
+ fs, lowered_specials = _lower_specials(special_overrides, f.specials)
+ f += lower_basics(fs)
ns = build_namespace(list_signals(f) \
| list_special_ios(f, True, True, True) \
self.visit_constant(node)
elif isinstance(node, Signal):
self.visit_Signal(node)
+ elif isinstance(node, ClockSignal):
+ self.visit_ClockSignal(node)
+ elif isinstance(node, ResetSignal):
+ self.visit_ResetSignal(node)
elif isinstance(node, _Operator):
self.visit_Operator(node)
elif isinstance(node, _Slice):
def visit_Signal(self, node):
pass
+
+ def visit_ClockSignal(self, node):
+ pass
+
+ def visit_ResetSignal(self, node):
+ pass
def visit_Operator(self, node):
for o in node.operands:
pass
# Default methods always copy the node, except for:
-# - Signals
+# - Signals, ClockSignals and ResetSignals
# - Unknown objects
# - All fragment fields except comb and sync
# In those cases, the original node is returned unchanged.
return self.visit_constant(node)
elif isinstance(node, Signal):
return self.visit_Signal(node)
+ elif isinstance(node, ClockSignal):
+ return self.visit_ClockSignal(node)
+ elif isinstance(node, ResetSignal):
+ return self.visit_ResetSignal(node)
elif isinstance(node, _Operator):
return self.visit_Operator(node)
elif isinstance(node, _Slice):
def visit_Signal(self, node):
return node
+ def visit_ClockSignal(self, node):
+ return node
+
+ def visit_ResetSignal(self, node):
+ return node
+
def visit_Operator(self, node):
return _Operator(node.op, [self.visit(o) for o in node.operands])
self.odomain = odomain
self.n = n
+ def iter_expressions(self):
+ yield self, "i", SPECIAL_INPUT
+ yield self, "o", SPECIAL_OUTPUT
+
def rename_clock_domain(self, old, new):
+ Special.rename_clock_domain(self, old, new)
if self.odomain == old:
self.odomain = new
- def get_clock_domains(self):
- return {self.odomain}
-
- def list_ios(self, ins, outs, inouts):
- r = set()
- if ins:
- r.update(list_signals(self.i))
- if outs:
- r.update(list_signals(self.o))
+ def list_clock_domains(self):
+ r = Special.list_clock_domains(self)
+ r.add(self.odomain)
return r
@staticmethod