Coding Style Guidelines
This document was created to provide Xilinx users with a guideline for producing fast, reliable, and reusable HDL code.
Table of Contents
Top-Down Design Section 1 13-4
Behavioral and Structural Code 13-4
Declarations, Instantiations, and Mappings 13-5
Naming Conventions 13-10
Signals and Variables Section 2 13-13
Inverted Signals 13-13
Rule for Signals 13-14
Rules for Variables and Variable Use 13-15
Packages Section 3 13-17
Package Contents 13-17
Functions and Procedures 13-19
Types, Subtypes, and Aliases 13-19
Technology-Specific Code (Xilinx) Section 4 13-21
Required Instantiation 13-21
Simulation of Instantiated Xilinx Primitives 13-22
Non-Generic Xilinx-Specific Code 13-22
Coding for Synthesis Section 5 13-30
Synchronous Design 13-30
Local Synchronous Sets and Resets 13-31
Registering Leaf-Level Outputs and Top-Level Inputs 13-32
Clock Enables 13-33
Finite State Machines 13-33
Logic-Level Reduction 13-35
If-Then-Else and Case Statements 13-35
Rules for If-Then-Else and Case Statements 13-36
For Loops 13-36
Rule for For Loops 13-37
Inadvertent Latch Inference 13-38
Rules for Avoidance of Latch Inference 13-39
Top-Down Design Section 1
HDL coding should start with a top-down design approach. Use a top-level block diagram to communicate to designers the naming required for signals and hierarchical levels. Signal naming is especially important during the debug stage. Consistent naming of signals, from top to bottom, will ensure that project manager A can easily recognize the signals written by designer B.
When creating synthesizable code (RTL), you should write two types of code: behavioral RTL (leaf-level logic inference, sub-blocks) and structural code (blocks) -- each exclusively in its own architecture. A simple example of behavioral RTL versus structural code is shown in Figure 13-1and Figure 13-2, respectively.
Figure 13 1 Behavioral Code
Figure 13 2 Structural Code
Keep leaf-level (behavioral sub-blocks) coding separate from structural coding (blocks).
Declarations, Instantiations, and Mappings. It is important to use a consistent, universal style for such things as entity declarations, component declarations, port mappings, functions, and procedures.
Declarations, Instantiations, and Mappings
It is important to use a consistent, universal style for such things as entity declarations, component declarations, port mappings, functions, and procedures.
For declarations, instantiations, and mappings use one line for each signal. The exception is for relatively small components, functions, and procedures.
Always use named association.
The combination of these two rules will help eliminate common coding mistakes. Therefore, this combination will greatly enhance the ease of debugging a design at every stage of verification. A simple example is shown Figure 13-3. Obeying these rules will also increase the readability, and therefore the reusability.
Figure 13 3 One Line Per Signal / Named Association
Liberal comments are mandatory to maintain reusable code. Although VHDL is sometimes considered to be self-documenting code, it requires liberal comments to clarify intent, as any VHDL user can verify.
Three primary levels of commenting:
Comments should include a header template for each entity-architecture pair and for each package- and package-body pair. See the example in Figure 13-4. The purpose should include a brief description of the functionality of each lower block instantiated within it.
Use comment headers for processes, functions, and procedures, as shown Figure 13-5. This should be a description of the purpose of that block of code.
Use comments internal to processes, functions, and procedures to describe what a particular statement is accomplishing. While the other two levels of commenting should always be included, this level is left to the designer to decipher what is required to convey intent. Inline comments are shown in Figure 13-6.
Figure 13 4 Header Template
Figure 13 5 Process, Function, and Procedure Header
Figure 13 6 Inline Comments
Proper indentation ensures readability and reuse. Therefore, a consistent style is warranted. Many text editors are VHDL-aware, automatically indenting for “blocks” of code, providing consistent indentation. Emacs and CodeWright are two of the most common editors that have this capability. Figure 13-7 shows an example of proper indentation. Proper indentation greatly simplifies reading the code. If it is easier to read, it is less likely that there will be coding mistakes by the designer.
se a VHDL-aware text editor that provides a consistent indentation style.
Figure 13 7 Proper Indentation
Naming conventions maintain a consistent style, which facilitates design reuse. If all designers use the same conventions, designer A can easily understand and use designer B’s VHDL code.
Entities, Architectures, Procedures, and Functions
Use all lowercase names with underscores, for readability and name delimiting.
Each entity should have a unique name that describes that block.
Architectures do not need unique names because they are individually bound to a specific entity that has a unique name. Names for architectures should be rtl, to indicate a leaf-level sub-block, and structural, to indicate a block with no leaf-level logic – with only sub-blocks.
For entities with more than one architecture, use “rtl_xilinx” (or “structural_xilinx”) for a Xilinx-specific architecture and “rtl_asic” (or “structural_asic”) for an ASIC-specific architecture.
Signal Naming Conventions
For a design implemented in VHDL, an up-front specification of signal naming conventions should help you reduce the amount of non-conformity. The primary motivating factor is enhanced readability during the verification of the design. General signal naming conventions are listed below.
General Signal Naming Guidelines
Use addr for addresses. This might include sys_addr, up_addr, etc.
Use clk for clock. This might include clk_div2 (clock divided by 2), clk_x2 (clk multiplied by 2), etc.
Use reset or rst for synchronous reset.
Use areset or arst for asynchronous reset.
Use areset_l for active-low asynchronous reset.
Use rw_l for read/write (write is active low).
The following rules specify the suggested nomenclature for other widely used signals
Use _io for bi-directional signals.
Use a _l suffix for active low signals _l.
Do not use _in and _out suffixes for port signal names.
se of in and out is very confusing in text, especially at hierarchical boundaries. Therefore, the use of _in and _out should be strictly monitored. If they must be used, be sure that _in indicates input, and, likewise, that _out is an output to the correct level of hierarchy. Figure 13-8 shows an example entity and the instantiation of that entity in a higher block. Here, data_in is connected to data_out, making the code confusing.
Figure 13-8 Confusing _in and _out suffixes
Use _i to denote local signal names that are internal representations of an output port. This nomenclature is used to easily identify the internal signal that will eventually be used as an output port.
The counter in Figure 13-9 provides a simple example of an output port that cannot be read. The output port count cannot be incremented because it would require count to be read. The problem is solved in the example by incrementing the local internal signal count_i. Some designers try to overcome this problem by using the port as an inout; however, not all synthesis compilers will allow this unless it is three-stated. Declaring the signal to be of type buffer is another common trap. This complicates the code because all signals to which it connects also must be of type buffer. Not all synthesis vendors support the data-type buffer. In addition, data-type buffer does not have all of the required defined functions to perform common arithmetic operations.
Figure 13-9 Internal Signals Representing Output Ports
Use _v to indicate a variable. Variables can be very useful if used correctly. The _v will serve as a reminder to the designer as to the intent and use of that signal.
Use _p0, _p1, and so forth, to represent a pipelined version of the signal when comes after the pipelining. Use _q0, _q1, and so forth, to represent a pipelined version of the when comes before the pipeline. See Figure 13-19 in section 4 for an example of how to use this pipelined signal naming convention.
Append a suffix to signals that use a clock enable and will be part of a clock-enabled path (i.e., multi-cycle path). For example, if the clock enable is enabled only one-quarter of clock cycles, the clock enable should be named to represent that -- ce4. Signals that use this enable might be named _ce4. This will greatly aid you in your ability to specify multi-cycle constraints.
Signals and Variables Section 2
Following some basic rules on the use of signals and variables can greatly reduce common coding problems.