0% found this document useful (0 votes)
2 views36 pages

Notes-Day3

The document discusses the necessity of Hardware Description Languages (HDLs) like VHDL for modern hardware design, emphasizing their advantages over traditional methods which are time-consuming and less maintainable. It outlines the levels of abstraction in design, from algorithmic to gate level, and the process of synthesis that automates the translation of high-level descriptions into detailed hardware implementations. The document also introduces basic VHDL syntax and structure, demonstrating how to describe simple digital components like a NAND gate.

Uploaded by

ly3924266
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
2 views36 pages

Notes-Day3

The document discusses the necessity of Hardware Description Languages (HDLs) like VHDL for modern hardware design, emphasizing their advantages over traditional methods which are time-consuming and less maintainable. It outlines the levels of abstraction in design, from algorithmic to gate level, and the process of synthesis that automates the translation of high-level descriptions into detailed hardware implementations. The document also introduces basic VHDL syntax and structure, demonstrating how to describe simple digital components like a NAND gate.

Uploaded by

ly3924266
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 36

MSc Electronic and Computer Engineering

Digital Design

12 Why do we need Hardware Description Languages (HDLs)?


This session introduces modern techniques for hardware design. These are based
around the use of hardware description languages HDLs. The basic idea is that instead
of designing a new piece of hardware one logic gate at a time, we just write a
description (using an HDL) of what we want the whole design to do, and this is
automatically translated into a detailed hardware design in a process called synthesis.

12.1 What’s the problem with traditional methods?


Traditional methods of logic design are based on truth tables, state transition tables,
Boolean logic and Karnaugh maps. To illustrate some of the issues, we start off by
looking at a simple case study. We’ll also use this case study in later sessions to
illustrate some of the features of VHDL.

Suppose we want a piece of hardware that adds two 16-bit numbers together

16
a 16
16 ADD sum
b

How would we approach this using traditional methods? We would have to exercise
some ingenuity to partition this large problem into a series of smaller problems that
are easier to solve. For example, we could partition into a sequence of sixteen 1-bit
adders

a0 + sum0
b0

a1 sum1
+
b1

a2 + sum2
b2

a3 + sum3
b3

and so on …

The procedure would then go as follows:


 We form the truth table for each of these units.

1
 We turn this truth table into a Karnaugh map
 We extract Booleans equation from the Karnaugh map
 We turn these Boolean equations into AND, OR and NOT gates
 Finally, we assemble the 16 units to make our complete circuit:

That’s the traditional design methodology. Let’s do some evaluation of this method.

Design effort
It’s quite a lot of work to get from the design brief (add 16-bit numbers) into the
design using logic gates. It would take about 10 minutes to complete and document
the process. But the chips used in mobile phones or computer games consoles contain
millions of logic gates. If we have to put this much effort into getting out a design that
conatins only a few dozen gates, then we are in trouble. The designer productivity will
be too low; it will take too much time, and cost too much money to undertake a big
project. We need a method that gives higher productivity.

Maintainability
When you are in the midst of designing a piece of hardware, you probably have a
pretty good understanding of the design you produce. However, it’s difficult to work
with gate level designs produced by someone else, or even with designs that were
produced by you a few weeks previously. Just by glancing at the logic schematics
above, can you tell what it actually does? We need a method that gives greater clarity
as to what the designs do.

Some implementation styles don’t use basic logic gates


Some types of hardware, e.g. FPGAs don’t actually use basic logic gates such as
AND gate and OR gates. But we put a lot of effort into getting the designs down to an
interconnection of basic logic gates. This effort was simply wasted if the design was

2
to be implemented on an FPGA. (FPGA design tools have translation utilities that
translate the logic gates into something that the FPGA can use, but the fact still
remains that the effort expended in getting out the gate-level design was largely
wasted, since the FPGA didn’t actually use it.)

12.2 VHDL
VHDL is the VHSIC Hardware Description Language. (VHSIC stands for Very High
Speed Integrated Circuit). The main motivation for its creation was to provide
rigorous and unambiguous specification of modules. Gradually it developed to be
used for other purposes such as synthesis. The other important HDL is Verilog. This
is older than VHDL, and its original form was not very powerful. Over the years, it
has been enhanced and extended with extra features, so that it is now as powerful as
VHDL.

VHDL is based around the notion of being able to view the modules in a design at
different levels of abstraction. Crudely speaking, a high level of abstraction contains
little detail, and a low level of abstraction contains a lot of detail. Low-level design
requires a lot of effort, and we want to avoid this effort until we are sure that it won’t
be wasted. We need to resolve all high level issues before we commit to any low level
design.

12.2.1 Levels of Abstraction


 Algorithmic
This describes the basic idea of what the design is supposed to do, without
reference to how this functionality is to be achieved. (Indeed, one of the
purposes of the design phase is to investigate different possible methods to
achieve the desired functionality). The initial specification of a design will
almost always be at the algorithmic level.
 Register transfer level (RTL)
The design is conceived as a group of interconnected modules. For each
module we know three things:
 What its interface to the other modules of the design is (how many inputs
and outputs, how many bits wide are they, etc.)
 What the logical relationship is between the inputs and the outputs (usually
expressed as something like a Boolean logic equation)
 What the timing is between the inputs and the outputs (i.e. what happens
on what clock cycle).
 Gate level
The design is constructed from basic logic gates1.

There may also be a 4th level, the physical level. This might refer, for example, to the
processing of a piece of silicon that would be necessary to manufacture the required
configuration of logic gates as an application-specific integrated circuit (ASIC).
Alternatively, it might be the generation of the configuration bit stream for a field
programmable gate array (FPGA).

1 Or whatever is the most fundamental design primitive for the hardware implementation we are
intending to use. This would Configurable Logic Blocks (CLBs) for an FPGA or a fuse map for a
CPLD.

3
12.3 Synthesis
A synthesis CAD tool is one that automatically maps a description from one level of
the hierarchy to a lower level on the hierarchy. The main types are as follows:-
 Physical synthesis
This performs the mapping from gate-level to physical level. For an ASIC, a
gate level representation is automatically translated to a mask level design of
an integrated circuit. For a PLD or an FPGA, a gate-level design is mapped to
a configuration file that controls how the fuses in the device should be blown,
or how the CLBs should be configured. CAD tools do this task extremely
well.
 Logic synthesis
This maps an RTL description to a gate level description. CAD tools also
perform this stage extremely well.
 Behavioural synthesis
This maps an algorithmic description to a register transfer or to a gate level
description. At present, automated synthesis tools cannot do this well. It is a
very active area of research, but for now, and the foreseeable future, this is a
task that must be done by humans.

Automatic synthesis leads to great productivity gains, because human designers can
confine their activities to high level design. It has often said that the output of a
designer is limited to about 10-50 items per day, fully debugged and properly
documented. This rate is true whether an item corresponds to a logic gate, a functional
unit of an RTL design, or an equation representing the behaviour of an entire digital
filter for a signal processing system. 10-50 logic gates will only form a very small part
of a system whereas 10-50 RTL functional units may be enough to describe an entire
system. The higher the level at which the designer is working, the more the designer
can produce.

Synthesis also helps us avoid the risk of putting a lot of effort into targeting one
particular manufacturing technology, only to find that we need to re-target the design
to a new technology. If all the low-level synthesis was done by humans, the re-
targeting could take thousands of man hours. If it was done by a CAD tool, then we
simply re-synthesise for the new target hardware, which means leaving a computer
running for a few days.

12.4 Summary
Traditional design methods have many problems. Designer productivity is too low.
Decisions about the implementation have to be made early in the design process. If
the design is re-targeted from one technology to another (say a design originally
implemented on an ASIC is moved to an FPGA) the whole design process needs to be
repeated.

HDLs aim to alleviate these problems. Specification is normally done at the


algorithmic level of abstraction. Design is then carried out at the RTL level, saying
what the modules of the design should do, and on which clock cycle the output is due.
This description in then automatically translated to implementation in a process called
synthesis.

4
HDLs also allow a specification for a module to be simulated. So we can try out
different combinations of input and see what the outputs would do. This can be done
before any detailed gate level design is attempted.

You should now know...

The meaning of the following:


 Level of abstraction
 Algorithmic level
 Register transfer level (RTL)
 Logic synthesis
 Physical synthesis

5
13 Introduction to VHDL
In this session we will look at how to do simple designs in VHDL.

13.1 Entity and Architecture


We'll start off with an extremely simple example: we will describe a NAND gate. The
first thing that we have to do is to say what the device looks like to the outside world.
This basically means describing its port map, i.e. the signals that flow in and out of
the device.

b nandgate
c

To describe this in VHDL, we use an entity declaration.

ENTITY nandgate IS
PORT ( a, b: IN STD_LOGIC; c: OUT STD_LOGIC );
END;

Everything in uppercase is a VHDL keyword, i.e. part of the language. Everything in


lower case is a name that I have chosen for the parts of my design. The entity has to
be given a name (we've chosen nandgate, but you could have chosen any other name).
Each of the signals in the port map is declared as having a mode and a type. The mode
can be IN or OUT, and simply says whether the signal is an input or an output. The
type STD_LOGIC represents a signal that bit can a value of ‘0’, ‘1’, ‘X’ or ‘U’. (‘X’
means unknown. ‘U’ means uninitialized, i.e. a signal that has not yet been assigned
any valid logical value.) STD_LOGIC is the normal way to describe logic signals that
appear at the input or output of gates, or at wires in between them.

Now that we have described the inputs and outputs, we need to say what the device
does, i.e. how its outputs respond to its inputs. This is done in an architecture:

ARCHITECTURE simple OF nandgate IS


BEGIN
c <= a NAND b;
END;

The ARCHITECTURE statement says that we are producing a description of what


goes on inside nandgate. It is possible (and indeed quite common) for us to try out
many different designs for what goes on inside nandgate. We have to give each
different design a name, so that we can tell VHDL which version we want to use. I
have chosen the name simple for this particular design. After the ARCHITECTURE
statement comes the word BEGIN. This introduces the main body of the architecture,
which explains how the outputs relate to the inputs. At the end of the body comes the
END statement, which says that we have reached the end of the body.

How the outputs relate to the inputs is described by the statement

c <= a NAND b;

6
The symbol <= (which is meant to look like a left-pointing arrow) is pronounced
"gets". It means that the signal c gets the value of a NANDed together with the value
of b. Whenever a or b change their value, this statement causes the value of c to be
updated.

If we want to check that our description is functioning correctly, we can feed it into a
simulator, a program that predicts how the outputs would change in response to
changes in the input. Here is the sort of thing we get if we run this code through a
simulator

The horizontal axis is time, ranging from 0 to 100 ns. Traces are shown for the signals
a, b and c. Whenever a or b changes its value, c receives a new value. In order to carry
out the simulation, we need to tell the simulator what we want each of the inputs a and
b to do (in this case we have toggled each from 0 to 1 and then back to 0). The
simulator then works out what the output c would do in response. You can see that c
is carrying out the logic function a NAND b, so the design is correct.

VHDL uses the following logical operators: NOT, AND, OR, NAND, NOR, XOR

13.2 Specifying another architecture


We are allowed to give many different descriptions of the way that the input related to
the output. So, for example, here is a second version of the architecture of the
nandgate.

ARCHITECTURE complicated OF nandgate IS


BEGIN
c <= NOT ( a AND b );
END;

This achieves exactly the same function as the first description, but does it in a
different way.

13.3 BEGIN and END statements


If you are used to C, C# or Java, you will know that sometimes you want to consider a
group of statements to be considered as one block. C, C# and Java use curly braces {
and } to indicated the beginning and end of a block respectively. So, for example, a
loop in C might look like this:

for (i=1; i<=n; i++)


{
a[i]=i;
b[i]=a[i]*a[i];
}

7
The braces show that the two statements should be considered collectively as a block
that makes up the body of the loop.

VHDL uses the keywords BEGIN and END. So in VHDL the loop would look like
this

FOR i IN ( 1 TO N ) LOOP
BEGIN
a(i) = i;
b(i) = a(i) * a(i);
END LOOP;

Note that indentation of the block is used to make it clearer where the block starts and
ends.

13.4 Semicolons
Like C or Java, VHDL uses the semicolon to indicate the end of a statement.

Statements that "open up" a block don't take semicolons. So in C these would be
wrong:

for (i=1; i<=n; i++); /* WRONG: shouldn't be a semicolon here */


{; /* ALSO WRONG: don't want a semicolon here */
a[i]=i;
b[i]=a[i]*a[i];
}

Similarly in VHDL these would be wrong

FOR i IN ( 1 TO N ) LOOP; --WRONG: shouldn't be a semicolon here


BEGIN; --ALSO WRONG: don't want a semicolon here
a(i) = i;
b(i) = a(i) * a(i);
END LOOP;

Let's have another look at our simple example:

ENTITY nandgate IS
PORT ( a, b: IN STD_LOGIC; c: OUT STD_LOGIC );
END;

ARCHITECTURE simple OF nandgate IS


BEGIN
c <= a NAND b;
END;

The keyword IS is "opening up" a block of statements, and therefore does not need a
semicolon. However, note that VHDL is a little inconsistent as to whether IS needs to
be followed by a BEGIN. In an ENTITY, the BEGIN is implied, and the END
statement is answering the IS. By contrast, in an ARCHITECTURE the word BEGIN
must also be there, and the END is answering the BEGIN.

8
13.5 Stylistic issues

13.5.1 Case
VHDL is not case sensitive. All three of these are identical in meaning, and you’ll see
all three styles in textbooks and design magazines:

ENTITY nandgate IS
PORT ( a, b: IN STD_LOGIC; c: OUT STD_LOGIC);
END;

entity NANDGATE is
port ( A, B: in std_logic; C: out std_logic);
end;

entity nandgate is
port ( a, b: in std_logic; c: out std_logic);
end;

It used to be considered good style to write all the keywords of VHDL in one case,
and all the names that we have chosen for our design in the other case. This makes it
easier to figure out what is going on in the design.

Nowadays it is normal to put everything in lowercase. Modern VHDL editors are


context sensitive, and can figure out which words are part of the VHDL language and
show them in a particular colour. So for the editors we use in labs, VHDL keywords
are automatically displayed in purple, and the names chosen by us for signals, entities
and architectures are shown in black.

In lectures we will show all keywords in uppercase to make it clearer to you what is
part of the VHDL language, and what is just a name that I have chosen.

13.5.2 Spaces and indents


You can put as many spaces as you like between words. So, for example, these are
both the same

