vendor.board: split off into nmigen-boards package.
authorwhitequark <cz@m-labs.hk>
Tue, 4 Jun 2019 09:47:04 +0000 (09:47 +0000)
committerwhitequark <cz@m-labs.hk>
Tue, 4 Jun 2019 09:52:33 +0000 (09:52 +0000)
The iCE40 programmers are also moved, since they're board-specific.
(It looks like iceprog isn't, but it only works with Lattice
evaluation kits.)

Fixes #80.

13 files changed:
LICENSE.txt
README.md
examples/board/blinky.py
nmigen/vendor/board/__init__.py [deleted file]
nmigen/vendor/board/ice40_hx1k_blink_evn.py [deleted file]
nmigen/vendor/board/icestick.py [deleted file]
nmigen/vendor/board/tinyfpga_bx.py [deleted file]
nmigen/vendor/conn/__init__.py [deleted file]
nmigen/vendor/conn/pmod.py [deleted file]
nmigen/vendor/fpga/__init__.py [deleted file]
nmigen/vendor/fpga/lattice_ice40.py [deleted file]
nmigen/vendor/lattice_ice40.py [new file with mode: 0644]
setup.py

index da069450dac607e3943d41c9a81137789cca207f..147ab4f517bfc9e3be543847fd11cec9de90d524 100644 (file)
@@ -1,4 +1,4 @@
-Copyright (C) 2011-2018 M-Labs Limited
+Copyright (C) 2011-2019 M-Labs Limited
 
 Redistribution and use in source and binary forms, with or without modification,
 are permitted provided that the following conditions are met:
index 52b4c56b937786fa34a46300e2e0525fc8ca50fa..3b4e07d8edc0b5fdd98b19a4519a371489121150 100644 (file)
--- a/README.md
+++ b/README.md
@@ -25,6 +25,7 @@ Thanks [LambdaConcept][] for being a sponsor of this project! Contact sb [at] m-
 ### Installation
 
     pip install git+https://github.com/m-labs/nmigen.git
+    pip install git+https://github.com/m-labs/nmigen-boards.git
 
 ### Introduction
 
index 32281632aa715c54912a3ec7bead948145e27368..53f49d054e5a8cce72bd5d940dea8574a4ed9241 100644 (file)
@@ -1,5 +1,5 @@
 from nmigen import *
-from nmigen.vendor.board.ice40_hx1k_blink_evn import *
+from nmigen_boards.ice40_hx1k_blink_evn import *
 
 
 class Blinky(Elaboratable):
