introduce conversion output object (prevents file IO in FHDL backends)
authorSebastien Bourdeauducq <sb@m-labs.hk>
Wed, 8 Apr 2015 12:28:23 +0000 (20:28 +0800)
committerSebastien Bourdeauducq <sb@m-labs.hk>
Wed, 8 Apr 2015 12:28:23 +0000 (20:28 +0800)
mibuild/altera/quartus.py
mibuild/generic_platform.py
mibuild/lattice/diamond.py
mibuild/sim/verilator.py
mibuild/xilinx/ise.py
mibuild/xilinx/vivado.py
migen/fhdl/conv_output.py [new file with mode: 0644]
migen/fhdl/edif.py
migen/fhdl/specials.py
migen/fhdl/verilog.py

index 0c0a995439a9f3c26e36413e8f7f6eec07ac853e..bdf14a6850b993ceeb8e0748dced2c022659f141 100644 (file)
@@ -81,10 +81,10 @@ class AlteraQuartusToolchain:
                        fragment = fragment.get_fragment()
                platform.finalize(fragment)
 
-               v_src, vns = platform.get_verilog(fragment)
-               named_sc, named_pc = platform.resolve_signals(vns)
+               v_output = platform.get_verilog(fragment)
+               named_sc, named_pc = platform.resolve_signals(v_output.ns)
                v_file = build_name + ".v"
-               tools.write_to_file(v_file, v_src)
+               v_output.write(v_file)
                sources = platform.sources | {(v_file, "verilog")}
                _build_files(platform.device, sources, platform.verilog_include_paths, named_sc, named_pc, build_name)
                if run:
@@ -92,7 +92,7 @@ class AlteraQuartusToolchain:
 
                os.chdir("..")
 
-               return vns
+               return v_output.ns
 
        def add_period_constraint(self, platform, clk, period):
                # TODO: handle differential clk
index 6d3e77e8c963b5d50f28e945c94bbc740e359e68..4c13fe72d916ba286719f2ae1b56f1e7a1f55589 100644 (file)
@@ -265,20 +265,11 @@ class GenericPlatform:
                        named_pc.append(template.format(**name_dict))
                return named_sc, named_pc
 
-       def _get_source(self, fragment, gen_fn):
-               if not isinstance(fragment, _Fragment):
-                       fragment = fragment.get_fragment()
-               # generate source
-               src, vns = gen_fn(fragment)
-               return src, vns
-
        def get_verilog(self, fragment, **kwargs):
-               return self._get_source(fragment, lambda f: verilog.convert(f, self.constraint_manager.get_io_signals(),
-                               return_ns=True, create_clock_domains=False, **kwargs))
+               return verilog.convert(fragment, self.constraint_manager.get_io_signals(), create_clock_domains=False, **kwargs)
 
        def get_edif(self, fragment, cell_library, vendor, device, **kwargs):
-               return self._get_source(fragment, lambda f: edif.convert(f, self.constraint_manager.get_io_signals(),
-                               cell_library, vendor, device, return_ns=True, **kwargs))
+               return edif.convert(fragment, self.constraint_manager.get_io_signals(), cell_library, vendor, device, **kwargs)
 
        def build(self, fragment):
                raise NotImplementedError("GenericPlatform.build must be overloaded")
index 3a12456cfbe76b8e779e5999787646f4f9140fb4..b04f3154673cdddbbc3b9eb57bc8ef5c826d0ef2 100644 (file)
@@ -75,10 +75,10 @@ class LatticeDiamondToolchain:
                        fragment = fragment.get_fragment()
                platform.finalize(fragment)
 
-               v_src, vns = platform.get_verilog(fragment)
-               named_sc, named_pc = platform.resolve_signals(vns)
+               v_output = platform.get_verilog(fragment)
+               named_sc, named_pc = platform.resolve_signals(v_output.ns)
                v_file = build_name + ".v"
-               tools.write_to_file(v_file, v_src)
+               v_output.write(v_file)
                sources = platform.sources + [(v_file, "verilog")]
                _build_files(platform.device, sources, platform.verilog_include_paths, build_name)
 
@@ -89,7 +89,7 @@ class LatticeDiamondToolchain:
 
                os.chdir("..")
 
-               return vns
+               return v_output.ns
 
        def add_period_constraint(self, platform, clk, period):
                # TODO: handle differential clk
