You are on page 1of 19

Structure of Computer Systems – Structural Design in the VHDL Language 1

8. STRUCTURAL DESIGN IN THE VHDL LANGUAGE

This laboratory work describes the structural design in the VHDL language. First, the advantages of
structural design and the elements of a structural description are presented: component declaration, component
instantiation, direct entity instantiation, and configuration specification. Next, the use of libraries, packages, and
generics is presented, and the way in which a library of components can be built is exemplified. Finally, the vari-
ants of the generate statement used in structural descriptions are described.

8.1. Advantages of Structural Design


Structural descriptions specify a system as a set of interconnected components. These descriptions al-
low to create multiple hierarchical levels, in which a design is divided into smaller design units. Each design
unit or component can be specified either by a behavioral description or a structural description. In the latter
case, a component may contain several sub-components, which can be specified by structural descriptions. Fi-
nally, each primitive component at the lowest level is specified by a behavioral description.
Structural design can be accomplished by using components. Any entity-architecture pair can be used as
a component in a higher-level architecture. Therefore, complex systems can be built in several steps from lower-
level components.
The main advantages of structural design are the following:
• Structural design on several hierarchical levels allows to define the details of one part of the design at a
time, preferably in parallel with other designers.
• Each component may be designed and tested individually before being integrated into the higher levels
of the design. This testing of intermediate levels is simpler than system testing, and is usually more
thorough. This means that the designer may have a higher degree of confidence in the components
used, which also contributes to the overall integrity of the system.
• Useful components may be collected into libraries, so that they may be reused later in the same design
or in other designs. One of the advantages of logic synthesis is that such components or modules are
technology independent. The level of reuse for components increases as more components become
available.

8.2. Elements of a Structural Description


A structural description consists of components interconnected by signals. A component may be de-
fined in an architecture by a component declaration, or it may be represented by a separate system specified as
an entity and an architecture. In order to use a component declared earlier, it must be instantiated within the
structural description. Component instantiations represent the basic statements in a structural architecture. These
instantiations are concurrent with each other. In a component instantiation the port mapping is specified, which
indicates the signals connected to the component’s ports. These signals may be specified as ports or internal sig-
nals of the system. In the latter case, they must be declared in the declarative part of the architecture.

8.2.1. Example of Structural Description


The elements of a structural description will be illustrated first with a complete example. The compo-
nents of the structural description will be examined then separately in the next sections. The example consists of
two D-type flip-flops connected in series as a pipeline. The circuit structure is illustrated in Figure 8.1.
2 Structure of Computer Systems – Structural Design in the VHDL Language

Figure 8.1. Circuit example to illustrate the structural description.

We assume that the D-type flip-flop is already defined in a library and has the entity and architecture
definition presented in Example 8.1.

Example 8.1
library ieee;
use ieee.std_logic_1164.all;

entity Dff is
port (D, Clk: in std_logic;
Q, Qn: out std_logic);
end Dff;

architecture arch_dff of Dff is


begin
process
begin
wait until Clk = '1';
Q <= D;
end process;
end arch_dff;

There is more than one way to describe this circuit using components. A possible description is pre-
sented in Example 8.2.

Example 8.2
library ieee;
use ieee.std_logic_1164.all;

entity delay2 is
port (din, clock: in std_logic;
qout: out std_logic);
end delay2;

architecture structural of delay2 is


signal intern: std_logic;

-- Component declaration
component dff is
port (d, clk: in std_logic;
q, qn: out std_logic);
end component dff;

-- Configuration specification
for all: dff use entity work.Dff (arch_dff)
port map (D => d, Clk => clk, Q => q, Qn => qn);
begin
-- Component instances
d1: dff port map
(d => din, clk => clock, q => intern, qn => open);
d2: dff port map
(d => intern, clk => clock, q => qout, qn => open);

end structural;
Structure of Computer Systems – Structural Design in the VHDL Language 3

The architecture contains three parts related to the use of components. These have been labeled with
comments and are the following: component declaration, configuration specification, and component instance.
The three parts are described in the next sections.

8.2.2. Component Declaration


A component declaration defines the interface with a design entity which describes that component. The
component declared in this way may be used later in component instantiation statements. However, the compo-
nent declaration does not specify the entity-architecture pair that describes the component or the ports of the
component; this information is contained either in the configuration specification or in the configuration declara-
tion.
The simplified syntax for a component declaration is the following:
component component_name [is]
generic (generic_list);
port (port_list);
end component [component_name];

The syntax for a component declaration is similar to the entity declaration. The generic clause speci-
fies the generics of the component, and the port clause specifies its ports. In practice, the name of the compo-
nent, the name of its generics and ports, as well as their order, are identical to the elements that appear in the
entity declaration corresponding to the component.
A component may be declared in an architecture, a block, an entity, or in a package. If the component is
declared in an architecture, it must be declared in the declarative part of the architecture, before the begin key-
word. In such a case, the component may be used (instantiated) in the architecture only. If the component is de-
clared in a package, it will be visible in any architecture that uses this package.
The component dff in Example 8.2 has been declared as:
component dff is
port (d, clk: in std_logic;
q, qn: out std_logic);
end component dff;

