vendor.xilinx_7series: apply false path / max delay constraints.

This commit is contained in:
Darrell Harmon 2019-09-23 18:47:54 -06:00 committed by whitequark
parent da53048ad4
commit f3a8880cb8
5 changed files with 70 additions and 7 deletions

View file

@ -533,3 +533,6 @@ class LatticeECP5Platform(TemplatedPlatform):
io_B=p_port[bit],
)
return m
# CDC primitives are not currently specialized for ECP5. While Diamond supports the necessary
# attributes (TBD); nextpnr-ecp5 does not.

View file

@ -564,3 +564,6 @@ class LatticeICE40Platform(TemplatedPlatform):
# Tristate and bidirectional buffers are not supported on iCE40 because it requires external
# termination, which is incompatible for input and output differential I/Os.
# CDC primitives are not currently specialized for iCE40. It is not known if iCECube2 supports
# the necessary attributes; nextpnr-ice40 does not.

View file

@ -78,6 +78,17 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
{% endfor %}
{{get_override("script_after_read")|default("# (script_after_read placeholder)")}}
synth_design -top {{name}}
foreach cell [get_cells -quiet -hier -filter {nmigen.vivado.false_path == "TRUE"}] {
set_false_path -to $cell
}
foreach cell [get_cells -quiet -hier -filter {nmigen.vivado.max_delay != ""}] {
set clock [get_clocks -of_objects \
[all_fanin -flat -startpoints_only [get_pin $cell/D]]]
if {[llength $clock] != 0} {
set_max_delay -datapath_only -from $clock \
-to [get_cells $cell] [get_property nmigen.vivado.max_delay $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_hierachical_synth.rpt
@ -361,12 +372,27 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
)
return m
# The synchronizer implementations below apply two separate but related timing constraints.
#
# First, the ASYNC_REG attribute prevents inference of shift registers from synchronizer FFs,
# and constraints the FFs to be placed as close as possible, ideally in one CLB. This attribute
# only affects the synchronizer FFs themselves.
#
# Second, the nmigen.vivado.false_path or nmigen.vivado.max_delay attribute affects the path
# into the synchronizer. If maximum input delay is specified, a datapath-only maximum delay
# constraint is applied, limiting routing delay (and therefore skew) at the synchronizer input.
# Otherwise, a false path constraint is used to omit the input path from the timing analysis.
def get_ff_sync(self, ff_sync):
m = Module()
flops = [Signal(ff_sync.i.shape(), name="stage{}".format(index),
reset=ff_sync._reset, reset_less=ff_sync._reset_less,
attrs={"ASYNC_REG": "TRUE"})
for index in range(ff_sync._stages)]
if ff_sync._max_input_delay is None:
flops[0].attrs["nmigen.vivado.false_path"] = "TRUE"
else:
flops[0].attrs["nmigen.vivado.max_delay"] = ff_sync._max_input_delay
for i, o in zip((ff_sync.i, *flops), flops):
m.d[ff_sync._o_domain] += o.eq(i)
m.d.comb += ff_sync.o.eq(flops[-1])
@ -378,6 +404,10 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
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:
flops[0].attrs["nmigen.vivado.false_path"] = "TRUE"
else:
flops[0].attrs["nmigen.vivado.max_delay"] = reset_sync._max_input_delay
for i, o in zip((0, *flops), flops):
m.d.reset_sync += o.eq(i)
m.d.comb += [

View file

@ -412,6 +412,10 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform):
return m
def get_ff_sync(self, ff_sync):
if ff_sync._max_input_delay is not None:
raise NotImplementedError("Platform {!r} does not support constraining input delay "
"for FFSynchronizer".format(self))
m = Module()
flops = [Signal(ff_sync.i.shape(), name="stage{}".format(index),
reset=ff_sync._reset, reset_less=ff_sync._reset_less,
@ -423,6 +427,10 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform):
return m
def get_reset_sync(self, reset_sync):
if reset_sync._max_input_delay is not None:
raise NotImplementedError("Platform {!r} does not support constraining input delay "
"for ResetSynchronizer".format(self))
m = Module()
m.domains += ClockDomain("reset_sync", async_reset=True, local=True)
flops = [Signal(1, name="stage{}".format(index), reset=1,