7.0 VHDL: A Hardware Description Language
7.1 Introduction to VHDL
VHDL stands for VHSIC Hardware Description Language, where VHSIC is an acronym for Very High-Speed Integrated Circuit. It is a standardized programming language used to model and describe the behavior and structure of digital systems, from simple logic gates to entire microprocessors.
In VHDL, a hardware module is described using several core components:
- Entity Declaration: This is the public interface of the module. It defines the module’s name and its ports, which are the input and output signals that connect it to the outside world.
- Architecture: This describes the internal implementation of the entity. It specifies how the module operates, either by describing its structure, its behavior, or the flow of data through it.
- Configuration, Package Declaration, Package Body: These are other VHDL constructs used for managing complex designs, defining reusable components, and declaring shared data types and functions.
The syntax for an Entity Declaration defines the ports and their direction, or mode:
- In: An input port that can only be read within the module.
- Out: An output port that can only be written to from within the module.
- Inout: A bidirectional port that can be both read from and written to.
- Buffer: An output port whose value can also be read internally.
The Architecture block is always linked to a specific entity and contains the logic that implements the entity’s function. It consists of a declarative part (for signals, constants, etc.) and a statement part that defines the circuit’s operation.
7.2 VHDL Modeling Styles
Within an architecture, a designer can use one or a combination of three main modeling styles to describe a circuit.
- Dataflow Modeling
This style describes the flow of data through the entity using concurrent signal assignment statements. These statements execute in parallel, reflecting the inherent parallelism of hardware. The primary concurrent statements available for dataflow modeling are:
- Logical and arithmetic operators (e.g., AND, +).
- The WHEN…ELSE or WITH…SELECT…WHEN constructs for conditional signal assignment.
- The GENERATE statement for creating regular, repetitive structures.
- The BLOCK statement for partitioning concurrent code.
- Behavioral Modeling
This style describes the behavior of an entity using a series of sequential statements that execute in a specific order, much like a traditional software program. These sequential statements must be placed inside a special construct, such as a PROCESS, FUNCTION, or PROCEDURE. While the statements inside a process are sequential, the process block itself is a concurrent statement that executes in parallel with other parts of the design.
The key sequential statements include:
- IF…THEN…ELSE
- WAIT
- CASE
- LOOP
Behavioral modeling is powerful and can be used to describe both combinational and sequential logic.
- Structural Modeling
This style describes an entity as a hierarchical composition of interconnected sub-components. The design is built by creating instances of other pre-defined components (entities) and specifying how their ports are connected with signals. Each component instantiation is a concurrent statement. This approach is analogous to creating a schematic by wiring together black-box symbols and is ideal for building large systems from smaller, reusable modules.
7.3 VHDL Examples: Logic Gates and Combinational Circuits
The following examples demonstrate the VHDL implementation of basic logic gates and common combinational circuits.
AND Gate
| X | Y | Z |
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
Library ieee;
use ieee.std_logic_1164.all;
entity and1 is
port(x,y:in bit ; z:out bit);
end and1;
architecture virat of and1 is
begin
z<=x and y;
end virat;
OR Gate
| X | Y | Z |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
Library ieee;
use ieee.std_logic_1164.all;
entity or1 is
port(x,y:in bit ; z:out bit);
end or1;
architecture virat of or1 is
begin
z<=x or y;
end virat;
NOT Gate
| X | Y |
| 0 | 1 |
| 1 | 0 |
Library ieee;
use ieee.std_logic_1164.all;
entity not1 is
port(x:in bit ; y:out bit);
end not1;
architecture virat of not1 is
begin
y<=not x;
end virat;
NAND Gate
| X | Y | Z |
| 0 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
Library ieee;
use ieee.std_logic_1164.all;
entity nand1 is
port(a,b:in bit ; c:out bit);
end nand1;
architecture virat of nand1 is
begin
c<=a nand b;
end virat;
NOR Gate
| X | Y | Z |
| 0 | 0 | 1 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 0 |
Library ieee;
use ieee.std_logic_1164.all;
entity nor1 is
port(a,b:in bit ; c:out bit);
end nor1;
architecture virat of nor1 is
begin
c<=a nor b;
end virat;
XOR Gate
| X | Y | Z |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
Library ieee;
use ieee.std_logic_1164.all;
entity xor1 is
port(a,b:in bit ; c:out bit);
end xor1;
architecture virat of xor1 is
begin
c<=a xor b;
end virat;
XNOR Gate
| X | Y | Z |
| 0 | 0 | 1 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
Library ieee;
use ieee.std_logic_1164.all;
entity xnor1 is
port(a,b:in bit ; c:out bit);
end xnor1;
architecture virat of xnor1 is
begin
c<=not(a xor b);
end virat;
Half-Adder
| A | B | Sum | Carry |
| 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 0 |
| 1 | 0 | 1 | 0 |
| 1 | 1 | 0 | 1 |
Library ieee;
use ieee.std_logic_1164.all;
entity half_adder is
port(a,b:in bit; sum,carry:out bit);
end half_adder;
architecture data of half_adder is
begin
sum<= a xor b;
carry <= a and b;
end data;
Full-Adder
| A | B | Cin | Sum | Cout |
| 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 1 | 0 |
| 0 | 1 | 0 | 1 | 0 |
| 0 | 1 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 | 0 |
| 1 | 0 | 1 | 0 | 1 |
| 1 | 1 | 0 | 0 | 1 |
| 1 | 1 | 1 | 1 | 1 |
Library ieee;
use ieee.std_logic_1164.all;
entity full_adder is
port(a,b,c:in bit; sum,carry:out bit);
end full_adder;
architecture data of full_adder is
begin
sum<= a xor b xor c;
carry <= ((a and b) or (b and c) or (a and c));
end data;
Half-Subtractor
| A | B | Diff | Borrow |
| 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 1 |
| 1 | 0 | 1 | 0 |
| 1 | 1 | 0 | 0 |
Library ieee;
use ieee.std_logic_1164.all;
entity half_sub is
port(a,c:in bit; d,b:out bit);
end half_sub;
architecture data of half_sub is
begin
d<= a xor c;
b<= ((not a) and c);
end data;
Full-Subtractor
| A | B | Bin | Sub | Borrow |
| 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 1 | 1 |
| 0 | 1 | 0 | 1 | 1 |
| 0 | 1 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 | 0 |
| 1 | 0 | 1 | 0 | 0 |
| 1 | 1 | 0 | 0 | 0 |
| 1 | 1 | 1 | 1 | 1 |
Library ieee;
use ieee.std_logic_1164.all;
entity full_sub is
port(a,b,c:in bit; sub,borrow:out bit);
end full_sub;
architecture data of full_sub is
begin
sub<= a xor b xor c;
borrow <= ((b xor c) and (not a)) or (b and c);
end data;
4-to-1 Multiplexer
Library ieee;
use ieee.std_logic_1164.all;
entity mux is
port(S1,S0,D0,D1,D2,D3:in bit; Y:out bit);
end mux;
architecture data of mux is
begin
Y<= (not S0 and not S1 and D0) or
(S0 and not S1 and D1) or
(not S0 and S1 and D2) or
(S0 and S1 and D3);
end data;
1-to-4 Demultiplexer
Library ieee;
use ieee.std_logic_1164.all;
entity demux is
port(S1,S0,D:in bit; Y0,Y1,Y2,Y3:out bit);
end demux;
architecture data of demux is
begin
Y0<= ((Not S0) and (Not S1) and D);
Y1<= (S0 and (Not S1) and D);
Y2<= ((Not S0) and S1 and D);
Y3<= (S0 and S1 and D);
end data;
8×3 Encoder
library ieee;
use ieee.std_logic_1164.all;
entity enc is
port(i0,i1,i2,i3,i4,i5,i6,i7:in bit; o0,o1,o2: out bit);
end enc;
architecture vcgandhi of enc is
begin
o0<=i4 or i5 or i6 or i7;
o1<=i2 or i3 or i6 or i7;
o2<=i1 or i3 or i5 or i7;
end vcgandhi;
3×8 Decoder
library ieee;
use ieee.std_logic_1164.all;
entity dec is
port(i0,i1,i2:in bit; o0,o1,o2,o3,o4,o5,o6,o7: out bit);
end dec;
architecture vcgandhi of dec is
begin
o0<=(not i0) and (not i1) and (not i2);
o1<=(not i0) and (not i1) and i2;
o2<=(not i0) and i1 and (not i2);
o3<=(not i0) and i1 and i2;
o4<=i0 and (not i1) and (not i2);
o5<=i0 and (not i1) and i2;
o6<=i0 and i1 and (not i2);
o7<=i0 and i1 and i2;
end vcgandhi;
4-bit Parallel Adder
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity pa is
port(a : in STD_LOGIC_VECTOR(3 downto 0);
b : in STD_LOGIC_VECTOR(3 downto 0);
ca : out STD_LOGIC;
sum : out STD_LOGIC_VECTOR(3 downto 0)
);
end pa;
architecture vcgandhi of pa is
Component fa is
port (a : in STD_LOGIC;
b : in STD_LOGIC;
c : in STD_LOGIC;
sum : out STD_LOGIC;
ca : out STD_LOGIC
);
end component;
signal s : std_logic_vector (2 downto 0);
signal temp: std_logic;
begin
temp<=’0′;
u0 : fa port map (a(0),b(0),temp,sum(0),s(0));
u1 : fa port map (a(1),b(1),s(0),sum(1),s(1));
u2 : fa port map (a(2),b(2),s(1),sum(2),s(2));
ue : fa port map (a(3),b(3),s(2),sum(3),ca);
end vcgandhi;
4-bit Parity Checker
library ieee;
use ieee.std_logic_1164.all;
entity parity_checker is
port (a0,a1,a2,a3 : in std_logic; p : out std_logic);
end parity_checker;
architecture vcgandhi of parity_checker is
begin
p <= (((a0 xor a1) xor a2) xor a3);
end vcgandhi;
4-bit Parity Generator
library ieee;
use ieee.std_logic_1164.all;
entity paritygen is
port (a0, a1, a2, a3: in std_logic; p_odd, p_even: out std_logic);
end paritygen;
architecture vcgandhi of paritygen is
begin
process (a0, a1, a2, a3)
begin
if (a0=’0′ and a1=’0′ and a2=’0′ and a3=’0′) then
p_odd <= ‘0’;
p_even <= ‘0’;
else
p_odd <= (((a0 xor a1) xor a2) xor a3);
p_even <= not(((a0 xor a1) xor a2) xor a3);
end if;
end process;
end vcgandhi;
These combinational building blocks are essential, but to create stateful systems, we need to model sequential logic.
7.4 VHDL Examples: Sequential Circuits
The following examples demonstrate VHDL code for common sequential circuits.
SR Latch
library ieee;
use ieee.std_logic_1164.all;
entity srl is
port(r,s:in bit; q,qbar:buffer bit);
end srl;
architecture virat of srl is
signal s1,r1:bit;
begin
q<= s nand qbar;
qbar<= r nand q;
end virat;
D Latch
library ieee;
use ieee.std_logic_1164.all;
entity Dl is
port(d:in bit; q,qbar:buffer bit);
end Dl;
architecture virat of Dl is
signal s1,r1:bit;
begin
q<= d nand qbar;
qbar<= d nand q;
end virat;
SR Flip Flop
library ieee;
use ieee.std_logic_1164.all;
entity srflip is
port(r,s,clk:in bit; q,qbar:buffer bit);
end srflip;
architecture virat of srflip is
signal s1,r1:bit;
begin
s1<=s nand clk;
r1<=r nand clk;
q<= s1 nand qbar;
qbar<= r1 nand q;
end virat;
JK Flip Flop
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity jk is
port( j : in STD_LOGIC;
k : in STD_LOGIC;
clk : in STD_LOGIC;
reset : in STD_LOGIC;
q : out STD_LOGIC;
qb : out STD_LOGIC
);
end jk;
architecture virat of jk is
begin
jkff : process (clk,reset)
variable m : std_logic := ‘0’;
begin
if (reset = ‘1’) then
m := ‘0’;
elsif (rising_edge (clk)) then
if (j /= k) then
m := j;
elsif (j = ‘1’ and k = ‘1’) then
m := not m;
end if;
end if;
q <= m;
qb <= not m;
end process jkff;
end virat;
D Flip Flop
Library ieee;
use ieee.std_logic_1164.all;
entity dflip is
port(d,clk:in bit; q,qbar:buffer bit);
end dflip;
architecture virat of dflip is
signal d1,d2:bit;
begin
d1<=d nand clk;
d2<=(not d) nand clk;
q<= d1 nand qbar;
qbar<= d2 nand q;
end virat;
T Flip Flop
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity Toggle_flip_flop is
port( t : in STD_LOGIC;
clk : in STD_LOGIC;
reset : in STD_LOGIC;
dout : out STD_LOGIC
);
end Toggle_flip_flop;
architecture virat of Toggle_flip_flop is
begin
tff : process (clk,reset)
variable m : std_logic := ‘0’;
begin
if (reset = ‘1’) then
m := ‘0’;
elsif (rising_edge (clk)) then
if (t = ‘1’) then
m := not m;
end if;
end if;
dout <= m;
end process tff;
end virat;
4-bit Up Counter
library IEEE;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity counter is
port(Clock, CLR : in std_logic;
Q : out std_logic_vector(3 downto 0)
);
end counter;
architecture virat of counter is
signal tmp: std_logic_vector(3 downto 0);
begin
process (Clock, CLR)
begin
if (CLR = ‘1’) then
tmp <= “0000”;
elsif (Clock’event and Clock = ‘1’) then
tmp <= tmp + 1;
end if;
end process;
Q <= tmp;
end virat;
4-bit Down Counter
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity dcounter is
port(Clock, CLR : in std_logic;
Q : out std_logic_vector(3 downto 0));
end dcounter;
architecture virat of dcounter is
signal tmp: std_logic_vector(3 downto 0);
begin
process (Clock, CLR)
begin
if (CLR = ‘1’) then
tmp <= “1111”;
elsif (Clock’event and Clock = ‘1’) then
tmp <= tmp – 1;
end if;
end process;
Q <= tmp;
end virat;
While VHDL is a powerful and standardized HDL, another language, Verilog, is also widely used in the industry and offers a different syntax and feature set.