8.2.3. Component Instantiation


A component instantiation associates signals or values with the ports of a component and associates
values with the generics of that component. The simplified syntax for a component instantiation statement is the
following:
label: [component] component_name
[generic map (generic_association_list)]
port map (port_association_list);
Component instantiation introduces a relationship to a unit declared earlier as a component. The name
of the instantiated component must match the name of the declared component. For the instantiated component
the generics and ports are specified, which represent the actual parameters of the declared component. The asso-
ciation list can be either named or positional.
Named association allows to list the generics and ports in an order that is different from the one speci-
fied in the component declaration. In this case, each generic or port is explicitly associated a value or signal. The
generic or port name is followed by the => symbol, and then by the value assigned to the generic or the signal to
which the port is to be connected. Ports of a component may be left unconnected by using the keyword open.
In Example 8.2, named association has been used for ports. The component instantiation from this ex-
ample is reproduced below:
d1: dff port map
(d => din, clk => clock, q => intern, qn => open);
d2: dff port map
(d => intern, clk => clock, q => qout, qn => open);
In a positional association list, the actual parameters (generics and ports) are specified in the same order
in which they appear in the component declaration. In this case, the generic or port names and the => symbol are
omitted. The component instantiations in Example 8.2 may be rewritten using positional association as follows:
4 Structure of Computer Systems – Structural Design in the VHDL Language

d1: dff port map (din, clock, intern, open);


d2: dff port map (intern, clock, qout, open);

In Example 8.2, there are two instantiations of the dff component, which are labeled d1 and d2. These
labels are mandatory and must be unique. Each instantiation creates a subcircuit containing the dff component
and the interconnections with this component.
In the previous examples, the distinction between the entity and the component declaration has been
indicated by using initial capitals in the entity name and the name of its ports, and lower-case letters in the com-
ponent instances and the internal signals in the resulting circuit. This distinction is made just for clarity and has
no special meaning, since the VHDL language is not case sensitive.

Notes
• Component instantiations are concurrent statements.
• A component instantiation represents the instantiation of the component declaration and not the entity
declaration. The relationship between the component declaration and the entity that describes the com-
ponent is controlled by the configuration specification.

8.2.4. Direct Entity Instantiation


It is not always necessary to define a component to instantiate it, because the VHDL ’93 version of the
language allows the direct instantiation of an entity. This instantiation represents the simplest form to specify a
structural system. The syntax of the direct entity instantiation is the following:
label: entity library_name.entity_name
[(architecture_name)]
[generic map (generic_association_list)]
port map (port_association_list);
The entity instantiation statement specifies the design entity and optionally the name of the architecture
to be used for this entity. The entity may later be used as a component. The entity is specified with the name of
the library to which the entity is compiled and with the entity name. All entities specified by the user are com-
piled implicitly to the library work, so that usually this library is specified in the entity instantiation statement.
The architecture name must be specified only when there is more than one architecture defined for a
single entity. If the architecture name is not specified and there is more than one architecture for the directly in-
stantiated entity, the last compiled architecture associated with the entity will be used.
Assuming that the entity and architecture for the D-type flip-flop of Example 8.1 are compiled to the
library work, the circuit in Figure 8.1 may be described without declaring a component, by using direct entity
instantiations, as shown in Example 8.3.

Example 8.3
library ieee;
use ieee.std_logic_1164.all;

entity delay2 is
port (din, clock: in std_logic;
qout: out std_logic);
end delay2;

architecture structural of delay2 is


signal intern: std_logic;
begin
d1: entity work.Dff (arch_dff)
port map (din, clock, intern, open);
d2: entity work.Dff (arch_dff)
port map (intern, clock, qout, open);
end structural;

8.2.5. Configuration Specification


When direct entity instantiations are not used, component declarations and their instantiations are not
enough for a complete specification of a structural architecture, because the description of component implemen-
Structure of Computer Systems – Structural Design in the VHDL Language 5

tation is not specified. In this case a configuration specification may be used. A configuration is a construct that
defines how component instances are associated with design entities and their architectures.
The reason for separating the entity and its components is to allow the association (called “binding”)
between entity and component to be made as late as possible in the simulation process. This association is car-
ried out only at the start of simulation, in the elaboration phase. In this way, the source modules of a hierarchical
design may be compiled in any order.
The syntax of a configuration specification is the following:
for instance_label: component_name
use entity library_name.entity_name
[(architecture_name)]
[generic map (generic_association_list)]
[port map (port_association_list)];
Several configuration specifications for components may be included in a configuration declaration,
which may represent a separate design unit, and therefore may be placed in a separate file. The syntax for a con-
figuration declaration is the following:
configuration configuration_name of entity_name is
for architecture_name
-- configuration specifications
end for;
-- other for clauses
end [configuration configuration_name];
The syntax of a configuration specification is similar to that of a direct entity instantiation. However, a
configuration specification represents a more flexible method when a different implementation must be used for
the same component. If some changes have to be made, they will be introduced only in the configuration file,
while the structural architecture will remain unchanged. Using direct entity instantiation would require all
changes to be introduced in the architecture.
A configuration specification has three parts. The first part specifies the components to which the con-
figuration applies. Each component is indicated by the label of the statement in which that component is instanti-
ated. It is possible to use the keyword all to select all components with the specified name. This keyword was
used in Example 8.2, the configuration specification from this example being reproduced below:
for all: dff use entity work.Dff (arch_dff)
port map (D => d, Clk => clk, Q => q, Qn => qn);

