0% found this document useful (0 votes)
22 views

ADE Lecture5

The document discusses sequential code in VHDL, including processes, signals, variables, and sequential statements like IF, WAIT, CASE, and LOOP. It provides examples of how these statements can be used to describe sequential logic circuits.

Uploaded by

mohammed
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
22 views

ADE Lecture5

The document discusses sequential code in VHDL, including processes, signals, variables, and sequential statements like IF, WAIT, CASE, and LOOP. It provides examples of how these statements can be used to describe sequential logic circuits.

Uploaded by

mohammed
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 39

Sequential Code

Advanced Digital Electronics


Lecture 5
Outlines
❖ PROCESS
❖ Signals and Variables
❖ IF
❖ WAIT
❖ CASE
❖ LOOP
❖ CASE versus IF
❖ CASE versus WHEN
❖ Using Sequential Code to Design Combinational Circuits
❖ Examples
Introduction
One important aspect of sequential code is that it is not
limited to sequential logic. Indeed, with it we can build
sequential circuits as well as combinational circuits. Sequential
code is also called behavioral code.
The statements discussed in this lecture are all
sequential, that is, allowed only inside PROCESSES, FUNCTIONS,
or PROCEDURES. They are:
IF, WAIT, CASE, and LOOP.
VARIABLES are also restricted to be used in sequential code only
(that is, inside a PROCESS, FUNCTION, or PROCEDURE). Thus,
contrary to a SIGNAL, a VARIABLE can never be global.
PROCESS
A PROCESS is a sequential section of VHDL code. It is
characterized by the presence of IF, WAIT, CASE, or LOOP, and
by a sensitivity list (except when WAIT is used). A PROCESS
must be installed in the main code, and is executed every
time a signal in the sensitivity list changes (or the condition
related to WAIT is fulfilled). Its syntax is shown below.

[label:] PROCESS (sensitivity list)


