diff --git a/examples/basic/tristate.py b/examples/basic/tristate.py new file mode 100644 index 000000000..3886b9696 --- /dev/null +++ b/examples/basic/tristate.py @@ -0,0 +1,11 @@ +from migen.fhdl.structure import * +from migen.fhdl import verilog + +n = 6 +pad = Signal(n) +o = Signal(n) +oe = Signal() +i = Signal(n) + +f = Fragment(tristates={Tristate(pad, o, oe, i)}) +print(verilog.convert(f, ios={pad, o, oe, i})) diff --git a/migen/fhdl/structure.py b/migen/fhdl/structure.py index 09d056d4d..fed0a3d94 100644 --- a/migen/fhdl/structure.py +++ b/migen/fhdl/structure.py @@ -229,6 +229,13 @@ class Array(list): else: return list.__getitem__(self, key) +class Tristate: + def __init__(self, target, o, oe, i=None): + self.target = target + self.o = o + self.oe = oe + self.i = i + # extras class Instance(HUID): @@ -327,10 +334,11 @@ class Memory(HUID): # class Fragment: - def __init__(self, comb=None, sync=None, instances=None, memories=None, sim=None): + def __init__(self, comb=None, sync=None, instances=None, tristates=None, memories=None, sim=None): if comb is None: comb = [] if sync is None: sync = dict() if instances is None: instances = set() + if tristates is None: tristates = set() if memories is None: memories = set() if sim is None: sim = [] @@ -340,9 +348,9 @@ class Fragment: self.comb = comb self.sync = sync self.instances = set(instances) + self.tristates = set(tristates) self.memories = set(memories) self.sim = sim - def __add__(self, other): newsync = defaultdict(list) @@ -352,6 +360,7 @@ class Fragment: newsync[k].extend(v) return Fragment(self.comb + other.comb, newsync, self.instances | other.instances, + self.tristates | other.tristates, self.memories | other.memories, self.sim + other.sim) diff --git a/migen/fhdl/tools.py b/migen/fhdl/tools.py index ab9f9d259..02564925d 100644 --- a/migen/fhdl/tools.py +++ b/migen/fhdl/tools.py @@ -64,7 +64,7 @@ def list_inst_ios(i, ins, outs, inouts): return set.union(*(list_inst_ios(e, ins, outs, inouts) for e in i)) else: return set() - else: + elif isinstance(i, Instance): subsets = [list_signals(item.expr) for item in filter(lambda x: (ins and isinstance(x, Instance.Input)) or (outs and isinstance(x, Instance.Output)) @@ -74,6 +74,33 @@ def list_inst_ios(i, ins, outs, inouts): return set.union(*subsets) else: return set() + else: + return set() + +def list_tristate_ios(i, ins, outs, inouts): + if isinstance(i, Fragment): + return list_tristate_ios(i.tristates, ins, outs, inouts) + elif isinstance(i, set): + if i: + return set.union(*(list_tristate_ios(e, ins, outs, inouts) for e in i)) + else: + return set() + elif isinstance(i, Tristate): + r = set() + if inouts: + r.update(list_signals(i.target)) + if ins: + r.update(list_signals(i.o)) + r.update(list_signals(i.oe)) + if outs: + r.update(list_signals(i.i)) + return r + else: + return set() + +def list_it_ios(i, ins, outs, inouts): + return list_inst_ios(i, ins, outs, inouts) \ + | list_tristate_ios(i, ins, outs, inouts) def list_mem_ios(m, ins, outs): if isinstance(m, Fragment): diff --git a/migen/fhdl/verilog.py b/migen/fhdl/verilog.py index 1c4d6082b..0e0821cdc 100644 --- a/migen/fhdl/verilog.py +++ b/migen/fhdl/verilog.py @@ -5,7 +5,7 @@ from migen.fhdl.structure import * from migen.fhdl.structure import _Operator, _Slice, _Assign from migen.fhdl.tools import * from migen.fhdl.namer import Namespace, build_namespace -from migen.fhdl import verilog_mem_behavioral +from migen.fhdl import verilog_behavioral as behavioral def _printsig(ns, s): if s.signed: @@ -135,11 +135,11 @@ def _list_comb_wires(f): return r def _printheader(f, ios, name, ns): - sigs = list_signals(f) | list_inst_ios(f, True, True, True) | list_mem_ios(f, True, True) - inst_mem_outs = list_inst_ios(f, False, True, False) | list_mem_ios(f, False, True) - inouts = list_inst_ios(f, False, False, True) - targets = list_targets(f) | inst_mem_outs - wires = _list_comb_wires(f) | inst_mem_outs + sigs = list_signals(f) | list_it_ios(f, True, True, True) | list_mem_ios(f, True, True) + it_mem_outs = list_it_ios(f, False, True, False) | list_mem_ios(f, False, True) + inouts = list_it_ios(f, False, False, True) + targets = list_targets(f) | it_mem_outs + wires = _list_comb_wires(f) | it_mem_outs r = "module " + name + "(\n" firstp = True for sig in sorted(ios, key=lambda x: x.huid): @@ -259,6 +259,12 @@ def _printinstances(f, ns, clock_domains): r += ");\n\n" return r +def _printtristates(f, ns, handler): + r = "" + for tristate in f.tristates: + r += handler(tristate, ns) + return r + def _printmemories(f, ns, handler, clock_domains): r = "" for memory in f.memories: @@ -270,7 +276,7 @@ def _printinit(f, ios, ns): signals = list_signals(f) \ - ios \ - list_targets(f) \ - - list_inst_ios(f, False, True, False) \ + - list_it_ios(f, False, True, False) \ - list_mem_ios(f, False, True) if signals: r += "initial begin\n" @@ -282,7 +288,8 @@ def _printinit(f, ios, ns): def convert(f, ios=None, name="top", clock_domains=None, return_ns=False, - memory_handler=verilog_mem_behavioral.handler, + memory_handler=behavioral.mem_handler, + tristate_handler=behavioral.tristate_handler, display_run=False): if ios is None: ios = set() @@ -297,7 +304,7 @@ def convert(f, ios=None, name="top", f = lower_arrays(f) ns = build_namespace(list_signals(f) \ - | list_inst_ios(f, True, True, True) \ + | list_it_ios(f, True, True, True) \ | list_mem_ios(f, True, True) \ | ios) @@ -306,6 +313,7 @@ def convert(f, ios=None, name="top", r += _printcomb(f, ns, display_run) r += _printsync(f, ns, clock_domains) r += _printinstances(f, ns, clock_domains) + r += _printtristates(f, ns, tristate_handler) r += _printmemories(f, ns, memory_handler, clock_domains) r += _printinit(f, ios, ns) r += "endmodule\n" diff --git a/migen/fhdl/verilog_mem_behavioral.py b/migen/fhdl/verilog_behavioral.py similarity index 85% rename from migen/fhdl/verilog_mem_behavioral.py rename to migen/fhdl/verilog_behavioral.py index a9c88e8cc..2835af260 100644 --- a/migen/fhdl/verilog_mem_behavioral.py +++ b/migen/fhdl/verilog_behavioral.py @@ -1,6 +1,7 @@ from migen.fhdl.structure import * +from migen.fhdl.tools import * -def handler(memory, ns, clock_domains): +def mem_handler(memory, ns, clock_domains): r = "" gn = ns.get_name adrbits = bits_for(memory.depth-1) @@ -72,3 +73,14 @@ def handler(memory, ns, clock_domains): r += "end\n\n" return r + +def tristate_handler(tristate, ns): + gn = ns.get_name + w, s = value_bits_sign(tristate.target) + r = "assign " + gn(tristate.target) + " = " \ + + gn(tristate.oe) + " ? " + gn(tristate.o) \ + + " : " + str(w) + "'bz;\n" + if tristate.i is not None: + r += "assign " + gn(tristate.i) + " = " + gn(tristate.target) + ";\n" + r += "\n" + return r