Block level design constraints in ALINT-PRO


Demonstrates how block level constraints can be used to describe behavioral, non-synthesizable, vendor or synchronization cells to enable precise linting in the ALINT-PRO. This process was verified with ALINT-PRO 2016.08.

The source code of the examples used in the article can be downloaded here. The file contains a single workspace with multiple projects. The "ADC_components" project contains the definition of all components used in this article together with the constraints. All other projects depend on the "ADC_components" project and use components from it. Projects from the workspace are referenced later in these instructions.

Block level design constraints

Block level design constraints is a set of console commands, which can be used to describe various properties of design units. This kind of description overrides HDL description and is used to give additional information to the tool in case when it is not possible to extract the information from the HDL code. Constraints commands are used to describe encrypted IP modules, non-synthesizable and behavioral descriptions, black boxes, and custom synchronization cells. Block level design constraints are applied to the design units from the current library, and cannot modify contents of attached libraries, global libraries or project libraries of other projects. Constraint commands should be specified in the *.adc files and added to the project as regular source files.

Block level constraints can be divided into two groups:

  • Block level getters - the commands are used to retrieve information about library cells or pins. This includes: get_libs, get_lib_pins, get_lib_cells, get_lib_cell_paths, and report_attributes.

  • Block level setters - the commands are used to specify characteristics of a design unit. This includes: set_cell, set_pin, create_cell_clock, create_generated_cell_clock, set_input_cell_delay, set_output_cell_delay.

Port and cell roles

The most common usage of the block level constraints is to specify cell and pin roles for a given cell. The cell role is used by different algorithms that analyze a cell as whole. For example, checker that states do not instantiate flip-flops on the top level will refer to cell type to perform the check. The role can be specified using set_cell command:

set_cell -kind <cell_kind> <lib_cells_pattern> [-if <boolean_condition>] [-f <list_file>]

The command accepts -kind <cell_kind> argument to define cell role, and the output of the get_lib_cells (<lib_cells_pattern)> to select lib cells to which the new role should be assigned to. There are also tow optional arguments: -if - specifies conditional expression when the constraint should be applied (see the Generic dependent constraints for additional details), and -f - common argument that specifies the file with additional arguments to the command. The -f and -if are common arguments shared by all constraint commands.

Let's assume we are going to describe flip-flop, which resides in the ADC_componets library:

entity FF is
    port (
        clk:  in  std_logic;
        rst:  in  std_logic;
        data: in  std_logic;
        Q:    out std_logic

So first we'll assign the flip-flop role with the set_cell command:

set_cell -kind flip-flop [get_lib_cells ADC_components/FF]

Now, we have to describe all pins of the cell. This can be done using the set_pin command:

set_pin [-kind <pin_kind>] [-polarity <signal_polarity> | -level <signal_level>]
        <lib_pins_pattern> [-if <boolean_condition>] [-f <list_file>]

The command accepts -kind argument to specify cells kind, optional -polarity (used to specify polarity for control signals) and -level (used when some output pin is constantly driven by the value) arguments. The command also accepts the output of the get_lib_pins (<lib_pins_pattern>) command, which defines pins to work with.

For our flip-flop we would create the following constraints:

set_pin -kind async-reset -polarity active-high [get_lib_pins ADC_components/FF/rst]
set_pin -kind input                             [get_lib_pins ADC_components/FF/data]
set_pin -kind output                            [get_lib_pins ADC_components/FF/Q]

These commands described all pins of the flip-flop except the clk pin. To describe clock pins the create_cell_clock constraint should be used:

create_cell_clock [-edge <signal_edge>] [-name <clock_name>] <source_objects>
                  [-if <boolean_condition>] [-f <list_file>]

The command accepts -edge (specifies clock edge and can be rising or falling), -name (specifies clock name and can be used for referencing from the create_generated_cell_clock command) and output of the get_lib_pins constraint (defines clock pins). For the out flip-flop the constraint will look this way:

create_cell_clock -edge rising [get_lib_pins ADC_components/FF/clk]

So now, we have described the custom flip-flop and it will be properly recognized by ALINT-PRO engine during the linting if met in the design. Please refer to the "ADC_components" project for the full description of the component.

Figure 1. The constrained elements.

Now let's try analyzing the project, which uses these components. The "ADC_constrained_elements" contains two cells: FDR, which is properly constrained, and FF_EMPTY, which is not constrained. Data is being send from one cell to the other and different clocks are applied to the cells. To run the analysis do the following:

  • Run the "ADC_components" project - click the Run button from the popup menu in the project manager on the ADC_components node

  • Run the "ADC_constrained_elements" project - click the Run button from the popup menu in the project manager on the ADC_constrained_elements node

  • Open Schematic Viewer - click the Show RTL Schematic button from the popup menu in the project manager on the ADC_constrained_elements node

  • Expand the uFF_UNCONSTRAINED instance - click the "+" sign in the top-left corner of the instance node.

Above actions will bring you Schematic Viewer with the scheme represented on Figure 1. As you can see, entered constraints affect components representation in the Schematic Viewer - the uFF instance of the FDR component is displayed as a flip-flop. And the FF_EMPTY cell is displayed as an empty without connections inside it. If you navigate to Violation Viewer (to open Violation Viewer, click the View | Linting Windows | Violation Viewer button from the main menu or choose Alt+7), you will see the following violations detected for the "ADC_constrained_elements" project (Figure 2).

Figure 2. The violations detected in the "ADC_constrained_elements" project.

To receive violations on crossing between asynchronous clock domains, constraints should be added to the second cell also. There is an "ADC_crossings" project in the workspace. It has the same structure as the "ADC_constrained_elements" project, but second cell is constrained.

If you run an analysis of the "ADC_crossings" project and open Violation Viewer, you'll see that now there are extra violations reported on non-synchronized crossing between clock domains (Figure 3). Not only a new CDC path is detected and reported as unsynchronized, but also the number of automatically detected clocks has increased (violation of rule ALDEC_CDC.6.1.1) simply because the cloc extraction algorithm now can take another valid clock endpoint, the uFFB flip-flop, into a count.

Figure 3. More violations reported on properly constrained cells.

Generated clocks

Another application for the design constraints is description of clock generators - e.g. cells that accept a clock, referred as master clock, and generate another clock, referred as generated cock, as an output. To constrain this output clock the create_generated_cell_clock command should be used:

create_generated_cell_clock -source <master_source> | -master_clock <cell_clock_name> [-divide_by <divide_by>]
                            [-multiply_by <multiply_by>] [-phase_shift <phase_shift>] [-name <name>] [-invert]
                            [-combinational] <source_objects> [-if <boolean_condition>] [-f <list_file>]

The command accepts -source and -master_clock arguments to specify master clock pin or master clock name. The -multiply_by and -divide_by arguments allow setting frequency changes of the generated clock, -invert argument defines clock with the inverted phase, and -combinational argument defines clock with the same frequency/phase as a master clock, the -phase_shift argument specifies difference in phase between master and generated clocks, and the -name argument specifies name of the generated clock.

Let's assume that we have the following clock generator:

entity CLK_GEN is
    generic (
        DIVA : integer := 2;
        DIVB : integer := 2
    port (
        CLK: in std_logic;
        CLK_OUT: out std_logic;
        CLK_OUT_DIVA: out std_logic;
        CLK_OUT_DIVB: out std_logic
end entity CLK_GEN;

This component have one input clock and three generated clocks, there are also two generic values, which define frequency of the generated clocks.

First we should define cell role, in our case it is clock generator, this can be done with the set_cell command:

set_cell -kind clock_generator [get_lib_cells ADC_components/CLK_GEN]

Now we have to define input clock, we can do it with the help of create_cell_clock_command:

create_cell_clock -edge falling [get_lib_pins ADC_components/CLK_GEN/CLK]

Once the main clock is defined we can proceed to creating generated clocks. First clock output (CLK_OUT) is a clock with same frequency, to define such clock, we should use the -combinational argument:

create_generated_cell_clock -combinational -source [get_lib_pins ADC_components/CLK_GEN/CLK]
                            [get_lib_pins ADC_components/CLK_GEN/CLK_OUT]

Here we specify pin of the master clock in the source argument and pin of the generated clock as a value without argument. Actual frequency of two other clocks depend on the generic value. To define such clock, we'll have to specify an expression as a value of -divide_by argument. The expression should follow regular TCL syntax and have to be written in curly brackets (the '{' and '}' characters). Generic variables can be referenced by their name with the preceding dollar sign. In our example the expressions are simple - just generic value itself, so we'll use the following description:

create_generated_cell_clock -divide_by {$DIVA} -source [get_lib_pins ADC_components/CLK_GEN/CLK] 
                            [get_lib_pins ADC_components/CLK_GEN/CLK_OUT_DIVA]
create_generated_cell_clock -divide_by {$DIVB} -source [get_lib_pins ADC_components/CLK_GEN/CLK] 
                            [get_lib_pins ADC_components/CLK_GEN/CLK_OUT_DIVB]

The above constraints are enough to describe clock generator cell for correct linting.

There is an "ADC_generator_unconstrained" project in the workspace. This project contains clock generator cell, which drives two flip-flops with different clocks (Figure 4).

Figure 4. The unconstrained clock generator cell.

ALINT-PRO automatically detects clock and resets used in the design. To view detected clocks, do the following:

  • Run the "ADC_components" project - click Run button from the popup menu in the project manager on the ADC_components node

  • Set the "ADC_generator_unconstrained" project as active project - click Set Project as Active button from the popup menu in the project manager on the ADC_generator_unconstrained node

  • Run the "ADC_generator_unconstrained" project - click Run button from the popup menu in the project manager on the ADC_generator_unconstrained node

  • Open Clocks and Resets Viewer - click the View | Design Management Windows | Clocks and Resets Viewer button from the main menu or choose Alt+5.

In the Clocks and Resets Viewer, you'll see that ALINT-PRO detected two clocks (Figure 5). Detected clock tree is not ideal: first - detected clocks are separate clocks, and second - no clocks are detected for TOP/clk port.

Figure 5. The detected clocks with unconstrained clock generator.

To improve auto-detect results, we should specify constraints for clock generator cell. There is an "ADC_generator" project, which has the same structure as "ADC_generator_unconstrained" project with the only difference - the clock generator cell is described with constraints. If you run the analysis and open Clocks and Resets Viewer, you'll see that now three clocks are detected (Figure 6): master clock - TOP/clk, and two generated clocks - TOP/uCLK_GEN/CLK_OUT_DIVA and TOP/uCLK_GEN/CLK_OUT_DIVB. So we see that detected clock tree is correct and correct linting results can be obtained.

Figure 6. The detected clocks with constrained clock generator.

Detected clocks can be saved in the *.adc file with the help of the save_constraints command. The command will save constraints to the main.adc file attached to the "ADC_generator" project (the main.adc file is specified in the project preferences in the Save Constraints to: option). After saving constraints you'll receive the following records for clocks:

create_clock -period 100 [ get_ports TOP/clk ]
create_generated_clock -source [ get_ports TOP/clk ] -divide_by 2 
                               [ get_pins TOP/uCLK_GEN/CLK_OUT_DIVA ]
create_generated_clock -source [ get_ports TOP/clk ] -divide_by 7 
                               [ get_pins TOP/uCLK_GEN/CLK_OUT_DIVB ]

So, we see, that generic values, supplied in the HDL code, were recognized by the engine and are inserted in the description of the generated clocks.

Describing Cells with Multiple Clocks

It is possible that single cell receives multiple clocks and its pins depend on different clocks, for example dual port RAM cell. To handle such situation, there is a set_input_cell_delay and set_output_cell_delay constraints:

set_input_cell_delay -clock <cell_clock_name> -reference_pin <lib_pin> [-add_delay] <objects> 
                     [-if <boolean_condition>] [-f <list_file>]
set_output_cell_delay -clock <cell_clock_name> -reference_pin <lib_pin> [-add_delay] <objects> 
                     [-if <boolean_condition>] [-f <list_file>]

These constraints accept clock name (-clock argument) or clock pin name (-reference_pin argument) and output of get_lib_cells command (<objects>). Once executed the command informs ALINT-PRO engine that these pins are sampled/driven by the specified clock. Let's take a look on the RAM cell:

entity RAM is
  port (
    clka  : in  std_logic;
    addra : in  std_logic_vector(5 downto 0);
    dataa : in  std_logic_vector(7 downto 0);
    qa    : out std_logic_vector(7 downto 0);
    clkb  : in  std_logic;
    addrb : in  std_logic_vector(5 downto 0);
    datab : in  std_logic_vector(7 downto 0);
    qb    : out std_logic_vector(7 downto 0)
end entity RAM;

All pins should be described with create_cell_clock and set_pin constraints as shown above. In addition set_input_cell_delay/set_output_cell_delay constraints should be specified for each non-clock pin of the cell. In our case constraints might look like this:

#Interface A
set_input_cell_delay -reference_pin  [get_lib_pins ADC_components/RAM/clka] 
                                     [get_lib_pins ADC_components/RAM/addra]
set_input_cell_delay -reference_pin  [get_lib_pins ADC_components/RAM/clka] 
                                     [get_lib_pins ADC_components/RAM/dataa]
set_output_cell_delay -reference_pin [get_lib_pins ADC_components/RAM/clka] 
                                     [get_lib_pins ADC_components/RAM/qa]

# Interface B
set_input_cell_delay -reference_pin  [get_lib_pins ADC_components/RAM/clkb] 
                                     [get_lib_pins ADC_components/RAM/addrb]
set_input_cell_delay -reference_pin  [get_lib_pins ADC_components/RAM/clkb] 
                                     [get_lib_pins ADC_components/RAM/datab]
set_output_cell_delay -reference_pin [get_lib_pins ADC_components/RAM/clkb] 
                                     [get_lib_pins ADC_components/RAM/qb]

When such constraints are defined for the cell and data connected to the pin and the pin itself are controlled by different clocks, then violation will be reported. You can run the "ADC_RAM" project to examine violations reported on such cells. The project contains RAM instance with all its inputs and outputs driven by the flip-flops, which are controlled by wrong clock domain. (Figure 7)

Figure 7. The detected CDC paths that start and end with a properly constrained RAM cell.

Generic Dependent Constraints

It is possible that some design constraints will be valid only for the certain generic values. For example, the specific pin may be an asynchronous or synchronous reset depending on the generic value. To handle such situation the -if argument should be used. This argument takes a TCL expression as a parameter. The generic values can be referenced by the preceding dollar character '$' before the generic name.

In the following example, there is a flip-flop with the ASYNC_RESET generic which controls if synchronous or asynchronous reset is inferred on the rst pin:

entity FF_GENERIC is
    generic (
        ASYNC_RESET: boolean := true
    port (
        clk:  in  std_logic;
        rst:  in  std_logic;
        data: in  std_logic_vector(7 downto 0);
        Q:    out std_logic_vector(7 downto 0)
end entity FF_GENERIC;

To describe such module we'll require two constraints for rst pin:

set_pin  -kind async-reset -polarity active-high [get_lib_pins ADC_components/FF_GENERIC/rst] -if {$ASYNC_RESET == true} 
set_pin  -kind sync-reset  -polarity active-high [get_lib_pins ADC_components/FF_GENERIC/rst] -if {$ASYNC_RESET == false}

Here we have one constraint which defines rst pin as asynchronous pin and one which defines it as a synchronous pin. However, these constraints have different expression specified in the -if argument. The corresponding constraint will be applied only if the expression evaluates to true, so only one of these constraints will be applied to a particular cell.

The "ADC_generic_dependent" project contains two instances of the FF_GENERIC cell with different generic value applied to them. The schematic for this project is shown on Figure 8. As you can see the uFF_ARST cell has asynchronous reset pin (the rst pin is displayed at the bottom of the cell) and the uFF_SRST cell has synchronous reset pin (the rst pin is displayed on the left side of the cell). This also affects violations detected by the checkers during design linting.

Figure 8. The cells with generic dependent constraints.

Custom synchronizer cells description

Description of a synchronizer cell is basically the same as of a regular cell. The only difference is the synchronized-data and non-synchronized-data pin kinds of the set_pin constraint command. These kinds mean the following:

  • non-synchronized-data - input pin which receives data from another domain. If a pin is marked with this kind and doesn't receive data from asynchronous domain - violation is reported.

  • synchronized-data - output pin which delivers synchronized data to the current domain. If a pin marked with this kind is not read in the current domain - violation is reported.

Let's take a look on the simple 2dff synchronizer cell:

	port (
		clk:  in  std_logic;
		data: in  std_logic_vector(7 downto 0);
		sync: out std_logic_vector(7 downto 0)

The cell kind needs to be defined as "synchronizer":

set_cell -kind synchronizer [get_lib_cells ADC_components/NDFF_SYNCHRONIZER]

The following constraints should be applied to its data and sync ports:

set_pin -kind non-synchronized-data [get_lib_pins ADC_components/NDFF_SYNCHRONIZER/data]
set_pin -kind synchronized-data     [get_lib_pins ADC_components/NDFF_SYNCHRONIZER/sync]

The "ADC_synchronizer" project constraints wrongly used NDFF_SYNCHRONIZER cell (Figure 9). The uNDFF_SYNCHRONIZER synchronizer is misplaced in the design: it receives data from the same domain, and synchronized data is not used in the target domain. This result in the violations from ALDEC_CDC.5.1 and ALDEC_CDC.5.2 checkers, which can be observed in the Violations Viewer.

Figure 9. The custom synchronizer.

Verifying values assigned by the constraints

Common task, when creating block level constraints, is to verify which constraints are applied to the particular pin. In ALINT-PRO there is a report_attributes console command. This command reports in the text format various characteristics of the supplied objects. As an input it accepts output of block and chip level getters (e.g. get_clocks, get_resets, get_lib_pins etc.).

For example, to check what constraints are applied to the dataa pin of the RAM cell from the above example, we can use the following command:

report_attributes [get_lib_pins ADC_components/RAM/dataa]

Which will return a set of attributes and their values:

type:       library pin
name:       ADC_components/RAM/dataa
kind:       input
direction:  in
sampled_by: clka

Here we can see, that this pin is a regular data input pin (kind: input) and is controlled by the clka clock pin (sampled_by: clka). If attributes of a given pin depend on the generic values, then, instead of a plain value, corresponding expression will be printed in the command output. Let's take a look on the attributes of the rst pin of FF_GENERIC component from the above example:

type:      library pin
name:      ADC_components/FF_GENERIC/rst
kind:      ($ASYNC_RESET == false) ? sync-reset : ($ASYNC_RESET == true) ? 
               async-reset : <unknown>
direction: in
polarity:  ($ASYNC_RESET == false) ? active-high : ($ASYNC_RESET == true) ? 
               active-high : <unknown>

Here the ternary expression was composed for the kind and polarity attributes. Ternary expressions have the following structure (<conditional_expression>) ? <true_condition> : <false_condition> and can be nested into each other. The conditional expression in this expression is the expression which was entered as a value of the -if argument of the corresponding constraint command.

To check attributes of the generated clock the following getter should be used: get_lib_cell_paths. This command accepts starting and ending lib cell pin and returns relations between pins, which were introduced by the design constraints. For example, if we want to check attributes of the CLK_OUT_DIVA generated clock of the CLK_GEN cell from the above example, we can use the following command:

report_attributes [get_lib_cell_paths -from ADC_components/CLK_GEN/CLK -to ADC_components/CLK_GEN/CLK_OUT_DIVA]

Following attributes will be reported:

type:             library cell path
name:             ADC_components/CLK_GEN/CLK:CLK_OUT_DIVA
kind:             cell clock
source_port:      CLK
destination_port: CLK_OUT_DIVA
divide_by:        $DIVA
inverted:         false
combinational:    false

Here we can examine all characteristics of the generated clock, and if some value is generic dependent we'll see the corresponding expression (e.g. divide_by: $DIVA).


Block level design constraints is a powerful mechanism which allows describing in the clear text format library cells of any complexity. This includes specifying pin roles (clock, reset, enable, data etc.), creating generated clocks, specifying dependencies between pins and clocks. It is also possible to specify design constraints, which are applied to the cell only when generics has a specific value. To facilitate constraints creation process ALINT-PRO offers report_attributes console command, which allows examining values assigned to the particular pin. Once entered, design constraints enable precise linting of a design, allowing utilizing complete set of rules, available in the product, for non-synthesizable and behavioral portions of the project.

ALINT-PRO applies the identical constraints mechanism to properly handle FPGA vendor primitives. The users are not supposed to describe the vendor primitives on their own, in fact this could be a very error-prone task, especially for complex primitives like dual-port RAMs or multi-clock FIFOs. The constraints are already defined and prepackaged into product for the most frequently used FPGA vendor libraries (Xilinx, Altera, Microsemi). Refer to Vendor Libraries Reference documentation provided in ALINT-PRO Help menu for detailed data on the supported primitives.

Ask Us a Question

Ask Us a Question

Captcha ImageReload Captcha
Incorrect data entered.
Thank you! Your question has been submitted. Please allow 1-3 business days for someone to respond to your question.
Internal error occurred. Your question was not submitted. Please contact us using Feedback form.