index b3d221d526cce715736ebdf334bef79f4affb5ae..5a4bd251d7569e7f6e6415bbb2a17dff8a6ca133 100644 (file)
@@ -127,10 +127,9 @@ class SimVerilatorToolchain:
                        fragment = fragment.get_fragment()
                platform.finalize(fragment)
 
-               v_src, vns = platform.get_verilog(fragment)
-               named_sc, named_pc = platform.resolve_signals(vns)
-               v_file = "dut.v"
-               tools.write_to_file(v_file, v_src)
+               v_output = platform.get_verilog(fragment)
+               named_sc, named_pc = platform.resolve_signals(v_output.ns)
+               v_output.write("dut.v")
 
                include_paths = []
                for source in platform.sources:
@@ -138,11 +137,11 @@ class SimVerilatorToolchain:
                        if path not in include_paths:
                                include_paths.append(path)
                include_paths += platform.verilog_include_paths
-               _build_sim(platform, vns, build_name, include_paths, sim_path, serial, verbose)
+               _build_sim(platform, v_output.ns, build_name, include_paths, sim_path, serial, verbose)
 
                if run:
                        _run_sim(build_name)
 
                os.chdir("..")
 
-               return vns
+               return v_output.ns
index 703e1bcca20b4ac6fa230e7aaa83c2fe678ad4aa..1ab01b91ed61f275a475c9114d57e8ca31a7f6bb 100644 (file)
@@ -145,10 +145,11 @@ class XilinxISEToolchain:
                vns = None
 
                if mode == "xst" or mode == "yosys":
-                       v_src, vns = platform.get_verilog(fragment)
+                       v_output = platform.get_verilog(fragment)
+                       vns = v_output.ns
                        named_sc, named_pc = platform.resolve_signals(vns)
                        v_file = build_name + ".v"
-                       tools.write_to_file(v_file, v_src)
+                       v_output.write(v_file)
                        sources = platform.sources | {(v_file, "verilog")}
                        if mode == "xst":
                                _build_xst_files(platform.device, sources, platform.verilog_include_paths, build_name, self.xst_opt)
@@ -163,10 +164,11 @@ class XilinxISEToolchain:
                        synthesize(fragment, platform.constraint_manager.get_io_signals())
 
                if mode == "edif" or mode == "mist":
-                       e_src, vns = platform.get_edif(fragment)
+                       e_output = platform.get_edif(fragment)
+                       vns = e_output.ns
                        named_sc, named_pc = platform.resolve_signals(vns)
                        e_file = build_name + ".edif"
-                       tools.write_to_file(e_file, e_src)
+                       e_output.write(e_file)
                        isemode = "edif"
 
                tools.write_to_file(build_name + ".ucf", _build_ucf(named_sc, named_pc))
index 065552e5f3113ad395cf3cb3c655210c984c03b8..5ef4c29748939f5a863b8f84e05bb85fe1c989e5 100644 (file)
@@ -111,10 +111,10 @@ class XilinxVivadoToolchain:
                if not isinstance(fragment, _Fragment):
                        fragment = fragment.get_fragment()
                platform.finalize(fragment)
-               v_src, vns = platform.get_verilog(fragment)
-               named_sc, named_pc = platform.resolve_signals(vns)
+               v_output = platform.get_verilog(fragment)
+               named_sc, named_pc = platform.resolve_signals(v_output.ns)
                v_file = build_name + ".v"
-               tools.write_to_file(v_file, v_src)
+               v_output.write(v_file)
                sources = platform.sources | {(v_file, "verilog")}
                self._build_batch(platform, sources, build_name)
                tools.write_to_file(build_name + ".xdc", _build_xdc(named_sc, named_pc))
@@ -123,7 +123,7 @@ class XilinxVivadoToolchain:
 
                os.chdir("..")
 