ENTITY nandgate IS
PORT (a,b: IN STD_LOGIC; c: OUT STD_LOGIC);
END;

ENTITY nandgate IS
PORT ( a, b: IN STD_LOGIC; c: OUT STD_LOGIC);
END;

13.5.3 Returns
Putting in a carriage return makes no difference to the function of your code. So the
following two are identical in function

ENTITY nandgate IS
PORT ( a, b: IN STD_LOGIC; c: OUT STD_LOGIC);
END;
ENTITY nandgate IS
PORT ( a, b: IN STD_LOGIC;
c: OUT STD_LOGIC);
END;

9
You can use whichever you feel is clearest.

13.5.4 Annotating END statements


In a long description, it can be easy to lose track of how many BEGIN and END pairs
you have in the code. To help you keep track, you can put the name of what you think
you are ending after the END statement. So, for example, you can write

ENTITY nandgate IS
PORT ( a, b: IN STD_LOGIC; c: OUT STD_LOGIC);
END ENTITY nandgate;

ARCHITECTURE simple OF nandgate IS


BEGIN
c <= a NAND b;
END ARCHITECTURE simple;

When you run the compiler, the code will be checked, and if there is a mismatch
between what you say you are ENDing and what VHDL thinks you are ending, then
this will be flagged as an error.

Although the annotation of END statements is normally optional, it is considered to


be good style. It is a useful safety precaution, which can save you from bugs that are
difficult and time consuming to find.

13.5.5 Comments
Comments are introduced by two dashes:

-- This is a comment

13.6 The IEEE library


The listings shown so far in this lecture have been incomplete, and if you try to use
them, then the compiler will give an error message something like “Cannot recognise
type STD_LOGIC”. A large number of features and extensions to the capabilities of
the VHDL language are bundled into a library called “IEEE”. The definitions used for
STD_LOGIC are held in this library. In order to use the features of this library, a
design must open the library and say which features of the library it wishes to access.

13.6.1 Opening libraries


The IEEE library is opened by this statement:

LIBRARY IEEE;

The IEEE library contains many sub-libraries, which in turn contain many features.
The VHDL name of a sub-library is a package. In order to say which features of
which packages we wish to access, we use a statement that looks like this:

USE IEEE.XXXX.YYYY

Where XXXX is the name of the required package, and YYYY is the name of the
specific feature that is to be used. Rather than listing each specific feature that we

10
want to use (which can be very tedious), often we will simply make all features within
a package visible by using the VHDL keyword ALL:

USE IEEE.XXXX.ALL

This opens up all features in the XXXX package of the IEEE library so that they can
be used by our design.

13.6.2 Using STD_LOGIC


The standard logic definitions are held in a package called std_logic_11642. So here is
a full listing for the NAND, that opens up the library to access the features of
STD_LOGIC type.

LIBRARY ieee;
USE ieee.std_logic_1164.all;

ENTITY nandgate IS
PORT ( a, b: IN STD_LOGIC; c: OUT STD_LOGIC );
END ENTITY nandgate;

ARCHITECTURE simple OF nandgate IS


BEGIN
c <= a NAND b;
END ARCHITECTURE simple;

13.7 Summary
We’ve looked at the basic features of VHDL, and seen some simple examples. The
two key parts of a description are the ENTITY, i.e. a list of inputs and outputs, and an
ARCHITECTURE, i.e. a description of the logical relationship between the inputs and
outputs. We’ve also looked at the STD_LOGIC data type, which represents a wire
carrying values of 1 and 0. The definition of the STD_LOGIC data type is held in the
library IEEE and must be imported at the start of each entity in our code.

You should now know...

The meaning of the following:


 Entity
 Port map
 Architecture
 Library and package
 Standard logic STD_LOGIC
 The STD_LOGIC values ‘0’, ‘1’, ‘X’ and ‘U’

2 1164 is simply the number of the IEEE standards document that defined the Standard Logic type.

11
14 Handling signals that are more than 1 bit wide
Most interesting design have inputs that are more than just a single bit. For example,
lets consider a device that has two 4-bit inputs a and b, and a 4-bit output c.

b c0
0
a
0

4 b1 c1
a 4
a
1

4 c Expanded out, it looks like this: b c2


b a
2
2

b3 c3
a
3

14.1 STD_LOGIC_VECTORs
In VHDL, quantities such as a, b and c are called STD_LOGIC_VECTORs. If you are
familiar with arrays in computer programming, you can think of a
STD_LOGIC_VECTOR as being an array of STD_LOGIC signals. So the input a
would be declared as being

STD_LOGIC_VECTOR(0 TO 3)

Now a contains four members a(0), a(1), a(2) and a(3). Each of these four members is
of type STD_LOGIC.

14.2 An example
Imagine that we wanted to represent a device like this:

b c0
0
a
0

b1 c1
a
1

b c2
2
a
2

b3 c3
a
3

The entity declaration would look like this.

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY orgate IS
PORT ( a, b: IN STD_LOGIC_VECTOR(0 TO 3);
c: OUT STD_LOGIC_VECTOR(0 TO 3));
END ENTITY orgate;

There are several ways that we could write the architecture. One way to describe it
would be like this, explicitly listing what happens for each bits:

12
ARCHITECTURE number1 OF orgate IS
BEGIN
c(0) <= a(0) OR b(0);
c(1) <= a(1) OR b(1);
c(2) <= a(2) OR b(2);
c(3) <= a(3) OR b(3);
END ARCHITECTURE number1;

Alternatively, we could just write this, which would be simpler and would mean
exactly the same thing

ARCHITECTURE number2 OF orgate IS


BEGIN
c <= a OR b;
END ARCHITECTURE number2;

VHDL knows that a, b and c are four bits wide, and will do the appropriate operation
for each of the bit positions.

Or, if we preferred, we could write this


ARCHITECTURE number3 OF orgate IS
BEGIN
c(0 TO 3) <= a(0 TO 3) OR b(0 TO 3);
END ARCHITECTURE number3;
This is effectively a loop, which tells VHDL to make four assignments, one for each
of the four bit positions 0, 1, 2 and 3.

14.3 STD_LOGIC_VECTOR values


The value of an STD_LOGIC is indicated by a string of values enclosed in double
quotes. So if a is a single bit, assignment looks like this:

a <= '1';

If a is 4-bits wide assignment looks like this:

a <= "1110";

By default, VHDL expects the values to be binary, but sometimes it can be useful to
use Hex numbers. This can be done by placing the letter X before the
STD_LOGIC_VECTOR value:

a <= X"E";

14.3.1 Direction of numbering


In the examples given above, the elements were numbered from 0 to 3

a: STD_LOGIC_VECTOR(0 TO 3);

a <= “1110”;
Element 0
Element 1
Element 2
Element 3

13
This feels normal and intuitive (indeed in the programming languages that you may
know, e.g. C or Java, this is the only way that you are allowed to do it). However, in
VHDL you also have the option to have arrays where the index counts downwards:

a: STD_LOGIC_VECTOR(3 DOWNTO 0);

a <= “1110”;
Element 3
Element 2
Element 1
Element 0

In both cases, the number would be interpreted as 14 signed or –2 unsigned: the left-
most bit is always interpreted as the msb and the right most is always interpreted as
the lsb.

