--- 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