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:
parent
a14a5723c1
commit
2f8669cad6
7 changed files with 229 additions and 60 deletions
29
nmigen/vendor/intel.py
vendored
29
nmigen/vendor/intel.py
vendored
|
|
@ -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
|
||||
|
|
|
|||
24
nmigen/vendor/xilinx_7series.py
vendored
24
nmigen/vendor/xilinx_7series.py
vendored
|
|
@ -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
|
||||
|
|
|
|||
24
nmigen/vendor/xilinx_spartan_3_6.py
vendored
24
nmigen/vendor/xilinx_spartan_3_6.py
vendored
|
|
@ -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
|
||||
|
|
|
|||
24
nmigen/vendor/xilinx_ultrascale.py
vendored
24
nmigen/vendor/xilinx_ultrascale.py
vendored
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue