VHDL
VHDL
Introduction to VHDL
By
Dr. Yaser Khalifa
Electrical and Computer Engineering Department
State University of New York at New Paltz
What is VHDL?
C
D
Entity
entity AOI is
port ( A , B , C , D : in STD_LOGIC ;
F : out STD_LOGIC ) ;
end AOI ;
architecture V1 of AOI is
begin
F <= not ( ( A and B ) or ( c and D ) ) ;
end V1 ;
Entity Declaration
architecture V2 of AOI is
signals AB, CD, O : STD_LOGIC ;
begin
AB <= A and B after 2 NS;
CD <= C and D after 2 NS;
O <= AB or CD after 2 NS;
F <= not O after 1 NS;
end V2 ;
Concurrent Statements
• VHDL statements are grouped into sequential and
concurrent statements. Concurrent statements are
used in data flow and structural descriptions.
Sequential statements are used in bahavioral
descriptions
A
B 2 NS
AB
AB <= A and B after 2 NS;
CD <= C and D after 2 NS;
O <= AB or CD after 2 NS;
F <= not O after 1 NS;
AB
F
Variables
Previously we have looked at signals as electrical
connections or “pieces of wires”.
Variables can be pieces of wire too, but they can also
be more abstract.
Variables can represent wires, registers, or be used to
store intermediate values in abstract calculations.
variable V: STD_LOGIC;
entity MUX2 is
port (SEL, A, B: in STD_LOGIC;
F: out STD_LOGIC);
end MUX2;
SEL
A
F
SELB
B
architecture STRUCTURE of MUX2 is
component INV
port (A: in STD_LOGIC;
F: out STD_LOGIC);
end component;
component AOI
port (A, B, C, D: in STD_LOGIC;
F: out STD_LOGIC);
end component;
signal SELB: STD_LOGIC;
begin
G1: INV port map(SEL, SELB);
G2: AOI port map(SEL, A, SELB, B, F);
end STRUCTURE;
Variables
variable V: STD_LOGIC;
process (A, B, C)
variable V: Std_logic; [ V = ’U’ ]
begin
V := A nand B; [ V = ’1’ ]
V := V nor C; [ V = ’0’ ]
F <= not V;
end process;
process (F)
begin
... A variable can be used ONLY inside the
end process; process. So, if we want a value passed
between processes, we MUST use a signal.
Structural Description
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity COMP4 is
port ( A, B : in STD_LOGIC_VECTOR ( 3 downto 0);
F : out STD_LOGIC) ;
end COMP4;
use WORK.GATESPKG.all ;
architecture STRUCT of COMP4 is
signal x : STD_LOGIC_VEXTOR ( 0 to 3 );
begin
u0: xnor2 port map (a(0) , b(0) , x(0)) ;
u1: xnor2 port map (a(1) , b(1) , x(1)) ;
u2: xnor2 port map (a(2) , b(2) , x(2)) ;
u3: xnor2 port map (a(3) , b(3) , x(3)) ;
u4: and4 port map (x(0) , x(1) , x(2) , x(3) , F) ;
end STRUCT;
Process Statement Execution
proc_x : process (a , b , c )
begin
x <= a and b and c;
end process;
proc_x : process
begin
x <= a and b and c;
wait on a , b , c ;
end process;
if C2 = '0' then
V := B;
W := C;
if C3 = '0' then
X := D;
Y := E;
end if;
else
V := C;
W := D;
end if;
An if statement is synthesised by generating a
multiplexer for every signal or variable assigned
within the statement.
The condition given at the top of the if statement
forms the select input to the multiplexer.
if C1 = '0' then A
V := A; V
else
V := B; B
end if
In the example below the if statement does not have an else part,
but the assignment V within the if still synthesizes to a
multiplexer.
V
V
process
begin
if Clock = ‘0’ then
F <= ‘0’;
else
F <= A;
end if;
end process;
case SEL is
when "00" => SEL
F <= A; 2
when "01" =>
F <= B;
A
when "10" =>
F <= C; B
when "11" => F
F <= D; C
when others => D
F <= 'X';
end case;
The others branch will catch any cases not already mentioned explicitly by the
when.
It is possible to cover several cases in the same when branch
by separating the values with vertical bars. In this example
the branch is executed if ADDRESS is:
16, 20, 24 or 28.
case ADDRESS is
when 16 | 20 | 24 | 28 =>
A <= '1';
B <= '1';
end case;
Each branch can also include any number of sequential
statements including other nested case statements as well!!
case ADDRESS is
when 16 | 20 | 24 | 28 =>
A <= '1';
B <= '1';
end case;
The null statement means do nothing
A <= '0';
B <= '0';
case ADDRESS is
when 0 to 7 =>
A <= '1';
when 8 to 15 =>
B <= '1';
when 16 | 20 | 24 | 28 =>
A <= '1';
B <= '1';
when others =>
null;
end case;
It is possible also to cover a whole range using the case statement.
case ADDRESS is
when 0 to 7 =>
A <= '1';
when 8 to 15 =>
B <= '1';
when 16 | 20 | 24 | 28 =>
A <= '1';
B <= '1';
end case;
If ADDRESS is:
1) =9
2) =19
What will be the values of A and B?
A <= '0';
B <= '0';
case ADDRESS is
when 0 to 7 =>
A <= '1';
when 8 to 15 =>
B <= '1';
when 16 | 20 | 24 | 28 =>
A <= '1';
B <= '1';
end case;
Case versus if:
for I in 0 to 3 loop
F(I) <= A(I) and B(3-I);
V := V xor A(I);
end loop;
The range can be ascending or descending, but the loop
parameter cannot change in increments greater than 1.
for I in 0 to 3 loop
F(I) <= A(I) and B(3-I);
V := V xor A(I);
end loop;
for I in 0 to 3 loop
F(I) <= A(I) and B(3-I);
V := V xor A(I);
if V = 'X' then
I := 4;
end if;
end loop;
FOR Loop are synthesized by making
multiple copies of the logic synthesized
inside the loop, one copy for each possible
value of the loop parameter.
A(0)
process (A, B) F(0)
B(3)
variable V: Std_logic;
begin
A(1)
V := '0'; B(2)
F(1)
for I in 0 to 3 loop
F(I) <= A(I) and B(3-I); A(2)
V := V xor A(I); B(1)
F(2)
end loop;
G <= V; A(3)
F(3)
end process; B(0)
A(0)
A(1) G
A(2)
A(3)
LOOPS
There are 3 different kinds of loop statements in
VHDL:
1) The while loop, tests a boolean condition at the
top of the loop, and only leaves the loop when
the condition is false.
3) for loop
Only the for loop is synthesizable, and that only if the
bounds are constant. The other loops can be useful in
test benches and behavioural models.
L1: for I in 0 to 7 loop
C := C + 1;
process (Clock)
begin
Q0 <= D0;
Q1 <= D1;
end if;
end process;
Each signal has a signal attribute S’EVENT, which has a boolean value True
or False.
S’Evant changes during any delta in which there is an event on the
signal (i.e. signal changes value).
process
begin
...
S <= '1';
wait for 10 NS;
S <= '1';
wait for 10 NS;
S <= '0';
wait for 10 NS;
S <= '0';
...
Rising_edge and Falling_edge Functions
Testing for a clock edge is such a common requirement that the package
std_logic_1164 includes standard functions Rising_edge and
Falling_edge .
The functions are given a signal of type STD_LOGIC and return a value
which is either True or False.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
...
process (Clock)
begin
if RISING_EDGE(Clock) then
Q <= D;
end if;
end process;
process (Clock)
begin
if Clock'EVENT and Clock = '1' then
Q <= D;
end if;
end process;
process (Clock)
begin
if RISING_EDGE(Clock) then
Q <= D;
end if;
end process;
...
signal Count :
STD_LOGIC_VECTOR(7 downto 0);
begin
process (Clock, Reset)
begin Load
Data Reset
if Reset = '0' then
Count <= "00000000"; Count
elsif RISING_EDGE(Clock) then
if Load = '1' then '1'
Count <= Data; >
else + Clock
Reset
if Reset = '1' then
Q <= '0';
Q
Data
elsif Enable = '1' then
Enable
Q <= Data;
end if; Clock
end if; >
end process;
Wait until Statement
Another_Flipflop: process
begin Reset
wait until Clock = '1';
if Reset = '1' then Q
Q <= '0'; Data
else
Q <= D;
end if;
end process; Clock >
Another_Flipflop: process
begin
wait until RISING_EDGE(Clock);
Using enumeration type allows you to give symbolic names to the states,
but say nothing about the hardware implementation.
You should choose meaningful names, as this makes the VHDL code
easy to understand. The names will also be visible during simulation,
which makes debugging easier.
Otherwise, there is no reliable way to get the VHDL and gate level
representations of the FSM into the same known state, and thus no way
to verify their equivalence.
architecture Explicit of FSM is
begin
process
type StateType is (Idle, Start, Stop, Clear);
variable State: StateType;
begin
wait until RISING_EDGE(Clock);
if Reset = '1' then
State := Idle; F <= '0'; G <= '1';
else
case State is
when Idle => State := Start; G <= '0';
when Start => State := Stop;
when Stop => State := Clear; F <= '1';
when Clear => State := Idle; F <= '0';
G <= '1';
end case;
end if;
end process;
end;
The following description of an FSM consists of a process synchronized
on a clock edge, and assigning the variable state (the state vector) and
signal F and G (the outputs).
Thus, four flip flops will be synthesized, two for the state vector, and one
each of the two outputs.
architecture Explicit of FSM is
begin
process
type StateType is (Idle, Start, Stop, Clear);
variable State: StateType;
begin
wait until RISING_EDGE(Clock);
if Reset = '1' then
State := Idle; F <= '0'; G <= '1';
else
case State is
when Idle => State := Start; G <= '0';
when Start => State := Stop;
when Stop => State := Clear; F <= '1';
when Clear => State := Idle; F <= '0';
G <= '1';
end case;
end if;
end process;
end;
architecture SeparateDecoding of FSM is
type StateType is (Idle, Start, Stop, Clear);
signal State: StateType;
begin
Change_state: process
begin
wait until RISING_EDGE(Clock);
if State = Clear or Reset = '1' then
State <= Idle;
elsif State = Idle then State <= Start;
elsif State = Start then State <= Stop;
else State <= Clear;
end if;
end process;
Output: process (State)
begin
F <= '0'; G <= '0';
if State = Clear then F <= '1';
elsif State = Idle then G <= '1';
end if;
end process;
end;
architecture RegistersPlusLogic of FSM is
type StateType is (Idle, Start, Stop, Clear);
signal State: StateType;
begin
Registers: process
begin
wait until RISING_EDGE(Clock);
if Reset = '0' then
State <= Idle;
else
State <= NextState;
end if;
end process;
C_logic: process (State)
begin
if State = Clear then NextState <= Idle;
F <= '1';
elsif State = Idle then NextState <= Start;
G <= '1';
elsif State = Start then NextState <= Stop;
else NextState <= Clear;
end if;
end process;
end;
Concatenation
• The concatenation operator “&” is used to
join together two arrays end to end to make
one longer array
F<= A & B;
• Concatenation can also be used to
concatenate arrays with single bits, or even
bits with bits.
F(3) = A
F(2) = B
F(1) = C
F(0) = unchanged
• Shift and rotate operations can be
performed in one line by combining
concatenation with slice names.
“0111”
Operator Overloading
library IEEE;
use IEEE.STD_LOGIC_1164.all; • This is illigal
because the
entity ADDER is
operator “+”
port(A, B: in
STD_LOGIC_VECTOR(7 downto 0); is not defined
SUM: out to work on
STD_LOGIC_VECTOR(7 downto 0)); type
end; Std_logic_vec
tor.
architecture A1 of ADDER is
begin
SUM <= A + B;
end;
• The Std_logic_vector type is declared in the
package Std_logic_1164.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
>
>=
<
<=
=
/=
• “+” is not defined in std_logic_1164, but it
can be defined for std_logic_vector and put
in a package.
A
B F
signal A, B: STD_LOGIC_VECTOR;
F <= A + B ;
Synthesis of Arithmetic
• The synthesis of the arithmetic operators depend
on the synthesis tool.
• Some tools will map the operators to discrete
gates. Others will make use of macro-cells
optimized for the target technology.
• A plus operator (+ ) can be implemented in
hardware using a ripple carry or a carry look-
ahead scheme. The implementation will be smaller
or faster, depending on which one you choose.
F <= A + B ;
Discrete
Gates ADDER8
Non-optimal Optimized
connection of structure
cells of cells
F <= A + B ;
Technology
ADDER8 independent
VHDL
code
Vendor
ADDER8 Specific
VHDL
code
• If your synthesis tool can not map an arithmetic
operator to an optimized macro-cell, you will need
to instantiate the macro-cell directly in your
VHDL code.
Ripple Carry
Carry Look-ahead
C1: SMALL-ADDER … (Ripple Carry Adder)
C1: FAST_ADDER8 … (Carry Look-Ahead Adder)
Ripple Carry
Carry Look-ahead
Resource Sharing
• Resource sharing allows a single hardware to be
shared by more than one VHDL operator
• Some tools share resources automatically.
process (A, B, C, D, K)
begin C D
A B
if K then
Z <= A + B; -- 8 Bit
+ +
else
Z <= C + D; K
end if; Z
end process;
process (A, B, C, D, K)
begin
if K then
Z <= A + B; -- 8 Bit
else
Z <= C + D;
end if;
end process;
A C B D
A B C D
K
+ +
K +
Z
Z
process (A, B, C, D, K)
variable V1, V2 : ...
• If your tool does not do begin
resource sharing, you must if K then
rewrite your code to V1 := A;
achieve same results. V2 := B;
else
V1 := C;
V2 := D;
end if;
Z <= V1 + V2;
end process;
State Machines (Again!)
A B C D
E
• 2 processes (AC) (BDE)
• 4 processes (AC) (B) (D) (E)
• 3 processes (A) (CE) (BD)
• 4 processes (A) (BC) (D) (E)
• 2 processes (ABCE) (D)
• 3 processes (A) (BCE) (D)
entity FSM1 is
port (Clock : in std_logic;
SlowRAN: in std_logic;
Read, Write: out std_logic); ST_Read ST_Write
end entity;
architecture RTL of FSM1 is
begin
SEQ_abd_COMB: process
type StateType is (ST_Read, ST_Write, ST_Delay);
variable State:StateType := ST_Read; ST_Delay
begin
wait until rising_edge*Clock);
case State is
when ST_Read => Read <= ‘1’;
Write <= ‘0’;
State := ST_Write;
when ST_Write => Read <= ‘0’;
Write <= ‘1’;
if (SlowRam = ‘1’) then
State := ST_Delay;
else
State := ST_Read
end if;
when ST_Delay => Read <= ‘0’;
Write <= ‘0’;
State := ST_Read;
end case;
end process SEQ_AND_COMB;
end architecture RTL;
entity FSM2 is
port (Clock : in std_logic;
SlowRAN: in std_logic;
Read, Write: out std_logic);
end entity;
architecture RTL of FSM2 is
type StateType is (ST_Read, ST_Write, ST_Delay);
signal CurrentState, NextState: StateType;
begin ST_Read ST_Write
SEQ: process (Clock)
begin
if rising_edge(Clock) then
if (Reset = ‘1’) then
CurrentState <= ST_Read;
else
CurrentState <= NextState; ST_Delay
end if;
end process SEQ;
COMB: process (CurrentState)
begin
case CurrentState is
when ST_Read => Read <= ‘1’;
Write <= ‘0’;
NextState := ST_Write;
when ST_Write => Read <= ‘0’;
Write <= ‘1’;
if (SlowRam = ‘1’) then
State := ST_Delay;
else
NextState := ST_Read
end if;
when ST_Delay => Read <= ‘0’;
Write <= ‘0’;
NextState := ST_Read;
end case;
end process COMB;
end architecture RTL;
SEQ: process (Clock)
begin
if rising_edge(Clock) then
if (Reset = ‘1’) then
CurrentState <= ST_Read;
else
CurrentState <= NextState;
end if;
end process SEQ;
COMB: process (CurrentState)
begin
case CurrentState is
when ST_Read => Read <= ‘1’;
Write <= ‘0’;
NextState := ST_Write;
when ST_Write => Read <= ‘0’;
Write <= ‘1’;
if (SlowRam = ‘1’) then
State := ST_Delay;
else
NextState := ST_Read
end if;
when ST_Delay => Read <= ‘0’;
Write <= ‘0’;
NextState := ST_Read;
end case;
end process COMB;
SlowRam
Read
D Q
Q
Reset
D Q
Write
Clock