ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.06.2025
Просмотров: 3489
Скачиваний: 2
TLFeBOOK
7 Signals and Variables
VHDL provides two objects for dealing with non-static data values: SIGNAL and VARIABLE. It also provides means for establishing default (static) values: CONSTANT and GENERIC. The last of these (the GENERIC attribute) was already seen in chapter 4. SIGNAL, VARIABLE, and CONSTANT will be studied together in this chapter.
CONSTANT and SIGNAL can be global (that is, seen by the whole code), and can be used in either type of code, concurrent or sequential. A VARIABLE, on the other hand, is local, for it can only be used inside a piece of sequential code (that is, in a PROCESS, FUNCTION, or PROCEDURE) and its value can never be passed out directly.
As will become apparent, the choice between a SIGNAL or a VARIABLE is not always easy, so an entire section and several examples will be devoted to the matter. Moreover, a discussion on the number of registers inferred by the compiler, based on SIGNAL and VARIABLE assignments, will also be presented.
7.1CONSTANT
CONSTANT serves to establish default values. Its syntax is shown below.
CONSTANT name : type := value;
Examples:
CONSTANT set_bit : BIT := '1';
CONSTANT datamemory : memory := (('0','0','0','0'),
('0','0','0','1'),
('0','0','1','1'));
A CONSTANT can be declared in a PACKAGE, ENTITY, or ARCHITECTURE. When declared in a package, it is truly global, for the package can be used by several entities. When declared in an entity (after PORT), it is global to all architectures that follow that entity. Finally, when declared in an architecture (in its declarative part), it is global only to that architecture’s code. The most common places to find a CONSTANT declaration is in an ARCHITECTURE or in a PACKAGE.
TLFeBOOK
130 |
Chapter 7 |
7.2SIGNAL
SIGNAL serves to pass values in and out the circuit, as well as between its internal units. In other words, a signal represents circuit interconnects (wires). For instance, all PORTS of an ENTITY are signals by default. Its syntax is the following:
SIGNAL name : type [range] [:= initial_value];
Examples:
SIGNAL control: BIT := '0';
SIGNAL count: INTEGER RANGE 0 TO 100;
SIGNAL y: STD_LOGIC_VECTOR (7 DOWNTO 0);
The declaration of a SIGNAL can be made in the same places as the declaration of a CONSTANT (described above).
A very important aspect of a SIGNAL, when used inside a section of sequential code (PROCESS, for example), is that its update is not immediate. In other words, its new value should not be expected to be ready before the conclusion of the corresponding PROCESS, FUNCTION or PROCEDURE.
Recall that the assignment operator for a SIGNAL is ‘‘<=’’ (Ex.: count<=35;). Also, the initial value in the syntax above is not synthesizable, being only considered in simulations.
Another aspect that might a¤ect the result is when multiple assignments are made to the same SIGNAL. The compiler might complain and quit synthesis, or might infer the wrong circuit (by considering only the last assignment, for example). Therefore, establishing initial values, like in line 15 of the example below, should be done with a VARIABLE.
Example 7.1: Count Ones #1 (not OK)
Say that we want to design a circuit that counts the number of ‘1’s in a binary vector (problem 6.9). Let us consider the solution below, which uses only signals. This code has multiple assignments to the same signal, temp, in lines 15 (once) and 18 (eight times). Moreover, since the value of a signal is not updated immediately, line 18 conflicts with line 15, for the value assigned in line 15 might not be ready until the conclusion of the PROCESS, in which case a wrong value would be computed in line 18. In this kind of situation, the use of a VARIABLE is recommended (example 7.2).
TLFeBOOK
Signals and Variables |
131 |
1 ---------------------------------------
2LIBRARY ieee;
3 USE ieee.std_logic_1164.all;
4 ---------------------------------------
5ENTITY count_ones IS
6PORT ( din: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
7 |
ones: OUT INTEGER RANGE 0 TO 8); |
8 |
END count_ones; |
9 |
--------------------------------------- |
10 |
ARCHITECTURE not_ok OF count_ones IS |
11SIGNAL temp: INTEGER RANGE 0 TO 8;
12BEGIN
13PROCESS (din)
14BEGIN
15temp <= 0;
16FOR i IN 0 TO 7 LOOP
17IF (din(i)='1') THEN
18temp <= temp + 1;
19END IF;
20END LOOP;
21ones <= temp;
22END PROCESS;
23END not_ok;
24 ---------------------------------------
Notice also in the solution above that the internal signal temp (line 11) seems unnecessary, because ones could have been used directly. However, to do so, the mode of ones would need to be changed from OUT to BUFFER (line 7), because ones is assigned a value and is also read (used) internally. Nevertheless, since ones is a genuine unidirectional (OUT) signal, the use of an auxiliary signal (temp) is an adequate design practice.
7.3VARIABLE
Contrary to CONSTANT and SIGNAL, a VARIABLE represents only local information. It can only be used inside a PROCESS, FUNCTION, or PROCEDURE (that is, in sequential code), and its value can not be passed out directly. On the other hand, its update is immediate, so the new value can be promptly used in the next line of code.
TLFeBOOK
132 |
Chapter 7 |
To declare a VARIABLE, the following syntax should be used:
VARIABLE name : type [range] [:= init_value];
Examples:
VARIABLE control: BIT := '0';
VARIABLE count: INTEGER RANGE 0 TO 100;
VARIABLE y: STD_LOGIC_VECTOR (7 DOWNTO 0) := "10001000";
Since a VARIABLE can only be used in sequential code, its declaration can only be done in the declarative part of a PROCESS, FUNCTION, or PROCEDURE.
Recall that the assignment operator for a VARIABLE is ‘‘:=’’ (Ex.: count:=35;). Also, like in the case of a SIGNAL, the initial value in the syntax above is not synthesizable, being only considered in simulations.
Example 7.2: Count Ones #2 (OK)
Let us consider the problem of example 7.1 once again. The only di¤erence in the solution below is that an internal VARIABLE is employed instead of a SIGNAL. Since the update of a variable is immediate, the initial value is established correctly and no complains regarding multiple assignments will be issued by the compiler. Simulation results can be verified in figure 7.1.
1 ---------------------------------------
2LIBRARY ieee;
3USE ieee.std_logic_1164.all;
4 ---------------------------------------
5ENTITY count_ones IS
6PORT ( din: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
7ones: OUT INTEGER RANGE 0 TO 8);
Figure 7.1
Simulation results of example 7.2.
TLFeBOOK
Signals and Variables |
133 |
8 END count_ones;
9 ---------------------------------------
10 ARCHITECTURE ok OF count_ones IS
11BEGIN
12PROCESS (din)
13VARIABLE temp: INTEGER RANGE 0 TO 8;
14BEGIN
15temp := 0;
16FOR i IN 0 TO 7 LOOP
17IF (din(i)='1') THEN
18temp := temp + 1;
19END IF;
20END LOOP;
21ones <= temp;
22END PROCESS;
23END ok;
24 ---------------------------------------
7.4SIGNAL versus VARIABLE
As already mentioned, choosing between a SIGNAL or a VARIABLE is not always straightforward. Their main di¤erences are summarized in table 7.1.
Table 7.1
Comparison between SIGNAL and VARIABLE.
SIGNAL |
VARIABLE |
|
Assignment |
<¼ |
:¼ |
Utility |
Represents circuit interconnects (wires) |
Represents local information |
Scope |
Can be global (seen by entire code) |
Local (visible only inside the |
corresponding PROCESS, FUNCTION, |
||
or PROCEDURE) |
||
Behavior |
Update is not immediate in sequential |
Updated immediately (new value can be |
code (new value generally only available |
used in the next line of code) |
|
at the conclusion of the PROCESS, |
||
FUNCTION, or PROCEDURE) |
||
Usage |
In a PACKAGE, ENTITY, or |
Only in sequential code, that is, in a |
ARCHITECTURE. In an ENTITY, all |
PROCESS, FUNCTION, or |
|
PORTS are SIGNALS by default |
PROCEDURE |
|
TLFeBOOK
134 |
Chapter 7 |
a
b
MUX y
c
d
sel (1:0)
Figure 7.2
Multiplexer of example 7.3.
We want to stress again that an assignment to a VARIABLE is immediate, but that is not the case with a SIGNAL. In general, the new value of a SIGNAL will only be available at the conclusion of the current run of the corresponding PROCESS. Though this might not be always the case, it is a safe practice to consider it so. The examples presented below will further illustrate this and other di¤erences between SIGNALS and VARIABLES.
Example 7.3: Bad versus Good Multiplexer
In this example, we will implement the same multiplexer of example 5.2 (repeated in figure 7.2). This is, indeed, a classical example regarding the choice of a SIGNAL versus a VARIABLE.
1 -- Solution 1: using a SIGNAL (not ok) --
2LIBRARY ieee;
3USE ieee.std_logic_1164.all;
4 -----------------------------------------
5ENTITY mux IS
6PORT ( a, b, c, d, s0, s1: IN STD_LOGIC;
7 |
y: OUT STD_LOGIC); |
8END mux;
9 -----------------------------------------
10 ARCHITECTURE not_ok OF mux IS
11SIGNAL sel : INTEGER RANGE 0 TO 3;
12BEGIN
13PROCESS (a, b, c, d, s0, s1)
14BEGIN
15sel <= 0;
16IF (s0='1') THEN sel <= sel + 1;
TLFeBOOK
Signals and Variables |
135 |
17END IF;
18IF (s1='1') THEN sel <= sel + 2;
19END IF;
20CASE sel IS
21WHEN 0 => y<=a;
22WHEN 1 => y<=b;
23WHEN 2 => y<=c;
24WHEN 3 => y<=d;
25END CASE;
26END PROCESS;
27END not_ok;
28 -----------------------------------------
1 -- Solution 2: using a VARIABLE (ok) ----
2LIBRARY ieee;
3 USE ieee.std_logic_1164.all;
4 -----------------------------------------
5ENTITY mux IS
6PORT ( a, b, c, d, s0, s1: IN STD_LOGIC;
7 |
y: OUT STD_LOGIC); |
8 |
END mux; |
9 |
----------------------------------------- |
10 |
ARCHITECTURE ok OF mux IS |
11BEGIN
12PROCESS (a, b, c, d, s0, s1)
13VARIABLE sel : INTEGER RANGE 0 TO 3;
14BEGIN
15sel := 0;
16IF (s0='1') THEN sel := sel + 1;
17END IF;
18IF (s1='1') THEN sel := sel + 2;
19END IF;
20CASE sel IS
21WHEN 0 => y<=a;
22WHEN 1 => y<=b;
23WHEN 2 => y<=c;
24WHEN 3 => y<=d;
25END CASE;
TLFeBOOK
136 |
Chapter 7 |
26END PROCESS;
27END ok;
28---------------------------------------
Comments:
A common mistake when using a SIGNAL is not to remember that it might require a certain amount of time to be updated. Therefore, the assignment sel <¼ sel þ 1 in the first solution (line 16) will result in one plus whatever value had been previously propagated to sel, for the assignment sel <¼ 0 (line 15) might not have had time to propagate yet. The same is true for sel <¼ sel þ 2 (line 18). This is not a problem when using a VARIABLE, for its assignment is always immediate.
A second aspect that might be a problem in solution 1 is that more than one assignment is being made to the same SIGNAL (sel, lines 15, 16, and 18), which might not be acceptable. Generally, only one assignment to a SIGNAL is allowed within a PROCESS, so the software will either consider only the last one (sel <¼ sel þ 2 in solution 1) or simply issue an error message and stop compilation. Again, this is never a problem when using a VARIABLE.
Figure 7.3
Simulation results of example 7.3.
TLFeBOOK
Signals and Variables |
137 |
Simulation results from both solutions are shown in figure 7.3 (bad mux in the upper graph, good mux in the lower graph). As can be seen, only solution 2 works properly.
Example 7.4: DFF with q and qbar #1
We want to implement the DFF of figure 7.4. This circuit di¤ers from that of example 6.1 by the absence of reset and the inclusion of qbar. The presence of qbar will help understand how an assignment to a SIGNAL is made (recall that a PORT is a SIGNAL by default).
1 ---- Solution 1: not OK ---------------
2LIBRARY ieee;
3 USE ieee.std_logic_1164.all;
4 ---------------------------------------
5ENTITY dff IS
6PORT ( d, clk: IN STD_LOGIC;
7q: BUFFER STD_LOGIC;
8 |
qbar: OUT STD_LOGIC); |
9 |
END dff; |
10 |
--------------------------------------- |
11 |
ARCHITECTURE not_ok OF dff IS |
12BEGIN
13PROCESS (clk)
14BEGIN
15IF (clk'EVENT AND clk='1') THEN
16q <= d;
17qbar <= NOT q;
18END IF;
19END PROCESS;
20END not_ok;
21 ---------------------------------------
d |
DFF |
q |
|||
clk |
qbar |
||||
Figure 7.4
DFF of example 7.4.
TLFeBOOK