ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 13.06.2025

Просмотров: 3485

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

6Sequential Code

As mentioned in chapter 5, VHDL code is inherently concurrent. PROCESSES, FUNCTIONS, and PROCEDURES are the only sections of code that are executed sequentially. However, as a whole, any of these blocks is still concurrent with any other statements placed outside it.

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 section 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, so its value can not be passed out directly.

We will concentrate on PROCESSES here. FUNCTIONS and PROCEDURES are very similar, but are intended for system-level design, being therefore seen in Part II of this book.

6.1PROCESS

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];

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 (appendix E).

TLFeBOOK

92

Chapter 6

d

q

DFF

clk

rst

Figure 6.1

DFF with asynchronous reset of example 6.1.

Figure 6.2

Simulation results of example 6.1.

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 (seen in section 4.2). 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 6.1: DFF with Asynchronous Reset #1

A D-type flip-flop (DFF, figure 6.1) 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 (discussed in section 6.3) to design a DFF with asynchronous reset. If rst ¼ ‘1’, then the output must be q ¼ ‘0’ (lines 14–15), regardless of the status of clk. Otherwise, the output must copy the input (that is, q ¼ d) at the positive edge of clk (lines 16–17). The EVENT attribute is used in line 16 to detect a clock transition. The PROCESS (lines 12–19) is run every time any of the signals that appear in its sensitivity list (clk and rst, line 12) changes. Simulation results, confirming the functionality of the synthesized circuit, are presented in figure 6.2.

TLFeBOOK


Sequential Code

93

1 --------------------------------------

2LIBRARY ieee;

3 USE ieee.std_logic_1164.all;

4 --------------------------------------

5ENTITY dff IS

6PORT (d, clk, rst: IN STD_LOGIC;

7

q: OUT STD_LOGIC);

8

END dff;

9

--------------------------------------

10

ARCHITECTURE behavior OF dff IS

11BEGIN

12PROCESS (clk, rst)

13BEGIN

14IF (rst='1') THEN

15q <= '0';

16ELSIF (clk'EVENT AND clk='1') THEN

17q <= d;

18END IF;

19END PROCESS;

20END behavior;

21 --------------------------------------

6.2Signals and Variables

Signals and variables will be studied in detail in the next chapter. However, it is impossible to discuss sequential code without knowing at least their most basic characteristics.

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), for its new value is generally only guaranteed to be available after the conclusion of the present run of the PROCESS.

TLFeBOOK

94

Chapter 6

Finally, recall from section 4.1 that the assignment operator for a SIGNAL is ‘‘<¼’’ (ex.: sig <¼ 5), while for a VARIABLE it is ‘‘:¼’’ (ex.: var :¼ 5).

6.3 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 (because the IF/ELSE statement might infer the construction of an unnecessary priority decoder), 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 6.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 6.3. It contains a single-bit input

C

O

U

clk N digit (3:0)

T

E

R

Figure 6.3

Counter of example 6.2.

TLFeBOOK


Sequential Code

95

Figure 6.4

Simulation results of example 6.2.

