lib.cdc: extract AsyncFFSynchronizer.

In some cases, it is necessary to synchronize a reset-like signal but
a new clock domain is not desirable. To address these cases, extract
the implementation of ResetSynchronizer into AsyncFFSynchronizer,
and replace ResetSynchronizer with a thin wrapper around it.
This commit is contained in:
awygle 2020-03-08 14:37:40 -07:00 committed by GitHub
parent a14a5723c1
commit 2f8669cad6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 229 additions and 60 deletions

View file

@ -400,15 +400,24 @@ class IntelPlatform(TemplatedPlatform):
o_dout=ff_sync.o,
)
def get_reset_sync(self, reset_sync):
def get_async_ff_sync(self, async_ff_sync):
m = Module()
rst_n = Signal()
m.submodules += Instance("altera_std_synchronizer",
p_depth=reset_sync._stages,
i_clk=ClockSignal(reset_sync._domain),
i_reset_n=~reset_sync.arst,
i_din=Const(1),
o_dout=rst_n,
)
m.d.comb += ResetSignal(reset_sync._domain).eq(~rst_n)
sync_output = Signal()
if async_ff_sync.edge == "pos":
m.submodules += Instance("altera_std_synchronizer",
p_depth=async_ff_sync._stages,
i_clk=ClockSignal(async_ff_sync._domain),
i_reset_n=~async_ff_sync.i,
i_din=Const(1),
o_dout=sync_output,
)
else:
m.submodules += Instance("altera_std_synchronizer",
p_depth=async_ff_sync._stages,
i_clk=ClockSignal(async_ff_sync._domain),
i_reset_n=async_ff_sync.i,
i_din=Const(1),
o_dout=sync_output,
)
m.d.comb += async_ff_sync.o.eq(~sync_output)
return m

View file

@ -407,21 +407,27 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
m.d.comb += ff_sync.o.eq(flops[-1])
return m
def get_reset_sync(self, reset_sync):
def get_async_ff_sync(self, async_ff_sync):
m = Module()
m.domains += ClockDomain("reset_sync", async_reset=True, local=True)
m.domains += ClockDomain("async_ff", async_reset=True, local=True)
flops = [Signal(1, name="stage{}".format(index), reset=1,
attrs={"ASYNC_REG": "TRUE"})
for index in range(reset_sync._stages)]
if reset_sync._max_input_delay is None:
for index in range(async_ff_sync._stages)]
if async_ff_sync._max_input_delay is None:
flops[0].attrs["nmigen.vivado.false_path"] = "TRUE"
else:
flops[0].attrs["nmigen.vivado.max_delay"] = str(reset_sync._max_input_delay * 1e9)
flops[0].attrs["nmigen.vivado.max_delay"] = str(async_ff_sync._max_input_delay * 1e9)
for i, o in zip((0, *flops), flops):
m.d.reset_sync += o.eq(i)
m.d.async_ff += o.eq(i)
if self._edge == "pos":
m.d.comb += ResetSignal("async_ff").eq(asnyc_ff_sync.i)
else:
m.d.comb += ResetSignal("async_ff").eq(~asnyc_ff_sync.i)
m.d.comb += [
ClockSignal("reset_sync").eq(ClockSignal(reset_sync._domain)),
ResetSignal("reset_sync").eq(reset_sync.arst),
ResetSignal(reset_sync._domain).eq(flops[-1])
ClockSignal("async_ff").eq(ClockSignal(asnyc_ff_sync._domain)),
async_ff_sync.o.eq(flops[-1])
]
return m

View file

@ -437,24 +437,30 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform):
m.d.comb += ff_sync.o.eq(flops[-1])
return m
def get_reset_sync(self, reset_sync):
if reset_sync._max_input_delay is not None:
def get_async_ff_sync(self, async_ff_sync):
if self._max_input_delay is not None:
raise NotImplementedError("Platform '{}' does not support constraining input delay "
"for ResetSynchronizer"
"for AsyncFFSynchronizer"
.format(type(self).__name__))
m = Module()
m.domains += ClockDomain("reset_sync", async_reset=True, local=True)
m.domains += ClockDomain("async_ff", async_reset=True, local=True)
flops = [Signal(1, name="stage{}".format(index), reset=1,
attrs={"ASYNC_REG": "TRUE"})
for index in range(reset_sync._stages)]
for index in range(async_ff_sync._stages)]
for i, o in zip((0, *flops), flops):
m.d.reset_sync += o.eq(i)
m.d.async_ff += o.eq(i)
if self._edge == "pos":
m.d.comb += ResetSignal("async_ff").eq(asnyc_ff_sync.i)
else:
m.d.comb += ResetSignal("async_ff").eq(~asnyc_ff_sync.i)
m.d.comb += [
ClockSignal("reset_sync").eq(ClockSignal(reset_sync._domain)),
ResetSignal("reset_sync").eq(reset_sync.arst),
ResetSignal(reset_sync._domain).eq(flops[-1])
ClockSignal("async_ff").eq(ClockSignal(asnyc_ff_sync._domain)),
async_ff_sync.o.eq(flops[-1])
]
return m
XilinxSpartan3APlatform = XilinxSpartan3Or6Platform

View file

@ -403,21 +403,27 @@ class XilinxUltraScalePlatform(TemplatedPlatform):
m.d.comb += ff_sync.o.eq(flops[-1])
return m
def get_reset_sync(self, reset_sync):
def get_async_ff_sync(self, async_ff_sync):
m = Module()
m.domains += ClockDomain("reset_sync", async_reset=True, local=True)
m.domains += ClockDomain("async_ff", async_reset=True, local=True)
flops = [Signal(1, name="stage{}".format(index), reset=1,
attrs={"ASYNC_REG": "TRUE"})
for index in range(reset_sync._stages)]
if reset_sync._max_input_delay is None:
for index in range(async_ff_sync._stages)]
if async_ff_sync._max_input_delay is None:
flops[0].attrs["nmigen.vivado.false_path"] = "TRUE"
else:
flops[0].attrs["nmigen.vivado.max_delay"] = str(reset_sync._max_input_delay * 1e9)
flops[0].attrs["nmigen.vivado.max_delay"] = str(async_ff_sync._max_input_delay * 1e9)
for i, o in zip((0, *flops), flops):
m.d.reset_sync += o.eq(i)
m.d.async_ff += o.eq(i)
if self._edge == "pos":
m.d.comb += ResetSignal("async_ff").eq(asnyc_ff_sync.i)
else:
m.d.comb += ResetSignal("async_ff").eq(~asnyc_ff_sync.i)
m.d.comb += [
ClockSignal("reset_sync").eq(ClockSignal(reset_sync._domain)),
ResetSignal("reset_sync").eq(reset_sync.arst),
ResetSignal(reset_sync._domain).eq(flops[-1])
ClockSignal("async_ff").eq(ClockSignal(asnyc_ff_sync._domain)),
async_ff_sync.o.eq(flops[-1])
]
return m