Electronic – VHDL Concurrent statement comparison

vhdl

I am learning VHDL and came across this example of 2 functionally equivalent ways of implementing the same thing. But I am having trouble understanding how they are functionally equivalent.

My confusion is in the 3 concurrent statement picture. Since they are all executed at the same time that means that F3 gets set to (A1 or A2). But since A1 and A2 are getting set at the same time that F3 is getting set, doesn't that mean A1 and A2 do not actually have values yet when F3 tries to get assigned to (A1 or A2)?

Thanks

1 concurrent statement

3 concurrent statements

Best Answer

There's a lot of technical details to simulation and instantiation. But I'd like to avoid the algebraic approaches and just focus on the visual aspects for a moment. It may help. (You've avoided variables, but I may decide to address them for a moment below.)

It's probably better if you think of a signal as the same thing as a named wire. So when you write the following within a begin..end block:

A1 <= ((NOT L) AND (NOT M) AND N);
A2 <= L and M;
F3 <= A1 or A2;

All it is doing is the following:

schematic

simulate this circuit – Schematic created using CircuitLab

Note that the order of the statements don't matter. They could be arranged in any permutation you wanted. The same schematic results from those three statements, regardless of order.

Your signal names are just wires with names. That's all. The only difference between the above and what results from:

F3 <= ((NOT L) AND (NOT M) AND N) or (L and M);

is:

schematic

simulate this circuit

In other words, two named wires are no longer named. That's all that happens. Since naming is a matter of convenience for humans, not for circuits, it makes no difference in the combinatorial result.

Now, there is a difference with VHDL variables. If you are familiar with C, it's perhaps better to see a variable as if it were the equivalent of a C #define and not as a physical wire in a schematic.

For example, if A1 and A2 were variables instead of signals, then:

A1 := ((NOT L) AND (NOT M) AND N);
A2 := L and M;
F3 <= A1 or A2;

Would produce the same logic as in the second schematic above, except perhaps the following might be a better way of seeing it:

schematic

simulate this circuit

No wires are really named A1 or A2. Instead, the expressions for A1 and A2 were, in effect, inserted into the wire-assignment for F3. (You could still label those wires, mentally. But it's better to imagine they aren't named at all, but instead just used to replace the symbols in the final line where the wire F3 is assigned.)

There are some subtle and not-so-subtle results from this difference.

In VHDL gate-level logic, you can add an after clause to a signal assignment. But you cannot do that with a variable. That's because a variable isn't a wire representing the output of some logic. It really is more like the C language's #define.

So you can write:

A1 <= ((NOT L) AND (NOT M) AND N) after 3 ns;
A2 <= L and M after 1 ns;
F3 <= A1 or A2 after 2 ns;

And this will affect simulation (but not instantiation.)

But, if A1 and A2 were variables, you cannot write:

A1 := ((NOT L) AND (NOT M) AND N) after 3 ns;    -- error!
A2 := L and M after 1 ns;                        -- error!
F3 <= A1 or A2 after 2 ns;

Variables cannot have delays like that. The above would be an error. This is because the variables replace their mnemonics found in wire assignments (the <= lines.) Variables are not wires. (Besides, the very idea of subexpressions with after clauses together with a final after clause on that wire assignment line would be quite confusing!)

Where all this actually gets interesting is in sequential logic (RTL) where you are indicating sensitivity to a std_logic signal's clock edge. Then the differences in variables and signal wires becomes far more interesting.

Assuming A1 and A2 are variables:

if rising_edge(CLK) then
    A1 := ((NOT L) AND (NOT M) AND N);
    A2 := L and M;
    F3 <= A1 or A2;
end if;

You get this (where only F3 depends on the rising edge of CLK (std_logic type), as A1 and A2 are more like "macros" representing some logic but not actual wires):

schematic

simulate this circuit

A variable represents a block of logic and not a wire. It is meaningless to imagine that the block is sensitive to an edge of CLK. Only signal wires can be. When a wire is placed within an if..end that depends upon a rising or falling edge of some other std_logic wire, this infers an FF. As a variable isn't a wire, an FF cannot be inferred for a variable.

That is very much different from the following case where A1 and A2 are signals/wires (which do depend upon the rising edge of CLK):

if rising_edge(CLK) then
    A1 <= ((NOT L) AND (NOT M) AND N);
    A2 <= L and M;
    F3 <= A1 or A2;
end if;

When you instead get:

schematic

simulate this circuit

Hopefully, that helps a little.