build.plat,vendor: always synchronize reset in default sync domain.
This change achieves two related goals. First, default_rst is no longer assumed to be synchronous to default_clk, which is the safer option, since it can be connected to e.g. buttons on some evaluation boards. Second, since the power-on / configuration reset is inherently asynchronous to any user clock, the default create_missing_domain() behavior is to use a reset synchronizer with `0` as input. Since, like all reset synchronizers, it uses Signal(reset=1) for its synchronization stages, after power-on reset it keeps its subordinate clock domain in reset, and releases it after fabric flops start toggling. The latter change is helpful to architectures that lack an end-of- configuration signal, i.e. most of them. ECP5 was already using a similar scheme (and is not changed here). Xilinx devices with EOS use EOS to drive a BUFGMUX, which is more efficient than using a global reset when the design does not need one; Xilinx devices without EOS use the new scheme. iCE40 requires a post-configuration timer because of BRAM silicon bug, and was changed to add a reset synchronizer if user clock is provided.
This commit is contained in:
parent
2512a9a12d
commit
b9e57fd67b
4 changed files with 27 additions and 20 deletions
5
nmigen/vendor/lattice_ice40.py
vendored
5
nmigen/vendor/lattice_ice40.py
vendored
|
|
@ -1,6 +1,7 @@
|
|||
from abc import abstractproperty
|
||||
|
||||
from ..hdl import *
|
||||
from ..lib.cdc import ResetSynchronizer
|
||||
from ..build import *
|
||||
|
||||
|
||||
|
|
@ -346,6 +347,8 @@ class LatticeICE40Platform(TemplatedPlatform):
|
|||
clk_i = self.request(self.default_clk).i
|
||||
if self.default_rst is not None:
|
||||
rst_i = self.request(self.default_rst).i
|
||||
else:
|
||||
rst_i = Const(0)
|
||||
|
||||
m = Module()
|
||||
# Power-on-reset domain
|
||||
|
|
@ -362,7 +365,7 @@ class LatticeICE40Platform(TemplatedPlatform):
|
|||
m.domains += ClockDomain("sync")
|
||||
m.d.comb += ClockSignal("sync").eq(clk_i)
|
||||
if self.default_rst is not None:
|
||||
m.d.comb += ResetSignal("sync").eq(~ready | rst_i)
|
||||
m.submodules.reset_sync = ResetSynchronizer(~ready | rst_i, domain="sync")
|
||||
else:
|
||||
m.d.comb += ResetSignal("sync").eq(~ready)
|
||||
return m
|
||||
|
|
|
|||
3
nmigen/vendor/xilinx_7series.py
vendored
3
nmigen/vendor/xilinx_7series.py
vendored
|
|
@ -1,6 +1,7 @@
|
|||
from abc import abstractproperty
|
||||
|
||||
from ..hdl import *
|
||||
from ..lib.cdc import ResetSynchronizer
|
||||
from ..build import *
|
||||
|
||||
|
||||
|
|
@ -164,7 +165,7 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
|
|||
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)
|
||||
m.submodules.reset_sync = ResetSynchronizer(rst_i, domain="sync")
|
||||
return m
|
||||
|
||||
def _get_xdr_buffer(self, m, pin, *, i_invert=False, o_invert=False):
|
||||
|
|
|
|||
18
nmigen/vendor/xilinx_spartan_3_6.py
vendored
18
nmigen/vendor/xilinx_spartan_3_6.py
vendored
|
|
@ -1,6 +1,7 @@
|
|||
from abc import abstractproperty
|
||||
|
||||
from ..hdl import *
|
||||
from ..lib.cdc import ResetSynchronizer
|
||||
from ..build import *
|
||||
|
||||
|
||||
|
|
@ -187,22 +188,23 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform):
|
|||
# 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 self.family != "6":
|
||||
# Spartan 3 lacks a STARTUP primitive with EOS output; use a simple ResetSynchronizer
|
||||
# in that case, as is the default.
|
||||
return super().create_missing_domain(name)
|
||||
|
||||
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")
|
||||
eos = Signal()
|
||||
m.submodules += Instance("STARTUP_SPARTAN6", o_EOS=eos)
|
||||
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"))
|
||||
m.submodules += Instance("BUFGCE", i_CE=eos, i_I=clk_i, o_O=ClockSignal("sync"))
|
||||
if self.default_rst is not None:
|
||||
m.d.comb += ResetSignal("sync").eq(rst_i)
|
||||
m.submodules.reset_sync = ResetSynchronizer(rst_i, domain="sync")
|
||||
return m
|
||||
|
||||
def _get_xdr_buffer(self, m, pin, *, i_invert=False, o_invert=False):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue