EDN logo

Design Features

February 3, 1997


VHDL and Verilog fundamentals--design entities, data types, and data objects

Douglas J Smith, VeriBest


To successfully design chips with Verilog or VHDL, you need to understand the basics of these hardware-description languages.

  When designing and modeling digital systems in VHDL or Verilog, you have to partition the design into natural abstract blocks, known as components. Each component is the instantiation of a design entity, which you normally model in a separate system file for easy management and individual compilation by simulation or synthesis tools. You then model the total system using a hierarchy of components, known as a design hierarchy, which consists of individual subcomponents (subdesign entities) brought together in one higher level component (design entity).

  When you use a tool to synthesize the coded models of design entities, you should partition the system into suitably sized design entities. When you synthesize one of these design entities, it should yield a maximum of about 5000 equivalent gates (an equivalent gate is the size of a two-input NAND gate). There is no absolute rule stating the best size circuit to synthesize and optimize, but anything from 2000 to 5000 equivalent gates typically gives good results without being too CPU-intensive.

Design entities

  Modeling digital systems in VHDL differs from modeling in Verilog. You construct design entities in VHDL using the following types of design units:

  The entity, package, and configuration declarations are primary design units that you find within a library--the host environment's storage area for compiled design units. The architecture and package body declarations are secondary design units because you cannot see them within a library (Figure 1). A VHDL design entity consists of two design units, an entity-architecture pair.

  In Verilog, a design entity has only one design unit, the module declaration. The module declaration describes a design's functional composition and its interface to other designs in the same environment. All declarations used within a model must be declared locally within the module. However, you often use the compiler directive `include to reference a separate system file. The `include directive is replaced with the contents of the file it references when a simulator, synthesizer, or similar tool compiles the file. This operation is useful for writing generic Verilog code in a separate file that can be referenced from the code in any other Verilog file.

Code structure

  A design unit may instantiate other design units, which in turn may instantiate still other design units hierarchically. This hierarchical code structure should reflect any hardware structure being modeled. Coded statements within a design unit fall into one of three categories: declaration, concurrent, or sequential.

  Declaration statements declare objects for use in concurrent and sequential statements. In VHDL, you must declare a sublevel design unit's component before it can be instantiated. Similarly, you must declare subprograms before using them. A subprogram in VHDL is a procedure or function. You place a declaration statement before the begin clause in an architecture, block, process, procedure, or function statement (Figure 2).

  In Verilog, you don't have to declare a design unit (a module statement) or a subprogram (a task or a function). There is no dedicated declarative region in a module, sequential block, concurrent block, task, or function (Figure 3).

  Concurrent statements are statements that are executed in parallel. They operate independently of all other concurrent statements. When you are modeling hardware structure, concurrent statements represent independent sections of the circuit you are modeling. The program executes each concurrent statement asynchronously with all other concurrent statements.

  In VHDL, block and process are concurrent statements. Signal assignments and procedure calls are concurrent, provided that they do not reside in a process statement. Similarly, a function call is concurrent, provided that the program calls it from within the expression of a concurrent signal assignment.

  In Verilog, the continuous assignment and always statement are concurrent. A continuous assignment uses the reserved word assign to assign data objects of any of the net data types. A task cannot be called concurrently.

  Sequential statements are executed depending on the procedural flow of constructs that surround them. VHDL sequential statements reside after the begin clause in a process. Verilog sequential statements reside in an always statement that may contain sequential begin-end procedural blocks. The assigned objects are of type reg or integer (Figure 3).

  Models in Verilog or VHDL pass data from one point to another using data objects. Each data object has a collection of possible values known as a value set; a data type defines this value set. The data types and data objects in Figure 4 that synthesis tools do not support, or that you do not typically need in a simulation test harness, are not discussed further.

VHDL data types.

  An enumerated data type contains a set of user-defined values. Each value may be an identifier (for example, Red, Multiply, or a character literal such as '0', '1', 'U', or 'Z'). An enumerated-type declaration's syntax is:

type enum_type_name is (enum_value {,enum_value});

where "enum_type_name" is the identifier name of the enumerated data type, and "enum_value" is an identifier or character literal. For example,

type Rainbow is (Red, Orange,
Yellow, Blue, Green, Indigo, Violet);

The order in which you declare enumerated values determines the numerical order of numbers that a synthesis tool assigns to the values. These assigned numbers enable you to use relational operators on enumerated data types. For example,

if (Red < Orange) then

