vendor.fpga.lattice_ice40: implement.

This commit is contained in:
whitequark 2019-06-01 16:46:50 +00:00
parent b1eab9fb3b
commit 321d245e95
3 changed files with 134 additions and 0 deletions

0
nmigen/vendor/__init__.py vendored Normal file
View file

0
nmigen/vendor/fpga/__init__.py vendored Normal file
View file

134
nmigen/vendor/fpga/lattice_ice40.py vendored Normal file
View file

@ -0,0 +1,134 @@
from abc import abstractproperty
import os
import subprocess
import tempfile
from ...build import *
__all__ = ["LatticeICE40Platform", "IceStormProgrammerMixin", "IceBurnProgrammerMixin"]
class LatticeICE40Platform(TemplatedPlatform):
"""
Required tools:
* ``yosys``
* ``nextpnr-ice40``
* ``icepack``
Available overrides:
* ``verbose``: enables logging of informational messages to standard error.
* ``read_opts``: adds options for ``read`` Yosys command.
* ``synth_opts``: adds options for ``synth_ice40`` Yosys command.
* ``script_after_read``: inserts commands after ``read_ilang`` in Yosys script.
* ``script_after_synth``: inserts commands after ``synth_ice40`` in Yosys script.
* ``yosys_opts``: overrides default options (``-q``) for Yosys.
* ``nextpnr_opts``: overrides default options (``-q --placer heap``).
Build products:
* ``{{name}}.rpt``: Yosys log.
* ``{{name}}.json``: synthesized RTL.
* ``{{name}}.tim``: nextpnr log.
* ``{{name}}.asc``: ASCII bitstream.
* ``{{name}}.bin``: binary bitstream.
"""
device = abstractproperty()
package = abstractproperty()
file_templates = {
**TemplatedPlatform.build_script_templates,
"{{name}}.il": r"""
# {{autogenerated}}
{{emit_design("rtlil")}}
""",
"{{name}}.ys": r"""
# {{autogenerated}}
{% for file in platform.extra_files %}
{% if file.endswith(".v") -%}
read_verilog {{get_override("read_opts")|join(" ")}} {{file}}
{% elif file.endswith(".sv") -%}
read_verilog {{get_override("read_opts")|join(" ")}} {{file}}
{% endif %}
{% endfor %}
read_ilang {{name}}.il
{{get_override("script_after_read")|default("# (script_after_read placeholder)")}}
synth_ice40 {{get_override("synth_opts")|join(" ")}} -top {{name}}
{{get_override("script_after_synth")|default("# (script_after_synth placeholder)")}}
write_json {{name}}.json
""",
"{{name}}.pcf": r"""
# {{autogenerated}}
{% for port, pins, extra in platform.iter_port_constraints() %}
{% if pins|count > 1 %}
{% for bit in range -%}
set_io {{port}}[{{bit}}] {{pins[bit]}}
{% endfor %}
{% else -%}
set_io {{port}} {{pins[0]}}
{% endif %}
{% endfor %}
""",
"{{name}}_pre_pack.py": r"""
# {{autogenerated}}
{% for port, frequency in platform.iter_clock_constraints() -%}
{# Clock in MHz #}
ctx.addClock("{{port}}", {{frequency/1000000}})
{% endfor%}
""",
}
command_templates = [
r"""
{{get_tool("yosys")}}
{{quiet("-q")}}
{{get_override("yosys_opts")|join(" ")}}
-l {{name}}.rpt
{{name}}.ys
""",
r"""
{{get_tool("nextpnr-ice40")}}
{{quiet("-q")}}
{{get_override("nextpnr_opts")|default(["--placer","heap"])|join(" ")}}
-l {{name}}.tim
--{{platform.device}}
--package {{platform.package}}
--json {{name}}.json
--pcf {{name}}.pcf
--pre-pack {{name}}_pre_pack.py
--asc {{name}}.asc
""",
r"""
{{get_tool("icepack")}}
{{name}}.asc
{{name}}.bin
"""
]
class IceStormProgrammerMixin:
def toolchain_program(self, products, name, *, mode=None):
if mode is None and hasattr(self, "prog_mode"):
mode = self.prog_mode
if mode not in ("sram", "flash"):
raise ValueError("iceprog mode must be one of \"sram\" or \"flash\", not {!r}; "
"specify it using .build(..., program_opts={\"mode\": \"<mode>\"})"
.format(mode))
iceprog = os.environ.get("ICEPROG", "iceprog")
bitstream = products.get("{}.bin".format(name))
if mode == "sram":
options = ["-S"]
if mode == "flash":
options = []
with tempfile.NamedTemporaryFile(prefix="nmigen_iceprog_") as bitstream_file:
bitstream_file.write(bitstream)
subprocess.run([iceprog, *options, bitstream_file.name], check=True)
class IceBurnProgrammerMixin:
def toolchain_program(self, products, name):
iceburn = os.environ.get("ICEBURN", "iCEburn")
bitstream = products.get("{}.bin".format(name))
with tempfile.NamedTemporaryFile(prefix="nmigen_iceburn_") as bitstream_file:
bitstream_file.write(bitstream)
subprocess.run([iceburn, "-evw", bitstream_file.name], check=True)