Constraints should be broken up into multiple files based on the type of constraint. For Dynamic Function eXchange, AMD recommends breaking up the design constraints into the three following types:
- Static
- Constraints (physical or timing) that reference only static objects (cell/pins/nets/ports), and do not reference any objects within an RP. These are global constraints and are applied to static synthesis, or at implementation of the initial configuration. It is not recommended to reapply these constraints for subsequent configurations where static is imported, as these constraints should already exist within the static DCP and reapplying them can cause unintended constraint interactions.
- Boundary
- These are timing constraints (such as
set_false_path
) that reference objects in both static and the RP. Write these constraints referencing the RP pin object, and not objects internal to the RM. For example, take the following two constraints:set_false_path -from [get_pins static_reset/C] -through [get_pins rp_inst/rst] set_false_path -from [get_pins static_reset/C] -to [get_pins rp_inst/*foo*/D]
The first constraint is preferred, as this constraint will not be lost when the RMs are converted to a black box after the initial configuration. Even when the RMs are carved out, the RP interface still exists in the static design, and the
rp_inst/rst
pin referenced in the constraint still exists in the design. If a constraint is defined using objects inside the RM, as shown in the second constraint, the constraint becomes invalid and is dropped from the design after carving. These constraints would have to be reapplied for every configuration if written using this syntax. - RM
- Constraints (physical or timing) that reference only RM logic.
While these constraints should all be scoped to the RM, how they get applied
will depend on what type of constraints they are:
- General RM constraints
- These constraints apply to every instance of the RM.
An example is a timing constraint, like a false path, multi-cycle
exception, or a
create_clock
for a local RM clock. These apply to the RM regardless of the physical location. - RP specific RM constraints
- These constraints are specific to the location (Pblock) in which the RM is being implemented. An example is physical constraints like specific block RAM placement, or PACKAGE_PIN constraints for embedded I/O.
- Embedded IO constraints
- I/O buffers which are instantiated inside a specific
IP's hierarchy are called as embedded IOBs in the DFX design flow.
IP such as DDR, GTs can have embedded IOBs where users or tools are
not required to add I/O Buffers at the top. When these IPs are
unused in a specific RM compile, tools must not insert I/O buffer
for them at the top. Users can enforce this by setting the attribute
IO_BUFFER_TYPE to NONE for those ports at the top RTL. When specific
embedded IOBs are unused in a specific RM compile, those I/O pads
should be connected all the way to the reconfigurable module
hierarchy in the netlist and be unconnected within the specific RM.
Also, to guide the I/O Placer, users are expected to keep corresponding PACKAGE_PIN constraints for those ports even in those compiles that do not use those I/O pads.
Important: If an RP has embedded I/O, the I/O (PACKAGE_PIN, IOSTANDARD, direction) must be reapplied for every configuration, even if the I/O pins are identical between every RM. In the Vivado database, a port is a top-level object. However, the I/O constraint information associated with that port is intentionally cleared out during carving of the RM if the associated I/O buffer is part of an RP.
In addition to this, it is also recommended to separate physical (Pblock, LOC, PACKAGE_PIN, etc) and timing constraints into separate XDC files. This allows for better control of when constraints are applied (synthesis vs implementation), and easier management of constraint files if constraints need to be modified.