Skip to content

xilinx: use FDPE instances to implement get_async_ff_sync() #1091

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 54 additions & 20 deletions amaranth/vendor/_xilinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@ def vendor_toolchain(self):
foreach cell [get_cells -quiet -hier -filter {amaranth.vivado.false_path == "TRUE"}] {
set_false_path -to $cell
}
foreach pin [get_pins -of \
[get_cells -quiet -hier -filter {amaranth.vivado.false_path_pre == "TRUE"}] \
-filter {REF_PIN_NAME == PRE}] {
set_false_path -to $pin
}
foreach cell [get_cells -quiet -hier -filter {amaranth.vivado.max_delay != ""}] {
set clock [get_clocks -of_objects \
[all_fanin -flat -startpoints_only [get_pin $cell/D]]]
Expand All @@ -180,6 +185,11 @@ def vendor_toolchain(self):
-to [get_cells $cell] [get_property amaranth.vivado.max_delay $cell]
}
}
foreach cell [get_cells -quiet -hier -filter {amaranth.vivado.max_delay_pre != ""}] {
set_max_delay \
-to [get_pins -of [get_cells $cell] -filter {REF_PIN_NAME == PRE}] \
[get_property amaranth.vivado.max_delay_pre $cell]
}
{{get_override("script_after_synth")|default("# (script_after_synth placeholder)")}}
report_timing_summary -file {{name}}_timing_synth.rpt
report_utilization -hierarchical -file {{name}}_utilization_hierarchical_synth.rpt
Expand Down Expand Up @@ -1191,29 +1201,53 @@ def get_ff_sync(self, ff_sync):
def get_async_ff_sync(self, async_ff_sync):
m = Module()
m.domains += ClockDomain("async_ff", async_reset=True, local=True)
flops = [Signal(1, name=f"stage{index}", reset=1,
attrs={"ASYNC_REG": "TRUE"})
for index in range(async_ff_sync._stages)]
if self.toolchain == "Vivado":
if async_ff_sync._max_input_delay is None:
flops[0].attrs["amaranth.vivado.false_path"] = "TRUE"
else:
flops[0].attrs["amaranth.vivado.max_delay"] = str(async_ff_sync._max_input_delay * 1e9)
elif async_ff_sync._max_input_delay is not None:
raise NotImplementedError("Platform '{}' does not support constraining input delay "
"for AsyncFFSynchronizer"
.format(type(self).__name__))
for i, o in zip((0, *flops), flops):
m.d.async_ff += o.eq(i)
# Instantiate a chain of async_ff_sync._stages FDPEs with all
# their PRE pins connected to either async_ff_sync.i or
# ~async_ff_sync.i. The D of the first FDPE in the chain is
# connected to GND.
flops_q = Signal(async_ff_sync._stages, reset_less=True)
flops_d = Signal(async_ff_sync._stages, reset_less=True)
flops_pre = Signal(reset_less=True)
for i in range(async_ff_sync._stages):
flop = Instance("FDPE", p_INIT=1, o_Q=flops_q[i],
i_C=ClockSignal(async_ff_sync._o_domain),
i_CE=Const(1), i_PRE=flops_pre, i_D=flops_d[i],
a_ASYNC_REG="TRUE")
m.submodules[f"stage{i}"] = flop
if self.toolchain == "Vivado":
if async_ff_sync._max_input_delay is None:
# This attribute should be used with a constraint of the form
#
# set_false_path -to [ \
# get_pins -of [get_cells -hier -filter {amaranth.vivado.false_path_pre == "TRUE"}] \
# -filter { REF_PIN_NAME == PRE } ]
#
flop.attrs["amaranth.vivado.false_path_pre"] = "TRUE"
else:
# This attributed should be used with a constraint of the form
#
# set_max_delay -to [ \
# get_pins -of [get_cells -hier -filter {amaranth.vivado.max_delay_pre == "3.0"}] \
# -filter { REF_PIN_NAME == PRE } ] \
# 3.0
#
# A different constraint must be added for each different _max_input_delay value
# used. The same value should be used in the second parameter of set_max_delay
# and in the -filter.
flop.attrs["amaranth.vivado.max_delay_pre"] = str(async_ff_sync._max_input_delay * 1e9)
elif async_ff_sync._max_input_delay is not None:
raise NotImplementedError("Platform '{}' does not support constraining input delay "
"for AsyncFFSynchronizer"
.format(type(self).__name__))

for i, o in zip((0, *flops_q), flops_d):
m.d.comb += o.eq(i)

if async_ff_sync._edge == "pos":
m.d.comb += ResetSignal("async_ff").eq(async_ff_sync.i)
m.d.comb += flops_pre.eq(async_ff_sync.i)
else:
m.d.comb += ResetSignal("async_ff").eq(~async_ff_sync.i)
m.d.comb += flops_pre.eq(~async_ff_sync.i)

m.d.comb += [
ClockSignal("async_ff").eq(ClockSignal(async_ff_sync._o_domain)),
async_ff_sync.o.eq(flops[-1])
]
m.d.comb += async_ff_sync.o.eq(flops_q[-1])

return m