Rather than specifying the configuration for all the components with the name dff, it would have been
possible to have separate configuration specifications for each instantiated component:
for d1: dff ...
for d2: dff ...
The second part of a configuration specification selects the entity to be used for a component or for all
components with the specified name, as well as the library in which the corresponding entity resides. This part
may also specify the architecture to be used for the selected entity, when there is more than one architecture.
The third part of the specification is optional. This part may explicitly specify how the generics and
ports of an instantiated component are associated with the generics and ports of the entity (the port bindings).
The generic map and port map clauses may be used for this purpose and the association may be positional or
named. Explicit association is only needed if the names of generics and ports in a component declaration are
different from the names of generics and ports in the entity declaration used for that component. In practice,
however, it is recommended to match these names.
If the configuration specification is missing completely for a component, a default association (default
binding) will be performed. This means that an entity with the same name from the current library will be se-
lected for the component, the most recently compiled architecture will be used, and the generics and ports are
associated to the generics and ports with the same names within the entity.
Most of the times, the default association is also the desired one, so that in these cases it is not neces-
sary to specify a configuration. However, there is one case when a configuration specification is necessary, when
the component is to be associated with an entity in a different library. A possibility to achieve this association
would be to use the library and use clauses to make all the entities in that library visible. For example, if the
entity dff were compiled to the library named basic, then the library and use clauses could be added to the
architecture, as illustrated in Example 8.4. In this case, the configuration specification is not necessary.
6 Structure of Computer Systems – Structural Design in the VHDL Language

Example 8.4
library ieee;
use ieee.std_logic_1164.all;
library basic;
use basic.all;

entity delay2 is
port (din, clock: in std_logic;
qout: out std_logic);
end delay2;

architecture structural of delay2 is


signal intern: std_logic;
component dff is
port (d, clk: in std_logic;
q, qn: out std_logic);
end component dff;
begin
d1: dff port map (din, clock, intern, open);
d2: dff port map (intern, clock, qout, open);
end structural;

The problem with this method is that all the entities in that library become visible, regardless of whether
they are going to be used or not. For this reason, conflicts can result between the names of entities in the library
and other names in the design units in which the library is visible. A better solution is to specify a configuration
to associate the component with the entity, and use the default names for generics and ports. This solution is il-
lustrated in Example 8.5.

Example 8.5
library ieee;
use ieee.std_logic_1164.all;
library basic;

entity delay2 is
port (din, clock: in std_logic;
qout: out std_logic);
end delay2;

architecture structural of delay2 is


signal intern: std_logic;
component dff is
port (d, clk: in std_logic;
q, qn: out std_logic);
end component dff;
for all: dff use entity basic.Dff;
begin
d1: dff port map (din, clock, intern, open);
d2: dff port map (intern, clock, qout, open);
end structural;

Notes
• In general, synthesis tools do not support configurations. The designer is required to ensure that entity
and component names, generics and ports match.
• For the configuration of some design entity, both the entity and the configuration must be declared in
the same library.

8.3. Libraries
A library represents a file or directory to which design units may be compiled. For example, an entity
declaration and its corresponding architecture, which reside in a file, may be compiled to a library. The internal
Structure of Computer Systems – Structural Design in the VHDL Language 7

format of the library may be specific for a design tool. Design units (entities, for example) within a library may
be used within other entities, provided that the library and design units are visible.
In order to use the design units from a package, first the library which contains that package must be
made accessible by using the library clause. In such a clause several library names can be specified, separated
by commas. In order to use the design units from a specific library, the packages, components, declarations,
functions, and procedures must be made visible via the use clause.
There are two predefined libraries that are used by default in each design: std and work. The std li-
brary contains the packages named standard and textio. The work library is the default storage place to
which the design units are compiled while they are in development. After verifying the accuracy of a design unit
that is currently in the work library, it may be compiled into another library, if the design unit must be reused in
the same design or in subsequent designs. The std and work libraries are implicitly visible in all designs, so
there is no need to use the library clause for these libraries.
In the previous laboratory works the predefined ieee library was used. This library contains the stan-
dard design units defined by the IEEE (others than those defined by the 1076 standard), such as the packages
named numeric_bit, numeric_std, and std_logic_1164.

Notes
• A library specified in a library clause before a primary design unit (entity, configuration, or package)
is visible in each secondary design unit (architecture or package body) associated with the primary de-
sign unit.

8.4. Packages
A package is a design unit that groups various declarations, which are visible in other design units.
From this viewpoint, declarations within packages differ from declarations within architectures, which are not
visible in other design units.
A package consists of a package declaration and, optionally, a package body. The package declaration
is used to declare types, components, functions, and procedures. The package body contains the definition of
functions and procedures of the package.

8.4.1. Package Declaration


A package declaration defines the interface to the package. The syntax of a package declaration is the
following:
package package_name is
[types]
[constants]
[signals]
[files]
[functions]
[procedures]
[use clauses]
[declarations]
end [package package_name];

In a package declaration types, subtypes, constants, signals, files, subprograms, components, and attrib-
utes may be declared. After declaring the package, it may be used in various independent designs. In order to
make visible the items of a package declaration in other design units, a use clause of the following form must be
used:
use library_name.package_name.item;

If all items in the package must be visible, the reserved word all may be used. Unless there is an item
in the package whose definition conflicts with the definition of an item in another package, usually all the ele-
ments of the package are declared visible. Making all items visible will not increase compile time.
The two-step specification of a package (declaration and body) allows to declare the so-called deferred
constants, which have no value assigned in the package declaration. The value for a deferred constant, however,
must be declared in the package body associated with the package declaration.
8 Structure of Computer Systems – Structural Design in the VHDL Language

A package declaration may contain a subprogram (function or procedure) declaration. The subprogram
body is not allowed in the package declaration, and must appear in the package body.

8.4.2. Package Body


A package body defines the bodies of subprograms and the values of deferred constants specified in the
package declaration. The syntax of a package body is the following:
package body package_name is
[subprograms]
[constants]
[types]
[signals]
[declarations]
end [package body package_name];

Apart from subprogram bodies and values of deferred constants, a package body may also contain dec-
larations similar to those of package declarations; however, these are visible only inside the package body.

Notes
• In a package body, declarations other than values of deferred constants and subprogram bodies are not
visible outside the package body, so that they can be used only locally.
• Each package declaration can have only one associated body.

8.4.3. Packages with Component Declarations


One of the frequent uses of packages is for keeping component declarations that can be reused in later
designs. After placing a component declaration in a package and compiling the package to a library, in order to
use the component only a use clause has to be specified.
To illustrate the use of packages that contain component declarations, consider the example used earlier
of the D-type flip-flop. The package declaration with the dff component is presented in Example 8.6.

Example 8.6
library ieee;
use ieee.std_logic_1164.all;

package dff_pkg is
component dff is
port (d, clk: in std_logic;
q, qn: out std_logic);
end component dff;
end package dff_pkg;

Assuming that the package dff_pkg has been compiled into the current library work, the dff compo-
nent can be used in the delay2 circuit of preceding examples as shown in Example 8.7.

Example 8.7
library ieee;
use ieee.std_logic_1164.all;
use work.dff_pkg.all;

entity delay2 is
port (din, clock: in std_logic;
qout: out std_logic);
end delay2;

architecture structural of delay2 is


signal intern: std_logic;
begin
d1: dff port map (din, clock, intern, open);
Structure of Computer Systems – Structural Design in the VHDL Language 9

d2: dff port map (intern, clock, qout, open);


end structural;

In this example there is no configuration specification, so the default configuration will be used.
A package may be compiled into another library too, different than the current library work. This is not
required to be the same library to which the entity associated with the component has been compiled. However,
in practice the package with a component’s declaration is compiled into the same library as the entity-
architecture pair corresponding to that component. Such libraries are provided by vendors of various device
families. Usually, the name of the package that contains the component declarations is the same as the name of
the library.

8.5. Generics and Parameterized Components


8.5.1. Principle of Generics
Generics represent a general mechanism for transmitting parameters to various instances of an entity or
component. The parameters transmitted to an entity or component represent static data. After model elaboration,
these data are not modified during simulation. Data contained in generics transmitted to an entity or component
can be used to modify the results of simulation, but the results cannot modify the generics.
Generics can be declared within entities or component declarations. The generic declaration must be
placed before the port declaration. The syntax of generic declaration is the following:
generic (generic_list);
The generic list contains the names of the generics, their type, and, optionally, the initial values as-
signed to them.
For simulation, the most used parameters transmitted to an entity or component are the delays of sig-
nals. The generics may also be used to transmit user-defined data types, such as the load capacity or resistance.
For synthesis, generics may be used to design parameterized components, for which the size and char-
acteristics are specified by the value of instantiation parameters. Generics are especially useful when it is desired
to reuse components or subsystems designed earlier. The most frequent use of generics is to parameterize the
size of ports, buffers, registers, or counters. For example, the same model of an arithmetic-logic unit may be used
for 16-bit or 32-bit operands. The number of pipeline stages of a datapath may also be parameterized.

8.5.2. Defining Generic Entities


Example 8.8 shows the entity and architecture declaration of a two-input AND gate to which three ge-
nerics are associated: the rise- and fall-edge delays (rise, fall) and the output load (load). With these infor-
mation, the description can accurately model an AND gate.

Example 8.8
library ieee;
use ieee.std_logic_1164.all;

entity and2 is
generic (rise, fall: time; load: integer);
port (i, j: in std_logic;
k: out std_logic);
end and2;

architecture arch_and2 of and2 is


signal tmp: std_logic;
begin
tmp <= i and j;
k <= tmp after (rise + (load * 2 ns))
when tmp = '1'
else tmp after (fall + (load * 3 ns));
end arch_and2;
10 Structure of Computer Systems – Structural Design in the VHDL Language