-               return vns
+               return v_output.ns
 
        def add_period_constraint(self, platform, clk, period):
                platform.add_platform_command("""create_clock -name {clk} -period """ + \
diff --git a/migen/fhdl/conv_output.py b/migen/fhdl/conv_output.py
new file mode 100644 (file)
index 0000000..793fad2
--- /dev/null
@@ -0,0 +1,35 @@
+from operator import itemgetter
+
+
+class ConvOutput:
+    def __init__(self):
+        self.main_source = ""
+        self.data_files = dict()
+
+    def set_main_source(self, src):
+        self.main_source = src
+
+    def add_data_file(self, filename_base, content):
+        filename = filename_base
+        i = 1
+        while filename in self.data_files:
+            parts = filename_base.split(".", maxsplit=1)
+            parts[0] += "_" + str(i)
+            filename = ".".join(parts)
+            i += 1
+        self.data_files[filename] = content
+        return filename
+
+    def __str__(self):
+        r = self.main_source + "\n"
+        for filename, content in sorted(self.data_files.items(),
+                                        key=itemgetter(0)):
+            r += filename + ":\n" + content
+        return r
+
+    def write(self, main_filename):
+        with open(main_filename, "w") as f:
+            f.write(self.main_source)
+        for filename, content in self.data_files.items():
+            with open(filename, "w") as f:
+                f.write(content)
index de5e4f3e32223d9d2223e6d5894ff64de8df2932..a3acc4668ac733faaed3fb31fc9675df8395fdf3 100644 (file)
@@ -1,10 +1,12 @@
 from collections import OrderedDict
+from collections import namedtuple
+
 from migen.fhdl.std import *
 from migen.fhdl.namer import build_namespace
 from migen.fhdl.tools import list_special_ios
 from migen.fhdl.structure import _Fragment
+from migen.fhdl.conv_output import ConvOutput
 
-from collections import namedtuple
 
 _Port = namedtuple("_Port", "name direction")
 _Cell = namedtuple("_Cell", "name ports")
@@ -125,7 +127,7 @@ def _generate_cells(f):
                        else:
                                cell_dict[special.of] = port_list
                else:
-                       raise ValueError("Edif conversion can only handle synthesized fragments")
+                       raise ValueError("EDIF conversion can only handle synthesized fragments")
        return [_Cell(k, v) for k, v in cell_dict.items()]
 
 def _generate_instances(f,ns):
@@ -146,7 +148,7 @@ def _generate_instances(f,ns):
                                        raise NotImplementedError("Unsupported instance item")
                        instances.append(_Instance(name=ns.get_name(special), cell=special.of, properties=props))
                else:
-                       raise ValueError("Edif conversion can only handle synthesized fragments")
+                       raise ValueError("EDIF conversion can only handle synthesized fragments")
        return instances
 
 def _generate_ios(f, ios, ns):
@@ -174,7 +176,7 @@ def _generate_connections(f, ios, ns):
                                else:
                                        raise NotImplementedError("Unsupported instance item")
                else:
-                       raise ValueError("Edif conversion can only handle synthesized fragments")
+                       raise ValueError("EDIF conversion can only handle synthesized fragments")
        for s in ios:
                io = ns.get_name(s)
                if io not in r:
@@ -182,11 +184,11 @@ def _generate_connections(f, ios, ns):
                r[io].append(_NetBranch(portname=io, instancename=""))
        return r
 
-def convert(f, ios, cell_library, vendor, device, name="top", return_ns=False):
+def convert(f, ios, cell_library, vendor, device, name="top"):
        if not isinstance(f, _Fragment):
                f = f.get_fragment()
        if f.comb != [] or f.sync != {}:
-               raise ValueError("Edif conversion can only handle synthesized fragments")
+               raise ValueError("EDIF conversion can only handle synthesized fragments")
        if ios is None:
                ios = set()
        cells = _generate_cells(f)
@@ -194,8 +196,9 @@ def convert(f, ios, cell_library, vendor, device, name="top", return_ns=False):
        instances = _generate_instances(f, ns)
        inouts = _generate_ios(f, ios, ns)
        connections = _generate_connections(f, ios, ns)
-       r =  _write_edif(cells, inouts, instances, connections, cell_library, name, device, vendor)
-       if return_ns:
-               return r, ns
-       else:
-               return r
+       src = _write_edif(cells, inouts, instances, connections, cell_library, name, device, vendor)
+
+       r = ConvOutput()
+       r.set_main_source(src)
+       r.ns = ns
+       return r
index 768f55e4b6e2cacd944ad218e6b69b1985441044..764fa79122be7f0662f9f5d3f9b8e0a15bb8195f 100644 (file)
@@ -48,7 +48,7 @@ class Tristate(Special):
                        yield self, attr, target_context
 
        @staticmethod
-       def emit_verilog(tristate, ns):
+       def emit_verilog(tristate, ns, add_data_file):
                def pe(e):
                        return verilog_printexpr(ns, e)[0]
                w, s = value_bits_sign(tristate.target)
@@ -123,7 +123,7 @@ class Instance(Special):
                                yield item, "expr", SPECIAL_INOUT
 
        @staticmethod
-       def emit_verilog(instance, ns):
+       def emit_verilog(instance, ns, add_data_file):
                r = instance.of + " "
                parameters = list(filter(lambda i: isinstance(i, Instance.Parameter), instance.items))
                if parameters:
@@ -198,7 +198,7 @@ class _MemoryPort(Special):
                        yield self, attr, target_context
 
        @staticmethod
-       def emit_verilog(port, ns):
+       def emit_verilog(port, ns, add_data_file):
                return "" # done by parent Memory object
 
 class Memory(Special):
@@ -237,7 +237,7 @@ class Memory(Special):
                return mp
 
        @staticmethod
-       def emit_verilog(memory, ns):
+       def emit_verilog(memory, ns, add_data_file):
                r = ""
                def gn(e):
                        if isinstance(e, Memory):
@@ -307,14 +307,10 @@ class Memory(Special):
                r += "\n"
 
                if memory.init is not None:
-                       memory_filename = gn(memory) + ".init"
-
-                       # XXX move I/O to mibuild?
-                       # (Implies mem init won't work with simple Migen examples?)
-                       f = open(memory_filename, "w")
+                       content = ""
                        for d in memory.init:
-                               f.write("{:x}\n".format(d))
-                       f.close()
+                               content += "{:x}\n".format(d)
+                       memory_filename = add_data_file(gn(memory) + ".init", content)
 
                        r += "initial begin\n"
                        r += "$readmemh(\"" + memory_filename + "\", " + gn(memory) + ");\n"
@@ -330,7 +326,7 @@ class SynthesisDirective(Special):
                self.signals = signals
 
        @staticmethod
-       def emit_verilog(directive, ns):
+       def emit_verilog(directive, ns, add_data_file):
                name_dict = dict((k, ns.get_name(sig)) for k, sig in directive.signals.items())
                formatted = directive.template.format(**name_dict)
                return "// synthesis " + formatted + "\n"
index bc050441443f3324159959a6077d8e35464ae561..c1cfc690e8b178b11301353ee67c43472b7b86ac 100644 (file)
@@ -6,6 +6,7 @@ from migen.fhdl.structure import _Operator, _Slice, _Assign, _Fragment
 from migen.fhdl.tools import *
 from migen.fhdl.bitcontainer import bits_for, flen
 from migen.fhdl.namer import Namespace, build_namespace
+from migen.fhdl.conv_output import ConvOutput
 
 def _printsig(ns, s):
        if s.signed:
@@ -257,20 +258,20 @@ def _lower_specials(overrides, specials):
                f.specials -= lowered_specials2
        return f, lowered_specials
 
-def _printspecials(overrides, specials, ns):
+def _printspecials(overrides, specials, ns, add_data_file):
        r = ""
        for special in sorted(specials, key=lambda x: x.huid):
-               pr = _call_special_classmethod(overrides, special, "emit_verilog", ns)
+               pr = _call_special_classmethod(overrides, special, "emit_verilog", ns, add_data_file)
                if pr is None:
                        raise NotImplementedError("Special " + str(special) + " failed to implement emit_verilog")
                r += pr
        return r
 
 def convert(f, ios=None, name="top",
-  return_ns=False,
   special_overrides=dict(),
   create_clock_domains=True,
   display_run=False):
+       r = ConvOutput()
        if not isinstance(f, _Fragment):
                f = f.get_fragment()
        if ios is None:
@@ -296,15 +297,14 @@ def convert(f, ios=None, name="top",
        ns = build_namespace(list_signals(f) \
                | list_special_ios(f, True, True, True) \
                | ios)
+       r.ns = ns
 
-       r = "/* Machine-generated using Migen */\n"
-       r += _printheader(f, ios, name, ns)
-       r += _printcomb(f, ns, display_run)
-       r += _printsync(f, ns)
-       r += _printspecials(special_overrides, f.specials - lowered_specials, ns)
-       r += "endmodule\n"
+       src = "/* Machine-generated using Migen */\n"
+       src += _printheader(f, ios, name, ns)
+       src += _printcomb(f, ns, display_run)
+       src += _printsync(f, ns)
+       src += _printspecials(special_overrides, f.specials - lowered_specials, ns, r.add_data_file)
+       src += "endmodule\n"
+       r.set_main_source(src)
 
-       if return_ns:
-               return r, ns
-       else:
-               return r
+       return r