In digital logic design, the normal numbering convention is that bit 0 is the least
significant bit (lsb). This is accomplished by having the index run downwards. So
unlike most programming languages, in VHDL it is normal for arrays to be numbered
downwards. You can use upward-numbering if you want, but this often leads to
confusion that creates awkward bugs in your code.

14.3.2 Aggregates
Aggregates are a group values, separated by commas, that will be used for an array.
Here is an example:
ARCHITECTURE example OF aggregate IS
SIGNAL nibble1, nibble2: STD_LOGIC_VECTOR ( 0 TO 3 );
BEGIN
nibble1 <= ( '0','1','0','0');
nibble2 <= ( '0','0','1','0');
END ARCHITECTURE example;

The assignment for nibble1 sets its 0th value to ‘0’, its 1st value to ‘1’, the 2nd to ‘0’
and so on. This way of doing things is called positional assignment: the 0th value
listed goes in the 0th position, the first goes in the first position and so on. We could
instead use named association. So these statements have the same effect:
nibble1 <= ( '0','1','0','0');
nibble1 <= ( 1 => '1', 0 => '0', 3 => '0', 2 => '0');

With named association, we can just specify the values of some of the bit positions,
and use an OTHERS value to provide a value for everything not explicitly mentioned.
So these are all the same:

nibble1 <= ( '0','1','0','0');


nibble1 <= ( 1 => '1', 0 => '0', 3 => '0', 2 => '0');
nibble1 <= ( 1 => '1', OTHERS => '0');

The OTHERS notation can be used as a convenient trick when we want to set all the
values of an array to a particular value:
nibble1 <= ( OTHERS => '1');

14
This would set all of the elements of nibble1 to '1'.

14.3.3 Concatenation
Concatenation merges two vectors to produce a longer vector. For example
ARCHITECTURE example OF aggregate IS
SIGNAL byte: STD_LOGIC_VECTOR ( 0 TO 7 );
SIGNAL nibble1, nibble2: STD_LOGIC_VECTOR ( 0 TO 3 );
BEGIN
nibble1 <= ( '0','1','0','0');
nibble2 <= ( '0','0','1','0');
byte <= nibble1 & nibble2;
END ARCHITECTURE example;

would cause byte to assume the value ( '0','1','0','0','0','0','1','0')

14.3.4 Literals
STD_LOGIC is a data type that has values '0', '1', ‘X’, ‘U’ etc. It is sub-type of
CHARACTER. An array of characters is a string, and is denoted by double quotes.
This is similar to the convention used in the C programming language: '1' is a
character; "1010" is an array of 4 characters. We can use this notation for
STD_LOGIC_VECTORS. So for example,
nibble1 <= ( '0','1','0','0');

could be written as
nibble1 <= "0100";

A value that is directly specified (as opposed to being calculated from other signals),
like “0100” in the code above is called a literal. Standard logic vector literals may be
specified in binary, octal or hexadecimal. By default, a string is interpreted as binary.
To make it explicit that we wish the string to be interpreted as a binary number, we
can place the letter B in front. For an octal string, we place the letter O in front, and
for hexadecimal, we place X in front. So if a is 12-bit std_logic_vector, then these are
all equivalent:
a <= "010011001010";
a <= B"010011001010";
a <= O"2312";
a <= X"4CA”

Long strings of ‘1’s and ‘0’s can be confusing, so in order to improve legibility, we
can introduce underscores:

a <= B"0100_1100_1010";

The underscores are ignored by VHDL; their only function is to space the digits out to
make it easier for a human to read. Note that if you do use underscores in your values,
you must put the B in front to make it clear that this should be interpreted as a binary
value. This (without the B) would be an error:
a <= "0100_1100_1010"; -- Wrong!

15
14.4 Summary
We’ve looked at the STD_LOGIC_VECTOR datatype, which represents multi-bit signals.
It is effectively an array of STD_LOGIC values. We have also seen the two main
notations for assigning values to STD_LOGIC_VECTORs and how to indicate the number
base for a STD_LOGIC_VECTOR value.

You should now know...

The meaning of the following:


 Standard logic vector (STD_LOGIC_VECTOR)
 Aggregates
 Named association
 Positional association

How to represent standard logic vector values

16
15 Number Representation and Arithmetic
Most forms of data that are handled by digital systems (e.g. samples of audio data,
pixel values for image and video data, ASCII data for representing text) are some
form of number. In this section we will look at the background to two of the most
important VHDL numerical data types (SIGNED and UNSIGNED). Before we do that, we
will briefly recap binary data representation formats for numbers.

15.1 Denary
In everyday life, we use the denary (base 10) number system whose digits can take the
values 0,1,2,3,4,5,6,7,8,9. An n-digit denary number with digits di is interpreted as
having the value

 d 10
i  0 , n 1
i
i

So, for example, the number 365 has three digits: d2=3, d1=6 and d0=5. Its value is

3  100 + 6  10 + 5  1, which is3

3  102 + 6  101 + 5  100

15.2 Unsigned binary


For digital systems, we deal with binary numbers where digits can have value 0,1.
These values are particularly convenient for the construction of simple, cheap and fast
electronic circuits. A digit that can take only the values 0 or 1 is called a binary digit
or bit. An n-bit binary number has the value

d 2
i  0 , n 1
i
i

So, for example, the denary number 5 equates to the 3-bit binary number 101, which
has digits d2=1, d1=0 and d0=1. Its value is

1  4 + 0  2 + 1  1, which is

1  22 + 0  21 + 5  20

The bit with the highest weighting is called the most significant bit (msb) and the bit
with the lowest weighting is the least significant bit (lsb). The msb is always the
leftmost bit and the lsb is the rightmost. For this 3-bit example, bit number 2 is the
msb and bit number 0 is the lsb.

The largest number that we can represent depends on the number of bits that we use.
For example, if we use 4 bits to represent a number, then there are 16 different values
that can be represented:

3 Remember that anything raised to the power of zero is 1, i.e. x 0  1 for all x

17
Number Unsigned binary representation
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
10 1010
11 1011
12 1100
13 1101
14 1110
15 1111

This form of representation is called unsigned binary. This is the representation


format used by the one of the main VHDL data types, UNSIGNED. It is quite
straightforward, but it cannot deal with negative numbers. For many purposes (e.g.
address generation inside a computer, pixel data for still image and video applications,
etc.) we would never expect to encounter a negative number, and unsigned binary is
perfectly satisfactory. However, for many other purposes we do need to be able to
deal with negative numbers and we therefore need to use a more sophisticated
approach to number representation.

15.3 Negative numbers: 2s complement


All cars have a device called an odometer that displays how many km (or miles) they
have travelled. On older cars the display was 5 digit, and therefore could represent all
numbers from 00,000 to 99,999. If the odometer display stood at 99,999 at the start of
your journey, then after 1 km it would roll over to say 00,000.

Similarly, if we have a 4-bit binary up-counter and it reads 1111, then the next state in
its count sequence will be 0000. This provides us with an alternative method for the
representation of negative numbers. –1 is the number that is 1 less than zero. In other
words, it is a number which when added to 1 gives zero. But we have just seen that
1111 when added to 1 gives 0000. Similarly, -2 is the number that gives zero when we
add 2 to it. This is 1110. The number system that this generates is shown below

Number 2s complement representation


-8 1000
-7 1001
-6 1010
-5 1011
-4 1100
-3 1101
-2 1110
-1 1111
0 0000
1 0001
2 0010
3 0011
4 0100

18
5 0101
6 0110
7 0111

Thus we interpret the value of an n-bit 2s complement number as

 d n 1 2 n 1  d 2
i 0 ,n  2
i
i

This is exactly the same as an unsigned binary number, except that the msb is
negatively weighted. So, for example, the interpretation of the number 1010 is

Unsigned binary 2s complement


1010 = 1010
= 1  23 + 0  22 + 1  21 + 0  20 = 1  -23 + 0  22 + 1  21 + 0  20
=18+04+12+01 = 1  -8 + 0  4 + 1  2 + 0  1
=8+2 = -8 + 2
= 10 = -6

Note that all negative numbers have an msb of 1 and all positive numbers have an
msb of 0. The msb of a 2s complement is therefore often referred to as the sign bit.

15.4 Addition of 2s complement numbers


Suppose we have a circuit that adds numbers according to the normal laws of
unsigned binary arithmetic. So for example, we could use the circuit to add 12 and 2
to get the answer 14

1100 (denary 12)


+ 0010 (denary 2)
= 1110 (denary 14)

What modification would we need to make to the circuit to make it add 2s


complement numbers? If we consider the example 1100 + 0010, then this is the
interpretation:

1100 (denary -4)


+ 0010 (denary 2)
= 1110 (denary -2)

But this is correct without any modification. An adder for unsigned binary works
without modification for 2s complement. This is why 2s complement is the normal
representation format for integer and fixed point numbers in digital systems4.

The VHDL data type SIGNED uses 2s complement representation.

4In fact there is one small difference between an unsigned binary adder and a 2s complement adder,
and this is related to the treatment of overflow conditions.

19
15.5 Arithmetic on STD_LOGIC_VECTORs
Now let’s look at a simple example to illustrate arithmetic on STD_LOGIC_VECTORs, a
comparator:
4
a
4 g
b

It has two inputs, a and b, both of which represent four-bit binary numbers. There is a
single one-bit output g, which represents the “greater than” condition. When a>b then
g=’1’; otherwise g=’0’.

This can’t be interpreted unless we know whether a and b are signed (2’s
complement) or unsigned numbers. Suppose a=1111 and b=0001. If the numbers are
unsigned then a is fifteen and b is one. So a>b and g=1. But if the numbers are signed
then a is minus one and b is plus one; a<b and g=’0’.

The way that VHDL handles this is by having two different versions of the arithmetic
operators +,-,>,< etc. one for unsigned numbers and one for signed. The signed
package is called STD_LOGIC_SIGNED. The unsigned is STD_LOGIC_UNSIGNED. We
have to import one or the other library to tell VHDL how we want the standard logic
vectors to be interpreted. So if we want the signed version it looks like this
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_signed.ALL;

ENTITY comp IS
PORT ( a, b: IN STD_LOGIC_VECTOR(3 DOWNTO 0);
g: OUT STD_LOGIC);
END ENTITY comp;

ARCHITECTURE simple OF comp IS


BEGIN
g <= '1' WHEN a>b ELSE '0';
END ARCHITECTURE simple;

If we wanted to use unsigned arithmetic, then line 3 would be changed to

USE ieee.std_logic_unsigned.ALL;

15.6 SIGNED and UNSIGNED types


The method of the previous section works well if you want all of the
STD_LOGIC_VECTORs to be interpreted as using the same number representation
format. However, if we want to mix 2s complement and unsigned numbers in your
code, then we need a different mechanism.

A more powerful package is STD_LOGIC_ARITH, which introduces two new data types,
SIGNED and UNSIGNED. These are declared and used in the same way that
STD_LOGIC_VECTORs would be. So for the following example

20
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_arith.ALL;

ENTITY comp2 IS
PORT ( a: IN SIGNED(3 DOWNTO 0);
b: IN UNSIGNED(3 DOWNTO 0);
g: OUT STD_LOGIC);
END ENTITY comp2;

ARCHITECTURE simple OF comp2 IS


BEGIN
g <= '1' WHEN a>b ELSE '0';
END ARCHITECTURE simple;

a would be interpreted as a 4-bit 2s complement numbers (lying in the range -8 to +7)


and b would be interpreted as 4-bit unsigned binary (lying in the range 0 to 15).

You should now know...

The meaning and purpose of the following:


 The packages
o STD_LOGIC_SIGNED,
o STD_LOGIC_UNSIGNED and
o STD_LOGIC_ARITH
 The VHDL types SIGNED and UNSIGNED

21
16 Dataflow and Structural VHDL
There are two fundamentally different ways that we can describe a design:
 Behavioural descriptions tell us what the design should do but not how we would
make it
 Structural descriptions tell us how we would make it but not what it would do
In this unit, we will look how a behavioural design (a 4-bit adder) might be
transformed by a synthesis tool into a structural netlist of logic gates.

As we do this, we will learn more about how to write behavioural and structural
VHDL. There are several different approaches to writing behavioural VHDL. The
easiest to understand is dataflow, a type of description where we build up the required
behaviour as a set of arithmetic and logical operations on data items.

16.1 Behavioural description versus structural description


Behavioural descriptions tell us what the design should do but not how we would
make it. So this is a behavioural description:

sum <= x+y;

By contrast, this is a structural description.

carry in

x
0 + sum
y 0
0
x
1 + sum
y 1
1
x
2 + sum
y 2
2
x
3 +
y sum
3 3

carry out

A structural description tells us how we would connect together several simpler units
to make a more complicated unit. In this case our simple units are full adders, and the
complicated unit is the 4-bit adder.

If we are going to build or circuits out of basic logic gates, then the above description
isn't quite finished. Although we have broken down our complicated (4-bit) unit into
simpler (1-bit) units, we still haven't shown how to make the full adders out of gates.

By contrast, in the description below everything is resolved into the most basic
building blocks we have (in this case logic gates).

22
This design is a special case. It is a netlist, a description that consists solely of the
interconnection of basic building blocks that are available to implement the design. A
netlist contains sufficient detail that it is immediately obvious how to build the device.

16.2 Example of transforming a high level description to a netlist


Imagine that we want to create a 4-bit adder:
4
x 4
4 sum
y

A human would normally describe this behaviourally:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_signed.ALL;

ENTITY adder IS
PORT ( x, y: IN STD_LOGIC_VECTOR(3 DOWNTO 0);
sum: OUT STD_LOGIC_VECTOR(3 DOWNTO 0) );
END ENTITY adder;

ARCHITECTURE behavioural OF adder IS


BEGIN
sum <= x + y;
END ARCHITECTURE behavioural;

The above code has all the advantages of a behavioural description. The code is
concise; you can easily see at a glance what function it performs; it contains no
detailed decisions about logic gates. This code would then be given to a synthesis
tool, a computer program whose purpose is to design a circuit that fulfils the required
behaviour.

23
16.2.1 Implementing the adder function
Here is a circuit that the synthesis tool might create in order to fulfil our 4-bit adder
requirement:
carry in

x
0 + sum
y 0
0
x
1 + sum
y 1
1
x
2 + sum
y 2
2
x
3 +
y sum
3 3

carry out

The four-bit adder is built up from four 1-bit full adders, which have the following
behaviour:

carry in x y Carry in Sum Carry out


0 0 0 0 0
x 0 0 1 1 0
+ sum 0 1 0 1 0
y 0 1 1 0 1
1 0 0 1 0
carry out 1 0 1 0 1
1 1 0 0 1
1 1 1 1 1

There are many ways to implement this. One possible way is shown below.

x
sum
y

carry in

carry out

In the remainder of this lecture, we will look in detail at the full adder circuit, and use
it to illustrate the features of dataflow VHDL. In the next lecture we will look at how
to connect together the full adders and create a structural 4-bit adder. We will also
look at how to feed the 4-bit adder circuit into a simulator.

16.3 A dataflow description of the full adder


Suppose we want to write a behavioural description of the full adder. In order to do
this, we must explain how we want the outputs of the design to relate to the inputs.
One way is simply to use the truth table to describe the device, like this:

24
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY fulladd IS
PORT ( x, y, cin: IN STD_LOGIC;
sum, cout: OUT STD_LOGIC);
END ENTITY fulladd;

ARCHITECTURE tedious_but_easy OF fulladd IS


BEGIN
sum <= '0' WHEN x='0' AND y='0' AND cin='0'
ELSE '1' WHEN x='0' AND y='0' AND cin='1'
ELSE '1' WHEN x='0' AND y='1' AND cin='0'
ELSE '0' WHEN x='0' AND y='1' AND cin='1'
ELSE '1' WHEN x='1' AND y='0' AND cin='0'
ELSE '0' WHEN x='1' AND y='0' AND cin='1'
ELSE '0' WHEN x='1' AND y='1' AND cin='0'
ELSE '1' WHEN x='1' AND y='1' AND cin='1';
cout <= '0' WHEN x='0' AND y='0' AND cin='0'
ELSE '0' WHEN x='0' AND y='0' AND cin='1'
ELSE '0' WHEN x='0' AND y='1' AND cin='0'
ELSE '1' WHEN x='0' AND y='1' AND cin='1'
ELSE '0' WHEN x='1' AND y='0' AND cin='0'
ELSE '1' WHEN x='1' AND y='0' AND cin='1'
ELSE '1' WHEN x='1' AND y='1' AND cin='0'
ELSE '1' WHEN x='1' AND y='1' AND cin='1';
END tedious_but_easy;

This is easy and obvious, but also tedious. There are many neater ways to describe the
behaviour. We could take inspiration from the gate level design of the full adder, and
write this

ARCHITECTURE simple OF fulladd IS


BEGIN
sum <= cin XOR x XOR y;
cout <= ( x AND y ) OR ( cin AND x ) OR ( y AND cin );
END ARCHITECTURE simple;

This is much neater and nicer, but requires us to think a bit harder about how the
outputs relate to the inputs.

It’s important to realise that as far as a synthesis tool is concerned, both descriptions
are the same thing. They simply say how the outputs relate to the inputs. The second
architecture is not ordering the synthesis tool to use two XOR gates, 3 AND gates and
an OR gate. It’s simply a shorthand for saying how the output relates to the inputs.
The synthesis tool is free to do whatever it wants to find a circuit that has the same
input-output relation.

25
16.3.1 Local signals
Now let’s look at a slight modification of our description.

n1
x
sum
y
n2
cin

cout
n3

n4

We have given names to the internal nodes of the circuit (n1, n2, n3, n4). Once we
have given them names, we are free to use them in our description. So here is a
slightly different description

ARCHITECTURE number3 OF fulladd IS


SIGNAL n1, n2, n3, n4: STD_LOGIC;
BEGIN
n1 <= x XOR y;
sum <= cin XOR n1;
n2 <= x AND y;
n3 <= cin AND x;
n4 <= y AND cin;
cout <= n2 OR n3 OR n4;
END ARCHITECTURE number3;

This is basically the same as the simple architecture of fulladd, but this time we have
used the local signals n1, n2, n3 and n4 as part of the description. In order to use the
names, we have to declare that they exist, that they are signals, and that they carry
logic values (e.g. ‘1’, ‘0’, ‘X’ and ‘U’) which means that they are of type
STD_LOGIC. The declaration of local signals takes place between the
ARCHITECTURE statement and the first BEGIN.

16.4 Connecting entities together: structural VHDL


Now let’s look at how to use simple designs as building blocks to make more
complex designs. We’ll do this building a structural description of a 4-bit adder. A
structural description says how we connect together simple components to make a
more complicated component. We have already designed a full adder in an entity
fulladd and an architecture called dataflow. When we compiled this code, it was
placed into a library ready to be used by other designs. By default, the current
working library is called work. So our full adder is stored with the following name:

work.fulladd(dataflow)

The name is constructed from the library name followed by a point, then the entity
name, then the architecture name.

26
16.4.1 Placing library components into a design
We can now build up a 4-bit adder structurally as follows:
cin

x
0 + sum
y 0
0 carry
x 1
1 + sum
y 1
1 carry
2
x
2 + sum
y 2
2 carry
3
x
3 +
y sum
3 3

cout

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY adder IS
PORT ( x, y: IN STD_LOGIC_VECTOR(3 DOWNTO 0);
cin: IN STD_LOGIC;
sum: OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
cout: OUT STD_LOGIC);
END ENTITY adder;
ARCHITECTURE structural OF adder IS
SIGNAL carry: STD_LOGIC_VECTOR(4 DOWNTO 0);
BEGIN
g0: ENTITY work.fulladd(dataflow)
PORT MAP (x(0),y(0),cin,sum(0),carry(1));
g1: ENTITY work.fulladd(dataflow)
PORT MAP (x(1),y(1),carry(1),sum(1),carry(2));
g2: ENTITY work.fulladd(dataflow)
PORT MAP (x(2),y(2),carry(2),sum(2),carry(3));
g3: ENTITY work.fulladd(dataflow)
PORT MAP (x(3),y(3),carry(3),sum(3),cout);
END ARCHITECTURE structural;

Each of the components that we have used is defined by a statement providing


 a name for the component5 (I’ve chosen g0 … g3, but I could have chosen any
name I like.)
 the keyword ENTITY
 the full name of the gate that I want to use
 the keyword PORT MAP
 a list of the wires that I am connecting to the inputs and outputs of the gate

In the jargon of VHDL, each of these statements is called an instantiation. We have


created four instances of the fulladd component and connected them together
appropriately.

The names appearing in the port maps are the names of the wires. Wherever the same
name occurs in the output list of one component and in the input list of another, that

5 Strictly speaking, g1 is a statement label, but you can think of it as just providing a name for the gate.

27
means that there is a wire connecting these two components. So, for example,
carry(2) is a wire connecting the output of c1 to the input of c2.

16.4.2 Positional association


How does VHDL know which of the wires I am connecting to c1 are inputs and
which are outputs? If we compare the instantiation
c0: entity work.fulladd(dataflow)
PORT MAP (x(0),y(0),cin,sum(0),carry(1));

with the definition of the full adder

ENTITY fulladd IS
PORT ( x, y, cin: IN STD_LOGIC; sum, cout: OUT STD_LOGIC);
END ENTITY fulladd;

We see that the first three signals in the port map are inputs and the last two are
outputs. So the first three signals in the instantiation x(0), y(0) and cin will be attached
to the inputs x, y and cin. Similarly, sum(0) will be connected to sum and carry(1) will
be connected to cout. This is called positional association.

16.4.3 Named association