Example 8.9 shows the description of a ripple carry adder in which a generic n is used, which specifies
the width of the adder. Within the entity, this generic is used to define the width of the ports. Within the architec-
ture, generic n is used to specify the range of the for loop.

Example 8.9
library ieee;
use ieee.std_logic_1164.all;

entity add_ripple is
generic (n: natural);
port (a, b: in std_logic_vector (n-1 downto 0);
cin: in std_logic;
s: out std_logic_vector (n-1 downto 0);
cout: out std_logic);
end add_ripple;

architecture structural of add_ripple is


begin
process (a, b, cin)
variable c: std_logic;
begin
c := cin;
for i in 0 to n-1 loop
s(i) <= a(i) xor b(i) xor c;
c := (a(i) and b(i)) or (a(i) and c) or
(b(i) and c);
end loop;
cout <= c;
end process;
end structural;

8.5.3. Using Generic Components


A generic entity may be used as a component in the same way as a non-generic entity. The only differ-
ence is that values must be specified for the generic parameters. These values must be constants and may be
specified as numeric values directly in the component instance’s generic map clause.
The description in Example 8.10 contains the declaration for the entity and2 of Example 8.8 in the form
of a component and the instantiation of this component using the generic map clause.

Example 8.10
library ieee;
use ieee.std_logic_1164.all;

entity test is
generic (rise, fall: time; load: integer);
port (a, b, c, d: in std_logic;
x, y: out std_logic);
end test;

architecture arch_test of test is


component and2 is
generic (rise, fall: time; load: integer);
port (i, j: in std_logic;
k: out std_logic);
end component and2;
begin
u1: and2 generic map (5 ns, 6 ns, 3)
port map (a, b, x);
u2: and2 generic map (4 ns, 5 ns, 5)
port map (c, d, y);
end arch_test;
Structure of Computer Systems – Structural Design in the VHDL Language 11

Generics may also be initialized with default values, which are replaced with actual values if they are
transmitted at component instantiation. Otherwise, the default values are used. An example of generic initializa-
tion is the following:
generic (rise, fall: time := 5 ns; load: integer := 0);

In Example 8.11, the entity add_ripple of Example 8.9 is used to build an 8-bit ripple carry adder.
The adder is declared as a component, which is then instantiated, specifying the value of generic n.

Example 8.11
library ieee;
use ieee.std_logic_1164.all;

entity add_8 is
port (a, b: in std_logic_vector (7 downto 0);
cin: in std_logic;
s: out std_logic_vector (7 downto 0);
cout: out std_logic);
end add_8;

architecture structural of add_8 is


component add_ripple is
generic (n: natural);
port (a, b: in std_logic_vector (n-1 downto 0);
cin: in std_logic;
s: out std_logic_vector (n-1 downto 0);
cout: out std_logic);
end component add_ripple;
begin
add: add_ripple
generic map (n => 8);
port map (a, b, cin, s, cout);
end add_8;

8.5.4. Types of Generic Parameters


In VHDL, generic parameters can be of any type. However, synthesis tools are limited in the types of
generic parameters supported. In general, the only types that may be used are integer types, although some syn-
thesis tools also allow enumeration types, of which the most useful are bit and boolean.
The model of the AND gate of Example 8.8 cannot be used for synthesis, because in the assignment
statements the after clause is used. Also, in Example 8.10 generics of type time are used when the AND gate is
declared as a component. The examples that present the ripple carry adder may be used for synthesis, since the
generic used is of type natural, a subtype of integer. The use of type natural ensures that users do not try
to create an adder with a negative number of bits.
All the array types used for synthesis are indexed using the type natural. Such types are
bit_vector, std_logic_vector, as well as the signed and unsigned types defined in both the
numeric_bit and numeric_std packages. Therefore, there should be no problems using generics to specify
the range of array ports, as in the ripple carry adder examples.
Using generic parameters of other types allow to parameterize other features of circuits. For example,
type boolean may be used in various conditional constructs. An example of this is presented in Section 8.6.2,
which describes the if generate statement. Note that a parameter of type boolean may be replaced by a pa-
rameter of type integer. For example, the Boolean value FALSE can be represented by the value 0 and TRUE by
the value 1.

8.5.5. Building a Library of Components


In this section we present the way in which a library with some basic components may be built. In this
library several packages will be placed. Each package contains a set of basic components, such as flip-flops, reg-
isters, or counters. Each class of components is defined for several widths. For this, the components are param-
eterized via generics.
12 Structure of Computer Systems – Structural Design in the VHDL Language

First, we define a D-type flip-flop with asynchronous reset, and a set of n D-type flip-flops with com-
mon clock and asynchronous reset. The declarations of the entities and architectures for these components are
presented in Example 8.12.

Example 8.12
-- Set of D-type flip-flops
-- Sizes: (1, n)

library ieee;
use ieee.std_logic_1164.all;

entity rdff1 is
port (clk, reset: in std_logic;
d: in std_logic;
q: buffer std_logic);
end rdff1;

architecture arch_rdff1 of rdff1 is


