---
 migen/build/lattice/icestorm.py   | 126 ++++++++++++++++++++++++++++++++++++++
 migen/build/lattice/platform.py   |   5 +-
 migen/build/lattice/programmer.py |   7 +++
 3 files changed, 137 insertions(+), 1 deletion(-)
 create mode 100644 migen/build/lattice/icestorm.py

diff --git a/migen/build/lattice/icestorm.py b/migen/build/lattice/icestorm.py
new file mode 100644
index 0000000..1ab1d93
--- /dev/null
+++ b/migen/build/lattice/icestorm.py
@@ -0,0 +1,126 @@
+# This file is Copyright (c) 2015 William D. Jones <thor0...@comcast.net>
+# License: BSD
+
+import os
+import sys
+import subprocess
+
+from migen.fhdl.structure import _Fragment
+
+from migen.build.generic_platform import *
+from migen.build import tools
+from migen.build.lattice import common
+
+
+def _format_constraint(c):
+    pass
+
+
+def _format_pcf(signame, pin, others, resname):
+    return "set_io " + signame + " " + pin + "\n"
+
+
+def _build_pcf(named_sc, named_pc):
+    r = ""
+    for sig, pins, others, resname in named_sc:
+        if len(pins) > 1:
+            for i, p in enumerate(pins):
+                r += _format_pcf(sig + "[" + str(i) + "]", p, others, resname)
+        else:
+            r += _format_pcf(sig, pins[0], others, resname)
+    if named_pc:
+        r += "\n" + "\n\n".join(named_pc)
+    return r
+
+
+def _build_yosys(device, sources, vincpaths, build_name):
+    ys_contents = ""
+    incflags = ""
+    for path in vincpaths:
+        incflags += " -I" + path
+    for filename, language, library in sources:
+        ys_contents += "read_{}{} {}\n".format(language, incflags, filename)
+
+    ys_contents += """synth_ice40 -top top -blif 
{build_name}.blif""".format(build_name=build_name)
+
+    ys_name = build_name + ".ys"
+    tools.write_to_file(ys_name, ys_contents)
+
+
+def _run_icestorm(build_name, source, yosys_opt, pnr_opt, icepack_opt):
+    if sys.platform == "win32" or sys.platform == "cygwin":
+        source_cmd = "call "
+        script_ext = ".bat"
+        shell = ["cmd", "/c"]
+        build_script_contents = "@echo off\nrem Autogenerated by Migen\n"
+        fail_stmt = " || exit /b"
+    else:
+        source_cmd = "source "
+        script_ext = ".sh"
+        shell = ["bash"]
+        build_script_contents = "# Autogenerated by Migen\nset -e\n"
+        fail_stmt = ""
+
+    build_script_contents += """
+yosys {yosys_opt} {build_name}.ys
+arachne-pnr {pnr_opt} -p {build_name}.pcf {build_name}.blif -o 
{build_name}.txt{fail_stmt}
+icepack {icepack_opt} {build_name}.txt {build_name}.bin{fail_stmt}
+"""
+    build_script_contents = build_script_contents.format(build_name=build_name,
+        yosys_opt=yosys_opt, pnr_opt=pnr_opt, icepack_opt=icepack_opt,
+        fail_stmt=fail_stmt)
+    build_script_file = "build_" + build_name + script_ext
+    tools.write_to_file(build_script_file, build_script_contents, 
force_unix=False)
+    command = shell + [build_script_file]
+    r = subprocess.call(command)
+    if r != 0:
+        raise OSError("Subprocess failed")
+
+
+class LatticeIceStormToolchain:
+    def __init__(self):
+        self.yosys_opt = "-q"
+        self.pnr_opt = ""
+        self.icepack_opt = ""
+
+    # platform.device should be of the form "ice40-{1k,8k}-{tq144, etc}""
+    def build(self, platform, fragment, build_dir="build", build_name="top",
+        run=True):
+        tools.mkdir_noerror(build_dir)
+        cwd = os.getcwd()
+        os.chdir(build_dir)
+
+        if not isinstance(fragment, _Fragment):
+            fragment = fragment.get_fragment()
+        platform.finalize(fragment)
+
+        v_output = platform.get_verilog(fragment)
+        named_sc, named_pc = platform.resolve_signals(v_output.ns)
+        v_file = build_name + ".v"
+        v_output.write(v_file)
+        sources = platform.sources | {(v_file, "verilog", "work")}
+        _build_yosys(platform.device, sources, platform.verilog_include_paths, 
build_name)
+
+        tools.write_to_file(build_name + ".pcf", _build_pcf(named_sc, 
named_pc))
+        if run:
+            (family, size, package) = self.parse_device_string(platform.device)
+            new_pnr_opts = self.pnr_opt + " -d " + size + " -P " + package
+            _run_icestorm(build_name, False, self.yosys_opt, new_pnr_opts,
+                self.icepack_opt)
+
+        os.chdir(cwd)
+
+        return v_output.ns
+
+    def parse_device_string(self, device_str):
+        (family, size, package) = device_str.split("-")
+        if family not in ["ice40"]:
+            raise ValueError("Unknown device family")
+        if size not in ["1k", "8k"]:
+            raise ValueError("Invalid device size")
+        if package not in ["tq144", "ct256"]:
+            raise ValueError("Invalid device package")
+        return (family, size, package)
+
+    def add_period_constraint(self, platform, clk, period):
+        pass
diff --git a/migen/build/lattice/platform.py b/migen/build/lattice/platform.py
index 7374223..50fc4e4 100644
--- a/migen/build/lattice/platform.py
+++ b/migen/build/lattice/platform.py
@@ -1,5 +1,5 @@
 from migen.build.generic_platform import GenericPlatform
-from migen.build.lattice import common, diamond
+from migen.build.lattice import common, diamond, icestorm
 
 
 class LatticePlatform(GenericPlatform):
@@ -9,6 +9,9 @@ class LatticePlatform(GenericPlatform):
         GenericPlatform.__init__(self, *args, **kwargs)
         if toolchain == "diamond":
             self.toolchain = diamond.LatticeDiamondToolchain()
+        elif toolchain == "icestorm":
+            self.bitstream_ext = ".bin"
+            self.toolchain = icestorm.LatticeIceStormToolchain()
         else:
             raise ValueError("Unknown toolchain")
 
diff --git a/migen/build/lattice/programmer.py 
b/migen/build/lattice/programmer.py
index cc3c50b..2f091ab 100644
--- a/migen/build/lattice/programmer.py
+++ b/migen/build/lattice/programmer.py
@@ -52,3 +52,10 @@ class LatticeProgrammer(GenericProgrammer):
         xcf_content = _xcf_template.format(bitstream_file=bitstream_file)
         tools.write_to_file(xcf_file, xcf_content)
         subprocess.call(["pgrcmd", "-infile", xcf_file])
+
+
+class IceStormProgrammer(GenericProgrammer):
+    needs_bitreverse = False
+
+    def flash(self, address, data_file):
+        subprocess.call(["iceprog", "-o", str(address), data_file])
-- 
2.6.3

_______________________________________________
M-Labs devel mailing list
https://ssl.serverraum.org/lists/listinfo/devel

Reply via email to