Ug901 Vivado Synthesis en Us 2024.1
Ug901 Vivado Synthesis en Us 2024.1
of this document
Synthesis
UG901 (v2023.2) November 1, 2023
Chapter 1
Introduction
Synthesis is the process of transforming a Register Transfer Level (RTL) specified design into a
gate-level representation. AMD Vivado™ synthesis is timing-driven and optimized for memory
usage and performance. Vivado synthesis supports a synthesizeable subset of:
In most instances, the Vivado tools also support Xilinx design constraints (XDC), which is based
on the industry-standard Synopsys design constraints (SDC).
IMPORTANT! Vivado synthesis does not support UCF constraints. Migrate UCF constraints to XDC
constraints. For more information, see ISE to Vivado Design Suite Migration Guide (UG911).
• Use Project Mode, selecting options from the Vivado Integrated Design Environment (IDE).
• Use Non-Project Mode, applying Tool Command Language (Tcl) commands or scripts and
controlling your own design files.
See the Vivado Design Suite User Guide: Design Flows Overview (UG892) for more information
about operation modes. This chapter covers both modes in separate subsections.
• Hardware, IP, and Platform Development: Creating the PL IP blocks for the hardware
platform, creating PL kernels, functional simulation, and evaluating the AMD Vivado™ timing,
resource use, and power closure. Also involves developing the hardware platform for system
integration. Topics in this document that apply to this design process include:
Chapter 2
Vivado Synthesis
Synthesis Methodology
The AMD Vivado™ IDE includes a synthesis and implementation environment that facilitates a
push button flow with synthesis and implementation runs. The tool manages the run data
automatically, allowing repeated run attempts with varying RTL source versions, target devices,
synthesis or implementation options, and physical or timing constraints.
• Create and save a strategy. A strategy is a configuration of command options that you can
apply to design runs for synthesis or implementation. See Creating Run Strategies.
• Queue the synthesis and implementation runs to launch sequentially or simultaneously with
multi-processor machines. See Running Synthesis.
• Monitor synthesis or implementation progress, view log reports, and cancel runs. See
Monitoring the Synthesis Run.
Using Synthesis
This section describes using the AMD Vivado™ IDE to set up and run Vivado synthesis. The
corresponding Tcl Console commands follow most Vivado IDE procedures, and most Tcl
commands link directly to the Vivado Design Suite Tcl Command Reference Guide (UG835).
Additionally, there is more information regarding Tcl commands and using Tcl in the Vivado Design
Suite User Guide: Using Tcl Scripting (UG894).
VIDEO: See the following for more information: Vivado Design Suite QuickTake Video: Synthesis Options
and Vivado Design Suite QuickTake Video: Synthesizing the Design.
2. Under the Constraints section of the Settings dialog box, select the Default Constraint Set as
the active constraint set; a set of files containing design constraints captured in Xilinx design
constraints (XDC) files that you can apply to your design. The two types of design constraints
are:
• Physical constraints: These constraints define pin placement and absolute, or relative,
placement of cells such as block RAMs, LUTs, Flip-Flops, and device configuration settings.
• Timing constraints: These constraints define the frequency requirements for the design.
Without timing constraints, the Vivado Design Suite optimizes the design solely for wire
length and placement congestion.
See Vivado Design Suite User Guide: Using Constraints (UG903) for more information about
organizing constraints.
New runs use the selected constraint set, and the Vivado synthesis targets this constraint set
for design changes.
3. From the Options area: Select a Strategy from the drop-down menu where you can view and
select a predefined synthesis strategy to use for the synthesis run. There are different
preconfigured strategies, as shown in the following figure.
You can also define your own strategy. When you select a synthesis strategy, the available
Vivado strategy displays in the dialog box. You can override synthesis strategy settings by
changing the option values described in Creating Run Strategies.
For a list of all the strategies and their respective settings, see the directive option in the
following list and see Vivado Preconfigured Strategies to see a matrix of strategy default
settings.
4. Select from the displayed options:
• flatten_hierarchy: Determines how Vivado synthesis controls hierarchy.
• none: Instructs the synthesis tool to never flatten the hierarchy. The output of
synthesis has the same hierarchy as the original RTL.
• full: Instructs the tool to fully flatten the hierarchy leaving only the top level.
• rebuilt: When set, rebuilt allows the synthesis tool to flatten the hierarchy, perform
synthesis, and rebuild the hierarchy based on the original RTL. This value allows the
QoR benefit of cross-boundary optimizations, with a final hierarchy that is similar to the
RTL for ease of analysis.
• gated_clock_conversion: Turns on and off the ability of the synthesis tool to convert the
clocked logic with enables.
The use of gated clock conversion also requires using an RTL attribute to work. See
GATED_CLOCK, for more information.
• bufg: Controls how many BUFGs the tool infers in the design. The Vivado design tools use
this option when other BUFGs in the design netlists are not visible to the synthesis
process.
The tool infers up to the amount specified, and tracks how many BUFGs are instantiated
in the RTL. For example, if the -bufg option is set to 12, and there are three BUFGs
instantiated in the RTL, the Vivado synthesis tool infers up to nine more BUFGs.
• directive: Replaces the -effort_level option. When specified, this option runs Vivado
synthesis with different optimizations. See Vivado Preconfigured Strategies for a list of all
strategies and settings. Values are:
• Default: Default settings. See Vivado Preconfigured Strategies.
• RuntimeOptimized: Performs fewer timing optimizations and eliminates some RTL
optimizations to reduce synthesis runtime.
• AreaOptimized_high: Performs general area optimizations, including forcing ternary
adder implementation, applying new thresholds for using carry chain in comparators,
and implementing area-optimized multiplexers.
• AreaOptimized_medium: Performs general area optimizations, including changing the
threshold for control set optimizations, forcing ternary adder implementation, lowering
multiplier threshold of inference into DSP blocks, moving shift register into block RAM,
applying lower thresholds for use of CARRY chain in comparators, and also area
optimized MUX operations.
• AlternateRoutability: Set of algorithms to improve route-ability (less use of MUXFs and
CARRYs)
• AreaMapLargeShiftRegToBRAM: Detects large shift registers and implements them
using dedicated block RAM.
• AreaMultThresholdDSP: Lower threshold for dedicated DSP block inference.
• FewerCarryChains: Higher operand size threshold to use LUTs instead of the carry
chain.
• LogicCompaction: Arranges CARRY chains and LUTs in such a way that it makes the
logic more compact using fewer SLICES. This could have a negative effect on timing
QoR.
• PerformanceOptimized: Performs general timing optimizations, including logic level
reduction at the expense of area.
• PowerOptimized_high: Performs general timing optimizations including logic level
increase at the expense of area.
• PowerOptimized_medium: Performs general timing optimizations by lowering logic
level reduction at the expense of area.
• retiming: For non-AMD Versal™ devices only. For controlling retiming in Versal, select the
-no_retiming option. This boolean option <on|off> provides an option to perform for
intra-clock sequential paths by automatically moving registers (register balancing) across
combinatorial gates or LUTs. It maintains the original behavior and latency of the circuit
and does not require changes to the RTL sources. The default is off.
Note: When retiming in OOC mode, registers that are driven by or that are driving ports are not
retimed.
• no_retiming: This is for Versal devices only. In Versal, retiming is turned on by default. Use
this boolean option <on|off> to turn off retiming. This has no effect on non-Versal devices.
• fsm_extraction: Controls how synthesis extracts and maps finite state machines.
FSM_ENCODING describes the options in more detail.
• keep_equivalent_registers: Prevents merging of registers with the same input logic.
• resource_sharing: Sets the sharing of arithmetic operators between different signals. The
values are auto, on, and off. The auto value sets performing resource sharing depend on
the timing of the design.
• control_set_opt_threshold: Sets the threshold for the clock to enable optimization to the
lower number of control sets. The default is auto which means the tool chooses a value
based on the device being targeted. Any positive integer value is supported.
The given value is the number of fanouts necessary for the tool to move the control sets
into the D logic of a register. If the fanout is higher than the value, the tool attempts to
have that signal drive the control_set_pin on that register.
• no_lc: When checked, this option turns off LUT combining.
• no_srlextract: When checked, this option turns off SRL extraction for the full design so
that they are implemented as simple registers.
• shreg_min_size: Is the threshold for inference of SRLs. The default setting is 3. This sets
the number of sequential elements that would result in the inference of an SRL for fixed
delay chains (static SRL). Strategies define this setting as 5 and 10 also. See Vivado
Preconfigured Strategies for a list of all strategies and settings.
• max_bram: Describes the maximum number of block RAM allowed in the design. Often
this is used when there are black boxes or third-party netlists in the design and allow the
designer to save room for these netlists.
Note: The default setting of -1 indicates that the tool chooses the maximum number allowed for the
specified part.
• max_uram: Sets the maximum number of UltraRAM (AMD UltraScale+™ device block
RAMs) blocks allowed in design. The default setting of -1 indicates that the tool chooses
the maximum number allowed for the specified part.
• max_dsp: Describes the maximum number of block DSP allowed in the design. Often this
is used when there are black boxes or third-party netlists in the design and allows room for
these netlists. The default setting of -1 indicates that the tool chooses the maximum
number allowed for the specified part.
• max_bram_cascade_height: Controls the maximum number of block RAM that can be
cascaded by the tool. The default setting of -1 indicates that the tool chooses the
maximum number allowed for the specified part.
• max_uram_cascade_height: Controls the maximum number of UltraScale+ device
UltraRAM blocks that can be cascaded by the tool. The default setting of -1 indicates that
the tool chooses the maximum number allowed for the specified part.
• cascade_dsp: Controls how adders in sum DSP block outputs are implemented. By default,
the sum of the DSP outputs is computed using the block built-in adder chain. The value
tree forces the sum to be implemented in the fabric. The values are auto, tree, and force.
The default is auto.
• no_timing_driven: (Optional) Disables the default timing-driven synthesis algorithm. This
results in a reduced synthesis runtime, but ignores the effect of timing on synthesis.
• sfcu: Run synthesis in single-file compilation unit mode.
• assert: Enable VHDL assert statements to be evaluated. A severity level of failure or error
stops the synthesis flow and produces an error. A severity level of warning generates a
warning.
• debug_log: Prints out extra information in the synthesis log file for debugging purposes.
The -debug_log should be added to the More Options field.
• The tcl.pre and tcl.post options are hooks for Tcl files that run immediately before and
after synthesis.
Note: Paths in the tcl.pre and tcl.post scripts are relative to the associated run directory of
the current project: <project>/<project.runs>/<run_name>.
See Vivado Design Suite User Guide: Using Tcl Scripting (UG894) for more information about
Tcl scripting.
Use the DIRECTORY property of the current project or current run to define the relative
paths in your scripts.
5. Click Finish.
VIDEO: See the following for more information: Vivado Design Suite QuickTake Video: Creating and
Managing Runs.
Select Settings from the Flow Navigator, select Synthesis, and select a Strategy from the
Strategy drop-down list, shown in previous figure, and click OK.
1. From the File menu or the Flow Navigator, select the Add Sources command to open the Add
Sources wizard, shown in the following figure.
Chapter 4: Using Block Synthesis Strategies describes the available Block Synthesis
Strategies.
IMPORTANT! Vivado Design Suite does not support the UCF format. See ISE to Vivado Design Suite
Migration Guide (UG911) for the UCF to XDC conversion procedure.
The Vivado tools automatically identify and set the best top-module candidate, and
automatically manage the compile order. The top-module file and all sources that are under the
active hierarchy are passed to synthesis and simulation in the correct order.
In the Sources window, a pop-up menu provides the Hierarchy Update command. The provided
options specify to the Vivado IDE how to handle changes to the top module and to the source
files in the design.
The default setting, Automatic Update and Compile Order, specifies that the tool manages the
compilation order as shown in the Compilation Order window, and shows which modules are
used and where they are in the hierarchy tree in the Hierarchy window.
To modify the compile order before synthesis, select a file, and right-click Hierarchy Update >
Automatic Update, Manual Compile Order so that the Vivado IDE can automatically determine
the best top module for the design and allows for manual specification of the compilation order.
Manual Compile is off by default. If you select a file and move it in the Compile Order window, a
popup menu asks if you want Manual Compile turned on, as shown in the following figure.
From the Sources window Compile order tab, drag, and drop files to arrange the compilation
order, or use the menu Move Up or Move Down commands.
Other options are available from the Hierarchy Update context menu, as shown in the following
figure.
See Vivado Design Suite User Guide: Design Flows Overview (UG892) for information about design
flows.
TIP: In Verilog, reference header files that are specifically applied to a single Verilog source (for
example; a particular `define macro), with an `include statement instead of marking it as a
global `include file.
See Vivado Design Suite User Guide: Using the Vivado IDE (UG893), for information about the
Sources window.
RTL Linter
Vivado Synthesis comes with an RTL linter that can analyze your code to determine if there are
any code segments that, while legal, could cause issues with your design.
The second way is with the IDE. In the RTL ANALYSIS section of the Project Manager, there is a
Run Linter button that will run the Linter with the current part and top level.
Note: The RTL linter currently does not work on OOC modules. This will be supported in a later release.
Linter Output
After running the linter, the tool will create a new tab with the results.
Figure 4: Linter
The output will have a Rule ID, the RTL name of the signal or port with the problem, the
hierarchy where this is found, and a message and file name of the potential problem. In the
previous figure, there is a port called “in3” in test.v, that is never used.
Stop reporting on any ASSIGN-1 issues in the x/y hierarchy. Waivers can use the following
options in any combination.
One you get the correct waivers for your design, you can write these to a Tcl file for future use in
your flow:
Running Synthesis
A run defines and configures aspects of the design that are used during synthesis. A synthesis
run defines the following:
1. Select Flow > Create Runs, or in Design Runs, click the Create Runs button to open the
Create New Runs wizard. The Create New Runs dialog box opens, as shown in the following
figure.
3. Click the Add button and configure the synthesis run with the Name, Constraints Set, Part,
Strategy, and check Make Active, if you want this run to be the active run.
The Vivado IDE contains a default strategy. You can set a specific name for the strategy run
or accept the default name(s), which are numbered as synth_1, synth_2, and so forth. To
create your own run strategy, see Creating Run Strategies.
5. In the Launch Options page, set the options as follows, click Next.
• In the Launch Directory drop-down option, browse to and select the directory from which
to launch the run.
• In the Options area, choose one of the following:
• Launch runs on local host: Runs the options from the machine on which you are
working. The Number of jobs drop-down lets you specify how many runs to launch.
Note: The number of jobs can significantly affect the amount of memory used by the Vivado
tool. Turning this to a very high number could cause the tool to take up large amounts of
memory depending on the sizes of the individual runs or OOC runs in the design. Using too
much memory could lead to crashes in the tool.
• Launch runs on remote hosts (Linux only): Launches the runs on a remote host and
configures that host. See Vivado Design Suite User Guide: Implementation (UG904), for
more information about launching runs on remote hosts in Linux. Use the Configure
Hosts button to configure the hosts from the dialog box.
• Launch runs on cluster: Launches the runs on an external tool such as lsf. Hitting the
settings button allows the configuration of that cluster tool.
• Generate scripts only: Generates scripts to run later. Use runme.bat (Windows) or
runme.sh (Linux) to start the run.
6. After setting the Create New Runs wizard option, click Finish in the Launch Runs summary.
You can see the results in the Design Runs window, as shown in the following figure.
If the Design Runs window is not already displayed, select Window > Design Runs to open the
Design Runs window. A synthesis run can have multiple implementation runs. Use the tree
widgets in the window to expand, and collapse synthesis runs. The Design Runs window reports
the run status (when the run is not started, is in progress, is complete, or is out-of-date). Runs
become out-of-date when you modify source files, constraints, or project settings.
To reset, delete, or change properties on specific runs, right-click the run and select the
appropriate command.
To make a run active, select the run in the Design Runs window, right-click, and select the Make
Active command from the pop-up menu to set it as the active run.
The first two options start the active synthesis run. The third option opens the Launch Selected
Runs window.
Here, you can select to run on local host, run on a remote host, or generate the scripts to be run.
See Vivado Design Suite User Guide: Implementation (UG904), for more information about using
remote hosts.
• Lower OOC modules run separately from the top level and have their own constraints.
• OOC modules can be run as needed.
• After you have run synthesis on an OOC module, it does not need to be rerun unless you
change the RTL or constraints for that run.
• When the top level is run, the lower level OOC runs are treated as black boxes.
If any IP is synthesized in OOC mode, the top-level synthesis run infers a black box for these IP.
Hence, users cannot reference objects, such as pins, nets, and cells, internal to the IP as part of
the top-level synthesis constraints. During implementation, the netlists from the IP DCPs are
linked with the netlist produced when synthesizing the top-level design files, and the Vivado
Design Suite resolves the IP black boxes. The IP XDC output products generated during
implementation are applied along with any user constraints. If any constraints reference items
inside the IP, there are warnings during synthesis about this, but they can be resolved during
implementation.
This can result in a large runtime improvement for the top level because synthesis no longer
needs to improve for the top level because synthesis no longer needs to be run on the full design.
To set up a module for an OOC run, find that module in the hierarchy view, and right-click the
Set As Out-Of-Context for Synthesis option, shown in the following figure, and click OK.
The Set as Out-of-Context for Synthesis dialog box displays the following information and
options:
• New Fileset: Lists the New Fileset name, which you can edit.
• Generate Stub: A checkbox that you can check to have the tool create a stub file.
• Clock Constraint File: Choose to have the tool create a new XDC template for you, or you can
use the drop-down menu to copy an existing XDC file to this Fileset. This XDC file should
have clock definitions for all your clock pins on the OOC module.
RECOMMENDED: Leave the stub file option on. If you turn it off, you must create and set your stub files
in the project.
The tool sets up the OOC to run automatically. As shown in the following figure, you can see it as
a new run in the Design Runs window and as a block source in the Compile Order tab.
When you set a flow to Out-of-Context, a new run is set up in the tool.
To run the option, right-click and select Launch Runs, described in Launching a Synthesis Run.
This action sets the lower level as a top module and runs synthesis on that module without
creating I/O buffers.
The run saves the netlist from synthesis and creates a stub file (if you selected that option) for
later use. The stub file is the lower level with inputs and outputs and the black-box attribute set.
When you rerun the top-level module, the bottom-up synthesis inserts the stub file into the flow
and compiles the lower level as a black box. The implementation run inserts the lower-level
netlist, thus completing the design.
CAUTION! Do not use the Bottom-Up OOC flow when there are AMD IP in OOC mode in the lower levels
of the OOC module. To have AMD IP in an OOC module, turn off the IP OOC mode. Do not use this flow
when there are parameters on the OOC module or the ports of the OOC module are user-defined types.
Those circumstances cause errors later in the flow.
IMPORTANT! Vivado synthesis does not synthesize or optimize encrypted or non-encrypted synthesized
netlists; consequently, XDC constraints or synthesis attributes do not affect synthesis with an imported
core netlist. Also, Vivado synthesis does not read the core netlist and modify the instantiated components
by default; however, Vivado synthesis does synthesize secure IP and RTL. Constraints do affect synthesis
results.
In the More Options section, you can type -mode out_of_context to have the tool not
insert any I/O buffers in this level.
After you run synthesis, open the synthesized design and in the Tcl Console, type the
write_edif Tcl command in the Tcl Console. The syntax is as follows:
write_edif <design_name>.edf
IMPORTANT! The port names provided to the Vivado tool and the port names in the netlist must match.
In VHDL, describe the ports with a component statement, as shown in the following code
snippet:
component <name>
port (in1, in2 : in std_logic;
out1 : out std_logic);
end component;
Because Verilog does not have an equivalent of a component, use a wrapper file to communicate
the ports to the Vivado tool. The wrapper file looks like a typical Verilog file, but contains only
the ports list, as shown in the following code snippet:
In both modes, the Vivado tool merges the netlist after synthesis.
Note: If a design is from third-party netlists only, and no other RTL files are meant to be part of the project,
you can either create a project with those netlists, or you can use the read_edif and read_verilog Tcl
commands along with the link_design Tcl command in Non-Project Mode.
Incremental Synthesis
Vivado Synthesis can be run incrementally. In this flow, the tool puts incremental synthesis info in
the generated DCP file that can be referenced in later runs. It detects when the design has
changed and only re-runs synthesis on sections of the design that have changed. The key
advantage of this flow is that the runtime is significantly reduced for designs with small changes.
In addition, the QoR of the design fluctuates less when small changes are inserted into the RTL.
• Incremental Synthesis selection box: Use the Browse button to indicate if incremental
synthesis uses a known checkpoint, the last checkpoint created (default), or if incremental
synthesis is disabled.
Or
Note: The -auto_incremental option in read_checkpoint is the same as the default behavior in the
IDE.
This information is in the “Incremental Synthesis Report Summary.” The following is an example
of the report.
This section has information on which sections of the design changed and needed to be re-
synthesized. In addition, it also has information on how much of the design changed from
reference run to incremental run.
In addition, unusually large XDC files can trigger a re-synthesis of the full design. This improves in
future releases.
Note: Even though it is a Synthesis setting, -mode out_of_context does not trigger a full re-synthesis.
Note: Even though this is a synthesis setting, -mode out_of_context does not trigger a full resynthesis.
Most AMD-delivered IP has HDL that is encrypted with IEEE P1735, and no support is available
for third-party synthesis tools for AMD IP.
To instantiate AMD IP that is delivered with the Vivado IDE inside of a third-party synthesis tool,
the following flow is recommended:
• Open Synthesized Design: Opens the synthesized netlist, the active constraint set, and the
target device into a Synthesized Design environment so that you can perform I/O pin
planning, design analysis, and floorplanning.
• View Reports: Opens the Reports window so you can view reports.
• Don’t show this dialog again: Use the checkbox to stop this dialog box display.
TIP: You can revert to having the dialog box present by selecting Tools → Settings → Window Behavior.
VIDEO: See the following for more information: Vivado Design Suite QuickTake Video: Advanced Synthesis
using Vivado.
Open the Reports view, shown in the following figure, and select a report for a specific run.
To open a synthesized design, select Open Synthesized Design from the Flow Navigator or the
Flow menu.
With a synthesized design open, the Vivado IDE opens a Device window, as shown in the
following figure.
From this perspective, you can examine the design logic and hierarchy, view the resource usage
and timing estimates, or run design rule checks (DRCs). For more information, see the Vivado
Design Suite User Guide: Design Analysis and Closure Techniques (UG906)
• The Netlist and Hierarchy windows contain a navigable hierarchical tree-style view.
• The Schematic window allows selective logic expansion and hierarchical display.
• The Device window provides a graphical view of the device, placed logic objects, and
connectivity.
As you select logic objects in other windows, the Netlist window expands automatically to
display the selected logic objects, and the information about instances or nets displays in the
Instance or Net Properties windows.
The Synthesized Design window displays a graphical representation of the RTL logic hierarchy.
Each module is sized in relative proportion to the others, so you can determine the size and
location of any selected module.
To open the Hierarchy window, in the Netlist window, right-click to bring up the context menu.
Select Show Hierarchy, as shown in the following figure. Also, you can press F6 to open the
Hierarchy window.
In the Schematic window, view, and select any logic. You can display groups of timing paths to
show all of the instances on the paths. This aids floorplanning because it helps you visualize
where the timing critical modules are in the design.
To open the Schematic window, select one or more instances, nets, or timing paths, and select
Schematic from the window toolbar or the right-click menu, or press the F4 key.
The window opens with the selected logic displayed, as shown in the following figure.
You can select and expand the logic for any pin, instance, or hierarchical module.
As more physical constraints, such as Pblocks and LOC constraints, are assigned in the design,
the results of the timing analysis become more accurate, although these results still contain some
estimation of path delay. The synthesized design uses an estimate of routing delay to perform
analysis.
You can run timing analysis at this level to ensure that the correct paths are covered and for a
more general idea of timing paths.
IMPORTANT! Only timing analysis after implementation (place and route) includes the actual delays for
routing. Running timing analysis on the synthesized design is not as accurate as running timing analysis on
an implemented design.
In this example, synth_design is run with the -part option and the -top option.
In the Tcl Console, you can set synthesis options and run synthesis using Tcl command options.
To retrieve a list of options, type synth_design -help in the Tcl Console. The following
snippet is an example of the -help output: synth_design -help.
Description:
Synthesize a design using Vivado Synthesis and open that design
Syntax:
synth_design [-name <arg>] [-part <arg>] [-constrset <arg>] [-top <arg>]
[-include_dirs <args>] [-generic <args>] [-
verilog_define <args>]
[-flatten_hierarchy <arg>] [-gated_clock_conversion
<arg>]
[-directive <arg>] [-rtl] [-bufg <arg>] [-no_lc]
[-shreg_min_size <arg>] [-mode <arg>]
[-fsm_extraction <arg>][-rtl_skip_mlo][-rtl_skip_ip]
[-rtl_skip_constraints]
[-keep_equivalent_registers] [-resource_sharing <arg>]
[-cascade_dsp <arg>] [-control_set_opt_threshold <arg>]
[-max_bram <arg>] [-max_uram <arg>]
[-max_dsp <arg>] [-max_bram_cascade_height <arg>]
[-max_uram_cascade_height <arg>] [-retiming] [-
no_retimimg]
[-no_srlextract]
[-assert] [-no_timing_driven] [-sfcu] [-debug_log] [-
quiet] [-verbose]
Returns:
design object
Usage:
Name Description
----------------------------------------------------------------------------
--------------------
[-name] Design name
[-part] Target part
[-constrset] Constraint fileset to use.
[-top] Specify the top module name.
[-include_dirs] Specify verilog search directories.
[-generic] Specify generic parameters. Syntax: -generic
<name>=<value> -generic <name>=<value> ...
[-verilog_define] Specify verilog defines. Syntax:
-verilog_define <macro_name>[=<macro_text>]
-verilog_define <macro_name>[=<macro_text>]
For the -generic option, special handling needs to happen with VHDL boolean and
std_logic_vector type because those type do not exist in other formats. Instead of TRUE,
FALSE, or 0010, for example, Verilog standards should be given.
-generic my_gen=1‘b0
-generic my_gen=4‘b0010
Note: If you are using the -mode out_of_context option on the top-level, do not use the
PACKAGE_PIN property unless there is an I/O buffer instantiated in the RTL. The out_of_context
option tells the tool to not infer any I/O buffers including tristate buffers. Without the buffer, you get
errors in placer.
A verbose version of the help is available in the Vivado Design Suite Tcl Command Reference Guide
(UG835). To determine any Tcl equivalent to a Vivado IDE action, run the command in the Vivado
IDE and review the content in the Tcl Console or the log file.
The maximum number of simultaneous threads varies, depending on the number of processors
available on the system, the OS, and the stage of the flow (see Vivado Design Suite User Guide:
Implementation (UG904)).
The general.maxThreads Tcl parameter, which is common to all threads in Vivado, gives you
control to specify the number of threads to use when running RTL synthesis. For example:
Where the <new limit> must be an integer from 1 to 8 inclusive. For RTL synthesis, 4 is the
maximum number of threads that can be set effectively.
Setting Constraints
The following table shows the supported Tcl commands for Vivado timing constraints. The commands are linked to more information
to the full description in the Vivado Design Suite Tcl Command Reference Guide (UG835).
Chapter 3
Synthesis Attributes
Introduction
In the AMD Vivado™ Design Suite, Vivado synthesis can synthesize attributes of several types. In
most cases, these attributes have the same syntax and behavior.
• If Vivado synthesis supports the attribute. It uses the attribute and creates a logic that reflects
the used attribute.
• If the specified attribute is not recognized by the tool, the Vivado synthesis passes the
attribute and its value to the generated netlist.
It is assumed that a tool later in the flow can use the attribute. For example, the LOC constraint is
not used by synthesis. Still, the constraint is used by the Vivado placer and is forwarded by
Vivado synthesis.
Supported Attributes
ASYNC_REG
The ASYNC_REG is an attribute that affects many processes in the Vivado tools flow. The
purpose of this attribute is to inform the tool that a register is capable of receiving asynchronous
data in the D input pin relative to the source clock, or that the register is a synchronizing register
within a synchronization chain. The Vivado synthesis, when encountering this attribute treats it
as a DONT_TOUCH attribute and pushes the ASYNC_REG property forward in the netlist. This
process ensures that the object with the ASYNC_REG property is not optimized out, and that
tools later in the flow receive the property to handle it correctly.
For information on how other Vivado tools handle this attribute, see Vivado Design Suite
Properties Reference Guide (UG912).
You can place this attribute on any register; values are FALSE (default) and TRUE . This attribute
can be set in the RTL or the XDC.
IMPORTANT! Care should be taken when putting this attribute on loadless signals. The attribute and
signal might not be preserved. Attributes are case-insensitive, regardless of HDL.
BLACK_BOX
The BLACK_BOX attribute is a useful debugging attribute directs synthesis to create a black box
for that module or entity. When the attribute is found, even if there is valid logic for a module or
entity, Vivado synthesis creates a black box for that level. This attribute can be placed on a
module, entity, or component. Because this attribute affects the synthesis compiler, it can only be
set in the RTL.
IMPORTANT! In the Verilog example, no value is needed. The presence of the attribute creates the black
box.
For more information regarding coding style for Black Boxes, see Black Boxes.
CASCADE_HEIGHT
The CASCADE_HEIGHT attribute is an integer used to describe the length of the cascade chains
of large RAMS that are put into block RAMs. When a RAM that is larger than a single block RAM
is described, the Vivado synthesis tool determines how it must be configured.
Often, the tool chooses to cascade the block RAMs that it creates. This attribute can be used to
shorten the length of the chain. Place the attribute on the RAM in question, and you can place
the attribute in the RTL files. A value of 0 or 1 for this attribute effectively turns off any
cascading of block RAMs.
Note: This attribute is only applicable to AMD UltraScale™ and AMD Versal™ architecture block RAMs and
URAMs (UltraRAMs).
CLOCK_BUFFER_TYPE
Apply CLOCK_BUFFER_TYPE on an input clock to describe what type of clock buffer to use.
By default, Vivado synthesis uses BUFGs for clock buffers. Supported values are "BUFG",
"BUFH", "BUFIO", "BUFMR", "BUFR" or "none". The CLOCK_BUFFER_TYPE attribute can be
placed on any top-level clock port. It can be set in the RTL and XDC.
DIRECT_ENABLE
Apply DIRECT_ENABLE on an input port or other signal to have it go directly to the enable line
of a flop when there is more than one possible enable, or when you want to force the synthesis
tool to use the enable lines of the flop.
Note: For XDC usage, this attribute only works on type net, so you must use the get_nets command for
the object.
DIRECT_RESET
Apply DIRECT_RESET on an input port or other signal to have it go directly to the reset line of a
flop when there is more than one possible reset or when you want to force the synthesis tool to
use the reset lines of the flop.
end test;
Note:
For XDC usage, this attribute only works on type net, so you need to use the get_nets command for the
object.
DONT_TOUCH
Use the DONT_TOUCH attribute in place of KEEP or KEEP_HIERARCHY . The DONT_TOUCH
works in the same way as KEEP or KEEP_HIERARCHY attributes; however, unlike KEEP and
KEEP_HIERARCHY , DONT_TOUCH is forward-annotated to place and route to prevent logic
optimization.
CAUTION! Like KEEP and KEEP_HIERARCHY , be careful when using DONT_TOUCH . In cases where
other attributes conflict with DONT_TOUCH , the DONT_TOUCH attribute takes precedence.
The values for DONT_TOUCH are TRUE/FALSE or yes/no . You can place this attribute on any
signal, module, entity, or component.
Note: The DONT_TOUCH attribute is not supported on the port of a module or entity. If specific ports are
needed to be kept, either use the -flatten_hierarchy none setting or put a DONT_TOUCH on the module/
entity itself.
In general, the DONT_TOUCH attribute should be set in RTL only. Signals that need to be kept can
often be optimized before the XDC file is read. Therefore, setting this attribute in the RTL
ensures that it is used. There is one use case where it is recommended that DONT_TOUCH is set
in the XDC file. This would be when DONT_TOUCH is set to yes in the RTL, and it is desired to be
taken out without having to change the RTL. In this case, setting DONT_TOUCH to no in XDC
when that same signal has DONT_TOUCH set to yes in RTL effectively removes that attribute
without having to change the RTL.
Note: When using the XDC to remove a DONT_TOUCH that is set in RTL, you can end up getting warnings
after synthesis when the implementation flow reads the same XDC but the signal in question has been
optimized out. These warnings can be ignored. However, you can also bypass them by putting the
DONT_TOUCH attributes in an XDC file marked as for synthesis only.
DSP_FOLDING
The DSP_FOLDING attribute controls whether the Vivado synthesis folds two MAC structures
connected with an adder into one DSP primitive.
DSP_FOLDING_FASTCLOCK
The DSP_FOLDING_FASTCLOCK attribute tells the tool which port should become the new
faster clock when using DSP folding.
• yes: The tool uses this port to connect to the new clock.
DSP_FOLDING_FASTCLOCK is supported in RTL only. Place this attribute only on a port or a pin.
EXTRACT_ENABLE
EXTRACT_ENABLE controls whether registers infer enables. Typically, the Vivado tools extract or
not extract enables based on heuristics that typically benefit the most amount of designs. In
cases where Vivado is not behaving in a desired way, this attribute overrides the default behavior
of the tool.
If there is an undesired enable going to the CE pin of the flip-flop, this attribute can force it to the
D input logic. Conversely, if the tool is not inferring an enable that is specified in the RTL, this
attribute can tell the tool to move that enable to the CE pin of the flip-flop.
EXTRACT_ENABLE is placed on the registers and is supported in RTL and XDC. It can take
boolean values of: yes and no.
EXTRACT_RESET
EXTRACT_RESET controls if registers infer resets. Typically, the Vivado tools extract or not
extract resets based on heuristics that typically benefit the most designs. In cases where Vivado
is not behaving in a desired way, this attribute overrides the default behavior of the tool. If an
undesired synchronous reset goes to the flip-flop, this attribute can force it to the D input logic.
Conversely, if the tool is not inferring a reset specified in the RTL, this attribute can command the
tool to move that reset to the dedicated reset of the flop. This attribute can only be used with
synchronous resets; asynchronous resets are not supported.
EXTRACT_RESET is placed on the registers and supported in the RTL and XDC. It can take the
boolean values: yes or no. A value of no means that the reset does not go to the R pin of the
register but is routed through logic to the D pin of the register. A value of yes means that the
reset goes directly to the R pin of the register.
FSM_ENCODING
FSM_ENCODING controls encoding on the state machine. Typically, the Vivado tools choose an
encoding protocol for state machines based on heuristics that do the best for the most designs.
Certain design types work better with a specific encoding protocol.
FSM_ENCODING can be placed on the statemachine registers. The legal values for this are
one_hot, sequential, johnson, gray, user_encoding, and none. The auto value is the
default, and allows the tool to determine best encoding. The user_encoding value tells the
tool to still infer a statemachine, but to use the encoding given in the RTL by the user.
FSM_SAFE_STATE
FSM_SAFE_STATE instructs Vivado synthesis to insert logic into the state machine that detects
there is an illegal state, puts it into a known, good state on the next clock cycle.
For example, if there were a state machine with a "one_hot" encode, and that is in a "0101"
state (which is an illegal for "one_hot" ), the state machine would be able to recover. Place the
FSM_SAFE_STATE attribute on the state machine registers. You can set this attribute in either
the RTL or in the XDC.
• reset_state: Forces the state machine into the reset state using Hamming-2 encoding
detection for one bit/flip.
• power_on_state: Forces the state machine into the power-on state using Hamming-2
encoding detection for one bit/flip.
• default_state: Forces the state machine into the default state specified in RTL: the state that is
specified in default branch of the case statement in Verilog or the state specified in the
others branch of the case statement in VHDL. For this to work, a default or others
state must be in the RTL.
IMPORTANT! Because this attribute affects the compiler and can change the logical behavior of the
design, it can be set in the RTL only.
GATED_CLOCK
Vivado synthesis allows the conversion of gated clocks. To perform this conversion, use:
• A switch in the Vivado IDE that instructs the tool to attempt the conversion.
• The GATED_CLOCK RTL attribute or XDC property that instructs the tool about which signal
in the gated logic is the clock.
Place this attribute on the signal or port that is the clock. To control the switch:
CAUTION! Care should be taken when using attributes like KEEP_HIERARCHY, DONT_TOUCH, and
MARK_DEBUG. These attributes can interfere with gated clock conversion if placed on hierarchies or
instances that need to change to support the conversion.
IOB
The IOB attribute controls if a register should go into the I/O buffer. The values are TRUE or
FALSE. Place this attribute on the register that you want in the I/O buffer. This attribute can be
set only in the RTL.
IO_BUFFER_TYPE
Apply the IO_BUFFER_TYPE attribute on any top-level port to instruct the tool to use buffers.
Add the property with a value of "NONE" to disable the automatic inference of buffers on the
input or output buffers, which is the default behavior of Vivado synthesis. This attribute is only
supported, and can only be set in the RTL.
KEEP
Use the KEEP attribute to prevent optimizations where signals are either optimized or absorbed
into logic blocks. This attribute instructs the synthesis tool to keep the signal it was placed on,
and that signal is placed in the netlist.
For example, if a signal is an output of a 2-bit AND gate, and it drives another AND gate, the KEEP
attribute can be used to prevent that signal from being merged into a larger LUT that
encompasses both AND gates.
CAUTION! Be careful when using KEEP with other attributes. In cases where other attributes conflict with
KEEP, the attribute usually takes precedence.
KEEP is also commonly used with timing constraints. If there is a timing constraint on a signal
that would generally be optimized, KEEP prevents that and allows the correct timing rules to be
used.
Note: The KEEP attribute is not supported on the port of a module or entity. If you need to keep specific
ports, use the -flatten_hierarchy none setting or put a DONT_TOUCH on the module or entity
itself.
CAUTION! Take care when using KEEP attribute on loadless signals. Synthesis keeps those signals
resulting in issues later in the flow.
Examples are:
• When you have a MAX_FANOUT attribute on one signal and a KEEP attribute on a second
signal that is driven by the first; the KEEP attribute on the second signal would not allow
fanout replication.
• With a RAM_STYLE="block" , when there is a KEEP on the register that would need to
become part of the RAM, the KEEP attribute prevents the block RAM from being inferred.
• FALSE: Allows Vivado synthesis to optimize. The FALSE value does not force the tool to
remove the signal. The default value is FALSE.
RECOMMENDED: Set this attribute in the RTL only. Because signals that need to be kept are often
optimized before the XDC file is read, setting this attribute in the RTL ensures that the attribute is used.
Note: The KEEP attribute does not force the place and route to keep the signal. Instead, this is
accomplished using the DONT_TOUCH attribute.
KEEP_HIERARCHY
KEEP_HIERARCHY is used to prevent optimizations along the hierarchy boundaries. The Vivado
synthesis tool attempts to keep the same general hierarchy specified in the RTL, but for better
Quality of Results (QoR) reasons it can flatten or modify them.
If KEEP_HIERARCHY is placed on the instance, the synthesis tool keeps the boundary on that
level static.
This can affect QoR and also should not be used on modules that describe the control logic of 3-
state outputs and I/O buffers. The KEEP_HIERARCHY can be placed in the module or
architecture level or the instance. This attribute can be set in the RTL and in XDC. If it is used in
the XDC, it can only be put on the instance.
On Module
(* keep_hierarchy = "yes" *) module bottom (in1, in2, in3, in4, out1, out2);
On Instance
On Architecture
On Instance
MARK_DEBUG
This attribute is applicable to net objects. Some nets can have dedicated connectivity or other
aspects that prohibit visibility for debug purposes.
Syntax
Verilog Syntax
To set this attribute, place the proper Verilog attribute syntax on the signal in question:
(* MARK_DEBUG = "{TRUE|FALSE}" *)
VHDL Syntax
To set this attribute, place the proper VHDL attribute syntax on the signal in question.
XDC Syntax
set_property MARK_DEBUG value [get_nets <net_name>]
This recommended use ensures that the MARK_DEBUG goes onto the net connected to that pin,
regardless of its name.
Note: If a MARK_DEBUG is applied on a bit of a signal that was declared as a bit_vector, the whole bus gets
the MARK_DEBUG attribute. In addition, if a MARK_DEBUG is placed on a pin of a hierarchy, the full
hierarchy is kept.
MAX_FANOUT
MAX_FANOUT instructs Vivado synthesis on the fanout limits for registers and signals. You can
specify this either in RTL or as an input to the project. The value is an integer that indicates what
the fanout should be. A value of -1 tells the tool not to perform any replication.
Note: It replicates the register or the driver that drives the combinatorial signal to achieve the fan outputs,
black boxes, EDIF files, and Native Generic Circuit (NGC) files are not supported with this attribute.
RECOMMENDED: Using MAX_FANOUT attributes on global high fanout signals leads to sub-optimal
replication in synthesis. For this reason, AMD recommends only using MAX_FANOUT inside the hierarchies
on local signals with medium to low fanout.
On Signal
Note: This attribute can only be controlled through the Verilog RTL.
RAM_DECOMP
The RAM_DECOMP attribute instructs the tool to infer RTL RAMs that are too large to fit in a
single block RAM primitive to use a more power-friendly configuration.
For example, a RAM specified as 2 K x 36 would often be configured as two 2 K x 18 block RAMs
arranged side by side. This is the configuration that yields the fastest design. By setting
RAM_DECOMP, the RAM would instead be configured as two 1 K x 36 block RAMs. This is more
power-friendly because during a read or write, only the one RAM with the address being used is
active. It comes at the cost of timing because Vivado synthesis must use address decoding. The
RAM_DECOMP would force the second configuration of that RAM.
This attribute can be set in either RTL or XDC. Place the attribute on the RAM instance itself.
RAM_STYLE
RAM_STYLE instructs the Vivado synthesis tool on how to infer memory. Accepted values are:
• ultra: Instructs the tool to use the AMD UltraScale+™ URAM primitives.
• mixed: Instructs the tool to infer a combination of RAM types designed to minimize the
amount of space that is unused.
• auto: Lets the synthesis tool decide how to implement the RAM. This value is mainly used by
XPMs that must choose a value for RAM_STYLE. This is the same as the default behavior. That
must choose a value for RAM_STYLE.
By default, the tool selects which RAM to infer based on heuristics that give the best results for
most designs. Place this attribute on the array declared for the RAM or a hierarchy level.
For more information about RAM coding styles, see RAM HDL Coding Techniques.
RETIMING_BACKWARD
The RETIMING_BACKWARD attribute instructs the tool to move a register backward through
logic closer to the sequential driving elements. Unlike the retiming global setting, this attribute is
not timing-driven and works regardless of whether the retiming global setting is active or if there
are even timing constraints. If the global retiming setting is active, the RETIMING_BACKWARD
step happens first, and the global retiming can enhance that register to move further back the
chain. However, it does not interfere with the attribute and moves the register back to the
original location.
Note: Cells with DONT_TOUCH/MARK_DEBUG attributes, cells with timing exceptions (false_path,
multicycle_path), and user-instantiated cells block this attribute.
The RETIMING_BACKWARD attribute takes an integer as a value. This value describes the
amount of logic the register is allowed to cross. Larger values allow the register to cross more
logic. 0 would turn the attribute off.
RETIMING_FORWARD
The RETIMING_FORWARD attribute instructs the tool to move a register forward through logic
closer to the driven sequential elements. Unlike the retiming global setting, this attribute is not
timing-driven and works regardless of whether the retiming global setting is active or if there are
even timing constraints. If the global retiming setting is active, the RETIMING_FORWARD step
happens first, and the global retiming can enhance that register to move further up the chain.
However, it does not interfere with the attribute and moves the register back to the original
location.
Note: Cells with DONT_TOUCH/MARK_DEBUG attributes, cells with timing exceptions (false_path,
multicycle_path), and user-instantiated cells block this attribute.
The RETIMING_FORWARD attribute takes an integer as a value. This value describes the amount
of logic the register is allowed to cross. Larger values allow the register to cross more logic. 0
would turn the attribute off.
ROM_STYLE
ROM_STYLE instructs the synthesis tool on how to infer constant arrays into memory structures
like Block RAMs. Accepted values are:
• distributed: Instructs the tool to infer the LUT ROMs. Instructs the tool to infer constant
arrays into distributed RAM (LUTRAM) resources. By default, the tool selects which ROM to
infer based on heuristics that give the best results for the most designs.
• ultra: Instructs synthesis to use URAM primitives. (AMD Versal™ adaptive SoC parts only).
For information about coding for ROM, see ROM HDL Coding Techniques.
RW_ADDR_COLLISION
The RW_ADDR_COLLISION attribute is for specific types of RAMs. When RAM is a simple dual
port, and the read address is registered, Vivado synthesis infers a block RAM and sets the write
mode to WRITE_FIRST for best timing. Also, if a design writes to the same address it is reading
from, the RAM output is unpredictable. RW_ADDR_COLLISION overrides this behavior.
• yes: These inserts bypass logic so that when an address is read from the same time it is
written to, the value of the input is seen on the output making the whole array behave as
WRITE_FIRST.
• no: This is when you do not care about timing or the collision possibility. In this case, the write
mode is set to NO_CHANGE , resulting in power savings.
SHREG_EXTRACT
SHREG_EXTRACT instructs the synthesis tool on whether to infer SRL structures. Accepted
values are:
• NO: The does not infer SRLs and instead creates registers.
Place SHREG_EXTRACT on the signal declared for SRL or the module/entity with the SRL. It can
be set in the RTL or the XDC.
SRL_STYLE
SRL_STYLE instructs the synthesis tool on how to infer SRLs found in the design. Accepted
values are:
• register: The tool does not infer an SRL but instead only uses registers.
• srl: The tool infers an SRL without any registers before or after.
• srl_reg: The tool infers an SRL and leaves one register after the SRL.
• reg_srl: The tool infers an SRL and leaves one register before the SRL.
• reg_srl_reg: The tool infers an SRL and leaves one register before and one after the SRL.
Place SRL_STYLE on the signal declared for SRL. This attribute can be set in RTL and XDC. The
attribute can only be used on static SRLs. The indexing logic for dynamic SRLs is located within
the SRL component itself. Therefore, the logic cannot be created around the SRL component to
look up addresses outside of the component.
Note: Use care when using combinations of SRL_STYLE, SHREG_EXTRACT, and -shreg_min_size. The
SHREG_EXTRACT attribute always takes precedence over the others. If SHREG_EXTRACT is set to "no"
and SRL_STYLE is set to "srl", registers are used. The -shreg_min_size, being the global variable,
always has the least amount of precedence. If an SRL of length 10 is set and SRL_STYLE is set to "srl",
and -shreg_min_size is set to 20, the SRL is still inferred.
Note: In the following examples, the SRLs are all created with buses where the SRL shifts from one bit to
the next. If the code to use SRL_STYLE has many differently named signals driving each other, place the
SRL_STYLE attribute on the last signal in the chain. This includes if the last register in the chain is in a
different hierarchy level than the other registers. The attribute always goes on the last register in the chain.
TRANSLATE_OFF/TRANSLATE_ON OFF/ON
TRANSLATE_OFF and TRANSLATE_ON instruct the Synthesis tool to ignore blocks of code.
These attributes are given within a comment in RTL. The comment can start with one of the
following keywords:
• synthesis
• synopsy
• pragma
• xilinx
In newer versions of the tool, using a keyword has become optional. The tool works with
translate_off/on or off/on in the comment.
TRANSLATE_OFF starts the ignore, and it ends with TRANSLATE_ON. These commands cannot
be nested.
CAUTION! Be careful with the types of code that are included between the translate statements. If it is
code that affects the behavior of the design, a simulator could use that code, and create a simulation
mismatch.
USE_DSP
USE_DSP instructs the synthesis tool how to deal with synthesis arithmetic structures. By
default, unless there are timing concerns or threshold limits, synthesis attempts to infer mults,
mult-add, mult-sub, and mult-accumulate type structures into DSP blocks.
Adders, subtracters, and accumulators can go into these blocks also, but by default are
implemented with the logic instead of with DSP blocks. The USE_DSP attribute overrides the
default behavior and force these structures into DSP blocks.
• The "logic" value is used specifically for XOR structures to go into the DSP primitives. For
"logic" , this attribute can be placed on the module/architecture level only.
• The "simd" is used to instruct the tool to put SIMD structures (Single-instruction-multiple-
data) into DSPs. See the templates for examples.
• The "yes" and "no" values instruct the tool to either put the logic into a DSP or not. These
values can be placed in the RTL on signals, architecture, components, entities, and modules.
The priority is:
1. Signals
2. Architectures and components
3. Modules and entities
If the attribute is not specified, the default behavior is for Vivado synthesis to determine the
correct behavior. This attribute can be set in the RTL or the XDC.
CAUTION! When Vivado synthesis encounters unknown attributes, it attempts to forward them to the
synthesis output netlist, but you need to understand the risk. A custom attribute does not stop synthesis
optimizations from occurring, which means that if synthesis can optimize an item with a custom attribute,
it does so, and the attribute is lost.
If you need custom attributes to go through synthesis, you must use the DONT_TOUCH or
KEEP_HIERARCHY attributes to prevent synthesis from optimizing the objects that need the
attributes.
There are two types of objects that can have custom attributes: hierarchies and signals.
When using custom attributes on hierarchies, the -flatten_hierarchy switch must be set to
none or a KEEP_HIERARCHY placed on that level, because synthesis, by default, flattens the
design, optimizes the design, and rebuilds the design.
After a design is first flattened, the custom attribute on the hierarchy is lost.
Be careful while using custom attributes on signals as well. When a custom attribute is seen on a
signal, the synthesis tool attempts to put that attribute on the item; however, this item could be
translated to a register or a net, depending on how the tool evaluates the RTL code. Also, as with
hierarchies, because a signal has a custom attribute, the tool can optimize that signal, and the
attribute is lost. To retain custom attributes on signals with custom attributes, you must place the
DONT_TOUCH or the KEEP attribute on those signals.
Finally, because a signal in RTL could describe both a register and the net coming out of the
register, the synthesis tool checks any items with custom attributes and the DONT_TOUCH
attribute. If the net in question is driven by a register, synthesis copies that custom attribute to
the register and the net because there are multiple ways of using custom attributes. Sometimes,
the attribute is wanted on the register, and sometimes the net.
For example, the KEEP and DONT_TOUCH attributes are not allowed in the XDC.
This is because, at the time the attribute is read from the XDC file, components that have the
KEEP or DONT_TOUCH attribute might have already been optimized and would therefore not
exist at the time the attribute is read. For that reason, those attributes must always be set in the
RTL code. For more information on where to set specific attributes, see the individual attribute
descriptions in this chapter.
Note: At the time the XDC file is read, multi-bit signals exist as single nodes in Synthesis. Because of this,
putting attributes on individual bits of a vector signal puts that attribute on all bits of the signal.
To specify synthesis attributes in XDC, type the following in the Tcl Console:
For example:
In addition, you can set these attributes in the elaborated design, as follows:
1. Open the elaborated design, shown in the following figure, and select the item on which to
place an attribute, using either of the following methods:
• Click the item in the schematic.
• Select the item in the RTL Netlist view, as shown in the following figure.
2. In the Cell Properties window, click the Properties tab, and do one of the following:
• Modify the property.
• If the property does not exist, right-click, select Add Properties, and select the property
from the window that appears, or click the + sign.
This saves the attributes to your current constraint file or creates a new constraint file if one
does not exist.
Note: If the same attribute is put on the same object in both the XDC and in RTL, but the values of the
attributes are different, the XDC attribute is accepted, and the RTL attribute is ignored.
Generally, when an attribute is placed on a hierarchy, it affects only that boundary and not the
items inside that hierarchy. For example, placing a DONT_TOUCH on a specific level affects that
level only, and not the signals inside that level.
There are some exceptions to this rule. These are DSP_FOLDING , RAM_STYLE, ROM_STYLE,
SHREG_EXTRACT, and USE_DSP. When these attributes are placed on a hierarchy, they also
affect the signals inside that hierarchy.
Note: For the Verilog syntax of having the attribute inside block comments, /* attr = value */, this attribute
is attached to the next lexical item after the comment. If the comment is on its own line, the next item in
the RTL, no matter how far down, gets the attribute. If the attribute is specified at the end of the file, the
attribute gets attached to the module.
Chapter 4
Overview
AMD Vivado™ synthesis comes with many strategies and global settings that you can use to
customize how your design is synthesized. This Figure shows the available, pre-defined strategies
in the Synthesis Settings, and Table: Vivado Preconfigured Strategies provides a side-by-side
comparison of the strategy settings.
You can override certain settings, such as -retiming, using attributes or XDC files in the RTL or
XDC files for specific hierarchies or signals. However, in general, options affect the whole design.
As designs become more complex, the application of such settings can limit your design from
reaching its full potential. Certain hierarchies in a design might work better with different options
than others. The following figure shows a medium-sized design that has many different types of
hierarchy.
One option is to synthesize such hierarchies in out of context (OOC) mode; this is effective, but
complicates the design flow. The OOC flow separates the hierarchies that are assigned to be
synthesized in OOC mode, and runs them separately from the other parts of the design. This
means that synthesis runs more than one time per design. Also, the OOC constraints must be
separated from the constraints of the rest of the design, adding even more complexity.
The Block-Level Synthesis flow ( BLOCK_SYNTH ) uses a property that lets you use certain global
settings and strategies on specific levels of hierarchy in a top-down flow that is differs from the
top level of the full design.
Where:
For example:
Set the property to an instance name, and not on an entity or module name. By using instance
names, the Vivado synthesis tool is able to have more flexibility when there are modules/entities
that are instantiated multiple times. In the provided example, the fftEngine instance is being set,
so there are no LUT5 or LUT6 primitives.
Note: By setting a BLOCK_SYNTH on an instance, you affect that instance and everything below that
instance. For example, if fftEngine had other modules instantiated within it, those modules would also
not have any LUT5s or LUT6s primitives.
Note: In addition to affecting this instance, the BLOCK_SYNTH property also causes the hierarchy of this
instance to be hardened. Be careful with this, especially if this hierarchy contains I/O buffers or is inferring
input/output buffers.
When you put a BLOCK_SYNTH property on an instance, the instance gets that value for that
specific option; all other options use the default values.
Multiple BLOCK_SYNTH properties can be set on the same instance to try out different
combinations. For example, the following keeps equivalent registers, disables the FSM inference,
and uses the AlternateRoutability strategy:
To prevent impacting instances under the instance that require a different property setting, you
can nest BLOCK_SYNTH properties on multiple levels. If you only want this on one particular
level, you can set it on that level, and on the subsequent levels, you can set the default values
back, using the command as follows:
If the new level is the only hierarchy under fftEngine, this command ensures that only
fftEngine gets the MAX_LUT_INPUT = 4 property. You can also put an entirely different set
of options on this level as well, and not go back to the default.
Note: When performing the block level flow, the tool keeps this design in a top-down mode meaning that
the full design goes through synthesis. For the instance in question, Vivado synthesis preserves the
hierarchy to ensure that the logic of that level does not blur and stays within that level. This could have a
potential effect on QoR. For this reason, be careful when setting BLOCK_LEVEL properties. Only set them
on instances you know need them.
The following table lists the supported Vivado Block synthesis settings.
Chapter 5
Introduction
Hardware Description Language (HDL) coding techniques let you:
Coding examples are included in this chapter. Download the coding example files from Coding
Examples .
Advantages of VHDL
• Enforces stricter rules, in particular strongly typed, less permissive and error-prone
• Initialization of RAM components in the HDL source code is easier (Verilog initial blocks are
less convenient)
• Package support
• Custom types
• Enumerated types
• No reg versus wire confusion
Advantages of Verilog
• C-like syntax
• More compact code
• Block commenting
Advantages of SystemVerilog
• More compact code compared to Verilog
• Structures and enumerated types for better scalability
• Interfaces for higher level of abstraction
• Supported in Vivado synthesis
• Clocks
• Asynchronous and synchronous set and reset signals
• Clock enable
Coding Guidelines
• Do not asynchronously set or reset registers.
○ Control set remapping becomes impossible.
○ Sequential functionality in device resources, such as block RAM components and DSP
blocks, can be set or reset synchronously only.
○ If you use asynchronously set or reset registers, you cannot leverage device resources or
are configured sub-optimally.
• Do not describe flip-flops with both a set and a reset.
○ No flip-flop primitives feature both a set and a reset, whether synchronous or
asynchronous.
○ Flip-flop primitives featuring both a set and a reset can adversely affect area and
performance.
• Avoid operational set/reset logic whenever possible. There can be other, less expensive, ways
to achieve the desired effect, such as taking advantage of the circuit global reset by defining
an initial content.
• Always describe the clock enable, set, and reset control inputs of flip-flop primitives as active-
High. If they are described as active-Low, the resulting inverter logic penalizes circuit
performance.
• The number of Registers inferred during HDL synthesis might not precisely equal the number
of Flip-Flop primitives in the Design Summary section.
• The number of Flip-Flop primitives depends on the following processes:
○ Absorption of Registers into DSP blocks or block RAM components
○ Register duplication
Filename: registers_1.v
module registers_1(d_in,ce,clk,clr,dout);
input [7:0] d_in;
input ce;
input clk;
input clr;
output [7:0] dout;
reg [7:0] d_reg;
always @ (posedge clk)
begin
if(clr)
d_reg <= 8'b0;
else if(ce)
d_reg <= d_in;
end
assign dout = d_reg;
endmodule
Filename: registers_1.vhd
-- Flip-Flop with
-- Rising-edge Clock
-- Active-high Synchronous Clear
-- Active-high Clock Enable
-- File: registers_1.vhd
library IEEE;
use IEEE.std_logic_1164.all;
entity registers_1 is
port(
clr, ce, clk : in std_logic;
d_in : in std_logic_vector(7 downto 0);
dout : out std_logic_vector(7 downto 0)
);
end entity registers_1;
architecture rtl of registers_1 is
begin
process(clk) is
begin
if rising_edge(clk) then
if clr = '1' then
dout <= "00000000";
elsif ce = '1' then
dout <= d_in;
end if;
end if;
end process;
end architecture rtl;
Latches
The Vivado log file reports the type and size of recognized Latches.
Inferred Latches are often the result of HDL coding mistakes, such as incomplete if or case
statements.
Vivado synthesis issues a warning for the instance shown in the following reporting example.
This warning lets you verify that the inferred Latch functionality was intended.
=========================================================================
Report Cell Usage:
-----+----+-----
|Cell|Count
-----+----+-----
2 |LD | 1
-----+----+-----
===================================================================
entity latches is
port(
G, D, CLR : in std_logic;
Q : out std_logic
);
end latches;
Tristates
• Tristate buffers are usually modeled by a signal or an if-else construct.
• This applies whether the buffer drives an internal bus or an external bus on the board on
which the device resides.
• The signal is assigned a high impedance value in one branch of the if-else. Download the
coding example files from Coding Examples.
Tristate Implementation
Inferred Tristate buffers are implemented with different device primitives when driving the
following:
○ When an internal bus inferring a BUFT is driving an output of the top module, the Vivado
synthesis infers an OBUF.
=========================================================================
* Vivado log file *
=========================================================================
Report Cell Usage:
-----+-----+-----
|Cell |Count
-----+-----+-----
1 |OBUFT| 1
-----+-----+-----
=========================================================================
Filename: tristates_2.v
Filename: tristates_1.vhd
Filename: tristates_1.v
always @(T or I)
begin
if (~T)
O = I;
else
O = 1'bZ;
end
endmodule
Shift Registers
A Shift Register is a chain of Flip-Flops allowing propagation of data across a fixed (static) number
of latency stages. In contrast, in Dynamic Shift Registers, the length of the propagation chain
varies dynamically during circuit operation. Download the coding example files from Coding
Examples.
• A clock
• An optional clock enable
• A serial data input
• A serial data output
• SRL16E
• SRLC32E
Depending on the length of the Shift Register, Vivado synthesis does one of the following:
Filename: shift_registers_0.vhd
library ieee;
use ieee.std_logic_1164.all;
entity shift_registers_0 is
generic(
DEPTH : integer := 32
);
port(
clk : in std_logic;
clken : in std_logic;
SI : in std_logic;
SO : out std_logic
);
end shift_registers_0;
Filename: shift_registers_1.vhd
library ieee;
use ieee.std_logic_1164.all;
entity shift_registers_1 is
generic(
DEPTH : integer := 32
);
port(
clk : in std_logic;
clken : in std_logic;
SI : in std_logic;
SO : out std_logic
);
end shift_registers_1;
Filename: shift_registers_0.v
begin
if (clken)
shreg = {shreg[WIDTH-2:0], SI};
end
assign SO = shreg[WIDTH-1];
endmodule
Filename: shift_registers_1.v
integer i;
always @(posedge clk)
begin
if (clken)
begin
for (i = 0; i < WIDTH-1; i = i+1)
shreg[i+1] <= shreg[i];
shreg[0] <= SI;
end
end
assign SO = shreg[WIDTH-1];
endmodule
• A chain of Flip-Flops of the maximum length that it can accept during circuit operation.
• A Multiplexer that selects, in a given clock cycle, the stage at which data is to be extracted
from the propagation chain.
The Vivado synthesis tool can infer Dynamic Shift registers of any maximal length.
Vivado synthesis tool can implement Dynamic Shift registers optimally using the SRL-type
primitives available in the device family. The following figure illustrates the functionality of the
Dynamic Shift register.
Filename: dynamic_shift_registers_1.v
assign DO = data[SEL];
Filename: dynamic_shift_registers_1.vd
entity dynamic_shift_register_1 is
generic(
DEPTH : integer := 32;
SEL_WIDTH : integer := 5
);
port(
CLK : in std_logic;
SI : in std_logic;
CE : in std_logic;
A : in std_logic_vector(SEL_WIDTH - 1 downto 0);
DO : out std_logic
);
end dynamic_shift_register_1;
begin
process(CLK)
begin
if rising_edge(CLK) then
if CE = '1' then
SRL_SIG <= SRL_SIG(DEPTH - 2 downto 0) & SI;
end if;
end if;
end process;
DO <= SRL_SIG(conv_integer(A));
end rtl;
Multipliers
Vivado synthesis infers multiplier macros from multiplication operators in the source code. The
resulting signal width equals the sum of the two operand sizes. For example, multiplying a 16-bit
signal by an 8-bit signal produces a result of 24 bits.
RECOMMENDED: If you do not intend to use all most significant bits of a device, AMD recommends that
you reduce the size of operands to the minimum needed, especially if the Multiplier macro is implemented
on slice logic.
Multipliers Implementation
Multiplier macros can be implemented on:
• Slice logic
• DSP blocks
To force implementation of a Multiplier to slice logic or DSP block, set the USE_DSP attribute on
the appropriate signal, entity, or module to either:
• no (slice logic)
• yes (DSP block)
When a Multiplier does not fit on a single DSP block, Vivado synthesis decomposes the macro to
implement it. In that case, Vivado synthesis uses either of the following:
Use the KEEP attribute to restrict absorption of Registers into DSP blocks. For example, if a
Register is present on an operand of the multiplier, place KEEP on the output of the Register to
prevent the Register from being absorbed into the DSP block.
Filename: mult_unsigned.v
integer i;
always @(posedge clk)
begin
rA <= A;
rB <= B;
M[0] <= rA * rB;
for (i = 0; i < 3; i = i+1)
M[i+1] <= M[i];
end
endmodule
Filename: mult_unsigned.vhd
entity mult_unsigned is
generic(
WIDTHA : integer := 16;
WIDTHB : integer := 16
);
port(
A : in std_logic_vector(WIDTHA - 1 downto 0);
B : in std_logic_vector(WIDTHB - 1 downto 0);
• Multiply-Add
• Multiply-Sub
• Multiply-Add/Sub
• Multiply-Accumulate
• A Multiplier
• An Adder/Subtractor
• Registers
• Vivado synthesis can implement a Multiply Accumulate in a DSP block if its implementation
requires only a single DSP resource.
• If the macro exceeds the limits of a single DSP, Vivado synthesis does the following:
○ Processes it as two separate Multiplier and Accumulate macros.
○ Takes into account DSP block resources availability in the targeted device.
Use the KEEP attribute to restrict absorption of Registers into DSP blocks. For example, to
exclude a register present on an operand of the Multiplier from absorption into the DSP block,
apply KEEP on the output of the register. For more information about the KEEP attribute, see
KEEP.
Filename: cmult.v
//
// Complex Multiplier (pr+i.pi) = (ar+i.ai)*(br+i.bi)
// file: cmult.v
// Common factor (ar ai) x bi, shared for the calculations of the real and
imaginary final products
//
always @(posedge clk)
begin
addcommon <= ar_d - ai_d;
mult0 <= addcommon * bi_dd;
common <= mult0;
end
// Real product
//
always @(posedge clk)
begin
ar_ddd <= ar_dd;
ar_dddd <= ar_ddd;
addr <= br_ddd - bi_ddd;
multr <= addr * ar_dddd;
commonr1 <= common;
pr_int <= multr + commonr1;
end
// Imaginary product
//
always @(posedge clk)
begin
ai_ddd <= ai_dd;
ai_dddd <= ai_ddd;
addi <= br_ddd + bi_ddd;
multi <= addi * ai_dddd;
commonr2 <= common;
pi_int <= multi + commonr2;
end
assign pr = pr_int;
assign pi = pi_int;
endmodule // cmult
Filename: cmult.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity cmult is
generic(AWIDTH : natural := 16;
BWIDTH : natural := 16);
port(clk : in std_logic;
ar, ai : in std_logic_vector(AWIDTH - 1 downto 0);
br, bi : in std_logic_vector(BWIDTH - 1 downto 0);
pr, pi : out std_logic_vector(AWIDTH + BWIDTH downto 0));
end cmult;
begin
process(clk)
begin
if rising_edge(clk) then
ar_d <= signed(ar);
ar_dd <= signed(ar_d);
ai_d <= signed(ai);
ai_dd <= signed(ai_d);
br_d <= signed(br);
br_dd <= signed(br_d);
br_ddd <= signed(br_dd);
bi_d <= signed(bi);
bi_dd <= signed(bi_d);
bi_ddd <= signed(bi_dd);
end if;
end process;
-- Imaginary product
--
process(clk)
begin
if rising_edge(clk) then
ai_ddd <= ai_dd;
ai_dddd <= ai_ddd;
addi <= resize(br_ddd, BWIDTH + 1) + resize(bi_ddd, BWIDTH + 1);
multi <= addi * ai_dddd;
commonr2 <= common;
pi_int <= multi + commonr2;
end if;
end process;
--
-- VHDL type conversion for output
--
pr <= std_logic_vector(pr_int);
pi <= std_logic_vector(pi_int);
end rtl;
endmodule // dynpreaddmultadd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity dynpreaddmultadd is
generic(
AWIDTH : natural := 12;
BWIDTH : natural := 16;
CWIDTH : natural := 17
);
port(
clk : in std_logic;
subadd : in std_logic;
ain : in std_logic_vector(AWIDTH - 1 downto 0);
bin : in std_logic_vector(BWIDTH - 1 downto 0);
cin : in std_logic_vector(CWIDTH - 1 downto 0);
din : in std_logic_vector(BWIDTH + CWIDTH downto 0);
pout : out std_logic_vector(BWIDTH + CWIDTH downto 0)
);
end dynpreaddmultadd;
begin
process(clk)
begin
if rising_edge(clk) then
a <= signed(ain);
b <= signed(bin);
c <= signed(cin);
d <= signed(din);
if subadd = '1' then
add <= resize(a, BWIDTH + 1) - resize(b, BWIDTH + 1);
else
add <= resize(a, BWIDTH + 1) + resize(b, BWIDTH + 1);
end if;
mult <= add * c;
p <= mult + d;
end if;
end process;
--
-- Type conversion for output
--
pout <= std_logic_vector(p);
end rtl;
The following are examples of the square of a difference; this can be used to efficiently replace
calculations on absolute values of differences.
It fits into a single DSP block and runs at full speed. The coding example files mentioned
previously also include an accumulator of the square of differences which also fits into a single
DSP block for the UltraScale architecture.
end
// Output result
assign square_out = p_reg;
endmodule // squarediffmult
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity squarediffmult is
generic(
SIZEIN : natural := 16
);
port(
clk, ce, rst : in std_logic;
ain, bin : in std_logic_vector(SIZEIN - 1 downto 0);
square_out : out std_logic_vector(2 * SIZEIN + 1 downto 0)
);
end squarediffmult;
begin
process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
a_reg <= (others => '0');
b_reg <= (others => '0');
diff_reg <= (others => '0');
m_reg <= (others => '0');
p_reg <= (others => '0');
else
a_reg <= signed(ain);
b_reg <= signed(bin);
diff_reg <= resize(a_reg, SIZEIN + 1) - resize(b_reg, SIZEIN + 1);
m_reg <= diff_reg * diff_reg;
p_reg <= m_reg;
end if;
end if;
end process;
--
FIR Filters
Vivado synthesis infers cascades of multiply-add to compose FIR filters directly from RTL.
There are several possible implementations of such filters; one example is the systolic filter
described in the 7 Series DSP48E1 Slice User Guide (UG479) and shown in the 8-Tap Even
Symmetric Systolic FIR (Verilog).
// sfir_even_symmetric_systolic_top.v
// FIR Symmetric Systolic Filter, Top module is
sfir_even_symmetric_systolic_top
endmodule
assign h[0] = 7;
assign h[1] = 14;
assign h[2] = -138;
assign h[3] = 129;
generate
genvar I;
for (I=0; I<nbtap; I=I+1)
if (I==0)
sfir_even_symmetric_systolic_element #(dsize) fte_inst0 (clk, h[I], datain,
shifterout, {32{1'b0}}, arraydata[I], arrayprod[I]);
else
sfir_even_symmetric_systolic_element #(dsize) fte_inst (clk, h[I],
arraydata[I-1], shifterout, arrayprod[I-1], arraydata[I], arrayprod[I]);
endgenerate
endmodule // sfir_even_symmetric_systolic_top
--
-- FIR filter top
-- File: sfir_even_symmetric_systolic_top.vhd
entity sfir_shifter is
generic(
DSIZE : natural := 16;
NBTAP : natural := 4
);
port(
clk : in std_logic;
datain : in std_logic_vector(DSIZE - 1 downto 0);
dataout : out std_logic_vector(DSIZE - 1 downto 0)
);
end sfir_shifter;
-- Declare signals
--
type CHAIN is array (0 to 2 * NBTAP - 1) of std_logic_vector(DSIZE - 1
downto 0);
signal tmp : CHAIN;
begin
process(clk)
begin
if rising_edge(clk) then
tmp(0) <= datain;
looptmp : for i in 0 to 2 * NBTAP - 2 loop
tmp(i + 1) <= tmp(i);
end loop;
end if;
end process;
end rtl;
--
-- FIR filter engine (multiply with pre-add and post-add)
-- submodule used in top (sfir_even_symmetric_systolic_top)
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sfir_even_symmetric_systolic_element is
generic(DSIZE : natural := 16);
port(clk : in std_logic;
coeffin, datain, datazin : in std_logic_vector(DSIZE - 1 downto 0);
cascin : in std_logic_vector(2 * DSIZE downto 0);
-- Declare signals
--
signal coeff, data, dataz, datatwo : signed(DSIZE - 1 downto 0);
signal preadd : signed(DSIZE downto 0);
signal product, cascouttmp : signed(2 * DSIZE downto 0);
begin
process(clk)
begin
if rising_edge(clk) then
coeff <= signed(coeffin);
data <= signed(datain);
datatwo <= data;
dataz <= signed(datazin);
preadd <= resize(datatwo, DSIZE + 1) + resize(dataz, DSIZE + 1);
product <= preadd * coeff;
cascouttmp <= product + signed(cascin);
end if;
end process;
end rtl;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sfir_even_symmetric_systolic_top is
generic(NBTAP : natural := 4;
DSIZE : natural := 16;
PSIZE : natural := 33);
port(clk : in std_logic;
datain : in std_logic_vector(DSIZE - 1 downto 0);
firout : out std_logic_vector(PSIZE - 1 downto 0));
end sfir_even_symmetric_systolic_top;
-- Declare signals
--
type DTAB is array (0 to NBTAP - 1) of std_logic_vector(DSIZE - 1 downto 0);
type HTAB is array (0 to NBTAP - 1) of std_logic_vector(0 to DSIZE - 1);
type PTAB is array (0 to NBTAP - 1) of std_logic_vector(PSIZE - 1 downto 0);
(std_logic_vector(TO_SIGNED(1, DSIZE))));
constant zero_psize : std_logic_vector(PSIZE - 1 downto 0) := (others =>
'0');
begin
-- Shifter
--
shift_u0 : entity work.sfir_shifter
generic map(DSIZE, NBTAP)
port map(clk, datain, shifterout);
end rtl;
The following are examples of the convergent rounding inference, which infers at the block full
performance, and also infers a 2-input AND gate (1 LUT) to implement the LSB correction.
reg pattern_detect;
wire [15:0] pattern = 16'b0000000000000000;
wire [39:0] c = 40'b0000000000000000000000000111111111111111; // 15 ones
entity convergentRoundingEven is
port (clk : in std_logic;
a : in std_logic_vector (23 downto 0);
b : in std_logic_vector (15 downto 0);
zlast : out std_logic_vector (23 downto 0));
end convergentRoundingEven;
signal ar : signed(a'range);
signal br : signed(b'range);
signal z1 : signed(a'length + b'length - 1 downto 0);
begin
multadd <= z1 + c + 1;
process(clk)
begin
if rising_edge(clk) then
ar <= signed(a);
br <= signed(b);
z1 <= ar * br;
multaddr <= multadd;
if multadd(15 downto 0) = pattern then
pattern_detect <= true;
else
pattern_detect <= false;
end if;
end if;
end process;
if rising_edge(clk) then
if pattern_detect = true then
zlast <= std_logic_vector(multaddr(39 downto 17)) & "0";
else
zlast <= std_logic_vector(multaddr(39 downto 16));
end if;
end if;
end process;
end beh;
reg pattern_detect;
wire [15:0] pattern = 16'b1111111111111111;
wire [39:0] c = 40'b0000000000000000000000000111111111111111; // 15 ones
assign multadd = z1 + c;
always @(posedge clk)
begin
areg <= a;
breg <= b;
z1 <= areg * breg;
pattern_detect <= multadd[15:0] == pattern ? 1'b1 : 1'b0;
multadd_reg <= multadd;
end
entity convergentRoundingOdd is
port (clk : in std_logic;
a : in std_logic_vector (23 downto 0);
b : in std_logic_vector (15 downto 0);
zlast : out std_logic_vector (23 downto 0));
end convergentRoundingOdd;
architecture beh of convergentRoundingOdd is
signal ar : signed(a'range);
signal br : signed(b'range);
signal z1 : signed(a'length + b'length - 1 downto 0);
begin
multadd <= z1 + c;
process(clk)
begin
if rising_edge(clk) then
ar <= signed(a);
br <= signed(b);
z1 <= ar * br;
multaddr <= multadd;
if multadd(15 downto 0) = pattern then
pattern_detect <= true;
else
pattern_detect <= false;
end if;
end if;
end process;
process(clk)
begin
if rising_edge(clk) then
if pattern_detect = true then
zlast <= std_logic_vector(multaddr(39 downto 17)) & "1";
else
zlast <= std_logic_vector(multaddr(39 downto 16));
end if;
end if;
end process;
end beh;
Whether to use distributed RAM or dedicated block RAM can depend upon the characteristics of
the RAM described in the HDL source code, the availability of block RAM resources, and
whether you have forced a specific implementation style using RAM_STYLE attribute.
• Support for any size and data width. Vivado synthesis maps the memory description to one or
several RAM primitives
• Single-port, simple-dual port, true dual port
• Up to two write ports
• Multiple read ports
Provided that only one write port is described, Vivado synthesis can identify RAM descriptions
with two or more read ports that access the RAM contents at addresses different from the write
address.
• Write enable
• RAM enable (block RAM)
• Data output reset (block RAM)
• Optional output register (block RAM)
• Byte write enable (block RAM)
• Each RAM port can be controlled by its distinct clock, port enable, write enable, and data
output reset
• Initial contents specification
• Vivado synthesis can use parity bits as regular data bits to accommodate the described data
widths
Note: For more information on parity bits see the user guide for the device you are targeting.
• xilinx_ultraram_single_port_no_change.v
• xilinx_ultraram_single_port_no_change.vhd
• xilinx_ultraram_single_port_read_first.v
• xilinx_ultraram_single_port_read_first.vhd
• xilinx_ultraram_single_port_write_first.v
• xilinx_ultraram_single_port_write_first.vhd
The Vivado tool includes templates of UltraRAM VHDL and Verilog code. The following figure
shows the template files.
See the UltraScale Architecture Memory Resources User Guide (UG573) for more information.
• The UltraRAM only has one clock, so while true dual port operation is supported, both ports
are synchronous to each other.
• The aspect ratio of the UltraRAM is not configurable like block RAM, it is always configured as
4 K x 72.
• The resets on the output registers can only be reset to 0.
• The write modes (read_first, write_first, no_change) do not exist in this primitive.
The regular UltraRAM behaves like no_change; however, if you describe read_first or
write_first in RTL, the Vivado synthesis creates the correct logic.
• Finally, the INIT for RAM does not exist, the UltraRAM powers up in a 0 condition.
• Direct instantiation: Provides you the most control but is the hardest to perform.
• XPM flow: Allows you to specify the type of RAM you want along with the behavior, but gives
no access to the RTL.
• Inference RAM: Is in the middle of the two, relatively easy, and gives more control to the user
on how the RAM is created.
RAM_STYLE
The RAM_STYLE attribute has a value called ultra. By default, Vivado synthesis uses a heuristic
to determine what type of RAM to infer, URAM, block RAM or LUTRAM. If you want to force the
RAM into an UltraRAM, you can use the RAM_STYLE attribute to tell Vivado synthesis to infer
the URAM primitives.
CASCADE_HEIGHT
When cascading multiple UltraRAMs (URAMs) together to create a larger RAM, Vivado synthesis
limits the height of the chain to eight to provide flexibility to the place and route tool. To change
this limit, you can use the CASCADE_HEIGHT attribute to change the default behavior.
Note: This option is only applicable to UltraScale architecture block RAMs and URAMs.
In addition to the attributes that only affect the specific RAMs on which they are put, there is
also a global setting which affects all RAMs in the design.
The Synthesis Settings menu has the -max_uram_cascade_height setting. The default value
is -1 which means that the Vivado synthesis tool determines the best course of action, but this
can be overridden by other values. In case of a conflict between the global setting and a
CASCADE_HEIGHT attribute, the attribute is used for that specific RAM.
Inference Capabilities
The Vivado Synthesis tool can do many types of memories using the UltraRAM primitives. For
examples, see the Coding Guidelines.
• In single port memory, the same port that reads the memory also writes to it. All three of the
write modes for the block RAM are supported, but it should be noted that the UltraRAM itself
acts like a NO_CHANGE memory. If WRITE_FIRST or READ_FIRST behavior is described in
the RTL, the UltraRAM created is set in simple dual-port mode.
• In a simple dual port memory, one port reads from the RAM while another writes to it. Vivado
synthesis can infer these memories into UltraRAM.
TIP: One stipulation is that both ports must have the same clock.
• In True Dual Port mode, both ports can read from and write to the memory. In this mode, only
the NO_CHANGE mode is supported.
CAUTION! Care should also be taken when simulating the true dual port RAM. In the previous versions of
block RAM, there was address collision that was taken care of by the simulation models; with the
UltraRAM, it is different. In the UltraRAM, port A always happens before port B. If Port A has a write and
Port B is a read from that address, the memory is written to and read from, but if Port A has the read and
Port B has the write, the old value is seen during the read.
CAUTION! Be sure to never read and write to the same address during the same clock cycle on a true
dual-port memory because the RTL and post-synthesis simulations could be different.
For both the simple dual-port memory and the true dual-port memory, the clocks have to be the
same for both ports.
In addition to the different styles of RAMs, there are also a few other features of the UltraRAM
that can be inferred. The RAM has a global enable signal that precedes the write enable. It has
the standard write enable, and byte write enable support. The data output also has a reset like
the previous block RAM; however, in this case, there is no SRVAL that can be set. Only resets of
0 are supported.
Note: The tool does not create the pipeline registers for you; they must be in the RTL code for Vivado
synthesis to make use of them.
The synthesis log file has a section about URAMs and how many rows and columns are used to
create the RAM matrix. You can use this section to add pipeline registers in the RTL.
To calculate the number of rows and columns of the matrix yourself, remember that the
UltraRAM is configured as a 4 K x 72.
To calculate the number of rows, take your address space of the RAM in RTL and divide by 4 K. If
this number is higher than the number specified by CASCADE_HEIGHT, remove the extra RAMs,
and start them on a new column in the log.
Note: The whole matrix is reproduced to get the extra 8 bits of data space needed to create the RAM, but
that does not matter to the calculation of pipeline registers.
• Write-first: New content is immediately made available for reading Write-first is also known
as read-through.
• No-change: Data output does not change as new content is loaded into RAM.
Vivado synthesis provides inference support for all of these synchronization modes. You can
describe a different synchronization mode for each port of the RAM.
Filename: rams_dist.v
input clk;
input we;
input [5:0] a;
input [5:0] dpra;
input [15:0] di;
output [15:0] spo;
output [15:0] dpo;
reg [15:0] ram [63:0];
endmodule
Filename: rams_dist.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity rams_dist is
port(
clk : in std_logic;
we : in std_logic;
a : in std_logic_vector(5 downto 0);
di : in std_logic_vector(15 downto 0);
do : out std_logic_vector(15 downto 0)
);
end rams_dist;
do <= RAM(to_integer(unsigned(a)));
end syn;
Filename: rams_sp_rf_rst.v
endmodule
Filename: rams_sp_rf_rst.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity rams_sp_rf_rst is
port(
clk : in std_logic;
en : in std_logic;
we : in std_logic;
rst : in std_logic;
addr : in std_logic_vector(9 downto 0);
di : in std_logic_vector(15 downto 0);
do : out std_logic_vector(15 downto 0)
);
end rams_sp_rf_rst;
end syn;
Filename: rams_sp_wf.v
Filename: rams_sp_wf.vhd
entity rams_sp_wf is
port(
clk : in std_logic;
we : in std_logic;
en : in std_logic;
addr : in std_logic_vector(9 downto 0);
di : in std_logic_vector(15 downto 0);
do : out std_logic_vector(15 downto 0)
);
end rams_sp_wf;
end syn;
Filename: rams_sp_rf.vhd
entity rams_sp_rf is
port(
clk : in std_logic;
we : in std_logic;
en : in std_logic;
addr : in std_logic_vector(9 downto 0);
di : in std_logic_vector(15 downto 0);
do : out std_logic_vector(15 downto 0)
);
end rams_sp_rf;
end syn;
Filename: rams_sp_nc.v
input clk;
input we;
input en;
input [9:0] addr;
input [15:0] di;
output [15:0] dout;
Filename: rams_sp_nc.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity rams_sp_nc is
port(
clk : in std_logic;
we : in std_logic;
en : in std_logic;
addr : in std_logic_vector(9 downto 0);
di : in std_logic_vector(15 downto 0);
do : out std_logic_vector(15 downto 0)
);
end rams_sp_nc;
end syn;
Filename: simple_dual_one_clock.v
input clk,ena,enb,wea;
input [9:0] addra,addrb;
input [15:0] dia;
output [15:0] dob;
reg [15:0] ram [1023:0];
reg [15:0] doa,dob;
endmodule
Filename: simple_dual_one_clock.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
entity simple_dual_one_clock is
port(
clk : in std_logic;
ena : in std_logic;
enb : in std_logic;
wea : in std_logic;
addra : in std_logic_vector(9 downto 0);
addrb : in std_logic_vector(9 downto 0);
dia : in std_logic_vector(15 downto 0);
dob : out std_logic_vector(15 downto 0)
);
end simple_dual_one_clock;
process(clk)
begin
if clk'event and clk = '1' then
if enb = '1' then
dob <= RAM(conv_integer(addrb));
end if;
end if;
end process;
end syn;
Filename: simple_dual_two_clocks.v
input clka,clkb,ena,enb,wea;
input [9:0] addra,addrb;
input [15:0] dia;
output [15:0] dob;
reg [15:0] ram [1023:0];
reg [15:0] dob;
Filename: simple_dual_two_clocks.vhd
entity simple_dual_two_clocks is
port(
clka : in std_logic;
clkb : in std_logic;
ena : in std_logic;
enb : in std_logic;
wea : in std_logic;
addra : in std_logic_vector(9 downto 0);
addrb : in std_logic_vector(9 downto 0);
dia : in std_logic_vector(15 downto 0);
dob : out std_logic_vector(15 downto 0)
);
end simple_dual_two_clocks;
process(clkb)
begin
if clkb'event and clkb = '1' then
if enb = '1' then
dob <= RAM(conv_integer(addrb));
end if;
end if;
end process;
end syn;
Dual-Port Block RAM with Two Write Ports in Read First Mode
Verilog Example
Filename: ram_tdp_rf_rf.v
module rams_tdp_rf_rf
(clka,clkb,ena,enb,wea,web,addra,addrb,dia,dib,doa,dob);
input clka,clkb,ena,enb,wea,web;
input [9:0] addra,addrb;
input [15:0] dia,dib;
output [15:0] doa,dob;
reg [15:0] ram [1023:0];
reg [15:0] doa,dob;
endmodule
Filename: ram_tdp_rf_rf.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
entity rams_tdp_rf_rf is
port(
clka : in std_logic;
clkb : in std_logic;
ena : in std_logic;
enb : in std_logic;
wea : in std_logic;
web : in std_logic;
addra : in std_logic_vector(9 downto 0);
addrb : in std_logic_vector(9 downto 0);
dia : in std_logic_vector(15 downto 0);
dib : in std_logic_vector(15 downto 0);
doa : out std_logic_vector(15 downto 0);
dob : out std_logic_vector(15 downto 0)
);
end rams_tdp_rf_rf;
process(CLKB)
begin
if CLKB’event and CLKB = ‘1’ then
if ENB = ‘1’ then
DOB <= RAM(to_integer(unsigned(ADDRB)));
if WEB = ‘1’ then
RAM(to_integer(unsigned(ADDRB))) := DIB;
end if;
end if;
end if;
end process;
end syn;
Filename: rams_pipeline.v
module rams_pipeline (clk1, clk2, we, en1, en2, addr1, addr2, di, res1,
res2);
input clk1;
input clk2;
input we, en1, en2;
input [9:0] addr1;
input [9:0] addr2;
input [15:0] di;
output [15:0] res1;
output [15:0] res2;
reg [15:0] res1;
reg [15:0] res2;
reg [15:0] RAM [1023:0];
reg [15:0] do1;
reg [15:0] do2;
Filename: rams_pipeline.vhd
entity rams_pipeline is
port(
clk1, clk2 : in std_logic;
we, en1, en2 : in std_logic;
addr1 : in std_logic_vector(9 downto 0);
addr2 : in std_logic_vector(9 downto 0);
di : in std_logic_vector(15 downto 0);
res1 : out std_logic_vector(15 downto 0);
res2 : out std_logic_vector(15 downto 0)
);
end rams_pipeline;
process(clk2)
begin
if rising_edge(clk2) then
do2 <= ram(to_integer(unsigned(addr2)));
end if;
end process;
process(clk1)
begin
if rising_edge(clk1) then
if en1 = '1' then
res1 <= do1;
end if;
end if;
end process;
process(clk2)
begin
if rising_edge(clk2) then
if en2 = '1' then
res2 <= do2;
end if;
end if;
end process;
end beh;
From the standpoint of HDL modeling and inference, the concept is best described as a column-
based write:
Vivado synthesis inference lets you take advantage of the block RAM byte write enable feature.
The described RAM is implemented on block RAM resources, using the byte write enable
capability, provided that the following requirements are met:
For other write column widths, such as 5-bit or 12-bit (non multiple of 8-bit or 9-bit), Vivado
synthesis uses separate RAMs for each column:
Filename: bytewrite_tdp_ram_rf.v
module bytewrite_tdp_ram_rf
#(
//--------------------------------------------------------------------------
parameter NUM_COL = 4,
parameter COL_WIDTH = 8,
parameter ADDR_WIDTH = 10,
// Addr Width in bits : 2 *ADDR_WIDTH = RAM Depth
parameter DATA_WIDTH = NUM_COL*COL_WIDTH // Data Width in bits
//----------------------------------------------------------------------
) (
input clkA,
input enaA,
input [NUM_COL-1:0] weA,
input [ADDR_WIDTH-1:0] addrA,
input [DATA_WIDTH-1:0] dinA,
output reg [DATA_WIDTH-1:0] doutA,
input clkB,
input enaB,
input [NUM_COL-1:0] weB,
input [ADDR_WIDTH-1:0] addrB,
input [DATA_WIDTH-1:0] dinB,
// Core Memory
reg [DATA_WIDTH-1:0] ram_block [(2**ADDR_WIDTH)-1:0];
integer i;
// Port-A Operation
always @ (posedge clkA) begin
if(enaA) begin
for(i=0;i<NUM_COL;i=i+1) begin
if(weA[i]) begin
ram_block[addrA][i*COL_WIDTH +: COL_WIDTH] <= dinA[i*COL_WIDTH +:
COL_WIDTH];
end
end
doutA <= ram_block[addrA];
end
end
// Port-B Operation:
always @ (posedge clkB) begin
if(enaB) begin
for(i=0;i<NUM_COL;i=i+1) begin
if(weB[i]) begin
ram_block[addrB][i*COL_WIDTH +: COL_WIDTH] <= dinB[i*COL_WIDTH +:
COL_WIDTH];
end
end
endmodule // bytewrite_tdp_ram_rf
Filename: bytewrite_tdp_ram_rf.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity bytewrite_tdp_ram_rf is
generic(
SIZE : integer := 1024;
ADDR_WIDTH : integer := 10;
COL_WIDTH : integer := 9;
NB_COL : integer := 4
);
port(
clka : in std_logic;
ena : in std_logic;
wea : in std_logic_vector(NB_COL - 1 downto 0);
addra : in std_logic_vector(ADDR_WIDTH - 1 downto 0);
dia : in std_logic_vector(NB_COL * COL_WIDTH - 1 downto 0);
doa : out std_logic_vector(NB_COL * COL_WIDTH - 1 downto 0);
clkb : in std_logic;
enb : in std_logic;
web : in std_logic_vector(NB_COL - 1 downto 0);
addrb : in std_logic_vector(ADDR_WIDTH - 1 downto 0);
dib : in std_logic_vector(NB_COL * COL_WIDTH - 1 downto 0);
dob : out std_logic_vector(NB_COL * COL_WIDTH - 1 downto 0)
);
end bytewrite_tdp_ram_rf;
begin
Filename: bytewrite_tdp_ram_wf.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity bytewrite_tdp_ram_wf is
generic(
SIZE : integer := 1024;
ADDR_WIDTH : integer := 10;
COL_WIDTH : integer := 9;
NB_COL : integer := 4
);
port(
clka : in std_logic;
ena : in std_logic;
wea : in std_logic_vector(NB_COL - 1 downto 0);
addra : in std_logic_vector(ADDR_WIDTH - 1 downto 0);
dia : in std_logic_vector(NB_COL * COL_WIDTH - 1 downto 0);
doa : out std_logic_vector(NB_COL * COL_WIDTH - 1 downto 0);
clkb : in std_logic;
enb : in std_logic;
web : in std_logic_vector(NB_COL - 1 downto 0);
addrb : in std_logic_vector(ADDR_WIDTH - 1 downto 0);
dib : in std_logic_vector(NB_COL * COL_WIDTH - 1 downto 0);
dob : out std_logic_vector(NB_COL * COL_WIDTH - 1 downto 0)
);
end bytewrite_tdp_ram_wf;
begin
end process;
Filename: bytewrite_tdp_ram_nc.v
//
// True-Dual-Port BRAM with Byte-wide Write Enable
// No-Change mode
//
// bytewrite_tdp_ram_nc.v
//
// ByteWide Write Enable, - NO_CHANGE mode template - Vivado recomended
module bytewrite_tdp_ram_nc
#(
//---------------------------------------------------------------
parameter NUM_COL = 4,
parameter COL_WIDTH = 8,
parameter ADDR_WIDTH = 10, // Addr Width in bits : 2**ADDR_WIDTH = RAM Depth
parameter DATA_WIDTH = NUM_COL*COL_WIDTH // Data Width in bits
//---------------------------------------------------------------
) (
input clkA,
input enaA,
input [NUM_COL-1:0] weA,
input [ADDR_WIDTH-1:0] addrA,
input [DATA_WIDTH-1:0] dinA,
output reg [DATA_WIDTH-1:0] doutA,
input clkB,
input enaB,
input [NUM_COL-1:0] weB,
input [ADDR_WIDTH-1:0] addrB,
input [DATA_WIDTH-1:0] dinB,
output reg [DATA_WIDTH-1:0] doutB
);
// Core Memory
reg [DATA_WIDTH-1:0] ram_block [(2**ADDR_WIDTH)-1:0];
// Port-A Operation
generate
genvar i;
for(i=0;i<NUM_COL;i=i+1) begin
// Port-B Operation:
generate
for(i=0;i<NUM_COL;i=i+1) begin
always @ (posedge clkB) begin
if(enaB) begin
if(weB[i]) begin
ram_block[addrB][i*COL_WIDTH +: COL_WIDTH] <= dinB[i*COL_WIDTH +:
COL_WIDTH];
end
end
end
end
endgenerate
endmodule // bytewrite_tdp_ram_nc
Filename: bytewrite_tdp_ram_nc.vhd
--
-- True-Dual-Port BRAM with Byte-wide Write Enable
-- No change mode
--
-- bytewrite_tdp_ram_nc.vhd
--
-- NO_CHANGE ByteWide WriteEnable Block RAM Template
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity bytewrite_tdp_ram_nc is
generic(
SIZE : integer := 1024;
end bytewrite_tdp_ram_nc;
begin
end loop;
end if;
end if;
end process;
end byte_wr_ram_nc;
Asymmetric RAMs
The following sections provide VHDL and Verilog coding examples for asymmetric RAMs.
Filename: asym_ram_sdp_read_wider.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity asym_ram_sdp_read_wider is
generic(
WIDTHA : integer := 4;
SIZEA : integer := 1024;
ADDRWIDTHA : integer := 10;
WIDTHB : integer := 16;
SIZEB : integer := 256;
ADDRWIDTHB : integer := 8
);
port(
clkA : in std_logic;
clkB : in std_logic;
enA : in std_logic;
enB : in std_logic;
weA : in std_logic;
addrA : in std_logic_vector(ADDRWIDTHA - 1 downto 0);
addrB : in std_logic_vector(ADDRWIDTHB - 1 downto 0);
diA : in std_logic_vector(WIDTHA - 1 downto 0);
doB : out std_logic_vector(WIDTHB - 1 downto 0)
);
end asym_ram_sdp_read_wider;
begin
-- Write process
process(clkA)
begin
if rising_edge(clkA) then
if enA = '1' then
if weA = '1' then
my_ram(conv_integer(addrA)) <= diA;
end if;
end if;
end if;
end process;
-- Read process
process(clkB)
begin
if rising_edge(clkB) then
for i in 0 to RATIO - 1 loop
if enB = '1' then
readB((i + 1) * minWIDTH - 1 downto i * minWIDTH) <=
my_ram(conv_integer(addrB & conv_std_logic_vector(i, log2(RATIO))));
end if;
end loop;
regB <= readB;
end if;
end process;
Filename: asym_ram_sdp_read_wider.v
endmodule
Filename: asym_ram_sdp_write_wider.v
begin
if (value < 2)
log2 = value;
else
begin
shifted = value-1;
for (res=0; shifted>0; res=res+1)
shifted = shifted>>1;
log2 = res;
end
end
endfunction
endmodule
Simple Dual Port Asymmetric RAM When Write Wider than Read
(VHDL)
Filename: asym_ram_sdp_write_wider.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity asym_ram_sdp_write_wider is
generic(
WIDTHA : integer := 4;
SIZEA : integer := 1024;
ADDRWIDTHA : integer := 10;
WIDTHB : integer := 16;
SIZEB : integer := 256;
ADDRWIDTHB : integer := 8
);
port(
clkA : in std_logic;
clkB : in std_logic;
enA : in std_logic;
enB : in std_logic;
weB : in std_logic;
addrA : in std_logic_vector(ADDRWIDTHA - 1 downto 0);
addrB : in std_logic_vector(ADDRWIDTHB - 1 downto 0);
diB : in std_logic_vector(WIDTHB - 1 downto 0);
doA : out std_logic_vector(WIDTHA - 1 downto 0)
);
end asym_ram_sdp_write_wider;
begin
-- read process
process(clkA)
begin
if rising_edge(clkA) then
if enA = '1' then
readA <= my_ram(conv_integer(addrA));
end if;
regA <= readA;
end if;
end process;
-- Write process
process(clkB)
begin
if rising_edge(clkB) then
for i in 0 to RATIO - 1 loop
if enB = '1' then
if weB = '1' then
my_ram(conv_integer(addrB & conv_std_logic_vector(i, log2(RATIO)))) <=
diB((i + 1) * minWIDTH - 1 downto i * minWIDTH);
end if;
end if;
end loop;
regB <= readB;
end if;
end process;
end behavioral;
Filename: asym_ram_tdp_read_first.v
input clkB;
input weA, weB;
input enaA, enaB;
input [ADDRWIDTHA-1:0] addrA;
input [ADDRWIDTHB-1:0] addrB;
input [WIDTHA-1:0] diA;
input [WIDTHB-1:0] diB;
if (weA)
endmodule
Filename: asym_ram_tdp_read_first_first.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity asym_ram_tdp_read_first is
generic(
WIDTHA : integer := 4;
SIZEA : integer := 1024;
ADDRWIDTHA : integer := 10;
WIDTHB : integer := 16;
SIZEB : integer := 256;
ADDRWIDTHB : integer := 8
);
port(
clkA : in std_logic;
clkB : in std_logic;
enA : in std_logic;
enB : in std_logic;
weA : in std_logic;
weB : in std_logic;
addrA : in std_logic_vector(ADDRWIDTHA - 1 downto 0);
addrB : in std_logic_vector(ADDRWIDTHB - 1 downto 0);
diA : in std_logic_vector(WIDTHA - 1 downto 0);
diB : in std_logic_vector(WIDTHB - 1 downto 0);
doA : out std_logic_vector(WIDTHA - 1 downto 0);
doB : out std_logic_vector(WIDTHB - 1 downto 0)
);
end asym_ram_tdp_read_first;
begin
if L < R then
return L;
else
return R;
end if;
end;
begin
process(clkA)
begin
if rising_edge(clkA) then
if enA = '1' then
readA <= my_ram(conv_integer(addrA));
if weA = '1' then
my_ram(conv_integer(addrA)) <= diA;
end if;
end if;
regA <= readA;
end if;
end process;
process(clkB)
begin
if rising_edge(clkB) then
for i in 0 to RATIO - 1 loop
if enB = '1' then
readB((i + 1) * minWIDTH - 1 downto i * minWIDTH) <=
my_ram(conv_integer(addrB & conv_std_logic_vector(i, log2(RATIO))));
if weB = '1' then
my_ram(conv_integer(addrB & conv_std_logic_vector(i, log2(RATIO)))) <=
diB((i + 1) * minWIDTH - 1 downto i * minWIDTH);
end if;
end if;
end loop;
regB <= readB;
end if;
end process;
end behavioral;
Filename: asym_ram_tdp_write_first.v
if (weA)
RAM[{addrA, lsbaddr}] = diA[(i+1)*minWIDTH-1 -: minWIDTH];
endmodule
Filename: asym_ram_tdp_write_first.vhd
--Asymmetric RAM
--True Dual Port write first mode.
--asym_ram_tdp_write_first.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity asym_ram_tdp_write_first is
generic(
WIDTHA : integer := 4;
SIZEA : integer := 1024;
ADDRWIDTHA : integer := 10;
end asym_ram_tdp_write_first;
begin
process(clkA)
begin
if rising_edge(clkA) then
if enA = '1' then
if weA = '1' then
my_ram(conv_integer(addrA)) <= diA;
readA <= diA;
else
readA <= my_ram(conv_integer(addrA));
end if;
end if;
regA <= readA;
end if;
end process;
process(clkB)
begin
if rising_edge(clkB) then
for i in 0 to RATIO - 1 loop
if enB = '1' then
if weB = '1' then
my_ram(conv_integer(addrB & conv_std_logic_vector(i, log2(RATIO)))) <=
diB((i + 1) * minWIDTH - 1 downto i * minWIDTH);
end if;
-- The read statement below is placed after the write statement -- on
purpose
-- to ensure write-first synchronization through the variable
-- mechanism
readB((i + 1) * minWIDTH - 1 downto i * minWIDTH) <=
my_ram(conv_integer(addrB & conv_std_logic_vector(i, log2(RATIO))));
end if;
end loop;
regB <= readB;
end if;
end process;
end behavioral;
• The external data file is an ASCII text file with any name.
• Each line in the external data file describes the initial content at an address position in the
RAM.
• There must be as many lines in the external data file as there are rows in the RAM array. An
insufficient number of lines is flagged.
• The addressable position related to a given line is defined by the direction of the primary
range of the signal modeling the RAM.
• You can represent RAM content in either binary or hexadecimal. You cannot mix both.
• The external data file cannot contain any other content, such as comments.
The following external data file initializes an 8 x 32-bit RAM with binary values:
00001110110000011001111011000110
00101011001011010101001000100011
01110100010100011000011100001111
01000001010000100101001110010100
00001001101001111111101000101011
00101101001011111110101010100111
11101111000100111000111101101101
10001111010010011001000011101111
00000001100011100011110010011111
11011111001110101011111001001010
11100111010100111110110011001010
11000100001001101100111100101001
10001011100101011111111111100001
11110101110110010000010110111010
01001011000000111001010110101110
11100001111111001010111010011110
01101111011010010100001101110001
01010100011011111000011000100100
11110000111101101111001100001011
10101101001111010100100100011100
01011100001010111111101110101110
01011101000100100111010010110101
11110111000100000101011101101101
11100111110001111010101100001101
01110100000011101111111000011111
00010011110101111000111001011101
01101110001111100011010101101111
10111100000000010011101011011011
11000001001101001101111100010000
00011111110010110110011111010101
01100100100000011100100101110000
10001000000100111011001010001111
11001000100011101001010001100001
10000000100111010011100111100011
11011111010010100010101010000111
10000000110111101000111110111011
10110011010111101111000110011001
00010111100001001010110111011100
10011100101110101111011010110011
01010011101101010001110110011010
01111011011100010101000101000001
10001000000110010110111001101010
11101000001101010000111001010110
11100011111100000111110101110101
01001010000000001111111101101111
00100011000011001000000010001111
10011000111010110001001011100100
11111111111011110101000101000111
11000011000101000011100110100000
01101101001011111010100011101001
10000111101100101001110011010111
11010110100100101110110010100100
01001111111001101101011111001011
11011001001101110110000100110111
10110110110111100101110011100110
10011100111001000010111111010110
00000000001011011111001010110010
10100110011010000010001000011011
11001010111111001001110001110101
00100001100010000111000101001000
00111100101111110001101101111010
11000010001010000000010100100001
11000001000110001101000101001110
10010011010100010001100100100111
initial begin
$readmemb("rams_20c.data", ram, 0, 63);
end
Filename: rams_sp_rom.v
initial
begin
ram[63] = 20'h0200A; ram[62] = 20'h00300; ram[61] = 20'h08101;
ram[60] = 20'h04000; ram[59] = 20'h08601; ram[58] = 20'h0233A;
ram[57] = 20'h00300; ram[56] = 20'h08602; ram[55] = 20'h02310;
ram[54] = 20'h0203B; ram[53] = 20'h08300; ram[52] = 20'h04002;
ram[51] = 20'h08201; ram[50] = 20'h00500; ram[49] = 20'h04001;
endmodule
Filename: rams_sp_rom.vhd
entity rams_sp_rom is
port(
clk : in std_logic;
we : in std_logic;
addr : in std_logic_vector(5 downto 0);
di : in std_logic_vector(19 downto 0);
do : out std_logic_vector(19 downto 0)
);
end rams_sp_rom;
begin
process(clk)
begin
if rising_edge(clk) then
if we = '1' then
RAM(to_integer(unsigned(addr))) <= di;
end if;
do <= RAM(to_integer(unsigned(addr)));
end if;
end process;
end syn;
Filename: rams_init_file.v
initial begin
$readmemb("rams_init_file.data",ram);
end
Note: The external file initializing the RAM needs to be in bit vector form. External files in integer or hex
format do not work.
Filename: rams_init_file.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
entity rams_init_file is
port(
clk : in std_logic;
we : in std_logic;
addr : in std_logic_vector(5 downto 0);
din : in std_logic_vector(31 downto 0);
dout : out std_logic_vector(31 downto 0)
);
end rams_init_file;
end syn;
Note:
The external file initializing the RAM needs to be in bit vector form. External files in integer or hex format
do not work.
3D RAM Inference
RAMs Using 3D Arrays
The following examples show inference of RAMs using 3D arrays.
filename: rams_sp_3d.sv
generate
for(i=0;i<NUM_RAMS;i=i+1)
begin:u
always @ (posedge clk)
begin
if (ena[i]) begin
if(we[i])
begin
mem[i][addr[i]] <= din[i];
end
dout[i] <= mem[i][addr[i]];
end
end
end
endgenerate
endmodule
Filename: ram_sp_3d.vhd
library ieee;
use ieee.std_logic_1164.all;
package mypack is
type myarray_t is array(integer range<>) of std_logic_vector;
type mem_t is array(integer range<>) of myarray_t;
end package;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.mypack.all;
entity rams_sp_3d is generic (
NUM_RAMS : integer := 2;
A_WID : integer := 10;
D_WID : integer := 32
);
port (
clk : in std_logic;
we : in std_logic_vector(NUM_RAMS-1 downto 0);
ena : in std_logic_vector(NUM_RAMS-1 downto 0);
addr : in myarray_t(NUM_RAMS-1 downto 0)(A_WID-1 downto 0);
din : in myarray_t(NUM_RAMS-1 downto 0)(D_WID-1 downto 0);
dout : out myarray_t(NUM_RAMS-1 downto 0)(D_WID-1 downto 0)
);
end rams_sp_3d;
end arch;
Filename: rams_sdp_3d.sv
genvar i;
generate
for(i=0;i<NUM_RAMS;i=i+1)
begin:port_a_ops
always @ (posedge clka)
begin
if (ena[i]) begin
if(wea[i])
begin
mem[i][addra[i]] <= dina[i];
end
end
end
end
endgenerate
//PORT_B
generate
for(i=0;i<NUM_RAMS;i=i+1)
begin:port_b_ops
always @ (posedge clkb)
begin
if (enb[i])
doutb[i] <= mem[i][addrb[i]];
end
end
endgenerate
endmodule
filename: rams_sdp_3d.vhd
library ieee;
use ieee.std_logic_1164.all;
package mypack is
type myarray_t is array(integer range<>) of std_logic_vector;
type mem_t is array(integer range<>) of myarray_t;
end package;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.mypack.all;
entity rams_sdp_3d is generic (
NUM_RAMS : integer := 2;
A_WID : integer := 10;
D_WID : integer := 32
);
port (
clka : in std_logic;
clkb : in std_logic;
wea : in std_logic_vector(NUM_RAMS-1 downto 0);
ena : in std_logic_vector(NUM_RAMS-1 downto 0);
enb : in std_logic_vector(NUM_RAMS-1 downto 0);
addra : in myarray_t(NUM_RAMS-1 downto 0)(A_WID-1 downto 0);
process(clkb)
begin
if(clkb'event and clkb='1') then
for i in 0 to NUM_RAMS-1 loop
if(enb(i) = '1') then
doutb(i) <= mem(i)(to_integer(unsigned(addrb(i))));
end if;
end loop;
end if;
end process;
end arch;
Filename: rams_tdp_3d.sv
//PORT_B
generate
for(i=0;i<NUM_RAMS;i=i+1)
begin:port_b_ops
always @ (posedge clkb)
begin
if (enb[i]) begin
if(web[i])
begin
mem[i][addrb[i]] <= dinb[i];
end
doutb[i] <= mem[i][addrb[i]];
end
end
end
endgenerate
endmodule
Filename: rams_sp_struct.sv
module rams_sdp_struct #(
parameter A_WID = 10,
D_WID = 32
)
(
input clk,
input we,
input ena,
input [A_WID-1:0] raddr, waddr,
input Packet din,
output Packet dout
);
Filename: rams_sp_record.vhd
library ieee;
use ieee.std_logic_1164.all;
package mypack is
type Packet is record
addr : std_logic_vector(3 downto 0);
data : std_logic_vector(27 downto 0);
end record Packet;
type mem_t is array(integer range<>) of Packet;
end package;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.mypack.all;
entity rams_sp_record is generic (
A_WID : integer := 10;
D_WID : integer := 32
);
port (
clk : in std_logic;
we : in std_logic;
ena : in std_logic;
addr : in std_logic_vector(A_WID-1 downto 0);
din : in Packet;
dout : out Packet
);
end rams_sp_record;
end arch;
Filename: rams_sdp_struct.sv
module rams_sdp_struct #(
parameter A_WID = 10,
D_WID = 32
)
(
input clk,
input we,
input ena,
input [A_WID-1:0] raddr, waddr,
input Packet din,
output Packet dout
);
Filename: rams_sdp_record.vhd
library ieee;
use ieee.std_logic_1164.all;
package mypack is
type Packet is record
addr : std_logic_vector(3 downto 0);
data : std_logic_vector(27 downto 0);
end record Packet;
type mem_t is array(integer range<>) of Packet;
end package;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.mypack.all;
entity rams_sdp_record is generic (
A_WID : integer := 10;
D_WID : integer := 32
);
port (
clk : in std_logic;
we : in std_logic;
ena : in std_logic;
raddr : in std_logic_vector(A_WID-1 downto 0);
waddr : in std_logic_vector(A_WID-1 downto 0);
din : in Packet;
dout : out Packet
);
end rams_sdp_record;
process(clk)
begin
if(clk'event and clk='1') then
if(ena = '1') then
dout <= mem(to_integer(unsigned(raddr)));
end if;
end if;
end process;
end arch;
Filename: rams_tdp_struct.sv
module rams_tdp_struct #(
parameter A_WID = 10,
D_WID = 32
)
(
input clka,
input clkb,
input wea,
input web,
input ena,
input enb,
input [A_WID-1:0] addra,
input [A_WID-1:0] addrb,
input Packet dina, dinb,
output Packet douta, doutb
);
endmodule
Filename: rams_tdp_record.vhd
library ieee;
use ieee.std_logic_1164.all;
package mypack is
type Packet is record
addr : std_logic_vector(3 downto 0);
data : std_logic_vector(27 downto 0);
end record Packet;
type mem_t is array(integer range<>) of Packet;
end package;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.mypack.all;
entity rams_tdp_record is generic (
A_WID : integer := 10;
D_WID : integer := 32
);
port (
clka : in std_logic;
clkb : in std_logic;
wea : in std_logic;
web : in std_logic;
ena : in std_logic;
enb : in std_logic;
addra : in std_logic_vector(A_WID-1 downto 0);
addrb : in std_logic_vector(A_WID-1 downto 0);
dina : in Packet;
dinb : in Packet;
douta : out Packet;
doutb : out Packet
);
end rams_tdp_record;
process(clka)
begin
if(clka'event and clka='1') then
if(ena = '1') then
douta <= mem(to_integer(unsigned(addra)));
if(wea = '1') then
mem(to_integer(unsigned(addra))) <= dina;
end if;
end if;
end if;
end process;
process(clkb)
begin
if(clkb'event and clkb='1') then
if(enb = '1') then
end arch;
Black Boxes
A design can contain EDIF files generated by:
• Synthesis tools
• Schematic text editors
• Any other design entry mechanism
These modules must be instantiated to be connected to the rest of the design. Use BLACK_BOX
instantiation in the HDL source code.
Vivado synthesis lets you apply specific constraints to these BLACK_BOX instantiations. After
you make a design a BLACK_BOX, each instance of that design is a BLACK_BOX. Download the
coding example files from Coding Examples.
// Black Box
// black_box_1.v
//
(* black_box *) module black_box1 (in1, in2, dout);
input in1, in2;
output dout;
endmodule
black_box1 U1 (
.in1(DI_1),
.in2(DI_2),
.dout(DOUT)
);
endmodule
-- Black Box
-- black_box_1.vhd
library ieee;
use ieee.std_logic_1164.all;
entity black_box_1 is
port(DI_1, DI_2 : in std_logic;
DOUT : out std_logic);
end black_box_1;
architecture rtl of black_box_1 is
component black_box1
port(I1 : in std_logic;
I2 : in std_logic;
O : out std_logic);
end component;
begin
U1 : black_box1 port map(I1 => DI_1, I2 => DI_2, O => DOUT);
end rtl;
FSM Components
Vivado Synthesis Features
• Specific inference capabilities for synchronous Finite State Machine (FSM) components.
• Built-in FSM encoding strategies to accommodate your optimization goals.
• FSM extraction is enabled by default.
• Use -fsm_extraction off to disable FSM extraction.
FSM Description
Vivado synthesis supports specification of Finite State Machine (FSM) in both Moore and Mealy
form. An FSM consists of the following:
• A state register
• A next state function
• An outputs function
FSM Diagrams
The following diagram shows an FSM representation that incorporates Mealy and Moore
machines.
Figure 19: FSM Representation Incorporating Mealy and Moore Machines Diagram
FSM Registers
• Specify a reset or power-up state for Vivado synthesis to identify a Finite State Machine
(FSM) or set the value of FSM_ENCODING to "none".
• The State Register can be asynchronously or synchronously reset to a particular state.
Note: Use synchronous reset logic over asynchronous reset logic for an FSM.
• Guarantees that only one bit switches between two consecutive states.
• Is appropriate for controllers exhibiting long paths without branching.
• Minimizes hazards and glitches.
• Can be used to minimize power dissipation.
Filename: fsm_1.v
parameter s1 = 3'b000;
parameter s2 = 3'b001;
parameter s3 = 3'b010;
parameter s4 = 3'b011;
parameter s5 = 3'b111;
always@(posedge clk)
begin
if(reset)
begin
state <= s1;
sm_out <= 1'b1;
end
else
begin
case(state)
s1: if(flag)
begin
state <= s2;
sm_out <= 1'b1;
end
else
begin
state <= s3;
sm_out <= 1'b0;
end
s2: begin state <= s4; sm_out <= 1'b0; end
s3: begin state <= s4; sm_out <= 1'b0; end
s4: begin state <= s5; sm_out <= 1'b1; end
s5: begin state <= s1; sm_out <= 1'b1; end
endcase
end
end
endmodule
Filename: fsm_1.vhd
entity fsm_1 is
port(
clk, reset, flag : IN std_logic;
else
case state is
when s1 => if flag = '1' then
state <= s2;
sm_out <= '1';
else
state <= s3;
sm_out <= '0';
end if;
when s2 => state <= s4;
sm_out <= '0';
when s3 => state <= s4;
sm_out <= '0';
when s4 => state <= s5;
sm_out <= '1';
when s5 => state <= s1;
sm_out <= '1';
end case;
end if;
end if;
end process;
end behavioral;
FSM Reporting
The Vivado synthesis flags INFO messages in the log file, giving information about Finite State
Machine (FSM) components and their encoding. The following are example messages:
INFO: [Synth 8-802] inferred FSM for state register 'state_reg' in module
'fsm_test'
INFO: [Synth 8-3354] encoded FSM with state register 'state_reg' using
encoding 'sequential' in module 'fsm_test'
endmodule
entity roms_1 is
port(
clk : in std_logic;
en : in std_logic;
addr : in std_logic_vector(5 downto 0);
data : out std_logic_vector(19 downto 0)
);
end roms_1;
begin
process(clk)
begin
if rising_edge(clk) then
if (en = '1') then
data <= ROM(conv_integer(addr));
end if;
end if;
end process;
end behavioral;
Chapter 6
VHDL Support
Introduction
This chapter describes the supported VHDL language constructs in AMD Vivado™ synthesis and
notes any exceptions to support. VHDL compactly describes complicated logic, and lets you:
• Describe the structure of a system: how the system is decomposed into subsystems, and how
those subsystems are interconnected.
• Specify the function of a system using familiar language forms.
• Simulate a system design before it is implemented and programmed in hardware.
• Produce a detailed, device-dependent version of a design to be synthesized from a more
abstract specification.
For more information, see the IEEE VHDL Language Reference Manual (LRM).
Defined In IEEE
Type SubType Of Contains Values
Package
std_ulogic std_logic_1164 N/A Same values as std_logic
Does not contain predefined
resolution functions
X01 std_logic_1164 std_ulogic X, 0, 1
X01Z std_logic_1164 std_ulogic X, 0, 1, Z
UX01 std_logic_1164 std_ulogic U, X, 0, 1
UX01Z std_logic_1164 std_ulogic U, X, 0, Z
You can also take advantage of the predefined natural and positive types, overloading the integer
type.
RECOMMENDED: Although there is no restriction on the number of dimensions, describe no more than
three dimensions.
Objects of multi-dimensional array type can be passed to functions and used in component
instantiations. Objects of multi-dimensional array type that you can describe are signals,
constants, and variables.
VHDL Objects
VHDL objects include: Signals, Variables, Constants, and Operators.
Signals
Declare a VHDL signal in:
• An architecture declarative part: Use the VHDL signal anywhere within that architecture.
• A block: Use the VHDL signal within that block.
Assign the VHDL signal with the <= signal assignment operator.
Variables
A VHDL variable is:
Constants
You can declare a VHDL constant in any declarative region. The constant is used within that
region. You cannot change the constant values after they are declared.
Operators
Vivado synthesis supports VHDL operators.
• Entity declaration: Provides the external view of the circuit. Describes objects visible from the
outside, including the circuit interface, such as the I/O ports and generics.
• Architecture: Provides the internal view of the circuit, and describes the circuit behavior or
structure.
• name
• mode (in, out, inout, buffer)
• type
RECOMMENDED: Do not use unconstrained ports. Define ports that are constrained through generics.
Apply different values of those generics at instantiation. Do not have an unconstrained port on the top-
level entity.
Array types of more than one-dimension are not accepted as ports. The entity declaration can
also declare VHDL generics.
VHDL allows buffer port mode when a signal is used both internally, and as an output port when
there is only one internal driver. Buffer ports are a potential source of errors during synthesis,
and complicate validation of post-synthesis results through simulation.
In the previous coding example, signal C was modeled with a buffer mode, and is used both
internally and as an output port. Every level of hierarchy that can be connected to C must also be
declared as a buffer.
entity EXAMPLE is
port (
A,B,C : in std_logic;
D,E : out std_logic );
end EXAMPLE;
1. Create the design unit (entity and architecture) modeling the functionality to be instantiated.
2. Declare the component to be instantiated in the declarative region of the parent design unit
architecture.
3. Instantiate and connect this component in the architecture body of the parent design unit.
4. Map (connect) formal ports of the component to actual signals and ports of the parent design
unit.
Filename: instantiation_simple.vhd
This coding example shows the structural description of a half-Adder composed of four nand2
components.
--
-- A simple component instantiation example
-- Involves a component declaration and the component instantiation itself
--
-- instantiation_simple.vhd
--
entity sub is
generic(
WIDTH : integer := 4
);
port(
A, B : in BIT_VECTOR(WIDTH - 1 downto 0);
O : out BIT_VECTOR(2 * WIDTH - 1 downto 0)
);
end sub;
entity instantiation_simple is
generic(
WIDTH : integer := 2);
port(
X, Y : in BIT_VECTOR(WIDTH - 1 downto 0);
Z : out BIT_VECTOR(2 * WIDTH - 1 downto 0));
end instantiation_simple;
begin
inst_sub : sub -- component instantiation
generic map(
WIDTH => WIDTH
)
port map(
A => X,
B => Y,
O => Z
);
end ARCHI;
Filename: instantiation_recursive.vhd
--
-- Recursive component instantiation
--
-- instantiation_recursive.vhd
--
library ieee;
use ieee.std_logic_1164.all;
library unisim;
use unisim.vcomponents.all;
entity instantiation_recursive is
generic(
sh_st : integer := 4
);
port(
CLK : in std_logic;
DI : in std_logic;
DO : out std_logic
);
end entity instantiation_recursive;
• All NAND2 components use the design unit consisting of entity NAND2 and architecture
ARCHI.
• The design unit is compiled in the work library.
For all : NAND2 use entity work.NAND2(ARCHI);
The value of the top module name (-top) option in the synth_design command is the
configuration name instead of the top-level entity name.
VHDL GENERICS
VHDL GENERICs have the following properties:
For the same functionality that must be instantiated multiple times, but with different bus sizes,
you need describe only one design unit with generics. See the GENERIC Parameters Example.
Declaring Generics
You can declare generic parameters in the entity declaration part. Supported generics types are:
integer, boolean, string, and real.
Filename: generics_1.vhd
entity addern is
generic(
width : integer := 8
);
port(
A, B : in std_logic_vector(width - 1 downto 0);
Y : out std_logic_vector(width - 1 downto 0)
);
end addern;
Library IEEE;
use IEEE.std_logic_1164.all;
entity generics_1 is
port(
X, Y, Z : in std_logic_vector(12 downto 0);
A, B : in std_logic_vector(4 downto 0);
S : out std_logic_vector(17 downto 0));
end generics_1;
Note:
When overriding generic values during instantiation, splitting up different array elements is not supported.
For example, if there is a generic my_gen defined as an array, as follows, it does not work:
my_gen(1) => x,
my_gen(0) => y
Supported types of concurrent signal assignments are: Simple Signal Assignment Example, and
Concurrent Selection Assignment Example (VHDL).
entity concurrent_selected_assignment is
generic(
width : integer := 8);
port(
a, b, c, d : in std_logic_vector(width - 1 downto 0);
sel : in std_logic_vector(1 downto 0);
T : out std_logic_vector(width - 1 downto 0));
end concurrent_selected_assignment;
Generate Statements
Generate statements include:
• for-generate statements
• if-generate statements
Filename: for-generate.vhd
In this coding example, the for-generate statement describes the calculation of the result and
carries out for each bit position of this 8-bit adder.
--
-- A for-generate example
--
-- for_generate.vhd
--
entity for_generate is
port(
A, B : in BIT_VECTOR(0 to 7);
CIN : in BIT;
SUM : out BIT_VECTOR(0 to 7);
COUT : out BIT
);
end for_generate;
For example, when a generic indicates which device family is being targeted, the if-generate
statement tests the value of the generic against a specific device family and activates a section of
the HDL source code written specifically for that device family.
Filename: if_for_generate.vhd
In this coding example, a generic N-bit adder with a width ranging between 4 and 32 is described
with an if-generate and a for-generate statement.
Combinatorial Processes
You can model VHDL combinatorial logic with a process, which explicitly assigns signals a new
value every time the process is executed.
IMPORTANT! No signals should implicitly retain its current value, and a process can contain local
variables.
Memory Elements
Hardware inferred from a combinatorial process does not involve any memory elements.
A memory element process is combinatorial when all assigned signals in a process are always
explicitly assigned in all possible paths within a process block.
A signal that is not explicitly assigned in all branches of an if or case statement typically leads to a
Latch inference.
IMPORTANT! If Vivado synthesis infers unexpected Latches, review the HDL source code for a signal that
is not explicitly assigned.
Sensitivity List
A combinatorial process has a sensitivity list. The sensitivity list appears within parentheses after
the PROCESS keyword. A process is activated if an event (value change) appears on one of the
sensitivity list signals. For a combinatorial process, this sensitivity list must contain:
Missing Signals
Signals might be missing from the sensitivity list. If one or more signals is missing from the
sensitivity list:
• The synthesis results can differ from the initial design specification.
• Vivado synthesis issues a warning message.
• Vivado synthesis adds the missing signals to the sensitivity list.
IMPORTANT! To avoid problems during simulation, explicitly add all missing signals in the HDL source
code and re-run synthesis.
entity signal_in_process is
port(
A, B : in BIT;
S : out BIT
);
end signal_in_process;
entity variable_in_process is
port(
A, B : in std_logic_vector(3 downto 0);
ADD_SUB : in std_logic;
S : out std_logic_vector(3 downto 0)
);
end variable_in_process;
process(A, B, ADD_SUB)
variable AUX : std_logic_vector(3 downto 0);
begin
if ADD_SUB = '1' then
AUX := A + B;
else
AUX := A - B;
end if;
S <= AUX;
end process;
end archi;
If none of the branches match, a case statement executes the default branch.
• Constant bounds
• Stop test condition using the following operators: <, <=, >, and >=.
• Next step computations falling within one of the following specifications:
○ var = var + step
Filename: for_loop.vhd
--
-- For-loop example
--
-- for_loop.vhd
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
entity for_loop is
port(
a : in std_logic_vector(7 downto 0);
Count : out std_logic_vector(2 downto 0)
);
end for_loop;
Modelization of the synchronous logic (data, optional synchronous set/reset, optional clock
enable) is done in the if branch of the clock event.
Missing Signals
If any signals are missing from the sensitivity list, the synthesis results can differ from the initial
design specification. In this case, Vivado synthesis issues a warning message and adds the
missing signals to the sensitivity list.
IMPORTANT! To avoid problems during simulation, explicitly add all missing signals in the HDL source
code and re-run synthesis.
The wait statement is the first statement and the condition in the wait statement describes the
sequential logic clock.
IMPORTANT! The same sequential process cannot have both a sensitivity list and a wait statement, and
only one wait statement is allowed.
process begin
wait until rising_edge(clk) and clken = '1';
q <= d;
end process;
process begin
wait until rising_edge(clk);
if clken = '1' then
q <= d;
end if;
end process;
IMPORTANT! You cannot describe a sequential element with asynchronous control logic using a process
without a sensitivity list. Only a process with a sensitivity list allows such functionality. Vivado synthesis
does not allow the description of a Latch based on a wait statement. For greater flexibility, describe
synchronous logic using a process with a sensitivity list.
--
-- Register initialization
-- Specifying initial contents at circuit powes-up
-- Specifying an operational set/reset
--
-- File: VHDL_Language_Support/initial/initial_1.vhd
--
library ieee;
use ieee.std_logic_1164.all;
entity initial_1 is
Port(
clk, rst : in std_logic;
din : in std_logic;
dout : out std_logic
);
end initial_1;
end process;
A function or procedure consists of a declarative part and a body. The declarative part specifies:
IMPORTANT! Resolution functions are not supported except the function defined in the IEEE
std_logic_1164 package.
This coding example declares an ADD function within a package. The ADD function is a single-bit
Adder and is called four times to create a 4-bit Adder. The following example uses a function:
use work.PKG.all;
entity function_package_1 is
port(
A, B : in BIT_VECTOR(3 downto 0);
CIN : in BIT;
S : out BIT_VECTOR(3 downto 0);
COUT : out BIT
);
end function_package_1;
use work.PKG.all;
entity procedure_package_1 is
port(
A, B : in BIT_VECTOR(3 downto 0);
CIN : in BIT;
S : out BIT_VECTOR(3 downto 0);
COUT : out BIT
);
end procedure_package_1;
CAUTION! Care should be taken using asserts. Vivado can only support static asserts that do not create
or are created by behavior. For example, performing as assert on a value of a constant or an operator/
generic works; however, as an asset on the value of a signal inside an if statement does not work.
• numeric_bit
○ Unsigned and signed vector types based on bit.
○ Overloaded arithmetic operators, conversion functions, and extended functions for these
types.
• std_logic_1164
○ std_logic, std_ulogic, std_logic_vector, and std_ulogic_vector types.
• numeric_std
○ Unsigned and signed vector types based on std_logic.
○ Overloaded arithmetic operators, conversion functions, and extended functions for these
types. Equivalent to std_logic_arith.
• fixed_pkg
○ For fixed variable and pin types.
○ use ieee.fixed_pkg.all;
• float_pkg
○ For floating variable and pin types.
○ use ieee.float_pkg.all;
○ Overloaded arithmetic operators, conversion functions, and extended functions for these
types.
• std_logic_unsigned (Synopsys)
• std_logic_signed (Synopsys)
○ Signed arithmetic operators for std_logic and std_logic_vector
• std_logic_misc (Synopsys)
○ Supplemental types, subtypes, constants, and functions for the std_logic_1164 package,
such as and_reduce and or_reduce.
Defining a VHDL package permits access to shared definitions and models from other parts of
your project and requires the following:
• Package body: Describes the functions and procedures declared in the package declaration.
1. Use a library clause to include the library in which the package is compiled. For example:
library library_name;
2. Designate the package, or a specific definition contained in the package, with a use clause.
For example: use library_name.package_name.all.
3. Insert these lines immediately before the entity or architecture in which you use the package
definitions.
Because the work library is the default library, you can omit the library clause if the designated
package has been compiled into this library.
Chapter 7
Introduction
AMD Vivado™ synthesis supports a synthesizable subset of the VHDL-2008 standard. The
following section describes the supported subset and the procedures to use it.
You can also set files to VHDL-2008 with the set_property command in the Tcl Console. The
syntax is as follows:
Finally, in the Non-Project or Tcl flow, the command for reading in VHDL has VHDL-2008 as
follows:
If you want to read in more than one file, you can either use multiple read_vhdl commands or
multiple files with one command, as follows:
Operators
Matching Relational Operators
VHDL-2008 now provides relational operators that return bit or std_logic types. In the previous
VHDL standard, the relational operators (=, <, >=…) returned boolean types. With the new types,
code that needed to be written as:
if x = y then
out1 <= '1';
else
out1 <= '0';
end if;
out1 <= x ?= y;
would AND the 4 bits together and return 0 . The logical functions have unary support are: and,
nand, or, nor, xor, and xnor.
VHDL-2008 supports using logical operators when one of the operands is an array and one is a
scalar. For example, to AND one bit with all the bits of a vector, the following code was needed:
Statements
If-else- If and Case Generate
Previously in VHDL, if-generate statements took the form of the following:
if condition generate
--- statements
end generate;
An issue appears if you want to have different conditions; you would need to write multiple
generates and be very careful with the ordering of the generates. VHDL-2008 supports if-
else-if generate statements.
if condition generate
---statements
elsif condition2 generate
---statements
else generate
---statements
end generate;
Sequential Assignments
VHDL-2008 allows sequential signal and variable assignment with conditional signals. For
example, a register with an enable would be written as the following:
process(clk) begin
if clk'event and clk='1' then
if enable then
my_reg <= my_input;
end if;
end if;
end process;
process(clk) begin
if clk'event and clk='1' then
my_reg <= my_input when enable else my_reg;
end if;
end process;
process(clk) begin
if clk'event and clk='1' then
case? my_reg is
when "01--" => out1 <= in1;
when "000-" => out1 <= in2;
when "1111" => out1 <= in3;
when others => out1 <= in4;
end case?;
end if;
end process;
Note: For this statement to work, the signal in question must be assigned an explicit don’t care.
process(clk) begin
if clk'event and clk='1' then
with my_reg select?
out1 <= in1 when "11--",
in2 when "000-",
in3 when "1111",
in4 when others;
end if;
end process;
Note: For this statement to work, the signal in question must be assigned an explicit don’t care.
std_logic_vector(3 downto 0) :
(my_reg1, my_reg2, enable, reset) <= in1;
This example assigns all four signals to the individual bits of in1:
enable is in1(1)
reset is in1(0)
In addition, these signals can be assigned out of order, as shown in the following example:
(1=> enable, 0 => reset, 3 => my_reg1, 2 => my_reg2) <= in1;
Types
Unconstrained Element Types
Previously, in VHDL, types and subtypes had to be fully constrained in declaring the type. In
VHDL-2008, it is allowed to be unconstrained, and the constraining happens with the objects
that are of that type; consequently, types and subtypes are more versatile. For example:
In previous versions of VHDL, the preceding example was done with 2 subtypes. Now, in
VHDL-2008, this can be accomplished with one type. This can even be done for arrays, as shown
in the following example:
Miscellaneous
Reading Output Ports
In previous versions of VHDL, it was illegal to use signals declared as out for anything other than
an output.
So if you wanted to assign a value to an output, and also use that same signal for other logic, you
would either have to declare a new signal and have that drive the output and the other logic, or
switch from an out to a buffer type.
VHDL-2008 lets you use output values, as shown in the following example:
process(clk) begin
if clk'event an clk='1' then
out1 <= in1;
my_reg <= out1; -- THIS WOULD HAVE BEEN ILLEGAL in VHDL.
out2 <= my_reg;
end if;
end process;
In the previous case, the entity, my_entity had a port called in1 that was of type integer, but
in the upper-level, the signal, my_signal was of type std_logic_vector.
Previously in VHDL, you would have to create a new signal of type integer and do the
conversion outside of the instantiation, and assign that new signal to the port map.
In addition to type conversion, you can put logic into the port map, as shown in the following
example:
U0 : my_entity port map (clk => clk, enable => en1 and en2 ...
In this case, the lower-level has an enable signal. On the top level that enable is tied to the
AND of two other signals.
Previously in VHDL, this, like the previous example, would have needed a new signal and
assignment, but in VHDL-2008 can be accomplished in the port map of the instantiation.
With VHDL-2008, you can use the process(all) statement that looks for all the inputs to the
process and creates the logic.
process(all) begin
enable <= en1 and en2;
end process;
In previous versions of VHDL, having the length of gen2 be controlled by gen1 was illegal.
Generics in Packages
VHDL-2008 supports putting a generic in a package and being able to override that generic when
the package is declared. For example:
package my_pack is
generic(
length : integer);
This declares a subtype of std_logic_vector but does not specify the length. The calling VHDL file
specifies what the length should be when the package is instantiated:
library ieee;
use leee.std_logic_1164.all;
library ieee;
use ieee.std_logic_1164.all;
This code uses the same package to declare two different subtypes and be able to use them.
entity my_entity is
generic (type my_type);
This would declare an entity with an undetermined type, and the RTL that instantiates my_entity
would look like:
The previous code instantiates my_entity twice, but in one case, out1 is a bit, and in the other
case, out1 is a 4-bit vector.
Functions in Generics
In VHDL-2008, you can declare undefined functions inside of entities. For example
entity bottom is
generic (
function my_func (a,b : unsigned) return unsigned);
port ...
......
end entity bottom;
process(clk) is
begin
if rising_edge(clk) then
y <= my_func(a,b);
end if;
end process;
This uses the my_func function, inside of the entity, but it still has not defined what this function
actually accomplishes. That is defined as when the bottom is instantiated in an upper-level RTL.
inst_bot1 : bottom
generic map (
my_func => my_func1 )
port map ...
This ties the function my_func1 that was declared in a VHDL file or a package file to the generic
function my_func. As long as my_func1 has two inputs called a and b that are both unsigned, it is
able to work.
Because concatenation is not static, this would return an error or warning in VHDL; however, it is
allowed with VHDL-2008.
for I in my_signal'range...
This would require that the range of my_signal be fixed, but if my_signal was declared as an
unconstrained type, this would result in an error. VHDL-2008 now allows this by getting the
range at the time of elaboration.
Block Comments
In VHDL, comments “ -- “ were required for each line that had a comment. In VHDL-2008, there
is support for blocks of comments using the /* and */ lines.
process(clk) begin
if clk'event and clk='1' then
/* this
is
a block
comment */
out1 <= in1;
end if;
end process;
Chapter 8
Introduction
AMD Vivado™ synthesis supports a synthesizable subset of the VHDL-2019 standard. The
following section describes what is supported and how to use it.
You can also set files to VHDL-2019 with the set_property command in the Tcl Console. The
syntax is as follows:
For the non-project or Tcl flow, the command for reading in VHDL-2019 is :
If you want to read in more than one file, you can either use multiple read_vhdl commands or
multiple files with one command, as follows:
Note: This is a relatively new language for Vivado. New features in this language will be added each release
and will be added to the documentation
Interfaces
VHDL-2019 Interfaces are implemented using the record and view keywords. The type record
is used to set up the interface, for example :
Then the view acts like the SystemVerilog modport to indicate which signals act like inputs and
which act like outputs :
Then these views can be used for the port declarations of the hierarchies :
entity my_ent is
Port (
Int_1 : view TxView;
Int_2 : view RxView
);
end entity my_ent;
Conditional Identifiers
Vivado synthesis supports conditional identifiers that can be used to control synthesis based on
the Tool or the version.
For example, the following code will create an extra output if the Tool is a synthesis tool :
IDENTIFIER VALUE
VHDL_VERSION “2023.1”
TOOL_TYPE “SYNTHESIS”
TOOL_VENDOR “AMD/XILINX”
TOOL_NAME “Vivado”
TOOL_EDITION “ML Editions”
TOOLS_VERSION “2023.1”
VHDL_VERSION “2019”
64-bit Integers
For VHDL-2019, integer types are now 64-bit instead of 32-bit. This is automatic and the RTL
does not need to be changed to take advantage of this.
Chapter 9
Introduction
This chapter describes the AMD Vivado™ synthesis support for the Verilog Hardware Description
Language.
Coding examples are included in this chapter. Download the coding example files from Coding
Examples.
Verilog Design
Complex circuits are often designed using a top-down methodology.
• Varying specification levels are required at each stage of the design process. For example, at
the architectural level, a specification can correspond to a block diagram or an Algorithmic
State Machine (ASM) chart.
• A block or ASM stage corresponds to a register transfer block in which the connections are N-
bit wires, such as:
○ Register
○ Adder
○ Counter
○ Multiplexer
○ Interconnect logic
• Verilog allows the expression of notations such as ASM charts and circuit diagrams in a
computer language.
Verilog Functionality
Verilog provides both behavioral and structural language structures. These structures allow the
expression of design objects at high and low levels of abstraction.
• Designing hardware with Verilog allows the use of software concepts such as:
○ Parallel processing
○ Object-oriented programming
○ Synthesis in this context is the compilation of high-level behavioral and structural Verilog
HDL statements into a flattened gate-level netlist. The netlist can be used to custom-
program a programmable logic device such as a Virtex device.
○ Different synthesis methods are used for:
• Arithmetic blocks
• Interconnect logic
• Finite State Machine (FSM) components
For information about basic Verilog concepts, see the IEEE Verilog HDL Reference Manual.
Verilog-2001 Support
Vivado synthesis supports the following Verilog-2001 features.
• Generate statements
• Combined port/data type declarations
• ANSI-style port list
• Module operator port lists
• ANSI C style task/function declarations
• Comma-separated sensitivity list
• Combinatorial logic sensitivity
• Default nets with continuous assigns
• Sutherland, Stuart. Verilog 2001: A Guide to the New Features of the Verilog Hardware Description
Language (2002)
• IEEE Standard Verilog Hardware Description Language Manual (IEEE Standard1364-2001)
Instead of being bounded by two explicit values, the variable part select is defined by the starting
point of its range and the width of the vector. The starting point of the part select can vary. The
width of the part select remains constant.
Symbol Meaning
+ (plus) The part select increases from the starting point.
- (minus) The part select decreases from the starting point
Structural Verilog
Structural Verilog descriptions assemble several blocks of code and allow the introduction of
hierarchy in a design. The following table lists the concepts of hardware structure and their
descriptions.
Concept Description
Component Building or basic block
Port Component I/O connector
Signal Corresponds to a wire between components
The following table lists the Verilog Components, the view, and what the components describe.
○ Contains an association list (the parenthesized list). The list specifies the signals and ports
associated with a given local port.
• AND
• OR
• XOR
• NAND
• NOR
• NOT
not a_inv (a_not, a);not b_inv (b_not, b);and a1 (x, a_not, b);and a2 (y,
b_not, a);or out (c, x, y);
endmodule
Half-Adder Example
This coding example shows the structural description of a half-Adder composed of four, 2-input
nand modules.
nand NANDA (S3, X, Y);nand NANDB (S1, X, S3);nand NANDC (S2, S3, Y);nand
NANDD (S, S1, S2);assign C = S3;
endmodule
These primitives are additional to those included in Verilog, and are supplied with the AMD
Verilog libraries (unisim_comp.v).
Verilog Parameters
Verilog parameters do the following:
• Allow you to create parameterized code that can be easily reused and scaled.
• Make code more readable, more compact, and easier to maintain.
• Describe such functionality as:
○ Bus sizes
• Are constants. For each instantiation of a parameterized module, default operator values can
be overridden.
• Are the equivalent of VHDL generics. Null string parameters are not supported.
Use the Generics command line option to redefine Verilog parameters defined in the top-level
design block. This allows you to modify the design without modifying the source code. This
feature is useful for IP core generation and flow testing.
Filename: parameter_1.v
parameter SIZE = 1;
endmodule
parameter SIZE = 8;
endmodule
Filename: parameter_generate_for_1.v
//
// A shift register description that illustrates the use of parameters and
// generate-for constructs in Verilog
//
// File: parameter_generate_for_1.v
//
module parameter_generate_for_1 (clk, si, so);
parameter SIZE = 8;
input clk;
input si;
output so;
reg [0:SIZE-1] s;
assign so = s[SIZE-1];
genvar i;
generate
for (i = 1; i < SIZE; i = i+1)
begin : shreg
always @ (posedge clk)
begin
s[i] <= s[i-1];
end
end
endgenerate
endmodule
• Parameters and attributes can be applied to both instances and modules in the Verilog code.
• Attributes can also be specified in a constraints file.
• Case Sensitivity
• Blocking and Non-Blocking Assignments
• Integer Handling
Case Sensitivity
Vivado synthesis supports Verilog case sensitivity despite the potential of name collision.
• Because Verilog is case-sensitive, the names of modules, instances, and signals can
theoretically be made unique by changing capitalization.
○ Vivado synthesis can synthesize a design in which instance and signal names differ only by
capitalization.
○ Vivado synthesis errors out when module names differ only by capitalization.
• Do not rely on capitalization alone to make object names unique. Capitalization alone can
cause problems in mixed language projects.
For more information about the Verilog format for Vivado simulation, see Vivado Design Suite
User Guide: Logic Simulation (UG900).
always @(in1)
begin
if (in2)
out1 = in1;
end else
out1 <= in2;
if (in2)
begin
out1[0] = 1'b0;
out1[1] <= in1;
end else begin
out1[0] = in2;
out1[1] <= 1'b1;
end
Integer Handling
Vivado synthesis handles integers differently from other synthesis tools in some situations. In
those instances, the integers must be coded in a particular way.
○ Instance
○ Net
• Parallel Case
// synthesis parallel_case full_case
// synthesis parallel_case
// synthesis full_case
Verilog Constructs
The following table lists the support status of Verilog constructs in Vivado synthesis.
• wand Supported
• wor
All Drive strengths Ignored
Real and realtime registers Unsupported
All Named events Unsupported
Delay Ignored
Verilog Procedural Assignments
assign Supported with limitations. See Using assign and deassign
Statements.
deassign Supported with limitations. See Using assign and deassign
Statements.
force Unsupported
release Unsupported
forever statements Unsupported
repeat statements Supported, but repeat value must be constant
for statements Supported, but bounds must be static
delay (#) Ignored
event (@) Unsupported
wait Unsupported
named events Unsupported
parallel blocks Unsupported
specify blocks Ignored
disable Supported
Verilog Design Hierarchies
module definition Supported
macromodule definition Unsupported
$signed(expr) or $unsigned(expr)
• The return value from these calls is the same size as the input value.
• The sign of the return value is forced regardless of any previous sign.
$readmemb("rams_20c.data",ram, 0, 7);
Verilog Primitives
Vivado synthesis supports Verilog gate-level primitives except as shown in the following table.
Vivado synthesis does not support Verilog switch-level primitives, such as the following:
cmos, nmos, pmos, rcmos, rnmos, rpmos rtran, rtranif0, rtranif1, tran,
tranif0, tranif1
Primitive Status
pulldown and pullup Unsupported
drive strength and delay Ignored
Arrays of primitives Unsupported
Behavioral Verilog
Vivado synthesis supports the behavioral Verilog Hardware Description Language (HDL), except
as otherwise noted.
○ To specify an N-bit width (vectors) for a declared reg or wire, the left and right bit positions
are defined in square brackets separated by a colon.
○ In Verilog-2001, reg and wire data types can be signed or unsigned.
Initial Values
Initialize registers in Verilog-2001 when they are declared.
• When you assign a register as an initial value in a declaration, Vivado synthesis sets this value
on the output of the register at global reset or power up.
• When a value is assigned in this manner:
○ The value is carried in the Verilog file as an INIT attribute on the register.
• Assign the value to the register when the register reset line goes to the appropriate value. See
the following coding example.
• When you assign the initial value to a variable:
○ The value is implemented as a Flip-Flop, the output of which is controlled by a local reset.
Multi-Dimensional Arrays
Vivado synthesis supports multi-dimensional array types of up to two dimensions.
Data Types
The Verilog representation of the bit data type contains the following values:
• 0 = logic zero
• 1 = logic one
• x =unknown logic value
• z = high impedance
○ wand
○ wor
• registers
○ reg
○ integer
• constants
○ parameter
Legal Statements
Vivado synthesis supports behavioral Verilog legal statements.
○ if (condition) statement
○ else statement
○ forever statement
Expressions
Behavioral Verilog expressions include:
• Constants
• Variables with the following operators:
○ arithmetic
○ logical
- bitwise
- logical
○ relational
○ conditional
Logical Operators
The category (bitwise or logical) into which a logical operator falls depends on whether it is
applied to an expression involving several bits, or a single bit.
Supported Operators
Table 24: Supported Operators
Supported Expressions
Table 25: Supported Expressions
Evaluating Expressions
The (===) and (!==) operators in the following table are:
See Vivado Design Suite User Guide: Logic Simulation (UG900) for more information about Verilog
format for Vivado simulation.
Table 26: Evaluated Expressions Based On Most Frequently Used Operators (cont'd)
Blocks
Vivado synthesis supports some block statements, as follows:
• Block statements group statements together. They are designated by begin and end keywords.
Block statements execute the statements in the order listed within the block.
• Vivado synthesis supports sequential blocks only.
• Vivado synthesis does not support parallel blocks.
• All procedural statements occur in blocks that are defined inside modules.
• The two kinds of procedural blocks are initial block and always block
• Verilog uses begin and end keywords within each block to enclose the statements. Because
initial blocks are ignored during synthesis, only always blocks are described.
• always blocks usually take the following format. Each statement is a procedural assignment
line terminated by a semicolon.
always
begin
statement
.... end
Modules
A Verilog design component is represented by a module. Modules must be declared and
instantiated.
Module Declaration
• A Behavioral Verilog module declaration consists of:
○ The module name
assign O = A & B;
endmodule
Module Instantiation
A behavioral Verilog module instantiation statement does the following:
• Contains a port association list. The port association list specifies how the instance is
connected in the parent module. Each element of the port association list ties a formal port of
the module declaration to an actual net of the parent module.
• Is instantiated in another module. See the following coding example.
assign O = tmp | C;
endmodule
Continuous Assignments
Vivado synthesis supports both explicit and implicit continuous assignments.
wire mysignal;
...
assign mysignal = select ? b : a;
wire misignal = a | b;
Procedural Assignments
• Behavioral Verilog procedural assignments:
○ Assign values to variables declared as reg.
For more information on Verilog format for Vivado simulation, see Vivado Design Suite User Guide:
Logic Simulation (UG900).
• A combinatorial always block has a sensitivity list appearing within parentheses after
always@.
• An always block is activated if an event (value change or edge) appears on one of the
sensitivity list signals.
• The sensitivity list can contain:
○ Any signal that appears in conditions, such as if or case.
• By substituting a * (asterisk) in the parentheses for a list of signals, the always block is
activated for an event in any of the always block's signals as described.
○ if-else statements
○ case statements
• The if-else statements use true and false conditions to execute statements.
○ If the expression evaluates to true, the first statement is executed.
always @(sel or a or b or c or d)
begin
if (sel[1])
if (sel[0])
outmux = d;
else
else
outmux = c;
if (sel[0])
outmux = b;
end endmodule
else
outmux = a;
Case Statements
Vivado synthesis supports case statements.
• Do not use unsized integers in case statements. Always size integers to a specific number of
bits. Otherwise, results can be unpredictable.
• casez treats all z values in any bit position of the branch alternative as a don't care.
• casex treats all x and z values in any bit position of the branch alternative as a don't care.
• The question mark (?) can be used as a don't care in either the casez or casex case
statements.
Filename: top.v
always @ *
begin
case(sel)
2'b00 : outmux = a;
2'b01 : outmux = b;
2'b10 : outmux = c;
2'b11 : outmux = d;
endcase
end
endmodule
The for statement is supported also for next step computation falling in one of the following
specifications:
Repeat Statements
The repeat statement is supported for constant values only.
• A while loop:
○ Is not executed if the test expression is initially false.
disable <blockname>
• Describe a sequential circuit with an always block and a sensitivity list that contains the
following edge-triggered (with posedge or negedge) events:
○ A mandatory clock event
• If optional asynchronous control signals are modeled, the always block is structured as
follows:
always @(posedge CLK or posedge ACTRL1 or à ) begin
if (ACTRL1)
<$asynchronous part> else
<$synchronous_part> end
The following code example describes an active-High asynchronous reset and an active-Low
asynchronous set:
DO <= DI;
endmodule
The following code example describes a register with no asynchronous set/reset, and a
synchronous reset.
• If the right-hand expression is signed, the left-hand expression is padded with the sign bit.
• If the right-hand expression is unsigned, the left-hand expression is padded with 0 (zero).
• For unsized x or z constants only, the following rule applies:
If the value of the right-hand expression's leftmost bit is z (high impedance) or x (unknown),
regardless of whether the right-hand expression is signed or unsigned, the left-hand expression is
padded with that value (z or x, respectively).
○ Facilitates maintenance.
• Tasks and functions must be declared and used in a module. The heading contains the
following parameters:
○ Input parameters (only) for functions.
• The return value of a function is declared either signed or unsigned. The content is similar to
the content of the combinatorial always block.
//
// An example of a function in Verilog
//
// File: functions_1.v
//
module functions_1 (A, B, CIN, S, COUT);
input [3:0] A, B;
input CIN;
output [3:0] S;
output COUT;
wire [1:0] S0, S1, S2, S3;
reg S, COUT;
begin
S = A ^ B ^ CIN;
COUT = (A&B) | (A&CIN) | (B&CIN);
ADD = {COUT, S};
end
endfunction
endmodule
Filename: task_1.v
// Verilog tasks
// tasks_1.v
//
module tasks_1 (A, B, CIN, S, COUT);
input [3:0] A, B;
input CIN;
output [3:0] S;
output COUT;
reg [3:0] S;
reg COUT;
reg [1:0] S0, S1, S2, S3;
task ADD;
input A, B, CIN;
output [1:0] C;
reg [1:0] C;
reg S, COUT;
begin
S = A ^ B ^ CIN;
COUT = (A&B) | (A&CIN) | (B&CIN);
C = {COUT, S};
end
endtask
endmodule
else
Filename: functions_contant.v
endfunction
endmodule
• 4'b1010
• 4'o12
• 4'd10
• 4'ha
• The pound sign (#) and the at sign (@) are time control statements.
• These statements delay execution of the statement following them until the specified event is
evaluated as true.
• The pound (#) delay is ignored for synthesis.
This assignment blocks the current process from continuing to execute additional statements at
the same time, and is used mainly in simulation.
For more information regarding Verilog format for Vivado simulation, see Vivado Design Suite User
Guide: Logic Simulation (UG900).
Non-blocking assignments evaluate the expression when the statement executes, and allow
other statements in the same process to execute at the same time. The variable change occurs
only after the specified delay.
Verilog Macros
Verilog defines macros as follows:
if (request == 'TESTEQ1)
• If the macro has not been defined, the code following the 'else command is compiled.
• The 'else is not required, but 'endif must complete the conditional statement.
Use the Verilog Macros command line option to define (or redefine) Verilog macros.
• Verilog Macros let you modify the design without modifying the HDL source code.
• Verilog Macros is useful for IP core generation and flow testing.
Note: When synthesis runs, Vivado automatically sets the SYNTHESIS macro. So, when using ‘ifdef
SYNTHESIS, it is triggered during the synthesis run.
Include Files
Verilog allows you to separate HDL source code into more than one file. To reference the code in
another file, use the following syntax in the current file.
`include <path/file-to-be-included>
The previous line takes the contents of the file to be included and inserts it all into the current
file at the line with the `include.
The path can be a relative or an absolute path. In the case of a relative path, the Verilog compiler
looks in two different places for the file to be included.
• The first is relative to the file with the `include statement. The compiler looks there, and if
it can find the file, it inserts the contents of the file there.
• The second place it looks is relative to the -include_dirs option in the Verilog options
section of the General settings.
One-Line Comments
One-line comments start with a double forward slash (//).
Generate Statements
Behavioral Verilog generate statements:
• generate-loop (generate-for)
• generate-conditional (generate-if-else)
• generate-case (generate-case)
Use the generate-for loop the same way you use a normal Verilog for loop, with the following
limitations:
• Each branch of the if-else statement is enclosed by begin and end statements.
• The begin statement is named with a unique qualifier.
generate
if (IF_WIDTH < 10)
begin : if_name
multiplier_imp1 # (IF_WIDTH) u1 (a, b, sum_if);
end
else
begin : else_name
multiplier_imp2 # (IF_WIDTH) u2 (a, b, sum_if);
end
endgenerate
generate
case (WIDTH)
1:
begin : case1_name
adder #(WIDTH*8) x1 (a, b, ci, sum_case, c0_case);
end
2:
begin : case2_name
adder #(WIDTH*4) x2 (a, b, ci, sum_case, c0_case);
end default:
begin : d_case_name
adder x3 (a, b, ci, sum_case, c0_case);
end
endcase
endgenerate
Chapter 10
SystemVerilog Support
Introduction
AMD Vivado™ synthesis supports the subset of SystemVerilog RTL that can be synthesized. The
following sections describe those data types.
To target SystemVerilog for a specific *.v file in the Vivado IDE, right-click the file, and select
Source Node Properties. In the Source File Properties window, change the File Type to
SystemVerilog, and click OK.
The following sections describe the supported SystemVerilog types in the Vivado IDE.
Compilation Units
System Verilog supports both single file and multiple file compilation through use of Compilation
units.
A compilation unit is a collection of one or more SV source files compiled together. Every
compilation unit is associated with single library. The compilation unit scope is a scope that is
local to a global compilation unit, the scope has all the declarations that lie outside of any other
design scope. Generally functions, tasks, parameter, nets, variables, and user defined types
declared outside the module, interface, package or program come under the compilation unit
scope.
In Tcl mode
Or
IDE
In the previous case, if test1.sv has declarations in the compilation unit scope such as params,
typedefs, and so on, like
and read the files as mentioned previously. Compiler unit scope starts with reading file test1.sv
under lib1, but while reading test2.sv with lib2 would be illegal because compilation unit should
be associated with single library. This can be addressed by following ways:
read_verilog {test1.sv }
read_verilog {test2.sv}
read_verilog test3.sv
Data Types
The following data types are supported, as well as the mechanisms to control them.
Declaration
Declare variables in the RTL as follows:
Where:
○ struct
○ enum
4-state and 2-state refer to the values that can be assigned to those types, as follows:
X and Z states cannot always be synthesized; therefore, items that are 2-state and 4-state are
synthesized in the same way.
CAUTION! Take care when using 4-state variables; RTL versus simulation mismatches could occur.
• The types byte, shortint, int, integer, and longint default to signed values.
• The types bit, reg, and logic default to unsigned values.
See Vivado Design Suite User Guide: Logic Simulation (UG900) for more information about Verilog
format for simulation.
Real Numbers
Synthesis supports real numbers; however, they cannot be used to create logic. They can only be
used as parameter values. The SystemVerilog-supported real types are:
• real
• shortreal
• realtime
User-Defined Types
Vivado synthesis supports user-defined types, which are defined using the typedef keyword. Use
the following syntax:
or
Enum Types
Enumerated types can be declared with the following syntax:
This code generates an enum of int with seven values. The values that are given to these names
start with 0 and increment, so that, sun = 0 and sat = 6.
enum {sun=1, mon, tues, wed, thurs, fri, sat} day_of week;
In this case, sun=0, mon=3, tues=4, wed=5, thurs=10, fri=12, and sat=13.
The preceding example defines a signal called my_day that is of type day_of_week. You can
also specify a range of enums. For example, the preceding example can be specified as:
This creates an enumerated type called day_of_week with seven elements as follows: day0,
day1…day6.
Constants
SystemVerilog gives three types of elaboration-time constants:
• parameter: Is the same as the original Verilog standard and can be used in the same way.
• localparameter: Is similar to parameter but cannot be overridden by upper-level
modules.
• specparam: Is used for specifying delay and timing values; consequently, this value is not
supported in Vivado synthesis.
Type Operator
The type operator allows parameters to be specified as data types, which allows modules to have
different types of parameters for different instances.
Casting
Assigning a value of one data type to a different data type is illegal in SystemVerilog.
However, a workaround is to use the cast operator ('). The cast operator converts the data type
when assigning between different types. The usage is:
casting_type'(expression)
• integer_type
• non_integer_type
• real_type
• constant unsigned number
• user-created signing value type
Structures
A structure is a collection of data that can be referenced as one value, or the individual members
of the structure. This is similar to the VHDL concept of a record. The format for specifying a
structure is:
Unions
A union is a single section of data that can be referenced in different ways. The format for
specifying a union is:
logic [5:0] sig1; //packed array logic sig2 [5:0]; //unpacked array
Data types with predetermined widths do not need the packed dimensions declared:
Processes
Always Procedures
There are four always procedures:
• always
• always_comb
• always_latch
• always_ff
The procedure always_comb describes combinational logic. A sensitivity list is inferred by the
logic driving the always_comb statement.
For always you must provide the sensitivity list. The following examples use a sensitivity list of
in1 and in2:
always@(in1 or in2)
out1 = in1 & in2;
always_comb out1 = in1 & in2;
The procedure always_latch provides a quick way to create a latch. Like always_comb, a
sensitivity list is inferred, but you must specify a control signal for the latch enable, as in the
following example:
always_latch
if(gate_en) q <= d;
The procedure always_ff is a way to create Flip-Flops. Again, you must specify a sensitivity
list:
always_ff@(posedge clk)
out1 <= in1;
Block Statements
Block statements provide a mechanism to group sets of statements together. Sequential blocks
have a begin and end around the statement. The block can declare its own variables, and those
variables are specific to that block. The sequential block can also have a name associated with
that block. The format is as follows:
In the previous example, the block name is also specified after the end statement. This makes the
code more readable, but it is not required.
Note: Parallel blocks (or fork join blocks) are not supported in Vivado synthesis.
• Delay control: Specifies the amount of time between the statement its execution. This is not
useful for synthesis, and Vivado synthesis ignores the time statement while still creating logic
for the assignment.
• Event control: Makes the assignment occur with a specific event; for example,
always@(posedge clk). This is standard with Verilog, but SystemVerilog includes extra
functions.
The logical or operator is an ability to give any number of events so that any event triggers the
execution of the statement. To do this, use either a specific or, or separate with commas in the
sensitivity list. For example, the following two statements are the same:
always@(a or b or c)
always@(a,b,c)
SystemVerilog also supports the implicit event_expression @*. This helps to eliminate
simulation mismatches caused because of incorrect sensitivity lists.
For example:
See Vivado Design Suite User Guide: Logic Simulation (UG900) for the Verilog format for simulation.
Operators
Vivado synthesis supports the following SystemVerilog operators:
• Assignment operators (=, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, <<<=,
>>>=)
• Unary operators (+, -, !, ~, &, ~&, |, ~|, ^, ~^, ^~)
• Increment/decrement operators (++, --)
• Binary operators (+, -, *, /, %, ==, ~=, ===, ~==, &&, ||, **, <, <=, >,
>=, &, |, ^, ^~, ~^, >>, <<, >>>, <<<)
• Conditional operator (? :)
• Concatenation operator ({...})
Signed Expressions
Vivado synthesis supports both signed and unsigned operations. Signals can be declared as
unsigned or signed. For example:
if (expression)
command1;
else
command2;
The else is optional and assumes a latch or flip-flop depending on whether or not there was a
clock statement. Code with multiple if and else entries can also be supported, as shown in the
following example:
If (expression1)
Command1;
elsif (expression2)
command2;
elsif (expression3)
command3;
else
command4;
• If the first expression is found to be TRUE, the others are not evaluated.
• If unique or priority if-else statements are used, Vivado synthesis treats those as
parallel_case and full_case, respectively.
Case Statement
The syntax for a case statement is:
case (expression)
value1: statement1;
value2: statement2;
value3: statement3;
default: statement4;
endcase
The default statement inside a case statement is optional. The values are evaluated in order, so
if both value1 and value3 are true, statement1 is performed.
In addition to case, there are also the casex and casez statements. These statements let you
handle don't cares in the values (casex) or tri-state conditions in the values (casez).
If unique or priority case statements are used, Vivado synthesis treats those as parallel_case
and full_case respectively.
Loop Statements
Several types of loops that are supported in Vivado synthesis and SystemVerilog. One of the
most common is the for loop. Following is the syntax:
A for loop starts with the initialization and evaluates the expression. If the expression evaluates
to 0, it stops and executes; otherwise, if it evaluates to 1, it continues with the statement. When
it is done with the statement, it executes the step function.
• A repeat loop works by performing a function a stated number of times. Following is the
syntax:
repeat (expression) statement;
This syntax evaluates the expression to a number, and executes the statement the specified
number of times.
• Static task: Declarations retain their previous values the next time the task is called.
CAUTION! Be careful when using these tasks; Vivado synthesis treats all tasks as automatic.
Many simulators default to static tasks if the static or automatic is not specified, so there is a
chance of simulation mismatches. The way to specify a task as automatic or static is the
following:
The final function_name is optional but does make the code easier to read.
Because the function returns a value, it must either have a return statement or specifically state
the function name:
function_name = ....
CAUTION! Vivado synthesis treats all functions as automatic. However, some simulators might behave
differently. Be careful when using these functions with third-party simulators.
Connecting Modules
There are three main ways to instantiate and connect modules:
If the names of the ports of a module match the names and types of signals in an instantiating
module, the lower-level module can by hooked up by name. For example:
This connects the entire instance, as long as the upper-level module has the correct names and
types.
This connects the myout port to a signal called my_sig, the my_in port to a signal called din
and clk and my_in2 is hooked up to the clk and my_in2 signals.
Interfaces
Interfaces provide a way to specify communication between blocks. An interface is a group of
nets and variables that are grouped together to make connections between modules is easier to
write. The syntax for a basic interface is:
The interface_name at the end is optional but makes the code easier to read. For an example,
see the following code:
The previous code snippet instantiates two lower-level modules with some signals that are
common to both.
interface my_int
logic sel;
logic [9:0] data1, data2, result;
endinterface : my_int
module bottom1 (
my_int int1,
input clk,
input [9:0] d1, d2,
input s1,
output logic equal);
and
module bottom2 (
my_int int1,
input clk);
Inside the modules, you can also change how you access sel, data1, data2, and result.
According to the module, this is because there are no ports of these names. Instead, there is a
port called my_int. This requires the following change:
if (sel)
result <= data1;
to:
if (int1.sel)
int1.result <= int1.data1;
Finally, in the top-level module, the interface must be instantiated, and the instances reference
the interface:
module top(
input clk,
input s1,
input [9:0] d1, d2,
output equal);
my_int int3(); //instantiation
bottom1 u0 (int3, clk, d1, d2, s1, equal);
bottom2 u1 (int3, clk);
endmodule
Modports
In the previous example, the signals inside the interface are no longer expressed as inputs or
outputs. Before the interface was added, the port sel was an output for bottom1 and an input
for bottom2.
After the interface is added, that is no longer clear. In fact, the Vivado synthesis engine does not
issue a warning that these are now considered bidirectional ports, and in the netlist generated
with hierarchy, these are defined as inouts. This is not an issue with the generated logic, but it
can be confusing.
To specify the direction, use the modport keyword, as shown in the following code snippet:
interface my_int;
logic sel;
logic [9:0] data1, data2, result;
modport b1 (input result, output sel, data1, data2);
modport b2 (input sel, data1, data2, output result);
endinterface : my_int
module bottom1 (
my_int.b1 int1,
Packages
Packages provide an additional way to share different constructs. They have similar behavior to
VHDL packages. Packages can contain functions, tasks, types, and enums. The syntax for a
package is:
package package_name;
items
endpackage : package_name
The final package_name is not required, but it makes code easier to read. Packages are
referenced in other modules by the import command. Following is the syntax:
import package_name::item or *;
The import command must include items from the package to import or specify the whole
package.
SystemVerilog Constructs
The following table lists the SystemVerilog constructs. Constructs that are not supported are
shaded in gray.
Construct Status
Data type
Singular and aggregate types Supported
Nets and variables Supported
Variable declarations Supported
Vector declarations Supported
2-state (two-value) and 4-state (four-value) data types Supported
Signed and unsigned integer types Supported
User-defined types Supported
Enumerations Supported
Defining new data types as enumerated types Supported
Enumerated type ranges Supported
Type checking Supported
Enumerated types in numerical expressions Supported
Enumerated type methods Supported
Type parameters Supported
Type operator Supported
Cast operator Supported
Bitstream casting Supported
Const constants Supported
$cast dynamic casting Not Supported
Real, shortreal, and realtime data types Supported
Aggregate data types
Structures Supported
Packed/Unpacked structures Supported
Assigning to structures Supported
Packed arrays Supported
Unpacked arrays Supported
Operations on arrays Supported
Multidimensional arrays Supported
Indexing and slicing of arrays Supported
Array assignments Supported
Arrays as arguments to subroutines Supported
Construct Status
Array manipulation methods (those that do not return Not Supported
queue type)
Array querying functions Not Supported
Unpacked unions Supported
Tagged unions Not Supported(1)
Packed unions Supported
Processes
Combinational logic always_comb procedure Supported
Implicit always_comb sensitivities Supported
Latched logic always_latch procedure Supported
Sequential blocks Supported
Sequential logic always_ff procedure Supported
Iff event qualifier Supported
Aliases Supported
Conditional event controls Not Supported
Parallel blocks Not Supported
Procedural timing controls Not Supported
Sequence events Not Supported
Assignment statement
The continuous assignment statement Supported
Variable declaration assignment (variable initialization) Supported
Assignment-like contexts Supported
Array assignment patterns Supported
Structure assignment patterns Supported
Unpacked array concatenation Supported
Net aliasing Not Supported
Operators and expressions
$error, $warning, $info Supported only within initial blocks, and can only be used to
evaluate constant expressions; for example, parameters.
Aggregate expressions Supported
Arithmetic expressions with unsigned and signed types Supported
Assignment operators Supported
Assignment within an expression Supported
Concatenation operators Supported
Constant expressions Supported
Increment and decrement operators Supported
Operations on logic (4-state) and bit (2-state) types Supported
Wildcard equality operators Supported
Concatenation of stream_expressions Supported
Operators with real operands Not Supported
Construct Status
Re-ordering of the generic stream Not Supported
Set membership operator Not Supported
Streaming concatenation as an assignment target (unpack) Supported
Streaming dynamically sized data Not Supported
Procedural programming statement
Case statement violation reports and multiple processes Supported
Loop statements Supported
Unique-if, unique0-if and priority-if Supported
Assert Statements Not Supported
If statement violation reports and multiple processes Not Supported
Jump statements Not Recommended
Pattern matching conditional statements Not Supported
Set membership case statement Not Supported
unique-case, unique0-case, and priority-case Supported
Violation reports generated by unique-if, unique0-if, and Not Supported
priority-if constructs
Tasks
Coverage control functions Not Supported
Static and Automatic task Supported
Tasks memory usage and concurrent activation Not Supported
Functions
Return values and void functions Supported
Static and Automatic function Supported
Constant function Supported
Background process spawned by function call Not Supported
Virtual Functions Not Supported
Subroutine calls and argument passing
Argument binding by name Supported
Default argument value Supported
Pass by reference Supported
Pass by value Supported
Optional argument list Not Supported
Compiler Directives
Supported
Modules and Hierarchy
Default port values Supported
External modules Supported
Module instantiation syntax Supported
Member selects Supported
Construct Status
Overriding module parameters Supported
Top-level modules and $root Not Supported
Binding auxiliary code to scopes or instances Not Supported
Hierarchical names Supported
Upwards name referencing Not Supported
Interfaces
Interface syntax Supported
Modport expressions Supported
Parameterized interfaces Supported
Ports in interfaces Supported
Array of interface Supported
Clocking blocks and modports Not Supported
Dynamic Arrays Not Supported
Example of exporting tasks and functions Not Supported
Example of multiple task exports Not Supported
Interfaces and specify blocks Not Supported
Nested interface Not Supported
Virtual interfaces Not Supported
Packages
Package declarations Supported
Referencing data in packages Supported
Using packages in module headers Supported
Exporting imported names from packages Supported
The std built-in package Not Supported
Generate constructs
Supported
config statements
Supported
Class
Instances Supported
Member and method access Supported
Constructors Supported
Static class member and methods Supported
Access using 'this' and 'super' Supported
Object assignment Supported
Inheritance Supported
Data hiding and encapsulation Supported
Scope and resolution operator (::) Supported
Nested classes Supported
Construct Status
Objects inside structs Supported
Virtual Classes Not Supported
Abstract classes Not Supported
Assignment with base class object Not Supported
Object comparison with NULL Not Supported
Notes:
1. If used, tagged is ignored, and the tool produces a warning message.
Chapter 11
Introduction
AMD Vivado™ synthesis supports VHDL and Verilog mixed language projects except as
otherwise noted.
Instantiation
For instantiation, the following rules apply:
• Component instantiation based on default binding is used for binding Verilog modules to a
VHDL design unit.
• For a Verilog module instantiation in VHDL, Vivado synthesis does not support:
○ Configuration specification
○ Direct instantiation
○ Component configurations
1. Declare a module name with the same as name as the VHDL entity that you want to
instantiate (optionally followed by an architecture name).
2. Perform a normal Verilog instantiation.
1. Declare a VHDL component with the same name as the Verilog module to be instantiated.
VHDL direct entity instantiation is not supported when instantiating a Verilog module.
2. Observe case sensitivity.
3. Instantiate the Verilog component as if you were instantiating a VHDL component.
• Binding a component to a specific design unit from a specific library by using a VHDL
configuration declaration is not supported. Only the default Verilog module binding is
supported.
• The only Verilog construct that can be instantiated in a VHDL design is a Verilog module.
No other Verilog constructs are visible to VHDL code.
• During elaboration, Vivado synthesis treats all components subject to default binding as
design units with the same name as the corresponding component name.
• During binding, Vivado synthesis treats a component name as a VHDL design unit name
and searches for it in the logical library work.
○ If Vivado synthesis finds a VHDL design unit, Vivado synthesis binds it.
○ If Vivado synthesis does not find a VHDL design unit, it treats the component name as
a Verilog module name and searches for it using a case sensitive search. Vivado
synthesis selects and binds the first Verilog module matching the name.
• Because libraries are unified, a Verilog cell with the same name as a VHDL design unit
cannot exist in the same logical library.
• A newly-compiled cell or unit overrides a previously-compiled cell or unit.
Instantiation Limitations
VHDL in Verilog
Vivado synthesis has the following limitations when instantiating a VHDL design unit in a Verilog
module:
• The only VHDL construct that can be instantiated in a Verilog design is a VHDL entity. No
other VHDL constructs are visible to Verilog code. Vivado synthesis uses the entity-
architecture pair as the Verilog-VHDL boundary.
• Use explicit port association. Specify formal and effective port names in the port map.
• All parameters are passed at instantiation, even if they are unchanged.
• The override is named and not ordered. The parameter override occurs through instantiation,
not through defpas.
Acceptable Example
ff #(.init(2'b01)) u1 (.sel(sel), .din(din), .dout(dout));
Unacceptable Example
ff u1 (.sel(sel), .din(din), .dout(dout));
defpa u1.init = 2'b01;
Verilog in VHDL
Vivado synthesis has the following limitations when instantiating a Verilog module in a VHDL
design unit:
• Use explicit port association. Specify formal and effective port names in the port map.
• All parameters are passed at instantiation, even if they are unchanged.
• The parameter override is named and not ordered. The parameter override occurs through
instantiation, and not through defpas.
• Only component instantiation is supported when instantiating a Verilog module in VHDL.
Direct entity instantiation is not supported.
• The default work directory for compilation is available to both VHDL and Verilog.
• Mixed language projects accept a search order for searching unified logical libraries in design
units (cells). Vivado synthesis follows this search order during elaboration to select and bind a
VHDL entity or a Verilog module to the mixed language project.
• The boundary between VHDL and Verilog is enforced at the design unit level.
• A VHDL entity or architecture can instantiate a Verilog module. See Instantiating VHDL in
Verilog in the following section.
• A Verilog module can instantiate a VHDL entity. See Instantiating Verilog in VHDL.
Binding
Vivado synthesis performs binding during elaboration. During binding, the following actions
occur:
1. Vivado synthesis searches for a Verilog module with the same name as the instantiated
module with a user-specified list of unified logical libraries and with a user-specified order.
2. Vivado synthesis ignores any architecture name specified in the module instantiation.
3. If Vivado synthesis finds the Verilog module, synthesis binds the name.
4. If Vivado synthesis does not find the Verilog module, it treats the Verilog module as a VHDL
entity, and searches for the first VHDL entity matching the name using a case-sensitive
search for a VHDL entity in the user-specified list of unified logical libraries or the user-
specified order. This assumes that a VHDL design unit is stored with an extended identifier.
Generics Support
Vivado synthesis supports the following VHDL generic types and their Verilog equivalents for
mixed language designs: integer, real, string, boolean.
Port Mapping
Vivado synthesis supports port mapping for VHDL instantiated in Verilog and Verilog instantiated
in VHDL.
Use an equivalent component declaration to connect to a case sensitive port in a Verilog module.
Vivado synthesis assumes Verilog ports are in all lowercase.
Appendix A
The AMD Adaptive Computing Documentation Portal is an online tool that provides robust
search and navigation for documentation using your web browser. To access the Documentation
Portal, go to https://docs.xilinx.com.
Documentation Navigator
Documentation Navigator (DocNav) is an installed tool that provides access to AMD Adaptive
Computing documents, videos, and support resources, which you can filter and search to find
information. To open DocNav:
• From the AMD Vivado™ IDE, select Help → Documentation and Tutorials.
• On Windows, click the Start button and select Xilinx Design Tools → DocNav.
• At the Linux command prompt, enter docnav.
Note: For more information on DocNav, refer to the Documentation Navigator User Guide (UG968).
Design Hubs
AMD Design Hubs provide links to documentation organized by design tasks and other topics,
which you can use to learn key concepts and address frequently asked questions. To access the
Design Hubs:
Support Resources
For support resources such as Answers, Documentation, Downloads, and Forums, see Support.
References
These documents provide supplemental material useful with this guide:
Vivado Documentation
Coding Examples
Training Resources
Revision History
The following table shows the revision history for this document.
Copyright
© Copyright 2012-2023 Advanced Micro Devices, Inc. AMD, the AMD Arrow logo, UltraScale+,
Versal, Virtex, Vivado, and combinations thereof are trademarks of Advanced Micro Devices, Inc.
Other product names used in this publication are for identification purposes only and may be
trademarks of their respective companies.