Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/nmigen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 27063a3bd33e
Choose a base ref
...
head repository: m-labs/nmigen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 434b686d5e6a
Choose a head ref
  • 2 commits
  • 3 files changed
  • 1 contributor

Commits on Aug 4, 2019

  1. vendor.xilinx_spartan_3_6: reconsider bitgen defaults.

    Previously changed in 27063a3.
    
    I haven't realized the .bin file is the same as the .bit file without
    a small header. That means generating it is free and it's just easier
    to let programming tools to be able to always rely on its existence.
    whitequark committed Aug 4, 2019
    Copy the full SHA
    3d7214c View commit details
  2. vendor.xilinx_{spartan_3_6,7series}: reconsider default reset logic.

    On Xilinx devices, flip-flops are reset to their initial state with
    an internal global reset network, but this network is deasserted
    asynchronously to user clocks. Use BUFGCE and STARTUP to hold default
    clock low until after GWE is deasserted.
    whitequark committed Aug 4, 2019
    Copy the full SHA
    434b686 View commit details
Showing with 57 additions and 14 deletions.
  1. +4 −0 nmigen/build/plat.py
  2. +22 −5 nmigen/vendor/xilinx_7series.py
  3. +31 −9 nmigen/vendor/xilinx_spartan_3_6.py
4 changes: 4 additions & 0 deletions nmigen/build/plat.py
Original file line number Diff line number Diff line change
@@ -74,6 +74,10 @@ def build(self, fragment, name="top",

@abstractmethod
def create_missing_domain(self, name):
# Simple instantiation of a clock domain driven directly by the board clock and reset.
# Because of device-specific considerations, this implementation generally does NOT provide
# reliable power-on/post-configuration reset, and the logic should be replaced with family
# specific logic based on vendor recommendations.
if name == "sync" and self.default_clk is not None:
clk_i = self.request(self.default_clk).i
if self.default_rst is not None:
27 changes: 22 additions & 5 deletions nmigen/vendor/xilinx_7series.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from abc import abstractproperty

from ..hdl.ast import *
from ..hdl.dsl import *
from ..hdl.ir import *
from ..hdl import *
from ..build import *


@@ -123,8 +121,27 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
]

def create_missing_domain(self, name):
# No additional reset logic needed.
csuper().create_missing_domain(name)
# Xilinx devices have a global write enable (GWE) signal that asserted during configuraiton
# and deasserted once it ends. Because it is an asynchronous signal (GWE is driven by logic
# syncronous to configuration clock, which is not used by most designs), even though it is
# a low-skew global network, its deassertion may violate a setup/hold constraint with
# relation to a user clock. The recommended solution is to use a BUFGCE driven by the EOS
# signal. For details, see:
# * https://www.xilinx.com/support/answers/44174.html
# * https://www.xilinx.com/support/documentation/white_papers/wp272.pdf
if name == "sync" and self.default_clk is not None:
clk_i = self.request(self.default_clk).i
if self.default_rst is not None:
rst_i = self.request(self.default_rst).i

m = Module()
ready = Signal()
m.submodules += Instance("STARTUPE3", o_EOS=ready)
m.domains += ClockDomain("sync", reset_less=self.default_rst is None)
m.submodules += Instance("BUFGCE", i_CE=ready, i_I=clk_i, o_O=ClockSignal("sync"))
if self.default_rst is not None:
m.d.comb += ResetSignal("sync").eq(rst_i)
return m

def _get_xdr_buffer(self, m, pin, i_invert=None, o_invert=None):
def get_dff(clk, d, q):
40 changes: 31 additions & 9 deletions nmigen/vendor/xilinx_spartan_3_6.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
from abc import abstractproperty

from ..hdl.ast import *
from ..hdl.dsl import *
from ..hdl.ir import *
from ..hdl import *
from ..build import *


__all__ = ["XilinxSpartan3APlatform", "XilinxSpartan6Platform"]


# The interface to Spartan 3 and 6 are substantially the same. Handle
# differences internally using one class and expose user-aliases for
# convenience.


class XilinxSpartan3Or6Platform(TemplatedPlatform):
"""
Required tools:
@@ -33,7 +30,8 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform):
* ``ngdbuild_opts``: adds extra options for NGDBuild.
* ``map_opts``: adds extra options for MAP.
* ``par_opts``: adds extra options for PAR.
* ``bitgen_opts``: adds extra options for BitGen.
* ``bitgen_opts``: adds extra and overrides default options for BitGen;
default options: ``-g Compress``.
Build products:
* ``{{name}}.srp``: synthesis report.
@@ -154,16 +152,40 @@ def family(self):
""",
r"""
{{get_tool("bitgen")}}
{{get_override("bitgen_opts")|default(["-g Binary:Yes", "-g Compress"])|options}}
{{get_override("bitgen_opts")|default(["-g Compress"])|options}}
-w
-g Binary:Yes
{{name}}_par.ncd
{{name}}.bit
"""
]

def create_missing_domain(self, name):
# No additional reset logic needed.
return super().create_missing_domain(name)
# Xilinx devices have a global write enable (GWE) signal that asserted during configuraiton
# and deasserted once it ends. Because it is an asynchronous signal (GWE is driven by logic
# syncronous to configuration clock, which is not used by most designs), even though it is
# a low-skew global network, its deassertion may violate a setup/hold constraint with
# relation to a user clock. The recommended solution is to use a BUFGCE driven by the EOS
# signal (if available). For details, see:
# * https://www.xilinx.com/support/answers/44174.html
# * https://www.xilinx.com/support/documentation/white_papers/wp272.pdf
if name == "sync" and self.default_clk is not None:
clk_i = self.request(self.default_clk).i
if self.default_rst is not None:
rst_i = self.request(self.default_rst).i

m = Module()
ready = Signal()
if self.family == "6":
m.submodules += Instance("STARTUP_SPARTAN6", o_EOS=ready)
else:
raise NotImplementedError("Spartan 3 devices lack an end-of-startup signal; "
"ensure the design has an appropriate reset")
m.domains += ClockDomain("sync", reset_less=self.default_rst is None)
m.submodules += Instance("BUFGCE", i_CE=ready, i_I=clk_i, o_O=ClockSignal("sync"))
if self.default_rst is not None:
m.d.comb += ResetSignal("sync").eq(rst_i)
return m

def _get_xdr_buffer(self, m, pin, i_invert=None, o_invert=None):
def get_dff(clk, d, q):