Elecard's
VHDL Design Rules & Coding Style
� 2006 Elecard - all rights reserved
Introduction
This document
is only proposing a number of recommendations that, if followed, will
considerably reduce the design risks. If
you do not agree with some rules, or want to suggest adding others, please fell
free to contact: Denis Shekhalev [email protected].
Conventions
RTL: Register
Transfer Level (almost equivalent to � synthesizable �).
BEH :
Behavioral code almost equivalent to � synthesizable �).
SIM : Test
benches, test code and resources for simulation and verification in general.
1.
Design Data
Organization
1.1. Source Files Naming Convention :
��������������� Use the following notation for file naming
convention.
Design file |
Pc name |
Entity |
EntityName_e.vhd |
Architecture |
EntityName_a.vhd |
Entity/architecture pair |
EntityName_ea.vhd |
Package declaration |
PackageName_p.vhd |
Package body |
PackageName_b.vhd |
Package declaration and body |
PackageName_pb.vhd |
Configuration |
EntityNameConfigName_c.vhd |
Test bench |
EntityName_tb.vhd |
|
|
1.2. Only one design unit entity per file (with the exception of configurations
which may be grouped in one file).
1.3. In general, avoid splitting Entity and
Architecture in different files.
1.4. If one entity has several architectures,
there must exist only a unique entity section. Multiple architectures
are possible in the same file, be sure to put the one used for synthesis in the
last position (bottom of file), so the use of a configuration will not be compulsory
for synthesis.
1.5. RTL: A module (entity) should not contain
several different and independent functionalities.
1.6. Design units
should be placed in design libraries other than work The library name should reflect the family of
devices or of functions the library holds.
2.
Cosmetic Rules
2.1.
Every
design file must be properly documented in a standardized header. �Each
file should have a descriptive header which is a set of comments containing the
following information (Note: The project should decide which header information
is appropriate).
2.1.1.
Project name.
2.1.2.
File name.
2.1.3.
Title of the design unit.
2.1.4.
Description of the design unit including its purpose
and model limitations.
2.1.5.
Design library where the code is intended to be
compiled in.
2.1.6.
List of analysis dependencies, if any (e.g.
packages, components (for simulation)).
2.1.7.
Initialization of model (e.g. hardware RESET, port
and signal initialization).
2.1.8.
Notes or other items (e.g. synthesis aspect of
design unit).
2.1.9.
Author(s) and full address (email, phone number,
etc.).
2.1.10. Simulator(s),
simulator version(s), and platform(s) used.
2.1.11. Revision list
containing version number, authors), the dates, and a description of all changes
performed.
2.2. The comments and header information must
be kept accurate and up-to-date throughout code changes and
design iterations.
2.3. The files must not include any � hard tab � (HT)
but only soft spaces, and must be properly aligned and indented.
All declarative regions and block
statements should be indented by at least 2 spaces. A block statement can be
the concurrent statement part of an architecture, the else clause of an if
statement, the body of a subprogram, etc. If at all possible, indentation
levels in sequential statements should not exceed 4. Use subprograms to break
the code into manageable parts.
2.4. Use blank lines to group logically related
text of code.
2.5. Elements
in interface declarations
should be vertically aligned. Vertical alignment of interface declarations allows
quick identification of the various kind of interface declarations, their
names, directions, and types.
2.6. Total line length should be less
than 132 characters.
2.7. Only one single executable statement
per line.
2.8. The VHDL code must include significant
and value-adding comments, in English. Every process or
continuous assignment should be preceded by a comment summarizing its
purpose.
2.9. It should be easy to match the requirements
and the HDL code, both ways.
2.10. There should be no piece of code
commented out. Inactive or wrong code should be deleted. If needed, an
older version of the architecture can be kept as a reference, for comparison or
non-regression purpose.
2.11. Declare in the package declaration, only
those items which will be used by users of the package. Hide items which are
only used by the package body in the body of the package.
3.
Naming Rules
3.1. Use
the following requirements for identifier naming convention
IdentifierName ::= [prefix][partition]Identifier_Name[delayed][Polarity][_][Suffix]
������� PREFIXES are used in the naming of timing parameters in a manner compliant with
the VITAL (VHDL Initiative Toward ASIC Libraries) specification which could
allow back-annotation of timing parameters
PARTITION is one
character representing the partition name, preferably in lower case (e.g. V for
Receiver partition). The partition prefix is applicable only to ports or
internal signals and variables which are synthesized to registers. It is not
applicable to types, procedures, functions, process, block, entity or
architecture names.
IDENTIFER_NAME represents the
name of the object in mixed or upper case, with the first character in upper
case.
DELAYED is one
character "R" to indicate a register delay version of the original
signal. This is applicable only to ports or internal signals and variables
which are synthesized to registers.
POLARITY represents a logical polarity for
signals of type standard logic or standard logic vectors, where "T"
represents active TRUE, and "F" or "N" represents active FALSE.
This is applicable only to ports or internal signals and variables which are synthesized
to registers. If the identifier name ends with � "�" and the polarity
is active TRUE, then the polarity is omitted. Conversely if the identifier name
ends with an "F" and� the
polarity is false, men the polarity is omitted
SUFFIX represents additional information
about the identifiers. Summary of the recommended suffixes:
CATEGORY |
SUFFIX |
COMMENTS |
EXAMPLE |
Object |
_s |
signal from signal class, used in architectures and in subprograms. |
|
Object |
_inp, _outp, _inoutp |
Input port. Output port. Inout_port. Port. Port names and signals connecting to component ports may omit
the suffix. |
|
Object |
_v |
variable from variable class |
|
Object |
_i |
index of loop |
|
Object |
_g |
generic |
|
Object |
_c |
constant from a constant class, used in packages, architectures, and
subprograms |
|
Object |
_f |
file from a file class |
|
Library |
_lib |
Library which holds design units for a design. |
|
Package |
_pkg |
Package which holds constant, type, and subprogram definitions. |
|
Entity |
_nty |
Entity which defines the I/O Interfaces |
|
Type |
_t |
Type and subtype definitions |
|
Label |
_gen, _proc, _loop |
label for generate label for process label for loop |
|
Configuration |
_cfg |
Configuration |
|
3.2. Use
the following restrictions for identifier name naming convention
3.2.1. Adopt HDL-friendly Identifiers, OS-friendly
names for design units, always restrict yourself to using plain 7-bits Ascii (avoid accents) and adopt meaningful names (in
English).
3.2.2. Avoid too short names (like � i �, � n
�...) except for very short scope since they tend to be difficult to locate
with a text editor.
3.2.3. Avoid the use of extended identifiers
3.2.4. Use Short identifiers when the
scope is local, and Longer more explicit (English) identifiers for greater
scope or global items.
3.2.5. Use Upper and Lower cases for
improved readability e.g. LocalReadEnable.
3.2.6. Avoid using 1 (one), l (lower case L),
I (uppercase i) O (uppercase Oh) and 0 (zero) in
situations which may be visually ambiguous.
3.2.7. Do not use too long names for identifiers,
especially for entities. Try a maximum of 8 characters, and at least no more
than 16, identical with the file name.
3.3. Use
the following names for architecture naming convention: "rtl",
"behavioral", "structural", "functional" and etc.
3.4. Whenever possible, when installation
components in architecture, use as the component name the entity associated
with that component.
3.5. Use
the following restrictions for port naming convention
Port name |
Port definition |
clkXXXX |
Use for clock
signal�s |
rstXXXX |
Use for asynchronous reset |
sclrXXXX |
Use for synchronous reset |
enaXXXX |
Use for enable signal |
loadXXX |
Use for load signal |
3.6. Identifiers for
subprograms (i.e. procedures and functions) should be verb phrases descriptive
of their actions such that their functionality can be interpreted from the context
of usage.
4.
Coding Rules
4.1. Adopt VHDL 93 / 2001 standard
(VHDL '87 was messy and is definitely obsolete).
4.2. RTL: Use exclusively IEEE libraries
: std_logic_1164, �numeric_std.
Do NOT use Synopsys: std_logic_arith,
std_logic_(un)signed, numeric_bit,
and other horrendous and proprietary libraries. Math_real
should be avoided if possible in RTL code.
4.3. BEH & SIM: use also textio (ieee) and std_logic_textio (synopsys). Math_real is also possible and useful, recommended in test
benches.
4.4. Using specific non-standard packages
and libraries should be limited to a strict minimum and with great care
since this weakens the project's integrity, safety, portability and
reusability.
4.5. RTL + BEH: define only one single port
per line + a comment for every port.
4.6. Unconstrained arrays can be used in ports (very elegant style),
but this can cause trouble for unitary synthesis (always), and synthesis (not
all synthesizers, at the time of writing, do support unconstrained array in
ports).
4.7. Default values can be used for input and output ports.
4.8. RTL: records are possible and
sometimes recommended for inter-entity connectivity, but should be avoided
in top level ports.
4.9. Vectors directions:
4.9.1. Use descending (downto)
if the vector represents a number (or when in doubt...).
4.9.2. Use ascending (to) for the
first dimension of a memory array.
4.9.3. Ascending is also okay for a numbered collection of
items, like LED array etc...
4.10. RTL: Avoid hard values use attributes on objects.
4.11. Use
constants to define data parameters and table lookups.
4.12. Use attributes
of objects instead of fixed values or
constant unless the value is known and very unlikely to be modified
4.13. RTL:
Use "rising_edge" exclusively (it's time to give up clock'event and clk='1').
4.14.
RTL: When
�rst� exist in process then every signal
assigned inside "rising_edge" must be initialized.
4.15.
RTL:
Inside "if rst", only constant values can
be assigned (no asynchronous load). Furthermore, registers powering up at '0' are usually preferable.
4.16. RTL: "wait" is forbidden.
4.17. RTL: Avoid using attributes on types,
prefer the attributes on objects (signals or variables).
4.18. RTL: Do not use "BUFFER"
mode in ports. Use � out � mode
and internal signals with proper naming convention and suitable type. If
different type, convert in the continuous assignment.
4.19. RTL: Do not use "INOUT"
mode except at the very top level. Define the tri-state drivers only at
the top-level of the hierarchy, thus avoiding to rely on "tri-states
bubble-up". Remember that internal tri-states are strictly forbidden
(in most FPGA architectures) or non portable if allowed in the technology.
4.20. RTL: the tri-state and bi-directional
Input/Outputs must be coded in the top level as :
ExtBus
<= BusOut when Oen='1'
else (others=>'Z');
BusIn
<= ExtBus;
4.21. Input ports can be left unconnected (open)
at instantiation provided they are assigned default values at
declaration.
4.22. �It is possible, maybe recommended to use direct
instantiation which gets rid of the component declaration, but the instance
can then no longer be configured.
4.23. Instantiation must use named
Port Maps. Ordered port maps should not be allowed.
4.24. Do not leave ports unconnected
by omission : use "open".
4.25. �RTL:
Avoid recursive code ! This can work with some tools, and it will likely
improve over the years, but it's taking chances with tools and it may not be
very easy to understand.
4.26. �RTL:
Global signals and shared variables are not allowed. If needed for
simulation purpose, exclude them by synthesis pragmas
(but see below).
4.27. �RTL:
beware of proprietary pragmas. If absolutely
required, be sure to document their use and put a note in the header. �
4.28. A graphical (schematics) top-level,
automatically translated in structural VHDL can be a good idea. But always keep
the VHDL the master document.
4.29. �RTL:
Use as few variables as possible in synthesizable code, and never when
you may use signals instead. Use variables for their specific behavior
(factoring, intermediate results, re-using the FlipFlops
inputs etc..).
4.30.
BEH
& SIM: Use as many variables as possible in Test Benches and
Behavioral Models !
4.31. �RTL:
Never create latches, combinational feedback or asynchronous sequential logic,
whether intended or unintended !
4.32. �RTL:
It is not allowed to initialize signals at their declaration. It is not
allowed to initialize variables at their declaration in processes. It is
acceptable to initialize variables at their declaration inside functions.
4.33. �RTL:
Definitely avoid using procedures in RTL code. Using functions in RTL is
possible. Prefer functions declared in the architecture (local) rather than in
packages (too far) or in the process (too local).
4.34. �BEH
& SIM: Definitely use procedures
as much as possible.
4.35. �RTL:
Preferably code combinational logic inside sequential
processes.
4.36.
�RTL: Avoid combinational processes if
possible (see above). In case: Sensitivity Lists must be complete and
accurate (no missing, no extra).
4.37.
Use concurrent signal assignment statements
without a clock statement to describe the combinatorial logic. Alternatively,
use processes with sensitivity clauses and with variables used to compute the
values of complex terms
4.38. �BEH
& SIM: Do not use processes with sensitivity list.
4.39. �BEH
& SIM: Inside the processes make sure there is a wait or equivalent in every
branch!
4.40. �RTL:
Resource sharing.
Document (with appropriate comments) the intended operators that synthesis is
expected to share. In case of doubt, remove the operator(s) and factor it
(them) out � by hand � (like in continuous assignments).
4.41. �RTL:
Use as few proprietary (vendor-specific) macro-functions as
possible and properly isolate / document them. When possible, inference may be
preferable, but this depends on many design- vendors- and tools-specific
factors.
4.42. �RTL:
One single clock domain per entity (except on top level and clock domain
resynchronization-crossing entities indeed!).
4.43. �RTL:
All asynchronous input signals should be re-synchronized, preferably at
the top-level. Do not insert logic between the I/O and the input Flip-Flop! Synchronous
I/Os must be handled specifically (constraints etc...).
4.44. �RTL:
All the Entity's outputs should be registered. Combinational outputs can
also create combinational feedbacks through the hierarchy.
4.45. �RTL:
At the top level, combinational outputs should not be allowed. In
general, all the device's outputs should be direct Flip-Flop outputs. Avoid
relying on � not gate push back �.
4.46. RTL, BEH, SIM: Avoid active-low signals inside the design. The
internal logic should be active-high.
4.47. RTL:
4.48.
RTL: Isolate
unavoidable technology-specific code (internal tri-states, memory inference
/ instantiation, primitive�s instantiations like PLLs,
etc...
4.49. RTL: Complex entities or technology-specific
instances must have a behavioral model, for simulation
(or faster simulation).
4.50. RTL, SIM, BEH: Place documented
assertions (VHDL, OVL, or PSL) where appropriate. Refer to ABV
methodology.
4.51. SIM: At the end of the simulation, the
simulator should stop due to event starvation, to avoid useless
simulation runs (beyond stimulus range). The clock must therefore be stopped
(also).
4.52. When designing synchronous logic, avoid
VHDL structures that infer latches.
4.53. To avoid unwanted latches in combinational designs, all conditional
statements, conditional signal assignments, and selected signal assignments
must be complete. Thus, all conditions must be considered, and values must be
assigned under all conditions.
4.54. Avoid the definition of impure functions.
5.
Design Flow
5.1.
Use Scripts
(command line or Tcl preferably) for synthesis
and simulation tasks. Use GUIs when investigating, or other early
phases. A finalized design should never rely on any GUI.
5.2. Test Benches must be self-checking and regressionable. They should not use not-portable
run-time �simulator � commands (like force, unforce, etc...).
5.3. If an external stimulus (e.g. memory data)
is required, it shall be implemented by reading an ASCII file using STD.TextIO package to ensure portability.
5.4. Test benches, auxiliary files (vectors,
expected results, memory contents, behavioral models, etc...) should be versioned,
properly documented and archived.
5.5. Every step involved in producing the final
object (usually the bitstream) must be automated
through documented, versioned and archived scripts. The steps must be
documented since the scripts are tool-specific and version-specific.
5.6. Every entity must be white-box tested (unitary)
with (at least) one Test bench.
5.7. Every entity must be unitary synthesized
(simple entities may violate this rule).
5.8. The design must be simulatable
at the post-layout timing level.
5.9. The exact Type and Version (including
Services Pack info) of all the Tools used must be properly documented.
On some key projects, it may be desirable to maintain the availability of all
the tools used throughout the life of the product.
6.
List of material: