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
|
|
@ -7,10 +7,8 @@ import jinja2
|
|||
|
||||
from .. import __version__
|
||||
from .._toolchain import *
|
||||
from ..hdl.ast import *
|
||||
from ..hdl.cd import *
|
||||
from ..hdl.dsl import *
|
||||
from ..hdl.ir import *
|
||||
from ..hdl import *
|
||||
from ..lib.cdc import ResetSynchronizer
|
||||
from ..back import rtlil, verilog
|
||||
from .res import *
|
||||
from .run import *
|
||||
|
|
@ -87,22 +85,25 @@ class Platform(ResourceManager, metaclass=ABCMeta):
|
|||
return True
|
||||
return all(has_tool(name) for name in self.required_tools)
|
||||
|
||||
@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.
|
||||
# This implementation uses a single ResetSynchronizer to ensure that:
|
||||
# * an external reset is definitely synchronized to the system clock;
|
||||
# * release of power-on reset, which is inherently asynchronous, is synchronized to
|
||||
# the system clock.
|
||||
# Many device families provide advanced primitives for tackling reset. If these exist,
|
||||
# they should be used instead.
|
||||
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
|
||||
else:
|
||||
rst_i = Const(0)
|
||||
|
||||
m = Module()
|
||||
m.domains += ClockDomain("sync", reset_less=self.default_rst is None)
|
||||
m.d.comb += ClockSignal("sync").eq(clk_i)
|
||||
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 prepare(self, elaboratable, name="top", **kwargs):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue