Vivado allows for a portion of the design to be synthesized Out-Of-Context (OOC).
The basic idea with an OOC flow is that a part of the design is synthesized by itself.
This allows for a number of possibilities:
Quick iterations through synthesis of just this one part, while it is being worked on. By not synthesizing the rest of the design, you can have shorter iterations.
Quicker iterations through the rest of the design. If one part of the design has been determined to be stable, you can synthesize it OOC, and keep this synthesized version, while you iterate on the rest of the design. A change in the rest of the design would need only the rest of the design to be resynthesized, and you can save on the synthesis time for this specific part of the design.
OOC synthesis is especially interesting for IP Cores. You can synthesize your IP core in OOC mode and “release”/”ship” just the synthesized output.
This means that when using this IP core, you do not have to worry about the synthesis of the Core, as you refine your design.
However, OOC synthesis is impacted if your design-excerpt has 3-states (High-Impedance).
FPGAs allow high-impedance only at the I/O Boundaries, and not “within” the device.
If you are synthesizing something in OOC mode, Vivado synthesis does not know whether the specific signal will be on an I/O boundary, or if it will be connected to something else within the device.
As a result, the synthesis tool will convert this high-impedance signal to a logic value, rather than synthesizing as high-impedance.
For Example, the following code excerpt would be impacted:
assign my_signal = enable ? din1 : 1’bz;
After the synthesis in OOC mode, my_signal would no longer be able to get a Z.
Vivado synthesis has 2 possible options here:
Let the synthesis mimic the user’s HDL verbatim. (When this design unit is hooked up with the rest of the design, if the signal actually goes to an I/O then there is no issue. However, if this signal does not go to an I/O, an error situation would be encountered.)
Do not retain the 3-state.
Vivado synthesis chooses the latter option. The reason being, if any issue is going to arise later on, it is better to let the user know upfront.
The use-model of OOC makes it attractive to IP owners, but they would not be happy if the IP starts to have problems after being integrated into a large design. For this reason, the first option is avoided.
This brings us to the next question:
What if my signal is supposed to reach out ONLY to an I/O?
For example, all of the valid use cases for my signal need it to go to an I/O, and I want it to be able to drive a 3-state.
I would still like to be able to synthesize my portion of the design in OOC mode – and also retain the 3-state.
The way to achieve the above is to instantiate a 3-state buffer in the RTL.
This will ensure that even in the OOC mode of synthesis, my_signal can retain 3-state values.
Also, when this OOC synthesized portion is hooked up with the rest of the design, if the hookup is invalid (for example, my_signal getting connected to something “internal”), there will be errors in the flow.
(Thanks are due to Kawada san of Xilinx Japan, and Raphael Rousseau, for discussions related to this topic.)