Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
  • 3 commits
  • 8 files changed
  • 0 commit comments
  • 1 contributor
View
9 examples/basic/arrays.py
@@ -1,11 +1,12 @@
from migen.fhdl.structure import *
+from migen.fhdl.specials import Instance
from migen.fhdl.module import Module
from migen.fhdl import verilog
class Example(Module):
def __init__(self):
- dx = 5
- dy = 5
+ dx = 2
+ dy = 2
x = Signal(max=dx)
y = Signal(max=dy)
@@ -20,4 +21,8 @@ def __init__(self):
my_2d_array[x][y].eq(inp)
)
+ ina = Array(Signal() for a in range(dx))
+ outa = Array(Signal() for a in range(dy))
+ self.specials += Instance("test", Instance.Output("O", outa[y]), Instance.Input("I", ina[x]))
+
print(verilog.convert(Example()))
View
4 migen/fhdl/module.py
@@ -3,7 +3,7 @@
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
@@ -158,7 +158,7 @@ def finalize(self):
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
View
128 migen/fhdl/specials.py
@@ -1,14 +1,32 @@
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):
@@ -18,16 +36,13 @@ 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):
@@ -79,40 +94,19 @@ def __init__(self, name, value):
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):
@@ -144,20 +138,10 @@ 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"
@@ -214,27 +198,26 @@ def get_port(self, write_capable=False, async_read=False,
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 = ""
@@ -315,9 +298,6 @@ def __init__(self, template, **signals):
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())
View
24 migen/fhdl/structure.py
@@ -170,6 +170,16 @@ def __len__(self): # TODO: remove (use tools.value_bits_sign instead)
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:
@@ -260,6 +270,8 @@ def __getitem__(self, key):
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 = []
@@ -287,15 +299,3 @@ def __add__(self, other):
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)
View
101 migen/fhdl/tools.py
@@ -4,6 +4,11 @@
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):
@@ -64,10 +69,30 @@ def list_special_ios(f, ins, outs, inouts):
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
@@ -99,6 +124,8 @@ def value_bits_sign(v):
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 == "-":
@@ -168,11 +195,14 @@ def value_bits_sign(v):
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
@@ -203,13 +233,58 @@ def visit_ArrayProxy(self, node):
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)
View
21 migen/fhdl/verilog.py
@@ -203,7 +203,7 @@ def _printcomb(f, ns, display_run):
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):
@@ -258,23 +258,28 @@ def _printinit(f, ios, ns):
def convert(f, ios=None, name="top",
return_ns=False,
special_overrides=dict(),
+ create_clock_domains=True,
display_run=False):
if not isinstance(f, Fragment):
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]
except KeyError:
- cd = ClockDomain(cd_name)
- f.clock_domains.append(cd)
- ios |= {cd.clk, cd.rst}
+ if create_clock_domains:
+ cd = ClockDomain(cd_name)
+ f.clock_domains.append(cd)
+ ios |= {cd.clk, cd.rst}
+ else:
+ raise KeyError("Unresolved clock domain: '"+cd_name+"'")
+
_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) \
View
22 migen/fhdl/visit.py
@@ -9,6 +9,10 @@ def visit(self, node):
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):
@@ -39,6 +43,12 @@ def visit_constant(self, node):
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:
@@ -89,7 +99,7 @@ def visit_unknown(self, node):
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.
@@ -99,6 +109,10 @@ def visit(self, node):
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):
@@ -132,6 +146,12 @@ def visit_constant(self, node):
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])
View
17 migen/genlib/cdc.py
@@ -30,19 +30,18 @@ def __init__(self, i, o, odomain, n=2):
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

No commit comments for this range

Something went wrong with that request. Please try again.