You are on page 1of 14

Introduction to VHDL

VHDL stands for Very High Speed Integrated Circuit [VHSIC] Hardware Description Language. It was devleoped in 1985 by the Department of Defense in order to improve documentation and to reduce maintenance costs associated with hardware designs.

Entities
An entity is a component of a design whose behavior is to be designed and simulated. One
may think of an entity as consisting of three things:
1. name. e.g. half adder, chip board, transistor. Note that identifiers in VHDL
are case insensitive
2. input and output. represents the interface of the entity with its environment, and
is described using a port list
3. behavior. a description of how the entity converts input to output

Example 1. The following is an entity declaration. Similar to how object-oriented class


definitions separate the data and function declarations from implementation, Note how the
declaration does not describe behavior. Behavior is desribed using what is called an architecture.
entity half_adder is
port(x,y:in bit;
sum, carry: out bit);
end entity half_adder;

signal types.
bit. takes on the value 0 or 1
bit vector. takes on the value of a binary vector
std logic. takes on one of nine different values, including 0,1, x, and z
std logic vector. takes on a vector of standard logic values

Example 2. When specifying a vector signal, one uses the downto keyword to specify the
number of bits.
entity adder_32bit is
port(c_in : in std_logic;
a : in std_logic_vector (31 downto 0);
b : in std_logic_vector (31 downto 0);
sum : out std_logic_vector (31 downto 0);
c_out : out std_logic;
end entity adder_32bit;

Architectures
An architecture declaration serves the purpose of describing the behavior for some entity. It
consists of the following.
1. name.
2. an indication of what entity it should be applied to
3. declarations of constants, signals, and other entities which are represented as components
4. one or more statements and processes which describe the behavior of the corresponding
entity

Example 3. The following represents an architecture for the half adder.


architecture behavior of half_adder is
begin
carry <= (x and y) after 5 ns;
sum <= (x xor y) after 5 ns;
end architecture behavior;

Some notes on Example 3.


1. As in verilog, the <= operator denotes a concurrent signal assignment (CSA). Moreover, evaluating a block of CSAs is done similarly as in verilog. Namely, the signals
and variables on the right side of the CSAs are first sampled at some time t, followed
by an update of the signals and variables on the left side using the sampled values.
Thus, the updates are performed concurrently.
2. the xor and and bit operators are written explicitly. The same holds for the other
logical operators: or, nand, nor, xnor.
3. the after keyword is used to delay a CSA. In this case, the delays are 5 ns. In general,
the delay can be any arithmetic expression.
4. examples of declarations that might appear in an architecture declaration section:
signal s1 : std logic;
constant delay value : Time:= 5 ns;

Example 4. Define a full adder entity and provide an architecture for it.

Conditional CSAs
With the help of the when and else keywords, a CSA can be executed on condition that a
predicate evaluates to true.

Example 5. The following is an example of using conditinal CSAs to design a 16-bit


4-select mux.
library IEEE;
use IEEE.std_logic_1164.all;
entity mux4_16bit is
port (in0, in1, in2, in3 : in std_logic_vector (15 downto 0);
s0, s1 : in std_logic;
selection : out std_logic_vector (15 downto 0));
end entity mux4_16bit;

architecture behavior of mux4_16bit is


begin
selection <= in0 after 5 ns when s0 =
in1 after 5 ns when s0 =
in2 after 5 ns when s0 =
in3 after 5 ns when s0 =
"0000000000000000" after

0 and
1 and
0 and
1 and
5 ns;

s1
s1
s1
s1

=
=
=
=

0
0
1
1

else
else
else
else

end architecture behavior;


Note that in Example 5, if there were any combinations of s0 and s1 for which we did not
want the signal selection to change, then we could have used the keyword unaffected.
For example,
selection <= unaffected when s0 = 0 and s1 = 1 else
The unaffected keyword allows for the target of a CSA to remain unchanged.

Similar to the switch statement in C, and the case statement in verilog, VHDL has a simlar
mechanism for selecting a signal assignment.
Example 6. The following is an example of using signal selection to design a 16-bit 2-select
mux.
library IEEE;
use IEEE.std_logic_1164.all;
entity mux2_16bit is
port (in0, in1 : in std_logic_vector (15 downto 0);
s : in std_logic;
selection : out std_logic_vector (15 downto 0));
end entity mux2_16bit;

architecture behavior of mux2_16bit is


begin
with s select
selection <= in0 after 5 ns when 0 else
in1 after 5 ns when 1 else
"0000000000000000" after 5 ns when others;
end architecture behavior;
Note: when delay values are not specified for a CSA, the simulator will assign an infinitesimally small value for the delay for the purpose of ordering the events.

Processes
A process is an architectural construct that allows for the use of conventional programminglanguage concepts, such as variables, loops, and other control-flow statments. There exist
two different ways to define a process.
1. with a sensitivity list. As with verilog cyclic behaviors, the process is executed only
when an event occurs on one or more signals in the sensitivity list.
2. without a sensitivity list. In this case a process is inherently cyclic, and therefore
continue repeating indefinitely.
Example 7. The following architecture has a process called carry proc. Note the use of a
case statement, analogous to the verilog case statement.
library IEEE;
use IEEE.std_logic_1164.all;
entity half_adder is
port(x,y:in bit;
sum, carry: out bit);
end entity half_adder;

architecture behavior of half_adder is


begin
sum_proc: process(x,y) is
begin
if(x=y) then sum <= 0 after 5 ns;
else sum <= (x or y) after 5 ns;
end if;
end process sum_proc;
carry_proc: process(x,y) is
begin
case x is
when 0 => carry <= x after 5 ns;
when 1 => carry <= y after 5 ns;
when others => carry <= X after 5 ns;
end case
end process carry_proc;
end architecture behavior;

loops.
for loop.
for index_variable in start_value to end_value loop
statements
end loop;
while.
while predicate loop
statements
end loop;

Communicating Processes. We say that two processes communicate when one or more
of the target signals of one process are listed in the sensitivity list of the other.
Example 8. The following architecture exhibits inter-process communication.
library IEEE;
use IEEE.std_logic_1164.all;
entity full_adder is
port(in1, in2, c_in : in std_logic;
sum, c_out : out std_logic);
end entity full_adder;
architecture behavior of full_adder is
signal s1, s2,s3 : std_logic;
constant delay :Time:= 5 ns;
begin
HA1: process(in1, in2)
begin
s1 <= (in1 xor in2) after delay;
s3 <= (in1 and in2) after delay;
end process HA1;
HA2: process(s1, c_in)
begin
sum <= (s1 xor c_in) after delay;
s2 <= (s1 and c_in) after delay;
end process HA2;
OR1: process(s1, c_in)
begin
c_out <= (s2 or s3) after delay;
end process OR1;
end architecture behavior;

Wait statements. Wait statements suspend the execution of a process. There exist four
types of wait statements.
1. wait for time expression; suspend the process for some given amount of time.
2. wait on signal list; suspend process until an event occurs one or more signals in the
signal list.
3. wait until condition; suspend process until the condtion evaluates to true.
4. wait; suspend process indefinitely
Modeling Synchronous Devices. Process sensitivity lists can be used to model sequential behavior. Useful for modeling synchronous behavior are the rising edge() and
falling edge() functions which may be applied to a clock signal.

10

Example 9. An example of an entity-architecture description for an aysynchronous SR


D-flip-flop.
library IEEE;
use IEEE.std_logic_1164.all;
entity asynch_dff is
port(R, S, D, Clk : in std_logic;
Q, Qbar : out std_logic);
end entity asynch_dff;
architecture behavior of asynch_dff is
begin
output: process(R,S,Clk) is
begin
if (R = 0) then
Q <= 0 after 5 ns;
Qbar <= 1 after 5 ns;
elsif S= 0 then
Q <= 1 after 5 ns;
Qbar <= 0 after 5 ns;
elsif(rising_edge(Clk)) then
Q <= D after 5 ns;
Qbar <= (not D) after 5 ns;
end process output;
end architecture behavior;

11

Example 10. The following example shows how to use a wait statement within a process
to create a clock signal.
library IEEE;
use IEEE.std_logic_1164.all;
entity clock_waveform is
port(Clk : out std_logic);
end entity clock_waveform;
architecture behavior of clock_waveform is
begin
process is
begin
Clk <= 0, 1 after 10 ns;
wait for 20 ns;
end process;
end architecture behavior;

Modeling Finite State Machines. The modeling of finite state machines is done similary
as in verilog. The most straightforward way is to have two processes: one which is sensitive
to changes in either state or input, and one which is sensitive

Example 11. Given the Mealy machine M described below, the following is a VHDL model
for M .
x/S
0
1

S0
S1
S1 /1 S1 /1
S1 /0 S0 /0

12

library IEEE;
use IEEE.std_logic_1164.all;
entity state_machine is
port(reset, clk, x : in std_logic;
y : out std_logic);
end entity asynch_dff;
architecture behavior of asynch_dff is
type statetype is (state0,state1);
signal state, next_state : statetype := state0;
begin
level_sensitive: process(state,x) is
begin
case state is
when state0 =>
if x = 0then
next_state <= state1;
y <= 1;
else
next_state <= state0;
y <= 0;
end if
when state1 =>
if x = 1 then
next_state <= state0;
y <= 0;
else
next_state <= state1;
y <= 1;
end if
end case
end process level_sensitive;
edge_sensitive: process is
begin
wait until (rising_edge(clk));
if reset = 1 then state <= state0;
else state <= next_state;
end if;
end process edge_sensitive;
end architecture behavior;

13

Components. Components allow one to resuse an entity within an architecture. Recall


that in Example 8 we created a full adder by using two half adder processes. Instead we
could have used just one half adder component. The syntax is as follows.
library IEEE;
use IEEE.std_logic_1164.all;
entity full_adder is
port(in1, in2, c_in : in std_logic;
sum, c_out : out std_logic);
end entity full_adder;
architecture behavior of full_adder is
component half_adder is
port(x,y:in std_logic;
sum, carry: out std_logic);
end component half_adder;
component my_or is
port(x,y:in std_logic;
z: out std_logic);
end component my_or;
signal s1, s2,s3 : std_logic;
begin
H1: half_adder port map(x => in1, y => in2,
sum => s1, carry => s3);
H2: half_adder port map(x => s1, y => c_in,
sum => sum, carry => s2);
O: my_or port map(x => s2, y => y => s3, z => c_out);
end architecture behavior;

14

You might also like