fhdl: tristate support
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Thu, 14 Feb 2013 23:17:24 +0000 (00:17 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Thu, 14 Feb 2013 23:17:24 +0000 (00:17 +0100)
examples/basic/tristate.py [new file with mode: 0644]
migen/fhdl/structure.py
migen/fhdl/tools.py
migen/fhdl/verilog.py
migen/fhdl/verilog_behavioral.py [new file with mode: 0644]
migen/fhdl/verilog_mem_behavioral.py [deleted file]

diff --git a/examples/basic/tristate.py b/examples/basic/tristate.py
new file mode 100644 (file)
index 0000000..3886b96
--- /dev/null
@@ -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}))
index 09d056d4dbab3d1e23a6a7fe61af52d751b359ad..fed0a3d9499e60e1d48f205f76c2c4a6a93c5679 100644 (file)
@@ -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)
        
index ab9f9d2591933e51f8216020ecd60e0537d83422..02564925d6b00fca312422a04d4719fc99c9d0e3 100644 (file)
@@ -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):
index 1c4d6082b2361786b51b240b8a1d90f1ff9a8a5c..0e0821cdc9b326c5cf77fe842395ec40264d6966 100644 (file)
@@ -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_behavioral.py b/migen/fhdl/verilog_behavioral.py
new file mode 100644 (file)
index 0000000..2835af2
--- /dev/null
@@ -0,0 +1,86 @@
+from migen.fhdl.structure import *
+from migen.fhdl.tools import *
+
+def mem_handler(memory, ns, clock_domains):
+       r = ""
+       gn = ns.get_name
+       adrbits = bits_for(memory.depth-1)
+       
+       r += "reg [" + str(memory.width-1) + ":0] " \
+               + gn(memory) \
+               + "[0:" + str(memory.depth-1) + "];\n"
+
+       adr_regs = {}
+       data_regs = {}
+       for port in memory.ports:
+               if not port.async_read:
+                       if port.mode == WRITE_FIRST and port.we is not None:
+                               adr_reg = Signal(name_override="memadr")
+                               r += "reg [" + str(adrbits-1) + ":0] " \
+                                       + gn(adr_reg) + ";\n"
+                               adr_regs[id(port)] = adr_reg
+                       else:
+                               data_reg = Signal(name_override="memdat")
+                               r += "reg [" + str(memory.width-1) + ":0] " \
+                                       + gn(data_reg) + ";\n"
+                               data_regs[id(port)] = data_reg
+
+       for port in memory.ports:
+               r += "always @(posedge " + gn(clock_domains[port.clock_domain].clk) + ") begin\n"
+               if port.we is not None:
+                       if port.we_granularity:
+                               n = memory.width//port.we_granularity
+                               for i in range(n):
+                                       m = i*port.we_granularity
+                                       M = (i+1)*port.we_granularity-1
+                                       sl = "[" + str(M) + ":" + str(m) + "]"
+                                       r += "\tif (" + gn(port.we) + "[" + str(i) + "])\n"
+                                       r += "\t\t" + gn(memory) + "[" + gn(port.adr) + "]" + sl + " <= " + gn(port.dat_w) + sl + ";\n"
+                       else:
+                               r += "\tif (" + gn(port.we) + ")\n"
+                               r += "\t\t" + gn(memory) + "[" + gn(port.adr) + "] <= " + gn(port.dat_w) + ";\n"
+               if not port.async_read:
+                       if port.mode == WRITE_FIRST and port.we is not None:
+                               rd = "\t" + gn(adr_regs[id(port)]) + " <= " + gn(port.adr) + ";\n"
+                       else:
+                               bassign = gn(data_regs[id(port)]) + " <= " + gn(memory) + "[" + gn(port.adr) + "];\n"
+                               if port.mode == READ_FIRST or port.we is None:
+                                       rd = "\t" + bassign
+                               elif port.mode == NO_CHANGE:
+                                       rd = "\tif (!" + gn(port.we) + ")\n" \
+                                         + "\t\t" + bassign
+               if port.re is None:
+                       r += rd
+               else:
+                       r += "\tif (" + gn(port.re) + ")\n"
+                       r += "\t" + rd.replace("\n\t", "\n\t\t")
+               r += "end\n\n"
+       
+       for port in memory.ports:
+               if port.async_read:
+                       r += "assign " + gn(port.dat_r) + " = " + gn(memory) + "[" + gn(port.adr) + "];\n"
+               else:
+                       if port.mode == WRITE_FIRST and port.we is not None:
+                               r += "assign " + gn(port.dat_r) + " = " + gn(memory) + "[" + gn(adr_regs[id(port)]) + "];\n"
+                       else:
+                               r += "assign " + gn(port.dat_r) + " = " + gn(data_regs[id(port)]) + ";\n"
+       r += "\n"
+       
+       if memory.init is not None:
+               r += "initial begin\n"
+               for i, c in enumerate(memory.init):
+                       r += "\t" + gn(memory) + "[" + str(i) + "] <= " + str(memory.width) + "'d" + str(c) + ";\n"
+               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
diff --git a/migen/fhdl/verilog_mem_behavioral.py b/migen/fhdl/verilog_mem_behavioral.py
deleted file mode 100644 (file)
index a9c88e8..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-from migen.fhdl.structure import *
-
-def handler(memory, ns, clock_domains):
-       r = ""
-       gn = ns.get_name
-       adrbits = bits_for(memory.depth-1)
-       
-       r += "reg [" + str(memory.width-1) + ":0] " \
-               + gn(memory) \
-               + "[0:" + str(memory.depth-1) + "];\n"
-
-       adr_regs = {}
-       data_regs = {}
-       for port in memory.ports:
-               if not port.async_read:
-                       if port.mode == WRITE_FIRST and port.we is not None:
-                               adr_reg = Signal(name_override="memadr")
-                               r += "reg [" + str(adrbits-1) + ":0] " \
-                                       + gn(adr_reg) + ";\n"
-                               adr_regs[id(port)] = adr_reg
-                       else:
-                               data_reg = Signal(name_override="memdat")
-                               r += "reg [" + str(memory.width-1) + ":0] " \
-                                       + gn(data_reg) + ";\n"
-                               data_regs[id(port)] = data_reg
-
-       for port in memory.ports:
-               r += "always @(posedge " + gn(clock_domains[port.clock_domain].clk) + ") begin\n"
-               if port.we is not None:
-                       if port.we_granularity:
-                               n = memory.width//port.we_granularity
-                               for i in range(n):
-                                       m = i*port.we_granularity
-                                       M = (i+1)*port.we_granularity-1
-                                       sl = "[" + str(M) + ":" + str(m) + "]"
-                                       r += "\tif (" + gn(port.we) + "[" + str(i) + "])\n"
-                                       r += "\t\t" + gn(memory) + "[" + gn(port.adr) + "]" + sl + " <= " + gn(port.dat_w) + sl + ";\n"
-                       else:
-                               r += "\tif (" + gn(port.we) + ")\n"
-                               r += "\t\t" + gn(memory) + "[" + gn(port.adr) + "] <= " + gn(port.dat_w) + ";\n"
-               if not port.async_read:
-                       if port.mode == WRITE_FIRST and port.we is not None:
-                               rd = "\t" + gn(adr_regs[id(port)]) + " <= " + gn(port.adr) + ";\n"
-                       else:
-                               bassign = gn(data_regs[id(port)]) + " <= " + gn(memory) + "[" + gn(port.adr) + "];\n"
-                               if port.mode == READ_FIRST or port.we is None:
-                                       rd = "\t" + bassign
-                               elif port.mode == NO_CHANGE:
-                                       rd = "\tif (!" + gn(port.we) + ")\n" \
-                                         + "\t\t" + bassign
-               if port.re is None:
-                       r += rd
-               else:
-                       r += "\tif (" + gn(port.re) + ")\n"
-                       r += "\t" + rd.replace("\n\t", "\n\t\t")
-               r += "end\n\n"
-       
-       for port in memory.ports:
-               if port.async_read:
-                       r += "assign " + gn(port.dat_r) + " = " + gn(memory) + "[" + gn(port.adr) + "];\n"
-               else:
-                       if port.mode == WRITE_FIRST and port.we is not None:
-                               r += "assign " + gn(port.dat_r) + " = " + gn(memory) + "[" + gn(adr_regs[id(port)]) + "];\n"
-                       else:
-                               r += "assign " + gn(port.dat_r) + " = " + gn(data_regs[id(port)]) + ";\n"
-       r += "\n"
-       
-       if memory.init is not None:
-               r += "initial begin\n"
-               for i, c in enumerate(memory.init):
-                       r += "\t" + gn(memory) + "[" + str(i) + "] <= " + str(memory.width) + "'d" + str(c) + ";\n"
-               r += "end\n\n"
-       
-       return r