(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, are shown in figure 6.4.

1 ---------------------------------------------

2LIBRARY ieee;

3 USE ieee.std_logic_1164.all;

4 ---------------------------------------------

5ENTITY counter IS

6PORT (clk : IN STD_LOGIC;

7

digit : OUT INTEGER RANGE 0 TO 9);

8

END counter;

9

---------------------------------------------

10 ARCHITECTURE

counter OF counter IS

11BEGIN

12count: PROCESS(clk)

13VARIABLE temp : INTEGER RANGE 0 TO 10;

14BEGIN

15IF (clk'EVENT AND clk='1') THEN

16temp := temp + 1;

17IF (temp=10) THEN temp := 0;

18END IF;

19END IF;

20digit <= temp;

21END PROCESS count;

22END counter;

23 ---------------------------------------------

Comment: Note that the code above has neither a reset input nor any internal initialization scheme for temp (and digit, consequently). Therefore, the initial value of

TLFeBOOK

96

Chapter 6

temp in the physical circuit can be any 4-bit value. If such value is below 10 (see line 17), the circuit will count correctly from there. On the other hand, if the value is above 10, a number of clock cycles will be used until temp reaches full count (that is, 15, or ‘‘1111’’), being thus automatically reset to zero, from where the correct operation then starts. The possibility of wasting a few clock cycles in the beginning is generally not a problem. Still, if one does want to avoid that, temp ¼ 10, in line 17, can be changed to temp ¼> 10, but this will increase the hardware. However, if starting exactly from 0 is always necessary, then a reset input should be included (as in example 6.7).

Notice in the code above that we increment temp and compare it to 10, with the purpose of resetting temp once 10 is reached. This is a typical approach used in counters. Notice that 10 is a constant, so a comparator to a constant is inferred by the compiler, which is a relatively simple circuit to construct. However, if instead of a constant we were using a programmable parameter, then a full comparator would need to be implemented, which requires substantially more logic than a comparator to a constant. In this case, a better solution would be to load temp with such a parameter, and then decrement it, reloading temp when the 0 value is reached. In this case, our comparator would compare temp to 0 (a constant), thus avoiding the generation of a full comparator.

Example 6.3: Shift Register

Figure 6.5 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.

1 --------------------------------------------------

2LIBRARY ieee;

3USE ieee.std_logic_1164.all;

4--------------------------------------------------

d

DFF

DFF

DFF

DFF

q

clk rst

Figure 6.5

Shift register of example 6.3.

TLFeBOOK


Sequential Code

97

5ENTITY shiftreg IS

6

GENERIC (n: INTEGER := 4);

-- # of stages

7PORT (d, clk, rst: IN STD_LOGIC;

8

q: OUT STD_LOGIC);

9

END shiftreg;

10

--------------------------------------------------

11

ARCHITECTURE behavior OF shiftreg IS

12SIGNAL internal: STD_LOGIC_VECTOR (n-1 DOWNTO 0);

13BEGIN

14PROCESS (clk, rst)

15BEGIN

16IF (rst='1') THEN

17internal <= (OTHERS => '0');

18ELSIF (clk'EVENT AND clk='1') THEN

19internal <= d & internal(internal'LEFT DOWNTO 1);

20END IF;

21END PROCESS;

22q <= internal(0);

23END behavior;

24 --------------------------------------------------

Simulation results are shown in figure 6.6. As can be seen, q is indeed four positive clock edges behind d.

6.4WAIT

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

Figure 6.6

Simulation results of example 6.3.

TLFeBOOK

98

Chapter 6

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;

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.

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

TLFeBOOK


Sequential Code

99

output <= "00000000";

ELSIF (clk'EVENT AND clk='1') THEN output <= input;

END IF;

END PROCESS;

Finally, WAIT FOR is intended for simulation only (waveform generation for testbenches). Example: WAIT FOR 5ns;

Example 6.4: DFF with Asynchronous Reset #2

The code below implements the same DFF of example 6.1 (figures 6.1 and 6.2). However, here WAIT ON is used instead of IF only.

1 --------------------------------------

2LIBRARY ieee;

3 USE ieee.std_logic_1164.all;

4 --------------------------------------

5ENTITY dff IS

6PORT (d, clk, rst: IN STD_LOGIC;

7

q: OUT STD_LOGIC);

8

END dff;

9

--------------------------------------

10

ARCHITECTURE dff OF dff IS

11BEGIN

12PROCESS

13BEGIN

14WAIT ON rst, clk;

15IF (rst='1') THEN

16q <= '0';

17ELSIF (clk'EVENT AND clk='1') THEN

18q <= d;

19END IF;

20END PROCESS;

21END dff;

22 --------------------------------------

Example 6.5: One-digit Counter #2

The code below implements the same progressive 1-digit decimal counter of example 6.2 (figures 6.3 and 6.4). However, WAIT UNTIL was used instead of IF only.

TLFeBOOK

100

Chapter 6

1 ---------------------------------------------

2LIBRARY ieee;

3 USE ieee.std_logic_1164.all;

4 ---------------------------------------------

5ENTITY counter IS

6PORT (clk : IN STD_LOGIC;

7

digit : OUT INTEGER RANGE 0 TO 9);

8

END counter;

9

---------------------------------------------

10

ARCHITECTURE counter OF counter IS

11

BEGIN

12

PROCESS

-- no sensitivity list

13VARIABLE temp : INTEGER RANGE 0 TO 10;

14BEGIN

15WAIT UNTIL (clk'EVENT AND clk='1');

16temp := temp + 1;

17IF (temp=10) THEN temp := 0;

18END IF;

19digit <= temp;

20END PROCESS;

21END counter;

22 ---------------------------------------------

6.5CASE

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;

TLFeBOOK