The previous advice on how to discover the hold and setup times to use in out of context synthesis has been to extract the values from generated timing reports. This is error prone and the timing report for the critical path may not be the path with the precise figures required. The TCL commands required to get the correct timing reports have been provided but still required manual parsing of the text and copy & paste to a constraints file. How far can we go in using TCL to extract the correct values?
It is possible to extract timing data from the objects in your design after synthesis using timing_arc commands. This means is it possible to find the hold and setup times required for out of context synthesis that avoid timing errors on the boundary without making them more relaxed than is healthy for constraining. But as the values are only available after synthesis, it is not possible to use this method to constraint the design initially. Therefore, they can only be used for verification after at least one synthesis build cycle.
Setup Assumptions
Inputs and outputs are registered;
Inputs have known logic to drive inside the component, and
Outputs drive unknown logic outside the component.
We can't extract hold times from the unknown sequential primitives external to the component feeding the component's inputs.
We can extract known setup and hold times from sequential primitives driven by the inputs.
We can only guess at the setup and hold times on sequential primitives driven by the outputs.
But we can apply representative figures to the inputs and outputs based on the values extracted for the sequential primitives driven by the inputs.
We could tailor each input's setup and hold times to the maximum of each clocked primitive driven, but
For simplicity of construction we will take the maximum of each over all inputs, and
Apply the same values to all outputs as our best guess.
Each sequential primitive can have quite different values for setup and hold times. So for simplicity, and because we're mainly worried about giving sensible values for the boundary, we'll extract the values from sequential primitives fed by the inputs only.
Basic Example
Here is a really basic example for extracting these values using the properties in each timing arc. Note each pin and cell has many timing arcs, and the correct ones have to be selected using both a choice of pin or pins and choice of property. From initial experimentation looking for values that match those determined manually, and from the value types we ought to expect to find based the definition in the original Out of Context Synthesis blog, the correct timing arcs have been located and the property names of the timing values identified. Hold time requires 'min' delays, setup time requires 'max' delays, and the out of context synthesis blog determined than we should only use the 'slow' times for both minimum and maximum input and output delays.
Hence we have the initial insight on how to extract the required values. However there is a twist for outputs. Each design output is connected to a pin on the other side of the cell from the pin we are required to interogate. So firstly we have to "hop over" the cell from output to inputs. Secondly we have to take care with our choice of input pin(s). We typically want the D input, but may also want to check the other inputs, often the chip enable pin CE. The code below demonstrates how we need to traverse the design. It omits the reset pins from the equation as they are (generally) design inputs, but in due course they may yet be required.
More Realistic Example
We need to get the maximum setup time from all non-trivial inputs, e.g. D and CE and any other significant inputs. Here's some simple TCL code to illustrate:
In addition we may also want to retain knowledge of the primitive from which the value was extracted for explanation. This means dealing with a list of pairs {delay primitive} rather than just a list of delays.
Setup & Hold Time Extraction
The TCL code is not hideous to reverse engineer, but to provide some structure to the plan here's some pseudo code.
The TCL scripting requires significant care with verification against real netlists for unexpected errors from any assumptions. The code below adds the diagnostics for providing the primitive from which the hold and setup times were extracted for diagnostics.
A max_delay function is used to reduce a list of {delay primitive} pairs down to a single item with the maximum delay. The essential entry points are get_setup_hold_time [all_inputs]. This function relies on having a synthesised design open. 'check_setup_hold_times $ths $tsus 1' can then be used to verify both $ths and $tsus, the slow process hold and setup times respectively.
Clocks Checks
These two functions are much more trivial and provided to verify that all clocks have been defined.
The design_clock_pins function finds all input ports driving a clock pin and check_design_clocks verifies this pins have defined clock constraints.
Port Constraint Checks
It turns out it is possible to check that input and output delay constraints have been applied using:
However, the results for TCL function get_timing_paths are only available after synthesis. This means it is not possible to check the constraints have been applied during constraints setup above, and there are no get_input_delay nor get_output_delay functions. This is limiting because we would be able to check if a manual constraint already existed before printing a warning message about not being able to automatically apply one. As a result, each port for which we cannot automatically add a constraint is printed as a warning even if a manual constraint has already been provided. However, after synthesis we can at least verify all ports have been constrained. This is not done routinely as part of each OOC synthesis run, but manually as part of checking correct setup initially (with a synthesised design open).
Running Verification Checks
There are now three forms of verification, setup & hold times, clocks and port constraints, two of which require a synthesised design to be open. The following code ensures that a design is open for checks to be performed and performs all three checks. open_synth_design will re-use an open result or perform the synthesis if it is out of date. check_ooc_setup performs each of the three checks on the now open design and reports the number of warnings. This is a project mode function hence expects you will perform the checks manually rather than via a batch-based build. This is appropriate since once the values have been checked they are written into the constraints and only need to be re-verified when changes are made affecting any primitives the inputs drive and primitives driving the outputs.
Out of Context Synthesis Constraints Construction Process
Given the practical constraints that we cannot extract setup and hold times or check if input and output delay constraints have been applied pre-synthesis, the process is as follows:
Start with some nominal values for setup and hold times based on previous experience. Run OOC synthesis with automatically derived constraints. Either read the console transcript to see which ports could not be automatically constrained or check the synthesis timing report to see which inputs remain unconstrained. Also check the values of setup and hold times to use from this initial run. This is all achieved by running check_ooc_setup. Then add the missing constraints manually to your constraints file, and amend the setup and hold times. Now re-run OOC synthesis and repeat the process until all check_ooc_setup checks pass. From now on there is no need to re-run the checks, just work on the VHDL to achieve timing closure.
Conclusions
The extraction of timing data was previously a manual step. Whilst the generation of the correct reports could be automated, they still needed to be inspected and the values extracted by copy & paste. This solution automates the extraction of these values with the discovery of the TCL get_timing_arcs comand, and an investigation into the properties it offers. Another formation of the solution could be to have a function that writes out the input and output delay constraints as text, tailored to each port with their own setup and hold times, for copy & paste to the constraints file, instead of just applying the maximum value uniformly to all ports.
This blog should be taken together with two others, Specifying Boundary Timing Constraints in Vivado and Extracting Setup and Hold Times from Devices for Out of Context Synthesis. The three together define how to constrain a sub-design not connecting to device pins, firstly how to calculate the delay values to use for input and output constraints, then how to automate their application to pins with a variety of clock domains, and finally how to extract the fundamental setup and hold times to be used in the original calculations.