In this article, we will take a look at some elements of the VHDL language that are commonly used across all implementations. These elements give shape and format to your program. Some of these are essential to the functioning of your design. These basic elements make up the complete fundamental basis of VHDL syntax.
Contents
VHDL Design unit
A VHDL model (program) consists of two design units:
- Primary design unit.
- Secondary design unit.
The primary design unit consists of
- Entity
- Package
- Configuration
The secondary design unit consists of
- Architecture
- Package body
Entity
It describes the inputs and outputs of the circuit. One can imagine it as a black box which you can see from outside only. So, by looking at it, you only get the information about inputs and outputs and not really the inside.
Let’s look at an example of an entity:
entity adder_ff is port( a,b,cin : IN BIT; s,cout : OUT BIT); end adder_ff;
The code above shows an entity of a full adder. The name of the entity is “adder_ff” with three in
and two out
ports. ‘a’, ‘b’ and, ‘cin’ are inputs ports while ‘s’ and, ‘cout’ are output ports.
Architecture
It describes the innards of the circuit. What actually is happening from those inputs and how it generates the output. It describes the working/functionality of the circuit.
To model the architecture of an entity, we have several modeling methods:
- Dataflow
- Behavioral
- Structural
- Mixed
In the Dataflow modeling style, we define the flow of signal/information throughout the entity. Dataflow modeling is an intermediate abstraction layer. The concurrent statements are the primary mechanism in this style of modeling.
If you want to learn more, we have a separate article on the Dataflow modeling architecture in VHDL.
In behavioral modeling, we describe the functionality of an entity using sequential statements. Behavioral modeling is the highest abstraction layer in VHDL. A process is a primary mechanism of writing architecture in the behavioral style of modeling.
If you want to learn more, we have a separate article on the Behavioral modeling architecture in VHDL.
In structural modeling, we define the architecture of the entity using the interconnection of components. Every gate/buffer is also treated as a component. This is an advantage as you have to write a code block once and can use it as many times as you want to. But due to the use of components, this modeling style is at the lowest level of abstraction.
If you want to learn more, we have a separate article on the Structural modeling architecture in VHDL.
In mixed modeling, we combine the feature all modeling style, and this comes as an advantage. We can use all the optimum features from all the modeling styles. This gives an edge to mixed modeling. Hence, it is also a much more popular modeling style in developers.
Entity architecture pair
In VHDL, every entity (circuit under design) must have at least one architecture body. Although it can have more than one, this is not preferred as it creates ambiguity in hardware. That is why generally, we have only one architecture body for an entity, and we call it an entity-architecture pair. The entity-architecture pair is a crucial block of any VHDL program.
Let’s look at an example of an entity-architecture pair:
entity half_adder is port (a, b : in BIT; sum, carry : out BIT ); end half_adder; architecture arch_HA of half_adder is begin sum <= a xor b; carry <= a and b; end arch_HA;
In the above code, “half_adder” is an entity and “arch_HA” is its architecture. So here, “half_adder” and “arch_HA” is an entity-architecture pair.
Configuration
We know that an entity can have multiple architectural bodies associated with it. Now, if you create an entity and want to use an architecture body from another entity, we can use configuration for the purpose.
So, we use a configuration to bind an architecture body from an entity to another entity.
In the above figure, E1_A1 and E1_A2 are two architecture bodies associated with entity E1. And, E2_A1, E2_A2 are two architecture bodies that are associated with the entity E2. Now, to use the architecture body E1_A2 inside the entity E2, we need to bind them. We do that binding using a configuration.
We can use a configuration for two purposes:
- To bind architecture from one entity to another, or
- To bind a component from architecture to another entity.
Note that there aren’t any simulation semantics associated with a configuration, it is mostly used as an organizing tool in large programs by specifying a top-level entity in terms of low-level entities. You can implement configurations in two ways:
- By using a configuration specification: Used to bind component instantiations to specific entities that are stored in design libraries. Here the configuration appears in the declarations part of the architecture or whichever block the components are being instantiated in. You can do this for every instance separately or as a whole. In addition to that, you can also bind the instantiation of different components to the same entity.
- By using a configuration declaration: This specifies the entity represented by the entity-architecture pair, and the generic and port bindings.
Syntax of configuration specification:
for list-of-comp-labels : component name use binding-indication;
Syntax of binding indication:
entity entity-name[(architecture-name)] [generic map (generic-association)] -- used to specify values for generics or provide mapping --between generic parameters of the component and the entity to which it is to be bound [port map (port-association)] -- used to specify the port bindings between the component and the bound entity
The concept of using configurations can be only internalized when you are working on large circuits and wish to give a better structure to your programs. We will take up some examples on using configurations towards the end of this VHDL course. It’s okay if you don’t completely understand this concept right now.
Package
In VHDL, we use packages to store our common declarations like functions, procedures, components, types. We do this so that we can later use them in our other designs too.
Some people think that the package is the same as libraries. But that is not the case.
Consider this analogy, a library in VHDL is like a book that contains many chapters. A chapter is like a package. So, a book can have many chapters. Similarly, here a library may have many packages. Then in chapters, we have an explanation on multiple topics. Similarly, in VHDL, a package may contain multiple sub-programs (functions or procedures), components, or types declarations.
If you want to learn about the package declaration, we have explained package declaration in detail in the post on structural modeling in VHDL.
Subprograms
A subprogram performs and executes a certain computation in zero simulation time.
We define a subprogram using the subprogram body. The syntax for a subprogram body is:
subprogram-specification is subprogram-item-declarations begin subprogram(sequential)-statements -- Same as sequential-statements. end [ subprogram-name ];
The subprogram-specification specifies the type of subprogram, its interface, parameter names, class, type, and the mode (in
, out
or inout
). Parameters that are of mode in
can only be read by the subprogram. We can’t update their value within a subprogram. That’s why we also call them a read-only parameter. Similarly, the parameters of out
mode cannot be read by the subprogram. It can only write values to them.
To pass a value to a subprogram, we use a subprogram call. If the parameter is of signal class, then only a signal object is allowed to pass a value to it. And this applies to all other classes. You can only use the object of the same class as of the parameter to pass a value.
There are two main types of subprograms:
- Functions
- Procedures
Functions
We use functions to execute a set of sequential statements that are frequent in program execution. They return a single value using a return statement.
Function declaration syntax:
function function-name (Parameter : Parameter-type) return return-type is --Internal variable declarations here. begin --Sequential statements here.. .. .. return RETURN_VALUE; end function-name;
Syntax of a function call:
function-name ( list-of-actual-values )
Procedure
We use a procedure to divide a large behavioral description into smaller parts of code. It is always a good programming ethic to write multiple smaller modules rather than a single big piece of code.
A procedure may or may not return a value, and it can also return multiple values at a time.
Parameters of a procedure follow the same rules as functions. You may not explicitly define the class of the parameter. By default, it will be considered a constant if the mode is in
and a variable if the mode is either out
or inout
.
procedure procedure-name (Parameter : Parameter-type) is --Internal variable declarations here. begin --Behavioral description here.. .. .. end function-name;
Sub-program overloading
A subprogram is said to be overloaded if two or more subprograms are defined with the same name. Sometimes, we do this intentionally for our convenience.
Consider the example:
function COUNT (FRUITS: INTEGER) return INTEGER; function COUNT (VEGETABLES: BIT) return INTEGER;
In the above lines of code, the function name “COUNT” is overloaded because their names are the same. You may think, when we will call the function “COUNT,” it is equally likely to call the wrong function. But it is rather easy to identify the right function to call. Only the function name is overloaded here. The compiler can still select the function according to the type of parameter.
To call the first statement, you may write:
COUNT(10);
To call the second statement, you may write:
COUNT(“1”);
Basic elements of VHDL
Comments
Comments in any programming language give the coder a chance to write some data that the compiler can’t read. As a programmer, it’s a good habit to include comments. So that if any other programmer looks into your code or carryforwards your work, they can directly go through the verbal description in comments rather than reading the code.
In VHDL, to write a comment, you need to use two consecutive hyphens ( — ). For multiline comments, you have to include two hyphens on every line.
-- This line is a comment now and the VHDL compiler can no more read this, only you and I can.
Literals
This is simply a general term for every data storing element in the VHDL language. For example – A character having a value ‘1’ is a character literal. But an integer containing ‘1’ is an integer literal.
We use literals while creating an algorithm to generalize a storing element without explicitly mentioning its datatype.
Identifiers
Identifiers are just names/ labels for any data object, process, procedure, function, package, etc. Every programming language has a different set of rules for an identifier to be valid. The rules of VHDL for an identifier to be valid are as follows:
- It must only contain legal characters. Upper case letter(A – Z), a lower case letter (a – z), a digit(0 – 9), or an underscore( _ ) character.
- The first character of an identifier must be a letter.
- The last character must not be an underscore.
- Lower case and upper case letters are considered the same in identifiers.
- Two underscores must not appear consecutively.
Keywords
If you understand what identifiers are, then keywords are not different. Reserved identifiers are called keywords. Every programming language has a set of identifiers that are reserved; they are also called reserved keywords. The programmers can’t use those identifiers for their purpose—keywords like ‘Signal,’ ‘Variable,’ etc.
Data objects
It is very clear in the name itself. They are objects in VHDL that can store some data of specified types. A data object can belong to one of the three classes:
- Constant
- Variable
- Signals
To declare an object, we use an object declaration statement. In that statement, we specify the name, its type, its class, and optionally a value.
Examples of some data objects are:
signal clock: bit; variable count: Integer;
Data types
A data type specifies the type of values that a data object can take. In VHDL, there so many data types, and each has its own properties. We have a separate article on Datatypes in VHDL.
Attributes
Attributes allow you to assign extra information to data objects. They also allow you to fetch extra information about a data object. An attribute is a value, function, range, type, constant, or a signal. They can be associated with certain names.
There are two types of attributes in VHDL:
- Predefined attributes.
- User-defined attributes.
There are five classes of predefined attributes :
- Value attributes.
- Function attributes.
- Range attributes.
- Type attributes.
- Signal attributes.
In this post, we have summed up all the basic syntax elements necessary for VHDL programming. This post is to be considered as a guide that gives you an insight into using some language elements and the range that the language offers you. You will keep returning to this and we will introduce these concepts throughout this VHDL course. Don’t get intimidated yet! We are just beginning!
If you have any queries, kindly post them in the comments section below. We will be happy to help you.