Synthesis tools often provide an attribute to specify enumerated values to the set of identifiers or character literals.

  An integer-type declaration defines a range of integer numbers. You should always specify the actual range; otherwise, the IEEE 1076 '93 default of (2­31+1) to (231­1) is used. This range is excessive and, when synthesized, yields more logic than needed. This extra logic forces the optimizer tool to optimize away all redundant logic. When a synthesis tool synthesizes and assigns the necessary number of bits for an integer range, the tool counts from zero. Therefore, it makes sense to always specify integer ranges beginning from zero.

  You use composite data types to define collections of values (elements), which together constitute an array or record. An array's individual elements must all be of the same type, whereas record elements contain elements that are of different types.

  Composite-array data types are useful for modeling linear structures, such as RAMs and ROMs. An array's elements may be of any type, provided that all the elements are of the same type. An element is a constituent of a type. You specify the array's range with an upper and lower bound integer separated with to or downto. There is no difference between using to or downto when declaring an integer range. It is possible to specify arrays of arrays to any dimension; however, synthesis tools support only one or two dimensions. You do not need arrays of three or more dimensions for modeling hardware structure. The declaration of an array data type may specify a range, in which case the array is "constrained." It is possible to not specify a range of an array type, which allows you to defer the declaration of its range until you declare a signal or variable of that type.

  Composite-record data types are useful for modeling data packets. A record may contain values that belong to the same type or to different types. You make assignments to individual elements in the record using the record identifier name and element name separated by a period.

  It is not until a data object of one of the VHDL data types is declared in a model, using a type or subtype declaration, that the value set is defined.

VHDL data objects

  You always define the value set in a model using a type declaration along with the object kind, constant, variable, signal, or file. A constant holds one value of the specified type; once declared, a constant's value cannot change. A variable holds any single value from the values of the specified type. You often use variables to hold temporary values within a process, and the variables need not relate to a node in the implied circuit. A signal holds a list of values that includes its current value and a set of possible future values that are to appear as the signal's current value. A file refers to a system file and contains a sequence of values of a specified type. Synthesis tools do not support file objects, but they are useful in test harnesses. You write values to or read values from a file using procedures.

Verilog data type.

  In Verilog, the language itself defines a single-base data type that has the following four-value value set:

You declare data objects in a single-base data-type model to have one element, or an array of elements, of this type. For example,

wire W1;
wire [31:0] W2;

Verilog has more types of data objects than does VHDL, and those Verilog data objects relate closely to the detailed hardware structure being modeled.

  Two types of Verilog data objects are net and register. If a net (wire, wand, wor) or register (reg) data object is declared without a range, by default it is 1 bit wide and referred to as a "scalar." If you declare a range, the net or register data object has multiple bits and is a vector. You may reference a vector in its entirety, in part, or with each individual bit.

  The synthesizable net data objects in Figure 4 represent and model the physical connection of signals. You must always assign a net object using a continuous assignment statement. An assignment in Verilog is the basic mechanism for assigning values to net and register data types. In particular, a continuous assignment statement assigns values to any of the net data types and makes a connection to an actual wire in the inferred circuit.

  The register (reg) data object holds its value from one procedural assignment statement to the next. A procedural assignment is an assignment to a register data-type object and does not imply synthesis of a physical register, although you can use the assignment for this purpose. You use a procedural assignment to assign values under trigger conditions, such as if and case statements. A procedural assignment stores a value in a register data type, which holds the value until the next procedural assignment to that register data type.

  A parameter data object defines a constant. You should use only integer (not real) parameter constants with synthesis. Like all other data-type declaration statements, a parameter declaration statement's position defines in the code whether the parameter is global to a module or local to an always statement.

  You use integer data objects to declare general-purpose variables for use in loops; they have no direct hardware intent and hold numerical values. No range is specified when you declare an integer object. Integers are signed and produce 2's-complement results.


Author's biography

Douglas Smith received a BSEE from Bath University (Bath, UK), after which he worked as a digital designer at a number of companies developing µP-based circuit boards and ICs. He has experience designing PLDs, FPGAs, gate arrays, and standard cell-based chips, and his EDA background includes synthesis-product application engineering and product-marketing management at GenRad Ltd. Smith is a member of the technical staff at VeriBest (Huntsville, AL) and author of the book HDL Chip Design, the source of this article.



| EDN Access | Feedback | Subscribe to EDN | Table of Contents |


Copyright © 1997 EDN Magazine. EDN is a registered trademark of Reed Properties Inc, used under license.