When we synthesize our programmable logic designs we can, of course, select from a range of synthesis options. For example, we can limit fanout_limit or enable retiming. At a higher level, we can also request the synthesis engine to optimize for performance or area.

However, when we have a design which contains several instances of varying complexity, global synthesis options can be limiting.

For some high performance instances we may want to optimize for performance, while for other instances such optimization may be wasteful of resources.

In other words, one size very often does not fit all.

What we need is the ability to apply different synthesis strategies and options to each instantiation in our design.

We can do this within Vivado using block synthesis commands defined in an XDC file.

Ultra96 Board with JTAG and RS232 to USB module used in the example

Working with block synthesis, we can define both alternative synthesis strategies to the global strategy and apply finer grained control over specific synthesis options.

When it comes to synthesis strategies for each instance in the design, we can apply one of the following:

Default — Attempts to achieve a balance between area and performance.

Area_Optimised — Synthesis options focus on efficient logic footprint over performance.

Alternative_Routability — Improves routability of the design using fewer Mux F resources.

Performance_optimized — Synthesis options focus on performance over logic footprint.

You can find detailed information on the detailed synthesis settings for each strategy here.

If we wish to apply a specific strategy to aa instance, we can apply the desired strategy using the command below in an XDF file.

set_property BLOCK_SYNTH.STRATEGY {value} [get_cells ]

Synthesis strategies offer a very coarse level of control over synthesis performance. At times we need to more fine-grained control, as such we can also control the following synthesis options via block synthesis: Retiming, Adder Threshold, Comparator Threshold, SHREG Min Size, FSM Extraction, LUT Combining, Control Set Threshold, Max LUT Input, Mux F Mapping and Keep Equivalent Registers.

These can also be used in conjunction with the synthesis strategies.

Once we have decided to apply a block synthesis option to an instance, it is propagated down through the hierarchy of that instance.

Of course, we can also override inherited options at lower levels with another block synthesis option as demonstrated below.

Top down flow of block synthesis settings

Let’s wrap up this blog with a simple example based on the Ultra96 board and the PL design updates for my recent Ultra96 PetaLinux project.

In this project, the programmable logic design contains an AXI BRAM Controller and a AXI UART16550, which can be seen in the block diagram.

Programmable logic design

Running synthesis on this design with the default strategy and no block synthesis options defined within the XDC file results in the resource utilization defined below.

Default synthesis results

For this example, we will set a block synthesis option on the AXI BRAM Controller to optimize for performance as opposed to the default strategy that will be applied to all of the remaining blocks in the design.

Defining a block synthesis strategy on the AXI BRAM controller

By rerunning Vivado synthesis with this block synthesis option applied, we can see a small increase in the number of LUTs used in the solution.

This is to be expected as applying performance optimization to the AXI BRAM Controller will prohibit resource sharing, lowering the maximum allowable fan out along with other settings that will increase resource utilization.

Resource utilisation with block synthesis option applied

To ensure the block synthesis option has been correctly applied as part of the synthesis, we can check the synthesis report which shows the correct application.

Synthesis report showing the correct application of the block synthesis

While the example presented is simple, the ability to apply different synthesis options can be very important when we are working with complex designs.

Block synthesis can be especially powerful when we are working with congested designs — these are designs where the we have trouble achieving timing closure due to routing congestion.

We can obtain a congestion report for the design using the command:

report_design_analysis -congestion

Once the instance causing the congestion has been identified, we can apply a block synthesis option disabling the use of Mux F. Re-Running synthesis that will reduce the congestion, allowing better timing performance.

All told, block synthesis is a good tool in our FPGA designers tool box.

See My FPGA / SoC Projects: Adam Taylor on Hackster.io

Get the Code: ATaylorCEngFIET (Adam Taylor)

Additional Information on Xilinx FPGA / SoC Development can be found weekly on MicroZed Chronicles.