If you prefer, you can explicitly tell VHDL how you want to connect up the wires in
your design to the inputs and outputs of the gate, like this

c0: entity work.fulladd(dataflow)


PORT MAP (x=>x(0), y=>y(0), cin=>cin, sum=>sum(0), cout=>carry(1));

This is called named association. With named association, the order doesn’t matter,
so you could jumble up the order of the signals and write the instantiation like this

g0: entity work.fulladd(dataflow)


PORT MAP (cout=>carry(1), x=>x(0), y=>y(0), cin=>cin,
sum=>sum(0));

16.5 Summary
A behavioural description says what a design should do. Dataflow is a type of
behavioural description that relates the outputs to inputs using logical or arithmetic
assignments.
A structural description says how we construct a design from the composition of
simpler units. A structural description can be
 Hierarchic: made up from simpler units, which themselves then need to be
designed
 Netlist: made up from fundamental building blocks (e.g. logic gates)

You should now know...


The meaning of the following:
 Dataflow VHDL
 Local signals
 The WORK library
 Instantiation
 Positional association and named association

28
17 VHDL Simulation
A simulator is a software tool that takes a proposed design (which could be
behavioural or structural or a mixture of both) and predicts what outputs would result
from a given set of input transitions. Simulation one of the main methods of verifying
that a proposed design has the required behaviour.

17.1 How are statements processed?


Before we look at how a simulator works, let’s think about the thought process that a
human would go through to figure out how a circuit would respond to transitions in its
inputs.

Let’s look again at the full adder circuit, and for the sake of clarity, we will now give
names (g1…g6) to the gates.

g1 n1
x
g2 sum
y
n2
g3
cin

g4 g6 cout
n3

g5
n4

Imagine that the signals x, y and cin are initially at zero. Looking through the circuit,
we can see that n1, n2, n3, n4, sum and cout will all be at zero.

Now imagine that x changes its value from 0 to 1. Let’s think through what happens
next:
 x is the input to three gates: g1, g3 and g4. These gates are potentially affected by
the change, so we need to re-compute their outputs n1, n2, n3.
 We also know that gates g2, g5 and g6, which don’t have x as an input, can’t be
affected by this change, so there is no point to re-computing their outputs.
 The new value of n1 is 1 (i.e. it changed)
 The new value of n2 is 0 (i.e. it is unchanged)
 The new value of n3 is 0 (i.e. it is unchanged)
 n1 just changed, which means that any gate that has n1 as an input (i.e. g2) needs
to have its output (sum) re-computed.
 n2 and n3 didn’t change, so we don’t need to bother to examine any consequences
in gate g6, which has n2 and n3 as inputs.
 The new value of sum is 1.
 There are no more gates whose inputs have changed, so we can stop analysing the
circuit now.

17.2 Simulation of dataflow VHDL


The way that VHDL processes statements during simulation tries to capture the above
thought process.

29
ARCHITECTURE number3 OF fulladd IS
SIGNAL n1, n2, n3, n4: STD_LOGIC;
BEGIN
1 n1 <= x XOR y;
2 sum <= cin XOR n1;
3 n2 <= x AND y;
4 n3 <= cin AND x;
5 n4 <= y AND cin;
6 cout <= n2 OR n3 OR n4;
END ARCHITECTURE number3;

All statements 1-6 are scanned simultaneously, waiting for a signal on the right hand
side (RHS) to change. In the jargon of VHDL, a change to a signal is called an event.
A VHDL simulation proceeds by manipulating an event queue. If we assume that all
signals are initially at 0, then the event queue initially looks like this:

Time = 0
Signal Name: x y cin n1 n2 n3 n4 sum cout
Present value: 0 0 0 0 0 0 0 0 0
Next value: 1
Event time: 10

It has a list of the present value for each signal, any new value that has been scheduled
to take place in future, and the time at which the signal must assume this new value.
In this case then next event is that x will transition from ‘0’ to ‘1’ at time 10 ns.

Once the event queue is set up, the simulator proceeds by looking down the event
queue to find the time of the next pending event. It then jumps forward to the time of
the next event (10 ns), giving x its new value. An event has just occurred on signal x.
This triggers execution of the all of the statements that have x on the RHS:

1 n1 <= x XOR y; Gives new value of 1


3 n2 <= x AND y; Gives new value of 0
4 n3 <= cin AND x; Gives new value of 0

If the new value is different from the old value, it is placed on the event queue. The
queue now looks like this.

Time = 10
Signal Name: x y Cin n1 n2 n3 n4 sum cout
Present value: 1 0 0 0 0 0 0 0 0
Next value: 1
Event time: 10+

 is in an infinitesimal time interval. In VHDL, a signal assignment can never happen


instantaneously. (If it could, this would be equivalent to gate g1 have a zero delay,
which is impossible in real hardware and would give rise to situations where the
simulation would not faithfully reproduce the behaviour of real hardware.)

The simulator now looks down the event queue to find the next scheduled event.
There is only one item on the queue, the 0 to 1 transition on n1 at time 10+. The time
pointer is incremented to 10+and n1 takes its new value. Because an event has
occurred on n1, any statement with n1 on the RHS is triggered:

30
2 sum <= cin XOR n1; Gives new value of 1

If the new value is different from the old value, it is placed on the event queue. The
queue now looks like this.

Time = 10+
Signal Name: x y Cin n1 n2 n3 n4 sum cout
Present value: 1 0 0 1 0 0 0 0 0
Next value: 1
Event time: 10+
The simulator now looks down the event queue to find the time of the next scheduled
event, i.e. 10+2. The time pointer is incremented to 10+2and sum takes its new
value.

Time = 10+2
Signal Name: x y Cin n1 n2 n3 n4 sum cout
Present value: 1 0 0 1 0 0 0 1 0
Next value:
Event time:

There are no statements with sum on the RHS, so no further statements are triggered.
The simulator now looks down the queue to find the next scheduled event. There are
none, so simulation terminates.

17.3 Concurrent processing


Now we come to a very important point. Consider these two descriptions of the full
adder:

ARCHITECTURE number3 OF fulladd IS


SIGNAL n1, n2, n3, n4: STD_LOGIC;
BEGIN
n1 <= x XOR y;
sum <= cin XOR n1;
n2 <= x AND y;
n3 <= cin AND x;
n4 <= y AND cin;
cout <= n2 OR n3 OR n4;
END ARCHITECTURE number3;

ARCHITECTURE number4 OF fulladd IS


SIGNAL n1, n2, n3, n4: STD_LOGIC;
BEGIN
sum <= cin XOR n1;
cout <= n2 OR n3 OR n4;
n1 <= x XOR y;
n2 <= x AND y;
n3 <= cin AND x;
n4 <= y AND cin;
END ARCHITECTURE number4;

Although they are written in a different order, they do exactly the same thing. Unlike
programming languages such as C, which process lines in the order that they are
written, VHDL normally monitors all statements at the same time, and executes a

31
statement when one of its RHS values changes. This is called concurrent execution.
The style of VHDL that uses concurrent assignments through arithmetic or Boolean
operators is called dataflow VHDL.

17.4 Components with delays


Real components have delays. In the simulation of the full adder, we didn’t know
what the delay was, so the simulator used its default value of .  is the smallest
interval of time that the simulator can deal with. You can think of as meaning “a
moment” or “an instant”.

17.4.1 The AFTER keyword