[VARIABLE name type [range] [:= initial_value;]]
BEGIN
(sequential code)
END PROCESS [label];
PROCESS
VARIABLES are optional. If used, they must be declared
in the declarative part of the PROCESS (before the word
BEGIN, as indicated in the syntax above). The initial value is
not synthesizable, being only taken into consideration in
simulations. The use of a label is also optional. Its purpose is to
improve code readability. The label can be any word, except
VHDL reserved words.
To construct a synchronous circuit, monitoring a signal
(clock, for example) is necessary. A common way of detecting
a signal change is by means of the EVENT attribute. For
instance, if clk is a signal to be monitored, then clk’EVENT
returns TRUE when a change on clk occurs (rising or falling
edge). An example, illustrating the use of EVENT and PROCESS,
is shown next.
Example 1: DFF with Asynchronous Reset #1
A D-type flip-flop is the most
basic building block in sequential
logic circuits. In it, the output must
copy the input at either the positive
or negative transition of the clock
signal (rising or falling edge).
In the code presented below, we make use of the IF
statement to design a DFF with asynchronous reset. If rst = ‘1’,
then the output must be q = ‘0’ ,regardless of the status of clk.
Otherwise, the output must copy the input (that is, q = d) at
the positive edge of clk . The EVENT attribute is used to detect
a clock transition. The PROCESS is run every time any of the
signals that appear in its sensitivity list (clk and rst) changes.
Example 1: DFF with Asynchronous Reset #1
Simulation results, confirming the functionality of the
synthesized circuit, are presented in figure below:
Example 1: DFF with Asynchronous Reset #1
LIBRARY ieee;
USE ieee.std_logic_1164.all;
--------------------------------------
ENTITY dff IS
PORT (d, clk, rst: IN STD_LOGIC;
q: OUT STD_LOGIC);
END dff;
--------------------------------------
ARCHITECTURE behavior OF dff IS
BEGIN
PROCESS (clk, rst)
BEGIN
IF (rst='1') THEN q <= '0';
ELSIF (clk'EVENT AND clk='1') THEN q <= d;
END IF;
END PROCESS;
END behavior;
Signals and Variables
VHDL has two ways of passing non-static values around: by
means of a SIGNAL or by means of a VARIABLE.
A SIGNAL can be declared in a PACKAGE, ENTITY or
ARCHITECTURE (in its declarative part), while a VARIABLE can
only be declared inside a piece of sequential code (in a
PROCESS, for example). Therefore, while the value of the
former can be global, the latter is always local. The value of a
VARIABLE can never be passed out of the PROCESS directly; if
necessary, then it must be assigned to a SIGNAL. On the other
hand, the update of a VARIABLE is immediate, that is, we can
promptly count on its new value in the next line of code. That
is not the case with a SIGNAL (when used in a PROCESS).
IF
As mentioned earlier, IF, WAIT, CASE, and LOOP are the
statements intended for sequential code. Therefore, they can
only be used inside a PROCESS, FUNCTION, or PROCEDURE.
The natural tendency is for people to use IF more than
any other statement. Though this could, in principle, have a
negative consequence ,the synthesizer will optimize the
structure and avoid the extra hardware. The syntax of IF is
shown below.
IF conditions THEN assignments;
ELSIF conditions THEN assignments;
...
ELSE assignments;
END IF;
Example: IF (x<y) THEN temp:="11111111";
ELSIF (x=y AND w='0') THEN temp:="11110000";
ELSE temp:=(OTHERS =>'0');
Example 2: One-digit Counter #1
The code below implements a progressive 1-
digit decimal counter (0 → 9 → 0). A top-
level diagram of the circuit is shown in
figure. It contains a single-bit input (clk) and
a 4-bit output (digit). The IF statement is
used in this example. A variable, temp, was
employed to create the four flip-flops
necessary to store the 4-bit output signal.
Simulation results, confirming the correct
operation of the synthesized circuit.
Example 2: One-digit Counter #1
LIBRARY ieee;
USE ieee.std_logic_1164.all;
---------------------------------------------
ENTITY counter IS
PORT ( clk : IN STD_LOGIC;
digit : OUT INTEGER RANGE 0 TO 9);
END counter;
---------------------------------------------
ARCHITECTURE counter OF counter IS
BEGIN
count: PROCESS(clk)
VARIABLE temp : INTEGER RANGE 0 TO 10;
BEGIN
IF (clk'EVENT AND clk='1') THEN temp :=temp+1;
IF (temp=10) THEN temp := 0;
END IF;
END IF;
digit <= temp;
END PROCESS count;
END counter;
Example 3: Shift Register
Figure below shows a 4-bit shift register. The output bit
(q) must be four positive clock edges behind the input bit (d).
It also contains an asynchronous reset, which must force all
flip-flop outputs to ‘0’ when asserted. In this example, the IF
statement is again employed.
Example 3: Shift Register
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY shiftreg IS
GENERIC (n: INTEGER := 4); -- # of stages
PORT (d, clk, rst: IN STD_LOGIC;
q: OUT STD_LOGIC);
END shiftreg;
ARCHITECTURE behavior OF shiftreg IS
SIGNAL internal: STD_LOGIC_VECTOR (n-1 DOWNTO 0);
BEGIN
PROCESS (clk, rst)
BEGIN
IF (rst='1') THEN
internal <= (OTHERS => '0');
ELSIF (clk'EVENT AND clk='1') THEN
internal<=d&internal(internal'LEFT DOWNTO 1);
END IF;
END PROCESS;
q <= internal(0);
END behavior;
Example 3: Shift Register
Simulation results are shown in figure. q is indeed four
positive clock edges behind d.
WAIT
The operation of WAIT is sometimes similar to that of IF.
However, more than one form of WAIT is available. Moreover,
contrary to when IF, CASE, or LOOP are used, the PROCESS
cannot have a sensitivity list when WAIT is employed. Its syntax
(there are three forms of WAIT) is shown below:
WAIT UNTIL signal_condition;
WAIT ON signal1 [, signal2, ... ];
WAIT FOR time;
WAIT FOR is intended for simulation only (waveform generation
for testbenches). Example: WAIT FOR 5ns;
The WAIT UNTIL statement accepts only one signal, thus being
more appropriate for synchronous code than asynchronous.
Since the PROCESS has no sensitivity list in this case, WAIT UNTIL
must be the first statement in the PROCESS. The PROCESS will
be executed every time the condition is met.
WAIT
Example: 8-bit register with synchronous reset:
PROCESS -- no sensitivity list
BEGIN
WAIT UNTIL (clk'EVENT AND clk='1');
IF (rst='1') THEN output <= "00000000";
ELSIF(clk'EVENT AND clk='1')THEN output<= input;
END IF;
END PROCESS;
WAIT ON, on the other hand, accepts multiple signals.
The PROCESS is put on hold until any of the signals listed
changes. In the example below, the PROCESS will continue
execution whenever a change in rst or clk occurs.
Example: 8-bit register with asynchronous reset:
PROCESS
BEGIN
WAIT ON clk, rst;
IF (rst='1') THEN output <= "00000000";
ELSIF (clk'EVENT AND clk='1') THEN output <= input;
END IF;
END PROCESS;
Example 4: DFF with Asynchronous Reset #2
The code below implements the same DFF of example 1, here
WAIT ON is used instead of IF only.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY dff IS
PORT (d, clk, rst: IN STD_LOGIC;
q: OUT STD_LOGIC);
END dff;
ARCHITECTURE dff OF dff IS
BEGIN
PROCESS
BEGIN
WAIT ON rst, clk;
IF (rst='1') THEN q <= '0';
ELSIF (clk'EVENT AND clk='1') THEN q <= d;
END IF;
END PROCESS;
END dff;
Example 5: One-digit Counter #2
Code below implements the same progressive 1-digit decimal
counter of example 2, WAIT UNTIL was used instead of IF only.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY counter IS
PORT ( clk : IN STD_LOGIC;
digit : OUT INTEGER RANGE 0 TO 9);
END counter;
ARCHITECTURE counter OF counter IS
BEGIN
PROCESS -- no sensitivity list
VARIABLE temp : INTEGER RANGE 0 TO 10;
BEGIN
WAIT UNTIL (clk'EVENT AND clk='1');
temp := temp + 1;
IF (temp=10) THEN temp := 0;
END IF;
digit <= temp;
END PROCESS;
END counter;
CASE
CASE is another statement intended exclusively for
sequential code (along with IF, LOOP, and WAIT). Its syntax is
shown below:
CASE identifier IS
WHEN value => assignments;
WHEN value => assignments;
...
END CASE;

Example:
CASE control IS
WHEN "00" => x<=a; y<=b;
WHEN "01" => x<=b; y<=c;
WHEN OTHERS => x<="0000"; y<="ZZZZ";
END CASE;
CASE
The CASE statement (sequential) is very similar to WHEN
(combinational). Here too all permutations must be tested, so
the keyword OTHERS is often helpful. Another important
keyword is NULL (the counterpart of UNAFFECTED), which should
be used when no action is to take place. For example, WHEN
OTHERS => NULL;
CASE allows multiple assignments for each test condition
(as shown in the example above), while WHEN allows only one.
Like in the case of WHEN, here too ‘‘WHEN value’’ can
take up three forms:
WHEN value -- single value
WHEN value1 to value2 -- range, for enumerated data
-- types only
WHEN value1 | value2 |... -- value1 or value2 or ...
Example 6: DFF with Asynchronous Reset #3
The code below implements the same DFF of example 1
here CASE was used instead of IF only. Notice that a few
unnecessary declarations were intentionally included in the
code to illustrate their usage.
LIBRARY ieee; -- Unnecessary declaration, because
-- BIT was used instead of STD_LOGIC
USE ieee.std_logic_1164.all;
ENTITY dff IS
PORT (d, clk, rst: IN BIT; q: OUT BIT);
END dff;
ARCHITECTURE dff3 OF dff IS
BEGIN
PROCESS (clk, rst)
BEGIN
CASE rst IS
WHEN '1'=> q<='0';
WHEN '0'=> IF(clk'EVENT AND clk='1')THEN q<= d;
END IF;
WHEN OTHERS => NULL;--Unnecessary ,rst is BIT
END CASE;
END PROCESS;
END dff3;
LOOP
As the name says, LOOP is useful when a piece of code must be
instantiated several times. Like IF, WAIT, and CASE, LOOP is
intended exclusively for sequential code, so it too can only be
used inside a PROCESS, FUNCTION, or PROCEDURE.
There are several ways of using LOOP, as shown in the syntaxes:
FOR / LOOP: The loop is repeated a fixed number of times.
[label:] FOR identifier IN range LOOP
(sequential statements)
END LOOP [label];
WHILE / LOOP: The loop is repeated until a condition no longer
holds.
[label:] WHILE condition LOOP
(sequential statements)
END LOOP [label];
EXIT: Used for ending the loop.
[label:] EXIT [label] [WHEN condition];
NEXT: Used for skipping loop steps.
[label:] NEXT [loop_label] [WHEN condition];
LOOP: Examples
Example:
-- the loop will be repeated unconditionally until i -
-- reaches 5 (that is, six times).
FOR i IN 0 TO 5 LOOP -- the range must be static
x(i) <= enable AND w(i+2);
y(0, i) <= w(i);
END LOOP;
Example
--LOOP will keep repeating while i < 10.
WHILE (i < 10) LOOP
WAIT UNTIL clk'EVENT AND clk='1';
(other statements)
END LOOP;
LOOP: Examples
Example
-- the loop will end as soon as a value different from
‘0’ is found in the data vector.
FOR i IN data'RANGE LOOP
CASE data(i) IS
WHEN '0' => count:=count+1;
WHEN OTHERS => EXIT;
END CASE;
END LOOP;
Example
--NEXT causes LOOP to skip one iteration when i=skip
FOR i IN 0 TO 15 LOOP
NEXT WHEN i=skip; -- jumps to next iteration
)...(
END LOOP;
Example 7: Carry Ripple Adders
Figure below shows an 8-bit unsigned carry ripple adder. The top-
level diagram shows the inputs and outputs of the circuit: a and b
are the input vectors to be added, cin is the carry-in bit, s is the
sum vector, and cout is the carry-out bit. The one-level below-top
diagram shows how the carry bits propagate (ripple).

Each section of the latter diagram is a full-adder unit. Thus its


outputs: sj = aj XOR bj XOR cj
cj+1 = (aj AND bj)OR(aj AND cj)OR(bj AND cj)
Example 7: Carry Ripple Adders
Two solutions are presented, being one generic (that is,
for any number of bits) and the other specific for 8-bit
numbers. Also the use of vectors and FOR/LOOP is shown in
the first solution, and of integers and IF in the second.
Simulation results from either solution are shown below.
Example 7: Carry Ripple Adders
----- Solution 1: Generic, with VECTORS --------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY adder IS
GENERIC (length : INTEGER := 8);
PORT (a, b: IN STD_LOGIC_VECTOR (length-1 DOWNTO 0);
cin: IN STD_LOGIC;
s: OUT STD_LOGIC_VECTOR (length-1 DOWNTO 0);
cout: OUT STD_LOGIC);
END adder;
ARCHITECTURE adder OF adder IS
BEGIN
PROCESS (a, b, cin)
VARIABLE carry : STD_LOGIC_VECTOR (length DOWNTO 0);
BEGIN
carry(0) := cin;
FOR i IN 0 TO length-1 LOOP
s(i) <= a(i) XOR b(i) XOR carry(i);
carry(i+1):=(a(i) AND b(i))OR
(a(i) AND carry(i))OR
(b(i) AND carry(i));
END LOOP;
cout <= carry(length);
END PROCESS;
END adder;
Example 7: Carry Ripple Adders
---- Solution 2: non-generic, with INTEGERS ----
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY adder IS
PORT ( a, b: IN INTEGER RANGE 0 TO 255;
c0: IN STD_LOGIC;
s: OUT INTEGER RANGE 0 TO 255;
c8: OUT STD_LOGIC);
END adder;
ARCHITECTURE adder OF adder IS
BEGIN
PROCESS (a, b, c0)
VARIABLE temp : INTEGER RANGE 0 TO 511;
BEGIN
IF (c0='1') THEN temp:=1;
ELSE temp:=0;
END IF;
temp := a + b + temp;
IF (temp > 255) THEN c8 <= '1'; temp := temp---256;
ELSE c8 <= '0';
END IF;
s <= temp;
END PROCESS;
END adder;
CASE versus IF
The presence of ELSE in the IF/ELSE statement might infer the
implementation of a priority decoder (which would never occur
with CASE), when IF (a sequential statement) is used to implement
a fully combinational circuit, a multiplexer might be inferred
instead. Therefore, after optimization, a circuit synthesized from a
VHDL code based on IF not to differ from that based on CASE.
--Codes below implement same physical multiplexer circuit.
---- With IF: --------------
IF (sel="00") THEN x<=a;
ELSIF (sel="01") THEN x<=b;
ELSIF (sel="10") THEN x<=c;
ELSE x<=d;
---- With CASE: ------------
CASE sel IS
WHEN "00" => x<=a;
WHEN "01" => x<=b;
WHEN "10" => x<=c;
WHEN OTHERS => x<=d;
END CASE;
CASE versus WHEN
CASE and WHEN are very similar. However, while one is
concurrent (WHEN), the other is sequential (CASE). Their main
similarities and differences are summarized in table:
CASE versus WHEN
--From a functional point of view, the two codes
--below are equivalent.
---- With WHEN: ----------------
WITH sel SELECT
x <= a WHEN "000",
b WHEN "001",
c WHEN "010",
UNAFFECTED WHEN OTHERS;
---- With CASE: ----------------
CASE sel IS
WHEN "000" => x<=a;
WHEN "001" => x<=b;
WHEN "010" => x<=c;
WHEN OTHERS => NULL;
END CASE;
--------------------------------
Example 8: RAM
example below shows the implementation of a RAM (random
access memory), the circuit has a data input bus (data_in), a
data output bus (data_out), an address bus (addr), plus clock
(clk) and write enable (wr_ena) pins.

Simulation results:
Example 8: RAM
ENTITY ram IS
GENERIC ( bits: INTEGER := 8; -- # of bits per word
words: INTEGER:= 16); -- # of words in the memory
PORT ( wr_ena, clk:IN STD_LOGIC;
addr:IN INTEGER RANGE 0 TO words-1;
data_in:IN STD_LOGIC_VECTOR (bits-1 DOWNTO 0);
data_out:OUT STD_LOGIC_VECTOR (bits-1 DOWNTO 0));
END ram;
---------------------------------------------------
ARCHITECTURE ram OF ram IS
TYPEv_aryISARRAY(0TOwords-1)OFSTD_LOGIC_VECTOR(bits-1DOWNTO0);
SIGNAL memory: v_ary;
BEGIN
PROCESS (clk, wr_ena)
BEGIN
IF (wr_ena='1') THEN
IF(clk'EVENT AND clk='1')THEN memory(addr) <= data_in;
END IF;
END IF;
END PROCESS;
data_out <= memory(addr);
END ram;
Using Sequential Code to Design
Combinational Circuits
The sequential code can be used to implement either
sequential or combinational circuits. the following rules should
be observed:

Rule 1: Make sure that all input signals used (read) in the
PROCESS appear in its sensitivity list.
Rule 2: Make sure that all combinations of the input/output
signals are included in the code; that is, make sure that,
by looking at the code, the circuit’s complete truth-table
can be obtained (indeed, this is true for both sequential
as well as concurrent code).
Example 9: Bad Combinational Design
ENTITY example IS
PORT (a, b, c, d: IN STD_LOGIC;
sel: IN INTEGER RANGE 0 TO 3;
x, y: OUT STD_LOGIC);
END example;
--------------------------------------
ARCHITECTURE example OF example IS
BEGIN
PROCESS (a, b, c, d, sel)
BEGIN
IF (sel=0) THEN x<=a; y<='0';
ELSIF (sel=1) THEN x<=b; y<='1';
ELSIF (sel=2) THEN x<=c;
ELSE x<=d;
END IF;
END PROCESS;
END example;
Example 9: Bad Combinational Design
After compiling, the report files show that no flip-flops were
inferred (as expected). but, when we look at the simulation
results :

we notice something peculiar about y. Observe that, for the


same value of the input (sel = ‘‘11’’), two different results are
obtained for y). To avoid the extra logic required by the latch,
the specifications of should be used (‘X’ should be used for all
unknown or ‘‘don’t care’’ values). Thus the line y<='X'; must be
included after the indicated lines.
Home work:
Use WHEN to design a 3-state buffer of figure below
output=input when ena (enable) is low, or output = ‘‘ZZZZZZZZ’’
(high impedance) otherwise.
QUESTIONS?

You might also like