Writing VHDL For RTL Synthesis: 1 Structure
Writing VHDL For RTL Synthesis: 1 Structure
1 Structure
Much like a C program is mainly a series of function definitions, a VHDL specification
is mainly a series of entity/architecture definition pairs. An entity is an object with
a series of input and output ports that represent wires or busses, and an architecture
is the “guts” of an entity, comprising concurrent assignment statements, processes, or
instantiations of other entities.
Concurrent assignment statements that use logical expressions to define the values
of signals are one of the most common things in architectures. V HDL supports the
logical operators and, or, nand, nor, xnor, xnor, and not.
library ieee; -- add this to the IEEE library
use ieee.std_logic_1164.all; -- includes std_ulogic
entity full_adder is
port(a, b, c : in std_ulogic;
sum, carry : out std_ulogic);
end full_adder;
1
1.1 Components
Once you have defined an entity, the next thing is to instantiate it as a component within
another entity’s architecture.
The interface of the component must be defined in any architecture that instantiates
it. Then, any number of port map statements create instances of that component.
Here is how to connect two of the full adders to give a two-bit adder:
library ieee;
use ieee.std_logic_1164.all;
entity add2 is
port (
A, B : in std_logic_vector(1 downto 0);
C : out std_logic_vector(2 downto 0));
end add2;
begin
end imp;
1.2 Multiplexers
The when...else construct is one way to specify a multiplexer.
library ieee;
use ieee.std_logic_1164.all;
entity multiplexer_4_1 is
port(in0, in1, in2, in3 : in std_ulogic_vector(15 downto 0);
s0, s1 : in std_ulogic;
z : out std_ulogic_vector(15 downto 0));
end multiplexer_4_1;
2
The with...select is another way to describe a multiplexer.
architecture usewith of multiplexer_4_1 is
signal sels : std_ulogic_vector(1 downto 0); -- Local wires
begin
sels <= s1 & s0; -- vector concatenation
1.3 Decoders
Often, you will want to take a set of bits encoded in one way and represent them in
another. For example, the following one-of-eight decoder takes three bits and uses
them to enable one of eight.
library ieee;
use ieee.std_logic_1164.all;
entity dec1_8 is
port (
sel : in std_logic_vector(2 downto 0);
res : out std_logic_vector(7 downto 0));
end dec1_8;
entity priority is
port (
sel : in std_logic_vector(7 downto 0);
code : out std_logic_vector(2 downto 0));
end priority;
3
1.5 Arithmetic Units
VHDL has extensive support for arithmetic. Here is an unsigned 8-bit adder with carry
in and out. By default VHDL’s + operator returns a result that is the same width as
its arguments, so it is necessary to zero-extend them to get the ninth (carry) bit out.
One way to do this is to convert the arguments to integers, add them, then convert them
back.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity adder is
port (
A, B : in std_logic_vector(7 downto 0);
CI : in std_logic;
SUM : out std_logic_vector(7 downto 0);
CO : out std_logic);
end adder;
entity alu is
port (
A, B : in std_logic_vector(7 downto 0);
ADD : in std_logic;
RES : out std_logic_vector(7 downto 0));
end alu;
VHDL provides the usual arithmetic comparison operators. Note that signed and
unsigned versions behave differently.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity comparator is
port (
A, B : in std_logic_vector(7 downto 0);
GE : out std_logic);
end comparator;
Multiplication and division is possible, but is very costly in area and can be very
slow.
4
1.6 Generate statements
To get an unusual array, say that for a 4-bit ripple-carry adder, use a generate con-
struct, which expands its body into multiple gates when synthesized.
library ieee;
use ieee.std_logic_1164.all;
entity rippleadder is
port (a, b : in std_ulogic_vector(3 downto 0);
cin : in std_ulogic;
sum : out std_ulogic_vector(3 downto 0);
cout : out std_ulogic);
end rippleadder;
2 State-holding Elements
Although there are many ways to express something that behaves like a flip-flop in
VHDL , this is guaranteed to synthesize as you would like
library ieee;
use ieee.std_logic_1164.all;
entity flipflop is
port (Clk, D : in std_ulogic;
Q : out std_ulogic);
end flipflop;
entity flipflop_reset is
port (Clk, Reset, D : in std_ulogic;
Q : out std_ulogic);
end flipflop_reset;
5
2.1 Counters
Counters are often useful for delays, dividing clocks, and many other uses. Here is
code for a four-bit unsigned up counter with a synchronous reset:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity counter is
port(
Clk, Reset : in std_logic;
Q : out std_logic_vector(3 downto 0)
);
end counter;
Q <= count;
end imp;
entity shifter is
port (
Clk : in std_logic;
SI : in std_logic;
SO : out std_logic);
end shifter;
SO <= tmp(7);
end impl;
6
2.3 RAMs
While large amounts of memory should be stored off-chip, small RAMs (say 32 × 4
bits) can be implemented directly. Here’s how:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity ram_32_4 is
port (
Clk : in std_logic;
WE : in std_logic; -- Write enable
EN : in std_logic; -- Read enable
addr : in std_logic_vector(4 downto 0);
di : in std_logic_vector(3 downto 0); -- Data in
do : out std_logic_vector(3 downto 0)); -- Data out
end ram_32_4;
entity rom_32_4 is
port (
Clk : in std_logic;
en : in std_logic; -- Read enable
addr : in std_logic_vector(4 downto 0);
data : out std_logic_vector(3 downto 0));
end rom_32_4;
process (Clk)
begin
if (Clk’event and Clk = ’1’) then
if (en = ’1’) then
data <= ROM(conv_integer(addr));
end if;
end if;
end process;
end imp;
7
2.4 Finite-State Machines
Write a finite state machine as an entity containing two processes: a sequential pro-
cess with if statement sensitive to the edge of the clock and a combinational process
sensitive to all the inputs of the machine.
library ieee;
use ieee.std_logic_1164.all;
entity tlc is
port (
clk : in std_ulogic;
reset : in std_ulogic;
cars : in std_ulogic;
short : in std_ulogic;
long : in std_ulogic;
highway_yellow : out std_ulogic;
highway_red : out std_ulogic;
farm_yellow : out std_ulogic;
farm_red : out std_ulogic;
start_timer : out std_ulogic);
end tlc;
when HY =>
highway_yellow <= ’1’;
highway_red <= ’0’;
farm_yellow <= ’0’;
farm_red <= ’1’;
if (short = ’1’) then
next_state <= FG;
start_timer <= ’1’;
else
next_state <= HY;
start_timer <= ’0’;
end if;
8
when FG =>
highway_yellow <= ’0’;
highway_red <= ’1’;
farm_yellow <= ’0’;
farm_red <= ’0’;
if (cars = ’0’ or long = ’1’) then
next_state <= FY;
start_timer <= ’1’;
else
next_state <= FG;
start_timer <= ’0’;
end if;
when FY =>
highway_yellow <= ’0’;
highway_red <= ’1’;
farm_yellow <= ’1’;
farm_red <= ’0’;
if (short = ’1’) then
next_state <= HG;
start_timer <= ’1’;
else
next_state <= FY;
start_timer <= ’0’;
end if;
end imp;
Acknowledgements
Ken Shepard’s handouts for his EECS E4340 class formed a basis for these examples.
References
[1] IEEE Computer Society, 345 East 47th Street, New York, New York. IEEE Stan-
dard VHDL Language Reference Manual (1076–1993), 1994.
[2] IEEE Computer Society, 345 East 47th Street, New York, New York. IEEE Stan-
dard for VHDL Register Transfer Level (RTL) Synthesis (1076.6–1999), September
1999.