|
| 1 | +# Variables and Blocking |
| 2 | +## VHDL Variables |
| 3 | +VHDL is my favorite HDL because, despite how clumsy it can be, there are some very nice tricks you |
| 4 | +can use which have no Verilog/SystemVerilog equivalent. One of these is variables. |
| 5 | + |
| 6 | +Consider the following example: |
| 7 | +```vhdl |
| 8 | +process (clk) begin |
| 9 | + if rising_edge(clk) then |
| 10 | + if sel0 = '1' then |
| 11 | + x <= (a + b) + c; |
| 12 | + else |
| 13 | + x <= (a + b) - c; |
| 14 | + end if; |
| 15 | + end if; |
| 16 | +end process; |
| 17 | +``` |
| 18 | + |
| 19 | +We can see here that the expression (a + b) is used in both cases in both the if and else cases. |
| 20 | +It would be nice if we could write this without and code duplication. |
| 21 | + |
| 22 | +```vhdl |
| 23 | +a_plus_b <= a + b; |
| 24 | +
|
| 25 | +-- A bunch of code here... |
| 26 | +
|
| 27 | +process (clk) begin |
| 28 | + if rising_edge(clk) then |
| 29 | + if sel0 = '1' then |
| 30 | + x <= a_plus_b + c; |
| 31 | + else |
| 32 | + x <= a_plus_b - c; |
| 33 | + end if; |
| 34 | + end if; |
| 35 | +end process; |
| 36 | +``` |
| 37 | + |
| 38 | +This is better. However, we have now separated the expression (a + b) from the code block dependent |
| 39 | +on it. In this case it does not matter all that much because a_plus_b makes it very clear what |
| 40 | +the expression is, but there are a lot of other cases where we might have a more complicated |
| 41 | +expression that is not easily described by a signal name. |
| 42 | + |
| 43 | +```vhdl |
| 44 | +process (a, b) begin |
| 45 | + if sel1 = '1' then |
| 46 | + complex_logic <= a << 1; |
| 47 | + else |
| 48 | + complex_logic <= b >> 1; |
| 49 | + end if; |
| 50 | +end process; |
| 51 | +
|
| 52 | +-- A bunch of code here... |
| 53 | +
|
| 54 | +process (clk) begin |
| 55 | + if rising_edge(clk) then |
| 56 | + if sel0 = '1' then |
| 57 | + x <= complex_logic + c; |
| 58 | + else |
| 59 | + x <= complex_logic - c; |
| 60 | + end if; |
| 61 | + end if; |
| 62 | +end process; |
| 63 | +``` |
| 64 | + |
| 65 | +Now this becomes problematic. It is not clear what complex_logic is unless we actually look at where |
| 66 | +is assigned. This is where variables are useful. |
| 67 | + |
| 68 | +```vhdl |
| 69 | +process (clk) |
| 70 | + variable complex_logic : std_logic_vector(7 downto 0); |
| 71 | + begin |
| 72 | + if rising_edge(clk) then |
| 73 | + if sel1 = '1' then |
| 74 | + complex_logic := a << 1; |
| 75 | + else |
| 76 | + complex_logic := b >> 1; |
| 77 | + end if; |
| 78 | +
|
| 79 | + if sel0 = '1' then |
| 80 | + x <= complex_logic + c; |
| 81 | + else |
| 82 | + x <= complex_logic - c; |
| 83 | + end if; |
| 84 | + end if; |
| 85 | +end process; |
| 86 | +``` |
| 87 | + |
| 88 | +Using a variable complex_logic, we've eliminated the need for an extra process. |
| 89 | + |
| 90 | +### Signals vs. Variables |
| 91 | +But wait! Shouldn't the value of complex_logic be updated when the process has finished execution |
| 92 | +like any other signal assigned in a process? The answer is no: unlike signals, variables are always |
| 93 | +*updated at assignment* rather than at the end of process execution. There a few consequences of |
| 94 | +this behavior: |
| 95 | +* **Variables are always treated as the outputs of combinational logic, even when they are in a |
| 96 | +sequential block.** Combinational outputs are always a pure function of their inputs. That is, their |
| 97 | +values always reflect the values of their inputs at that moment, and thus, they are state-less. |
| 98 | +Because variables are updated at assignment rather than at a clock edge (or some other synchronous |
| 99 | +event), they too always reflect the values of their inputs at that moment. |
| 100 | + |
| 101 | +* **The scope of a variable is always limited to the process it is declared in.** If a signal x is |
| 102 | +assigned in a clocked process, then x is by definition a direct output of a flip-flop, since its |
| 103 | +value is only updated on a rising clock edge. But what about variables such as complex_logic? It is |
| 104 | +clearly assigned in a clocked process, yet we stated above that we can treat it as an output of |
| 105 | +combinational logic. In order to resolve this contradiction, the designers of VHDL chose to [only |
| 106 | +allow variables to be declared in processes, function, and |
| 107 | +procedures.](http://www.ics.uci.edu/~jmoorkan/vhdlref/var_dec.html) Since variables cannot be |
| 108 | +referenced outside of a process, it prevents the unwitting developer from mistakenly using it as the |
| 109 | +output of a flip-flop. This is contrary to blocking assignment in Verilog/SystemVerilog. More on |
| 110 | +this below. |
| 111 | + |
| 112 | +## Blocking Assignment in Verilog/SystemVerilog |
| 113 | +If you are a Verilog/SystemVerilog developer, you may have been upset by the fact that I stated that |
| 114 | +Verilog/SystemVerilog has no equivalent to VHDL variables. "Just use blocking (=) assignment!" you |
| 115 | +might say. However, blocking assignment is not equivalent to a variable, and is, in fact, much more |
| 116 | +dangerous to use. |
| 117 | + |
| 118 | +Let's consider the example above, implemented in SystemVerilog. |
| 119 | +TODO: switch to systemverilog syntax |
| 120 | +```verilog |
| 121 | +always_ff @(posedge clk) begin |
| 122 | + if sel1 begin |
| 123 | + complex_logic = a << 1; |
| 124 | + end else begin |
| 125 | + complex_logic = b >> 1; |
| 126 | + end |
| 127 | +
|
| 128 | + if sel0 begin |
| 129 | + x <= complex_logic + c; |
| 130 | + end else begin |
| 131 | + x <= complex_logic - c; |
| 132 | + end |
| 133 | +end |
| 134 | +``` |
| 135 | + |
| 136 | +It works! All we have to do is substitute the variable complex_logic with blocking assignments, |
| 137 | +and we get the same behavior. However, there is a slight problem. Remember when we said that a |
| 138 | +VHDL variable cannot be referenced outside of a process to avoid being interpreted as both an |
| 139 | +output of combinational logic and an output of a flip-flop? That is not true for blocking assignment |
| 140 | +in Verilog/SystemVerilog. If a signal is referenced below the blocking assignment, inside of the |
| 141 | +same sequential block, it is interpreted as an output of combinational logic just as a VHDL variable |
| 142 | +would. However, if it is referenced above the blocking assignment, or outside of the sequential |
| 143 | +block containing the blocking assignment, it is interpreted as the output of a flip-flop. This |
| 144 | +effectively means that there are two signals with the same name: one is the output of combinational |
| 145 | +logic, and the other is the output of a flip-flop that is fed by the same combinational logic. With |
| 146 | +blocking assignment, where we reference a signal matters. This is misleading, and thus should be |
| 147 | +avoided at all costs. |
| 148 | + |
| 149 | +```verilog |
| 150 | +always_ff @(posedge clk) begin |
| 151 | + if sel1 begin |
| 152 | + complex_logic = a << 1; |
| 153 | + end else begin |
| 154 | + complex_logic = b >> 1; |
| 155 | + end |
| 156 | +
|
| 157 | + if sel0 begin |
| 158 | + x <= complex_logic + c; // complex_logic is combinational here. |
| 159 | + end else begin |
| 160 | + x <= complex_logic - c; |
| 161 | + end |
| 162 | +end |
| 163 | +
|
| 164 | +always_ff @(posedge clk) begin |
| 165 | + if sel0 begin |
| 166 | + y <= complex_logic + c; // complex_logic is the output of a flip-flop here. |
| 167 | + end else begin |
| 168 | + y <= complex_logic - c; |
| 169 | + end |
| 170 | +end |
| 171 | +``` |
| 172 | + |
| 173 | +## References |
| 174 | +* [VHDL variables](http://www.ics.uci.edu/~jmoorkan/vhdlref/var_dec.html) |
0 commit comments