begin
p1: process (reset, clk)
begin
if (reset = '1') then
q <= '0';
elsif (clk'event and clk = '1') then
q <= d;
end if;
end process;
end arch_rdff1;

-----------------------------------------------

library ieee;
use ieee.std_logic_1164.all;

entity rdff is
generic (n: integer := 2);
port (clk, reset: in std_logic;
d: in std_logic_vector (n-1 downto 0);
q: buffer std_logic_vector (n-1 downto 0));
end rdff;

architecture arch_rdff of rdff is


begin
p1: process (reset, clk)
begin
if (reset = '1') then
q <= (others =>'0');
elsif (clk'event and clk = '1') then
q <= d;
end if;
end process;
end arch_rdff;

In the preceding example, the generic n is given a default value of 2. If an instantiation of the rdff
component does not specify a generic map clause, then the component will have the default size of 2. A sepa-
rate component has been created for a single flip-flop (component rdff1). This is because if n were equal to 1,
we would need to transmit as parameter a one-element wide vector, for example, "0", in the form
std_logic_vector(0 downto 0). The declarations for these two components are placed in the same file,
although they do not need to be.
In the following we describe a set of registers (made of D-type flip-flops) with synchronous load, asyn-
chronous reset, and synchronous preset. The description of a 1-bit register and an n-bit register is shown in Ex-
ample 8.13.
Structure of Computer Systems – Structural Design in the VHDL Language 13

Example 8.13
-- Set of registers
-- Sizes: (1, n)

library ieee;
use ieee.std_logic_1164.all;

entity reg1 is
port (clk, load: in std_logic;
reset, set: in std_logic;
d: in std_logic;
q: buffer std_logic);
end reg1;

architecture arch_reg1 of reg1 is


begin
p1: process (reset, set, clk)
begin
if (reset = '1') then
q <= '0';
elsif (set = '1') then
q <= '1';
elsif (clk'event and clk = '1') then
if (load = '1') then
q <= d;
else
q <= q;
end if;
end if;
end process;
end arch_reg1;

-----------------------------------------------

library ieee;
use ieee.std_logic_1164.all;

entity reg is
generic (n: integer := 2);
port (clk, load: in std_logic;
reset, set: in std_logic;
d: in std_logic_vector (n-1 downto 0);
q: buffer std_logic_vector (n-1 downto 0));
end reg;

architecture arch_reg of reg is


begin
p1: process (reset, set, clk)
begin
if (reset = '1') then
q <= (others =>'0');
elsif (set = '1') then
q <= (others =>'1');
elsif (clk'event and clk = '1') then
if (load = '1') then
q <= d;
else
q <= q;
end if;
end if;
end process;
end arch_reg;

When instantiating the component reg, n is used to indicate the width of the register. This component
cannot be used with n equal to 1, because the code q <= (others =>'0') implies that q is an aggregate, or an
array of more than one element. To the ports of the register can be connected signals that never change value, so
that some functions of the register may be permanently enabled (e.g. load) or disabled (e.g. reset). For example,
14 Structure of Computer Systems – Structural Design in the VHDL Language

if signals vdd and vss are connected to logical '1' and '0', respectively, then synthesis of an instantiation of com-
ponent reg with the load permanently enabled and the preset permanently disabled would result in a register
without the load and preset logic. The instantiation of this component with size 4 is the following:
u1: reg generic map (4)
port map (clock, vdd, rst, vss, data, q_out);
The components declared in Example 8.12 and 8.13 may be grouped into a package. This package will
be compiled into a library named basic. Example 8.14 contains the definition of the package named reg_pkg,
which consists of the components rdff1, rdff, reg1, and reg.

Example 8.14
library ieee;
use ieee.std_logic_1164.all;

package reg_pkg is
component rdff1 is
port (clk, reset: in std_logic;
d: in std_logic;
q: buffer std_logic);
end component rdff1;
component rdff is
generic (n: integer := 2);
port (clk, reset: in std_logic;
d: in std_logic_vector (n-1 downto 0);
q: buffer std_logic_vector (n-1 downto 0));
end component rdff;
component reg1 is
port (clk, load: in std_logic;
reset, set: in std_logic;
d: in std_logic;
q: buffer std_logic);
end component reg1;
component reg is
generic (n: integer := 2);
port (clk, load: in std_logic;
reset, set: in std_logic;
d: in std_logic_vector (n-1 downto 0);
q: buffer std_logic_vector (n-1 downto 0));
end component reg;
end package reg_pkg;

8.6. Generate Statement


The generate statement simplifies description of circuits with replicated structure. It is commonly
used to specify a group of identical components using specification of only one component and replicate it using
the statement’s generate mechanism. The generate statement is similar to a loop statement, with the differ-
ence that loop is a sequential statement, while generate is a concurrent statement. This means that a gener-
ate statement cannot appear inside a process.
There are two types of generate statements: for generate statement, used for replicated structures,
and if generate, used for conditional structures.

8.6.1. For generate Statement

The for generate statement replicates (copies) a group of concurrent statements a specified number
of times. This statement is in effect a concurrent form of the for loop statement. However, being a concurrent
statement, it may be used to replicate any other concurrent statements, such as processes, blocks, concurrent pro-
cedure calls, concurrent signal assignment statements, component instances and other generate statements.
The syntax of the for generate statement is the following:
label: for counter in range generate
[declarations
Structure of Computer Systems – Structural Design in the VHDL Language 15

begin]
concurrent_statements
end generate [label];

The syntax of this statement is similar to that of the for loop statement. The label preceding the for
construction is required. The iteration count is called generate constant, because its value is treated as a constant
value inside the loop. After an iteration, the iteration count is assigned the next value of the range. The range can
be ascending or descending. The range of the iteration count must be constant, because the synthesis tool must
know how many times to replicate the structure. Therefore, it is not possible to use a signal value to define the
range. The declarative part of the statement allows to declare local types, attributes, constants, signals, compo-
nents, subprograms, configurations, and files.

Note
• When the for generate statement does not contain any local declarations, then the reserved word
begin need not to be used. The same observation applies to the if generate statement.

To illustrate the use of the for generate statement, the ripple carry adder example will be rewritten
using concurrent signal assignment statements. The modified version is presented in Example 8.15.

Example 8.15
library ieee;
use ieee.std_logic_1164.all;

entity add_ripple is
generic (n: natural);
port (a, b: in std_logic_vector (n-1 downto 0);
cin: in std_logic;
s: out std_logic_vector (n-1 downto 0);
cout: out std_logic);
end add_ripple;

architecture structural of add_ripple is


signal c: std_logic_vector (n downto 0);
begin
c(0) <= cin;
gen: for i in 0 to n-1 generate
s(i) <= a(i) xor b(i) xor c(i);
c(i+1) <= (a(i) and b(i)) or
(a(i) and c(i)) or
(b(i) and c(i));
end generate;
cout <= c(n);
end structural;

In this example, the carry signal c has become a vector. Each carry bit is a separate signal, and the
number of signals needed depends on the generic parameter n. The size of the vector is specified by the generic
parameter, and this size is one bit larger than the operands being added to provide a carry output.
Assuming that the value of the generic n is 4, the equivalent architecture with that of the above se-
quence in which the for generate statement is used is the following:
architecture structural of add_ripple is
signal c: std_logic_vector (4 downto 0);
begin
c(0) <= cin;
s(0) <= a(0) xor b(0) xor c(0);
c(1) <= (a(0) and b(0)) or (a(0) and c(0))
or (b(0) and c(0));
s(1) <= a(1) xor b(1) xor c(1);
c(2) <= (a(1) and b(1)) or (a(1) and c(1))
or (b(1) and c(1));
s(2) <= a(2) xor b(2) xor c(2);
c(3) <= (a(2) and b(2)) or (a(2) and c(2))
or (b(2) and c(2));
s(3) <= a(3) xor b(3) xor c(3);
16 Structure of Computer Systems – Structural Design in the VHDL Language

c(4) <= (a(3) and b(3)) or (a(3) and c(3))


or (b(3) and c(3));
cout <= c(4);
end structural;

The circuit that results by synthesizing the description in the previous example is shown in Figure 8.2.

Figure 8.2. Four-bit ripple carry adder.

8.6.2. If generate Statement

The if generate statement specifies the conditional replication of a group of concurrent statements.
This statement is useful to generate circuits with replicated structure, but which contain some irregularities, such
as the first and the last element of the structure. Another use of this statement is to describe optional structures.
For example, an optional output register could be added to a general-purpose component, and this can be con-
trolled by a boolean generic parameter.
The syntax of the if generate statement is the following:
label: if condition generate
[declarations
begin]
concurrent_statements
end generate [label];
The condition is represented by a Boolean variable, a Boolean generic parameter, a Boolean or condi-
tional expression that evaluates to a Boolean constant. It is not possible to use a signal within the conditional
expression.
The if generate statement will be illustrated with an example that represents the description of an
optional output register. The example consists of the register description only, but this description may be added
to any generic entity.

Example 8.16
library ieee;
use ieee.std_logic_1164.all;

entity optional_reg is
generic (n: natural; mem: boolean);
port (a: in std_logic_vector (n-1 downto 0);
clk: in std_logic;
z: out std_logic_vector (n-1 downto 0));
end optional_reg;

architecture structural of optional_reg is


begin
gen: if mem generate
process
begin
wait until clk = '1';
z <= a;
end process;
end generate;

ngen: if not mem generate


z <= a;
Structure of Computer Systems – Structural Design in the VHDL Language 17

end generate;
end structural;

If the generic parameter mem is set to TRUE, the output z will be a registered version of input a. How-
ever, if the generic parameter is set to FALSE, the output z will be directly connected to input a.
It is important to consider both the possible conditions of the if generate statement, as illustrated in
the previous example. This is because in the VHDL language there is no else generate statement.

8.6.3. Component Instances in Generate Statements

When using components in generate statements, the following problem arises: because the compo-
nent instances are considered to be in a separate sub-block of the architecture, the components cannot be config-
ured from the architecture. In other words, configuration specifications are required to be in a sub-block at the
same level of scope as the component instances themselves, but the generate statements are considered to be a
separate level of scope.
The only possibility to add configuration specifications to component instances in a generate state-
ment is to add another sub-block (another level of scope) with a block statement. The block statement was
presented in Laboratory No. 6. A block statement has a declarative part in which declarations may be placed,
such as configuration specifications, and a part which contains concurrent statements.
Example 8.17 illustrates the use of a block to allow a component to be configured with a configuration
specification. This example describes a register with the generic size n built with the D-type flip-flop used in the
preceding examples.

Example 8.17
library ieee;
use ieee.std_logic_1164.all;

entity delay_n is
generic (n: natural);
port (d: in std_logic_vector (n-1 downto 0);
clk: in std_logic;
q: out std_logic_vector (n-1 downto 0));
end delay_n;

architecture structural of delay_n is


begin
gen: for i in 0 to n-1 generate
blk: block
component dff is
port (d, clk: in std_logic;
q, qn: out std_logic);
end component dff;
for all: dff use entity work.Dff;
begin
d1: dff port map (d(i), clk, q(i), open);
end block;
end generate;
end structural;

The component declaration may be also placed outside the architecture, as has been shown in Section
8.4.3, where the component has been declared in a separate package. The configuration specification, however,
must be placed in a block statement, in its declarative part.

8.7. Applications
8.7.1. Create separate files with the description of the set of flip-flops of Example 8.12, the set of
registers of Example 8.13, and the package reg_pkg of Example 8.14. Use the Active-HDL system to compile
these files to a library named basic.
18 Structure of Computer Systems – Structural Design in the VHDL Language

8.7.2. Design a synchronous counter with a generic size n. The inputs to the counter are the clock signal
clk, an asynchronous reset signal areset, a synchronous reset signal sreset, and an enable signal enable.
The output from the counter is the count vector. Create a file with the entity declaration and the architecture of
the counter, and another file with a package declaration containing this counter. Compile these files to the basic
library created for Application 8.7.1.
8.7.3. Create a test project for the synchronous counter created for Application 8.7.2, which was com-
piled to the basic library. Compile the test project and verify the operation of the counter.
8.7.4. Write the entity declaration and the architecture for the following logic gates:
a. and2 e. xor2
b. and4 f. nand2
c. or2 g. nand4
d. or4
Create a package with the above component declarations. Compile the files with these design units to a
library named logic.
8.7.5. Use generics to write the entity declaration and the architecture for the following n-input logic
gates:
a. andn
b. orn
c. nandn
Create a package with the andn, orn, and nandn component declarations. Compile the files with these
design units to the logic library created for Application 8.7.4.
8.7.6. Create a new project and implement the equation x = (a and b) or (c and d) using com-
ponents from the logic library created for Application 8.7.4.
8.7.7. Draw the block diagram of a 4-bit shift register implemented with D-type flip-flops. The input to
the shift register is sin, and the output is sout. Describe this shift register with the for generate statement.
8.7.8. Modify the description of the shift register in Application 8.7.7 to use an if generate state-
ment.
8.7.9. Draw the block diagram of an n-bit asynchronous binary counter which counts forward, built with
D-type flip-flops. Describe the counter using a generate statement.
8.7.10. Draw the block diagram of a synchronous decimal counter which counts forward, built with D-
type flip-flops. Describe the counter using a generate statement
8.7.11. Design a simple arithmetic-logic unit that allows to perform the following operations on 4-bit
operands: add, AND, OR, NOT, shift right, and shift left. Simulate the operation of this arithmetic-logic unit.
8.7.12. Design an 8-bit ripple carry adder and simulate the operation of this adder.
8.7.13. Draw the block diagram of an 8-bit pipelined ripple carry adder, inserting registers between
every two full adders. Describe the adder in VHDL and simulate its operation.
8.7.14. Implement the 16-bit adder of Figure 8.3 that uses carry lookahead on groups of 4 bits.
8.7.15. Write the equations of functions P and G generated by a 2-bit carry lookahead adder. Then write
the equations of the carry signals c2, c4, c6, and c8 that must be generated by an 8-bit adder which uses carry loo-
kahead on groups of 2 bits. Describe in VHDL this adder.
8.7.16. Design a binary multiplier for 8-bit numbers in sign-magnitude representation using the direct
multiplication method. Use structural design with components and component instantiation statements.
8.7.17. Design a binary multiplier for 8-bit numbers in 2’s complement representation using Booth’s
method. Use structural design with components and component instantiation statements.
8.7.18. Design a binary divider for numbers in sign-magnitude representation using the nonrestoring
division method. The dividend is a 16-bit number, and the divisor is an 8-bit number. Use structural design with
components and component instantiation statements.
Structure of Computer Systems – Structural Design in the VHDL Language 19

8.7.19. Design a decimal multiplier for 4-digit numbers using the right-and-left-hand components
method. Use structural design with components and component instantiation statements.

Figure 8.3. 16-bit adder built with 4-bit carry lookahead adders.

8.7.20. Describe in VHDL the architecture that uses horizontal microprogramming (Figure 4.5). Use
structural design with components and component instantiation statements.

You might also like