diff --git a/nmigen/vendor/board/__init__.py b/nmigen/vendor/board/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/nmigen/vendor/board/ice40_hx1k_blink_evn.py b/nmigen/vendor/board/ice40_hx1k_blink_evn.py
deleted file mode 100644 (file)
index 1039527..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-from ...build import *
-from ..fpga.lattice_ice40 import LatticeICE40Platform, IceBurnProgrammerMixin
-
-
-__all__ = ["ICE40HX1KBlinkEVNPlatform"]
-
-
-class ICE40HX1KBlinkEVNPlatform(IceBurnProgrammerMixin, LatticeICE40Platform):
-    device     = "hx1k"
-    package    = "vq100"
-    clocks     = [
-        ("clk3p3", 3.3e6),
-    ]
-    resources  = [
-        Resource("clk3p3", 0, Pins("13", dir="i"),
-                 extras={"GLOBAL": "1", "IO_STANDARD": "SB_LVCMOS33"}),
-
-        Resource("user_led", 0, Pins("59", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-        Resource("user_led", 1, Pins("56", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-        Resource("user_led", 2, Pins("53", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-        Resource("user_led", 3, Pins("51", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-
-        Resource("user_btn", 0, Pins("60"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-        Resource("user_btn", 1, Pins("57"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-        Resource("user_btn", 2, Pins("54"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-        Resource("user_btn", 3, Pins("52"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-    ]
-    connectors = [
-        Connector("pmod",  1, "10  9  8  7 - -  4  3  2  1 - -"), # J1
-        Connector("pmod",  5, "40 42 62 64 - - 37 41 63 45 - -"), # J5
-        Connector("pmod",  6, "25 24 21 20 - - 26 27 28 33 - -"), # J6
-        Connector("pmod", 11, "49 45 46 48 - -"), # J11
-        Connector("pmod", 12, "59 56 53 51 - -"), # J12
-    ]
diff --git a/nmigen/vendor/board/icestick.py b/nmigen/vendor/board/icestick.py
deleted file mode 100644 (file)
index 0d2ae75..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-from ...build import *
-from ..fpga.lattice_ice40 import LatticeICE40Platform, IceStormProgrammerMixin
-
-
-__all__ = ["ICEStickPlatform"]
-
-
-class ICEStickPlatform(IceStormProgrammerMixin, LatticeICE40Platform):
-    device     = "hx1k"
-    package    = "tq144"
-    clocks     = [
-        ("clk12", 12e6),
-    ]
-    resources  = [
-        Resource("clk12", 0, Pins("21", dir="i"),
-                 extras={"GLOBAL": "1", "IO_STANDARD": "SB_LVCMOS33"}),
-
-        Resource("user_led", 0, Pins("99", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-        Resource("user_led", 1, Pins("98", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-        Resource("user_led", 2, Pins("97", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-        Resource("user_led", 3, Pins("96", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-        Resource("user_led", 4, Pins("95", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-
-        Resource("serial", 0,
-            Subsignal("rx",  Pins("9", dir="i")),
-            Subsignal("tx",  Pins("8", dir="o")),
-            Subsignal("rts", Pins("7", dir="o")),
-            Subsignal("cts", Pins("4", dir="i")),
-            Subsignal("dtr", Pins("3", dir="o")),
-            Subsignal("dsr", Pins("2", dir="i")),
-            Subsignal("dcd", Pins("1", dir="i")),
-            extras={"IO_STANDARD": "SB_LVTTL", "PULLUP": "1"}
-        ),
-
-        Resource("irda", 0,
-            Subsignal("rx", Pins("106", dir="i")),
-            Subsignal("tx", Pins("105", dir="o")),
-            Subsignal("sd", Pins("107", dir="o")),
-            extras={"IO_STANDARD": "SB_LVCMOS33"}
-        ),
-
-        Resource("spiflash", 0,
-            Subsignal("cs_n", Pins("71", dir="o")),
-            Subsignal("clk",  Pins("70", dir="o")),
-            Subsignal("mosi", Pins("67", dir="o")),
-            Subsignal("miso", Pins("68", dir="i")),
-            extras={"IO_STANDARD": "SB_LVCMOS33"}
-        ),
-    ]
-    connectors = [
-        Connector("pmod", 0, "78 79 80 81 - - 87 88 90 91 - -"),  # J2
-
-        Connector("j", 1, "- - 112 113 114 115 116 117 118 119"), # J1
-        Connector("j", 3, "- -  62  61  60  56  48  47  45  44"), # J3
-    ]
-    prog_mode  = "flash"
diff --git a/nmigen/vendor/board/tinyfpga_bx.py b/nmigen/vendor/board/tinyfpga_bx.py
deleted file mode 100644 (file)
index 0031bb7..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-from ...build import *
-from ..fpga.lattice_ice40 import LatticeICE40Platform, TinyProgrammerMixin
-
-
-__all__ = ["TinyFPGABXPlatform"]
-
-
-class TinyFPGABXPlatform(TinyProgrammerMixin, LatticeICE40Platform):
-    device     = "lp8k"
-    package    = "cm81"
-    clocks     = [
-        ("clk16", 16e6),
-    ]
-    resources  = [
-        Resource("clk16", 0, Pins("B2", dir="i"),
-                 extras={"IO_STANDARD": "SB_LVCMOS33"}),
-
-        Resource("user_led", 0, Pins("B3", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
-
-        Resource("usb", 0,
-            Subsignal("d_p",    Pins("B4", dir="io")),
-            Subsignal("d_n",    Pins("A4", dir="io")),
-            Subsignal("pullup", Pins("A3", dir="o")),
-            extras={"IO_STANDARD": "SB_LVCMOS33"}
-        ),
-
-        Resource("spiflash", 0,
-            Subsignal("cs_n", Pins("F7", dir="o")),
-            Subsignal("clk",  Pins("G7", dir="o")),
-            Subsignal("mosi", Pins("G6", dir="o")),
-            Subsignal("miso", Pins("H7", dir="i")),
-            Subsignal("wp",   Pins("H4", dir="o")),
-            Subsignal("hold", Pins("J8", dir="o")),
-            extras={"IO_STANDARD": "SB_LVCMOS33"}
-        ),
-
-        Resource("spiflash4x", 0,
-            Subsignal("cs_n", Pins("F7", dir="o")),
-            Subsignal("clk",  Pins("G7", dir="o")),
-            Subsignal("dq",   Pins("G6 H7 H4 J8", dir="io")),
-            extras={"IO_STANDARD": "SB_LVCMOS33"}
-        ),
-    ]
-    connectors = [
-        Connector("gpio", 0,
-            # Left side of the board
-            #     1  2  3  4  5  6  7  8  9 10 11 12 13
-             "   A2 A1 B1 C2 C1 D2 D1 E2 E1 G2 H1 J1 H2"
-            # Right side of the board
-            #          14 15 16 17 18 19 20 21 22 23 24
-             "         H9 D9 D8 B8 A9 B8 A8 B7 A7 B6 A6"
-            # Bottom of the board
-            # 25 26 27 28 29 30 31
-             "G1 J3 J4 G9 J9 E8 J2"),
-    ]
diff --git a/nmigen/vendor/conn/__init__.py b/nmigen/vendor/conn/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/nmigen/vendor/conn/pmod.py b/nmigen/vendor/conn/pmod.py
deleted file mode 100644 (file)
index 5566c55..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-# Reference: https://www.digilentinc.com/Pmods/Digilent-Pmod_%20Interface_Specification.pdf
-
-from ...build import *
-
-
-__all__ = [
-    "PmodGPIOType1Resource",
-    "PmodSPIType2Resource",
-    "PmodSPIType2AResource",
-    "PmodUARTType3Resource",
-    "PmodUARTType4Resource",
-    "PmodUARTType4AResource",
-    "PmodHBridgeType5Resource",
-    "PmodDualHBridgeType6Resource",
-]
-
-
-def PmodGPIOType1Resource(name, number, *, pmod, extras=None):
-    return Resource(name, number,
-        Pins("1 2 3 4", dir="io", conn=("pmod", pmod)),
-        extras=extras
-    )
-
-
-def PmodSPIType2Resource(name, number, *, pmod, extras=None):
-    return Resource(name, number,
-        Subsignal("cs_n",  Pins("1", dir="o", conn=("pmod", pmod))),
-        Subsignal("clk",   Pins("2", dir="o", conn=("pmod", pmod))),
-        Subsignal("mosi",  Pins("3", dir="o", conn=("pmod", pmod))),
-        Subsignal("miso",  Pins("4", dir="i", conn=("pmod", pmod))),
-        extras=extras
-    )
-
-
-def PmodSPIType2AResource(name, number, *, pmod, extras=None):
-    return Resource(name, number,
-        Subsignal("cs_n",  Pins("1", dir="o", conn=("pmod", pmod))),
-        Subsignal("clk",   Pins("2", dir="o", conn=("pmod", pmod))),
-        Subsignal("mosi",  Pins("3", dir="o", conn=("pmod", pmod))),
-        Subsignal("miso",  Pins("4", dir="i", conn=("pmod", pmod))),
-        Subsignal("int",   Pins("7", dir="i", conn=("pmod", pmod))),
-        Subsignal("reset", Pins("8", dir="o", conn=("pmod", pmod))),
-        extras=extras
-        )
-
-
-def PmodUARTType3Resource(name, number, *, pmod, extras=None):
-    return Resource(name, number,
-        Subsignal("cts",   Pins("1", dir="o", conn=("pmod", pmod))),
-        Subsignal("rts",   Pins("2", dir="i", conn=("pmod", pmod))),
-        Subsignal("rx",    Pins("3", dir="i", conn=("pmod", pmod))),
-        Subsignal("tx",    Pins("4", dir="o", conn=("pmod", pmod))),
-        extras=extras
-    )
-
-
-def PmodUARTType4Resource(name, number, *, pmod, extras=None):
-    return Resource(name, number,
-        Subsignal("cts",   Pins("1", dir="i", conn=("pmod", pmod))),
-        Subsignal("tx",    Pins("2", dir="o", conn=("pmod", pmod))),
-        Subsignal("rx",    Pins("3", dir="i", conn=("pmod", pmod))),
-        Subsignal("rts",   Pins("4", dir="o", conn=("pmod", pmod))),
-        extras=extras
-    )
-
-
-def PmodUARTType4AResource(name, number, *, pmod, extras=None):
-    return Resource(name, number,
-        Subsignal("cts",   Pins("1", dir="i", conn=("pmod", pmod))),
-        Subsignal("tx",    Pins("2", dir="o", conn=("pmod", pmod))),
-        Subsignal("rx",    Pins("3", dir="i", conn=("pmod", pmod))),
-        Subsignal("rts",   Pins("4", dir="o", conn=("pmod", pmod))),
-        Subsignal("int",   Pins("7", dir="i", conn=("pmod", pmod))),
-        Subsignal("reset", Pins("8", dir="o", conn=("pmod", pmod))),
-        extras=extras
-    )
-
-
-def PmodHBridgeType5Resource(name, number, *, pmod, extras=None):
-    return Resource(name, number,
-        Subsignal("dir",   Pins("1", dir="o", conn=("pmod", pmod))),
-        Subsignal("en",    Pins("2", dir="o", conn=("pmod", pmod))),
-        Subsignal("sa",    Pins("3", dir="i", conn=("pmod", pmod))),
-        Subsignal("sb",    Pins("4", dir="i", conn=("pmod", pmod))),
-        extras=extras
-    )
-
-
-def PmodDualHBridgeType6Resource(name, number, *, pmod, extras=None):
-    return Resource(name, number,
-        Subsignal("dir",   Pins("1 3", dir="o", conn=("pmod", pmod))),
-        Subsignal("en",    Pins("2 4", dir="o", conn=("pmod", pmod))),
-        extras=extras
-    )
diff --git a/nmigen/vendor/fpga/__init__.py b/nmigen/vendor/fpga/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/nmigen/vendor/fpga/lattice_ice40.py b/nmigen/vendor/fpga/lattice_ice40.py
deleted file mode 100644 (file)
index 7355f6d..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-from abc import abstractproperty
-import os
-import subprocess
-import tempfile
-
-from ...hdl import *
-from ...build import *
-
-
-__all__ = ["LatticeICE40Platform",
-           "IceStormProgrammerMixin", "IceBurnProgrammerMixin", "TinyProgrammerMixin"]
-
-
-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``: adds extra options for Yosys.
-        * ``nextpnr_opts``: adds extra and overrides default options (``--placer heap``)
-          for nextpnr.
-
-    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 -sv {{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_name, pin_name, extras in platform.iter_port_constraints_bits() -%}
-                set_io {{port_name}} {{pin_name}}
-            {% 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")}}
-            {{verbose("-v")}}
-            {{name}}.asc
-            {{name}}.bin
-        """
-    ]
-
-    def iter_ports(self):
-        for res, pin, port in self._ports:
-            if isinstance(res.io[0], Pins):
-                yield port.io
-            elif isinstance(res.io[0], DiffPairs):
-                if res.extras.get("IO_STANDARD", "SB_LVCMOS") == "SB_LVDS_INPUT":
-                    yield port.p
-                else:
-                    yield port.p
-                    yield port.n
-            else:
-                assert False
-
-    def iter_port_constraints(self):
-        for res, pin, port in self._ports:
-            if isinstance(res.io[0], Pins):
-                yield port.io.name, list(res.io[0].map_names(self._mapping, res)), res.extras
-            elif isinstance(res.io[0], DiffPairs):
-                if res.extras.get("IO_STANDARD", "SB_LVCMOS") == "SB_LVDS_INPUT":
-                    yield port.p.name, list(res.io[0].p.map_names(self._mapping, res)), res.extras
-                else:
-                    yield port.p.name, list(res.io[0].p.map_names(self._mapping, res)), res.extras
-                    yield port.n.name, list(res.io[0].n.map_names(self._mapping, res)), res.extras
-            else:
-                assert False
-
-    def _get_io_buffer(self, m, pin, port, extras, o_invert=None):
-        def _get_dff(clk, d, q):
-            m.submodules += Instance("$dff",
-                p_CLK_POLARITY=0,
-                p_WIDTH=len(d),
-                i_CLK=clk,
-                i_D=d,
-                o_Q=q)
-
-        def _get_inverter(a, invert):
-            if invert is None:
-                return a
-            else:
-                y = Signal.like(a, name="{}_x{}".format(a.name, 1 if invert else 0))
-                for bit in range(len(a)):
-                    m.submodules += Instance("SB_LUT4",
-                        p_LUT_INIT=0b01 if invert else 0b10,
-                        i_I0=a[bit],
-                        i_I1=Const(0),
-                        i_I2=Const(0),
-                        i_I3=Const(0),
-                        o_O=y[bit])
-                return y
-
-        if "GLOBAL" in extras:
-            is_global_input = bool(extras["GLOBAL"])
-            del extras["GLOBAL"]
-        else:
-            is_global_input = False
-
-        if "o" in pin.dir:
-            if pin.xdr < 2:
-                pin_o  = _get_inverter(pin.o,  o_invert)
-            elif pin.xdr == 2:
-                pin_o0 = _get_inverter(pin.o0, o_invert)
-                pin_o1 = _get_inverter(pin.o1, o_invert)
-
-        if "i" in pin.dir and pin.xdr == 2:
-            i0_ff = Signal.like(pin.i0, name="{}_ff".format(pin.i0.name))
-            i1_ff = Signal.like(pin.i1, name="{}_ff".format(pin.i1.name))
-            _get_dff(pin.i_clk, i0_ff, pin.i0)
-            _get_dff(pin.i_clk, i1_ff, pin.i1)
-        if "o" in pin.dir and pin.xdr == 2:
-            o1_ff = Signal.like(pin.o1, name="{}_ff".format(pin.o1.name))
-            _get_dff(pin.o_clk, pin_o1, o1_ff)
-
-        for bit in range(len(port)):
-            io_args = [
-                ("io", "PACKAGE_PIN", port[bit]),
-                *(("p", key, value) for key, value in extras.items()),
-            ]
-
-            if "i" not in pin.dir:
-                i_type =     0b00 # PIN_NO_INPUT aka PIN_INPUT_REGISTERED
-            elif pin.xdr == 0:
-                i_type =     0b01 # PIN_INPUT
-            elif pin.xdr > 0:
-                i_type =     0b00 # PIN_INPUT_REGISTERED
-            if "o" not in pin.dir:
-                o_type = 0b0000   # PIN_NO_OUTPUT
-            elif pin.xdr == 0 and pin.dir == "o":
-                o_type = 0b0110   # PIN_OUTPUT
-            elif pin.xdr == 0:
-                o_type = 0b1010   # PIN_OUTPUT_TRISTATE
-            elif pin.xdr == 1 and pin.dir == "o":
-                o_type = 0b0101   # PIN_OUTPUT_REGISTERED
-            elif pin.xdr == 1:
-                o_type = 0b1101   # PIN_OUTPUT_REGISTERED_ENABLE_REGISTERED
-            elif pin.xdr == 2 and pin.dir == "o":
-                o_type = 0b0100   # PIN_OUTPUT_DDR
-            elif pin.xdr == 2:
-                o_type = 0b1100   # PIN_OUTPUT_DDR_ENABLE_REGISTERED
-            io_args.append(("p", "PIN_TYPE", (o_type << 2) | i_type))
-
-            if hasattr(pin, "i_clk"):
-                io_args.append(("i", "INPUT_CLK",  pin.i_clk))
-            if hasattr(pin, "o_clk"):
-                io_args.append(("i", "OUTPUT_CLK", pin.o_clk))
-
-            if "i" in pin.dir:
-                if pin.xdr == 0 and is_global_input:
-                    io_args.append(("o", "GLOBAL_BUFFER_OUTPUT", pin.i[bit]))
-                elif pin.xdr < 2:
-                    io_args.append(("o", "D_IN_0",  pin.i[bit]))
-                elif pin.xdr == 2:
-                    # Re-register both inputs before they enter fabric. This increases hold time
-                    # to an entire cycle, and adds one cycle of latency.
-                    io_args.append(("o", "D_IN_0",  i0_ff))
-                    io_args.append(("o", "D_IN_1",  i1_ff))
-            if "o" in pin.dir:
-                if pin.xdr < 2:
-                    io_args.append(("i", "D_OUT_0", pin_o[bit]))
-                elif pin.xdr == 2:
-                    # Re-register negedge output after it leaves fabric. This increases setup time
-                    # to an entire cycle, and doesn't add latency.
-                    io_args.append(("i", "D_OUT_0", pin_o0[bit]))
-                    io_args.append(("i", "D_OUT_1", o1_ff))
-
-            if pin.dir in ("oe", "io"):
-                io_args.append(("i", "OUTPUT_ENABLE", pin.oe))
-
-            if is_global_input:
-                m.submodules += Instance("SB_GB_IO", *io_args)
-            else:
-                m.submodules += Instance("SB_IO", *io_args)
-
-    def get_input(self, pin, port, extras):
-        self._check_feature("single-ended input", pin, extras,
-                            valid_xdrs=(0, 1, 2), valid_extras=True)
-        m = Module()
-        self._get_io_buffer(m, pin, port, extras)
-        return m
-
-    def get_output(self, pin, port, extras):
-        self._check_feature("single-ended output", pin, extras,
-                            valid_xdrs=(0, 1, 2), valid_extras=True)
-        m = Module()
-        self._get_io_buffer(m, pin, port, extras)
-        return m
-
-    def get_tristate(self, pin, port, extras):
-        self._check_feature("single-ended tristate", pin, extras,
-                            valid_xdrs=(0, 1, 2), valid_extras=True)
-        m = Module()
-        self._get_io_buffer(m, pin, port, extras)
-        return m
-
-    def get_input_output(self, pin, port, extras):
-        self._check_feature("single-ended input/output", pin, extras,
-                            valid_xdrs=(0, 1, 2), valid_extras=True)
-        m = Module()
-        self._get_io_buffer(m, pin, port, extras)
-        return m
-
-    def get_diff_input(self, pin, p_port, n_port, extras):
-        self._check_feature("differential input", pin, extras,
-                            valid_xdrs=(0, 1, 2), valid_extras=True)
-        # On iCE40, a differential input is placed by only instantiating an SB_IO primitive for
-        # the pin with z=0, which is the non-inverting pin. The pinout unfortunately differs
-        # between LP/HX and UP series:
-        #  * for LP/HX, z=0 is DPxxB   (B is non-inverting, A is inverting)
-        #  * for UP,    z=0 is IOB_xxA (A is non-inverting, B is inverting)
-        m = Module()
-        self._get_io_buffer(m, pin, p_port, extras)
-        return m
-
-    def get_diff_output(self, pin, p_port, n_port, extras):
-        self._check_feature("differential output", pin, extras,
-                            valid_xdrs=(0, 1, 2), valid_extras=True)
-        m = Module()
-        # Note that the non-inverting output pin is not driven the same way as a regular
-        # output pin. The inverter introduces a delay, so for a non-inverting output pin,
-        # an identical delay is introduced by instantiating a LUT. This makes the waveform
-        # perfectly symmetric in the xdr=0 case.
-        self._get_io_buffer(m, pin, p_port, extras, o_invert=False)
-        self._get_io_buffer(m, pin, n_port, extras, o_invert=True)
-        return m
-
-    # Tristate and bidirectional buffers are not supported on iCE40 because it requires external
-    # termination, which is incompatible for input and output differential I/Os.
-
-
-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")
-        if mode == "sram":
-            options = ["-S"]
-        if mode == "flash":
-            options = []
-        with products.extract("{}.bin".format(name)) as bitstream_filename:
-            subprocess.run([iceprog, *options, bitstream_filename], check=True)
-
-
-class IceBurnProgrammerMixin:
-    def toolchain_program(self, products, name):
-        iceburn = os.environ.get("ICEBURN", "iCEburn")
-        with products.extract("{}.bin".format(name)) as bitstream_filename:
-            subprocess.run([iceburn, "-evw", bitstream_filename], check=True)
-
-
-class TinyProgrammerMixin:
-    def toolchain_program(self, products, name):
-        tinyprog  = os.environ.get("TINYPROG", "tinyprog")
-        with products.extract("{}.bin".format(name)) as bitstream_filename:
-            subprocess.run([tinyprog, "-p", bitstream_filename], check=True)
diff --git a/nmigen/vendor/lattice_ice40.py b/nmigen/vendor/lattice_ice40.py
new file mode 100644 (file)
index 0000000..ab33856
--- /dev/null
@@ -0,0 +1,286 @@
+from abc import abstractproperty
+
+from ..hdl import *
+from ..build import *
+
+
+__all__ = ["LatticeICE40Platform"]
+
+
+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``: adds extra options for Yosys.
+        * ``nextpnr_opts``: adds extra and overrides default options (``--placer heap``)
+          for nextpnr.
+
+    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 -sv {{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_name, pin_name, extras in platform.iter_port_constraints_bits() -%}
+                set_io {{port_name}} {{pin_name}}
+            {% 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")}}
+            {{verbose("-v")}}
+            {{name}}.asc
+            {{name}}.bin
+        """
+    ]
+
+    def iter_ports(self):
+        for res, pin, port in self._ports:
+            if isinstance(res.io[0], Pins):
+                yield port.io
+            elif isinstance(res.io[0], DiffPairs):
+                if res.extras.get("IO_STANDARD", "SB_LVCMOS") == "SB_LVDS_INPUT":
+                    yield port.p
+                else:
+                    yield port.p
+                    yield port.n
+            else:
+                assert False
+
+    def iter_port_constraints(self):
+        for res, pin, port in self._ports:
+            if isinstance(res.io[0], Pins):
+                yield port.io.name, list(res.io[0].map_names(self._mapping, res)), res.extras
+            elif isinstance(res.io[0], DiffPairs):
+                if res.extras.get("IO_STANDARD", "SB_LVCMOS") == "SB_LVDS_INPUT":
+                    yield port.p.name, list(res.io[0].p.map_names(self._mapping, res)), res.extras
+                else:
+                    yield port.p.name, list(res.io[0].p.map_names(self._mapping, res)), res.extras
+                    yield port.n.name, list(res.io[0].n.map_names(self._mapping, res)), res.extras
+            else:
+                assert False
+
+    def _get_io_buffer(self, m, pin, port, extras, o_invert=None):
+        def _get_dff(clk, d, q):
+            m.submodules += Instance("$dff",
+                p_CLK_POLARITY=0,
+                p_WIDTH=len(d),
+                i_CLK=clk,
+                i_D=d,
+                o_Q=q)
+
+        def _get_inverter(a, invert):
+            if invert is None:
+                return a
+            else:
+                y = Signal.like(a, name="{}_x{}".format(a.name, 1 if invert else 0))
+                for bit in range(len(a)):
+                    m.submodules += Instance("SB_LUT4",
+                        p_LUT_INIT=0b01 if invert else 0b10,
+                        i_I0=a[bit],
+                        i_I1=Const(0),
+                        i_I2=Const(0),
+                        i_I3=Const(0),
+                        o_O=y[bit])
+                return y
+
+        if "GLOBAL" in extras:
+            is_global_input = bool(extras["GLOBAL"])
+            del extras["GLOBAL"]
+        else:
+            is_global_input = False
+
+        if "o" in pin.dir:
+            if pin.xdr < 2:
+                pin_o  = _get_inverter(pin.o,  o_invert)
+            elif pin.xdr == 2:
+                pin_o0 = _get_inverter(pin.o0, o_invert)
+                pin_o1 = _get_inverter(pin.o1, o_invert)
+
+        if "i" in pin.dir and pin.xdr == 2:
+            i0_ff = Signal.like(pin.i0, name="{}_ff".format(pin.i0.name))
+            i1_ff = Signal.like(pin.i1, name="{}_ff".format(pin.i1.name))
+            _get_dff(pin.i_clk, i0_ff, pin.i0)
+            _get_dff(pin.i_clk, i1_ff, pin.i1)
+        if "o" in pin.dir and pin.xdr == 2:
+            o1_ff = Signal.like(pin.o1, name="{}_ff".format(pin.o1.name))
+            _get_dff(pin.o_clk, pin_o1, o1_ff)
+
+        for bit in range(len(port)):
+            io_args = [
+                ("io", "PACKAGE_PIN", port[bit]),
+                *(("p", key, value) for key, value in extras.items()),
+            ]
+
+            if "i" not in pin.dir:
+                i_type =     0b00 # PIN_NO_INPUT aka PIN_INPUT_REGISTERED
+            elif pin.xdr == 0:
+                i_type =     0b01 # PIN_INPUT
+            elif pin.xdr > 0:
+                i_type =     0b00 # PIN_INPUT_REGISTERED
+            if "o" not in pin.dir:
+                o_type = 0b0000   # PIN_NO_OUTPUT
+            elif pin.xdr == 0 and pin.dir == "o":
+                o_type = 0b0110   # PIN_OUTPUT
+            elif pin.xdr == 0:
+                o_type = 0b1010   # PIN_OUTPUT_TRISTATE
+            elif pin.xdr == 1 and pin.dir == "o":
+                o_type = 0b0101   # PIN_OUTPUT_REGISTERED
+            elif pin.xdr == 1:
+                o_type = 0b1101   # PIN_OUTPUT_REGISTERED_ENABLE_REGISTERED
+            elif pin.xdr == 2 and pin.dir == "o":
+                o_type = 0b0100   # PIN_OUTPUT_DDR
+            elif pin.xdr == 2:
+                o_type = 0b1100   # PIN_OUTPUT_DDR_ENABLE_REGISTERED
+            io_args.append(("p", "PIN_TYPE", (o_type << 2) | i_type))
+
+            if hasattr(pin, "i_clk"):
+                io_args.append(("i", "INPUT_CLK",  pin.i_clk))
+            if hasattr(pin, "o_clk"):
+                io_args.append(("i", "OUTPUT_CLK", pin.o_clk))
+
+            if "i" in pin.dir:
+                if pin.xdr == 0 and is_global_input:
+                    io_args.append(("o", "GLOBAL_BUFFER_OUTPUT", pin.i[bit]))
+                elif pin.xdr < 2:
+                    io_args.append(("o", "D_IN_0",  pin.i[bit]))
+                elif pin.xdr == 2:
+                    # Re-register both inputs before they enter fabric. This increases hold time
+                    # to an entire cycle, and adds one cycle of latency.
+                    io_args.append(("o", "D_IN_0",  i0_ff))
+                    io_args.append(("o", "D_IN_1",  i1_ff))
+            if "o" in pin.dir:
+                if pin.xdr < 2:
+                    io_args.append(("i", "D_OUT_0", pin_o[bit]))
+                elif pin.xdr == 2:
+                    # Re-register negedge output after it leaves fabric. This increases setup time
+                    # to an entire cycle, and doesn't add latency.
+                    io_args.append(("i", "D_OUT_0", pin_o0[bit]))
+                    io_args.append(("i", "D_OUT_1", o1_ff))
+
+            if pin.dir in ("oe", "io"):
+                io_args.append(("i", "OUTPUT_ENABLE", pin.oe))
+
+            if is_global_input:
+                m.submodules += Instance("SB_GB_IO", *io_args)
+            else:
+                m.submodules += Instance("SB_IO", *io_args)
+
+    def get_input(self, pin, port, extras):
+        self._check_feature("single-ended input", pin, extras,
+                            valid_xdrs=(0, 1, 2), valid_extras=True)
+        m = Module()
+        self._get_io_buffer(m, pin, port, extras)
+        return m
+
+    def get_output(self, pin, port, extras):
+        self._check_feature("single-ended output", pin, extras,
+                            valid_xdrs=(0, 1, 2), valid_extras=True)
+        m = Module()
+        self._get_io_buffer(m, pin, port, extras)
+        return m
+
+    def get_tristate(self, pin, port, extras):
+        self._check_feature("single-ended tristate", pin, extras,
+                            valid_xdrs=(0, 1, 2), valid_extras=True)
+        m = Module()
+        self._get_io_buffer(m, pin, port, extras)
+        return m
+
+    def get_input_output(self, pin, port, extras):
+        self._check_feature("single-ended input/output", pin, extras,
+                            valid_xdrs=(0, 1, 2), valid_extras=True)
+        m = Module()
+        self._get_io_buffer(m, pin, port, extras)
+        return m
+
+    def get_diff_input(self, pin, p_port, n_port, extras):
+        self._check_feature("differential input", pin, extras,
+                            valid_xdrs=(0, 1, 2), valid_extras=True)
+        # On iCE40, a differential input is placed by only instantiating an SB_IO primitive for
+        # the pin with z=0, which is the non-inverting pin. The pinout unfortunately differs
+        # between LP/HX and UP series:
+        #  * for LP/HX, z=0 is DPxxB   (B is non-inverting, A is inverting)
+        #  * for UP,    z=0 is IOB_xxA (A is non-inverting, B is inverting)
+        m = Module()
+        self._get_io_buffer(m, pin, p_port, extras)
+        return m
+
+    def get_diff_output(self, pin, p_port, n_port, extras):
+        self._check_feature("differential output", pin, extras,
+                            valid_xdrs=(0, 1, 2), valid_extras=True)
+        m = Module()
+        # Note that the non-inverting output pin is not driven the same way as a regular
+        # output pin. The inverter introduces a delay, so for a non-inverting output pin,
+        # an identical delay is introduced by instantiating a LUT. This makes the waveform
+        # perfectly symmetric in the xdr=0 case.
+        self._get_io_buffer(m, pin, p_port, extras, o_invert=False)
+        self._get_io_buffer(m, pin, n_port, extras, o_invert=True)
+        return m
+
+    # Tristate and bidirectional buffers are not supported on iCE40 because it requires external
+    # termination, which is incompatible for input and output differential I/Os.
index 5307f88e3ef5f9ec3f01e5eac5fd9239ca3ab6aa..35211a9ac48dba87376839da7f40659c3b8cd6cb 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -19,7 +19,7 @@ setup(
     packages=find_packages(),
     python_requires=">=3.6",
     project_urls={
-        #"Documentation": "https://glasgow.readthedocs.io/",
+        #"Documentation": "https://nmigen.readthedocs.io/",
         "Source Code": "https://github.com/m-labs/nmigen",
         "Bug Tracker": "https://github.com/m-labs/nmigen/issues",
     },