Skip to content

Commit

Permalink
migen/build: Add Icestorm toolchain.
Browse files Browse the repository at this point in the history
cr1901 authored and sbourdeauducq committed May 8, 2016
1 parent 7051829 commit 8ccc5dc
Showing 3 changed files with 137 additions and 1 deletion.
126 changes: 126 additions & 0 deletions migen/build/lattice/icestorm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# This file is Copyright (c) 2015 William D. Jones <thor0505@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
5 changes: 4 additions & 1 deletion migen/build/lattice/platform.py
Original file line number Diff line number Diff line change
@@ -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 @@ def __init__(self, *args, toolchain="diamond", **kwargs):
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")

7 changes: 7 additions & 0 deletions migen/build/lattice/programmer.py
Original file line number Diff line number Diff line change
@@ -52,3 +52,10 @@ def load_bitstream(self, bitstream_file):
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])

0 comments on commit 8ccc5dc

Please sign in to comment.