Professional Documents
Culture Documents
SSC08 2004 e
SSC08 2004 e
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.
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;
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;
-- 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.
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;
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.
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;
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;
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;
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.
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.
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.
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;
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.
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;
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;
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;
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;
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;
-----------------------------------------------
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;
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;
-----------------------------------------------
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;
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;
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;
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
The circuit that results by synthesizing the description in the previous example is shown in Figure 8.2.
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;
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.
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;
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.