Suppose we did some measurements on the gates that we have available to build our
system, and we find that the NAND gate has a delay of 5 ns. We could modify our
description of the gate to this:

ARCHITECTURE with_timing_info OF nandgate IS


BEGIN
c <= a NAND b AFTER 10 NS;
END ARCHITECTURE with_timing_info;

Now, when a or b change, the value of c will be re-computed, but c will not get its
new value until 10 ns after the change in the input. VHDL knows about the following
units of time:

Unit Name Meaning


PS picosecond 10-12 seconds
NS nanosecond 10-9 seconds
US microsecond 10-6 seconds
MS millisecond 10-3 seconds
S second

17.4.2 The full adder example with component delays


So let’s re-write the description with some real component delays, and see how
simulation proceeds:

ARCHITECTURE delays OF fulladd IS


SIGNAL n1, n2, n3, n4: STD_LOGIC;
BEGIN
1 n1 <= x XOR y AFTER 10 NS;
2 sum <= cin XOR n1 AFTER 10 NS;
3 n2 <= x AND y AFTER 7 NS;
4 n3 <= cin AND x AFTER 7 NS;
5 n4 <= y AND cin AFTER 7 NS;
6 cout <= n2 OR n3 OR n4 AFTER 8 NS;
END ARCHITECTURE delays;

Imagine that the signals x, y and cin are initially at zero, so n1, n2, n3, n4, sum and
cout are also initially at zero. At time 10 ns x will go to one. The event queue initially
looks like this:

32
Time = 0
Signal Name: x y cin n1 n2 N3 n4 sum cout
Present value: 0 0 0 0 0 0 0 0 0
Next value: 1
Event time: 10

Once the event queue is set up, the simulator looks down the event queue to find the
time of the next scheduled event. It then jumps forward to the time of the next event
(10 ns), giving x its new value. An event has just occurred on signal x. This triggers
execution of the all of the statements that have x on the RHS:

1 n1 <= x XOR y AFTER 10 NS; Gives new value of 1


3 n2 <= x AND y AFTER 7 NS; Gives new value of 0
4 n3 <= cin AND x AFTER 7 NS; Gives new value of 0

If the new value is different from the old value, it is placed on the event queue. The
queue now looks like this.

Time = 10
Signal Name: X y Cin n1 n2 n3 n4 sum cout
Present value: 1 0 0 0 0 0 0 0 0
Next value: 1
Event time: 20

The simulator now looks down the event queue to find the next scheduled event.
There is only one item on the queue, the 0 to 1 transition on n1 at time 20. The time is
incremented to 20and n1 takes its new value. Because an event has occurred on n1,
any statement with n1 on the RHS is triggered:

2 sum <= cin XOR n1 AFTER 10 NS; Gives new value of 1

If the new value is different from the old value, it is placed on the event queue. The
queue now looks like this.

Time = 20
Signal Name: x y Cin n1 n2 n3 n4 sum cout
Present value: 1 0 0 1 0 0 0 0 0
Next value: 1
Event time: 30

The simulator now looks down the event queue to find the time of the next scheduled
event, i.e. 30. The time pointer is incremented to 30and sum takes its new value.

Time = 30
Signal Name: x y Cin n1 n2 n3 n4 sum cout
Present value: 1 0 0 1 0 0 0 1 0
Next value:
Event time:

There are no statements with sum on the RHS, so no further statements are triggered.
The queue is now empty, so simulation terminates.

33
17.5 Simulation of structural VHDL
For the sake of clarity, let’s look again at the structural description, and highlight
which of the signals are inputs:

cin

x
0 + sum
y 0
0 carry
x 1
1 + sum
y 1
1 carry
2
x
2 + sum
y 2
2 carry
3
x
3 +
y sum
3 3

cout

ARCHITECTURE structural OF adder IS


SIGNAL carry: STD_LOGIC_VECTOR(4 DOWNTO 0);
BEGIN
g0: entity work.fulladd(dataflow)
PORT MAP (x(0),y(0),cin, sum(0),carry(1));
g1: entity work.fulladd(dataflow)
PORT MAP (x(1),y(1),carry(1),sum(1),carry(2));
g2: entity work.fulladd(dataflow)
PORT MAP (x(2),y(2),carry(2),sum(2),carry(3));
g3: entity work.fulladd(dataflow)
PORT MAP (x(3),y(3),carry(3),sum(3),cout);
END ARCHITECTURE structural;

The way that this is handled by a VHDL simulator is as follows:


 All statements g0-g3 are scanned simultaneously, waiting for an event on an input
signal.
 If one of the inputs (shown in bold) to a full adder changes, then the output for
that full adder is recomputed.

17.6 Summary
Simulation advances through time updating signal values according to assignments.
Dataflow VHDL consists of a series of Boolean/arithmetic assignment statements.
These statements are concurrent: all are active at the same time; a statement is
triggered to re-evaluate its left hand side value when any a right-hand side value
changes. Structural VHDL consists of instantiations of library elements, which
operate concurrently. When an input to an instance changes, the new outputs are
evaluated.

You should now know...


The meaning of the following:
 Event
 Event queue
 Concurrent execution
 The AFTER keyword

34
Index

12 Why do we need Hardware Description Languages (HDLs)? 1


12.1 What’s the problem with traditional methods? 1
12.2 VHDL 3
12.2.1 Levels of Abstraction 3
12.3 Synthesis 4
12.4 Summary 4

13 Introduction to VHDL 6
13.1 Entity and Architecture 6
13.2 Specifying another architecture 7
13.3 BEGIN and END statements 7
13.4 Semicolons 8
13.5 Stylistic issues 9
13.5.1 Case 9
13.5.2 Spaces and indents 9
13.5.3 Returns 9
13.5.4 Annotating END statements 10
13.5.5 Comments 10
13.6 The IEEE library 10
13.6.1 Opening libraries 10
13.6.2 Using STD_LOGIC 11
2.7 Summary 11

14 Handling signals that are more than 1 bit wide 12


14.1 STD_LOGIC_VECTORs 12
14.2 An example 12
14.3 std_logic_vector values 13
14.3.1 Direction of numbering 13
14.3.2 Aggregates 14
14.3.3 Concatenation 15
14.3.4 Literals 15
14.4 Summary 16

15 Number Representation and Arithmetic 17


15.1 Denary 17
15.2 Unsigned binary 17
15.3 Negative numbers: 2s complement 18
15.4 Addition of 2s complement numbers 19
15.5 Arithmetic on STD_LOGIC_VECTORs 20
15.6 SIGNED and UNSIGNED types 20

16 Dataflow and Structural VHDL 22


16.1 Behavioural description versus structural description 22
16.2 Example of transforming a high level description to a netlist 23
16.2.1 Implementing the adder function 24
16.3 A dataflow description of the full adder 24
16.3.1 Local signals 26
16.4 Connecting entities together: structural VHDL 26

35
16.4.1 Placing library components into a design 27
16.4.2 Positional association 28
16.4.3 Named association 28
116.5 Summary 28

17 VHDL Simulation 29
17.1 How are statements processed? 29
17.2 Simulation of dataflow VHDL 29
17.3 Concurrent processing 31
17.4 Components with delays 32
17.4.1 The AFTER keyword 32
17.4.2 The full adder example with component delays 32
17.5 Simulation of structural VHDL 34
17.6 Summary 34

36

You might also like