Procedures and array element assigment from different processes.
Dear all,
I am surprised by the behaviour of the following code where I try to
assign (different) elements of an array from different processes. When
doing so with a procedure, it does not work as expected. Can somebody
explain me why?
Thanks a lot.
Seb.
=====
library ieee;
use ieee.std_logic_1164.all;
entity vector_splicing is
end vector_splicing;
architecture one of vector_splicing is
signal ok, still_ok, not_ok : std_logic_vector(1 downto 0);
signal clk : std_logic := '1';
procedure assign(signal d: inout std_logic_vector; i: in integer;
v: in std_logic) is
begin
d(i) <= v;
end assign;
begin
clk <= not clk after 5 ns;
process( clk )
begin
if rising_edge( clk ) then
ok(0) <= '0';
assign(still_ok, 0, '0');
assign(still_ok, 1, '1');
assign(not_ok, 0, '0');
end if;
end process;
process( clk )
begin
if rising_edge( clk ) then
ok(1) <= '1';
assign(not_ok, 1, '1');
end if;
end process;
Re: Procedures and array element assigment from different processes.
Seb wrote:
> I am surprised by the behaviour of the following code where I try to
> assign (different) elements of an array from different processes. When
> doing so with a procedure, it does not work as expected. Can somebody
> explain me why?
Your processes are both writing to the same signals.
This "shorts" the outputs together.
Consider a single process.
I don't know what you expected, but to
splice vectors consider
big_vec <= this_vec & this_bit & another_vec;
Re: Procedures and array element assigment from different processes.
Hi Mike,
Mike Treseler wrote:
> Your processes are both writing to the same signals.
Yes, but to differents elements of the array!
> I don't know what you expected,
I expeced the signals "ok", "still_ok" and "not_ok" to give the same
results. They all try to achieve the same thing: assign a value to an
element of a vector.
In the first case, the 2 elements of the vector "ok" are assigned from
two different processes, it works, hence the sig name.
In the second case, the 2 elements of the vector "still_ok" are assigned
in the same process, but with the use of a procedure, it works.
But oddly enough, in the third case, "not_ok" does not work. This time
the 2 elements are also assign by the procedure, but from different
processes. I was expecting it to just work fine as well and I do not
know the reasons why it does not. Is it intrinsic to VHDL or an effect
to the Modelsim simulator I use?
Obviously, this example seems artificial, but it is just an abstraction
and simplification of a real case, where indeed some elements of a large
vector are assigned through procedures in different processes generated
by generate statements.
> In the first case, the 2 elements of the vector "ok" are assigned from
> two different processes, it works, hence the sig name.
That's fine.
> In the second case, the 2 elements of the vector "still_ok" are assigned
> in the same process, but with the use of a procedure, it works.
Same thing using a procedure.
> But oddly enough, in the third case, "not_ok" does not work. This time
> the 2 elements are also assign by the procedure, but from different
> processes. I was expecting it to just work fine as well and I do not
> know the reasons why it does not.
Two non-'Z' drivers on the same signal.
> Is it intrinsic to VHDL or an effect
> to the Modelsim simulator I use?
>> In the first case, the 2 elements of the vector "ok" are assigned from
>> two different processes, it works, hence the sig name.
>
>
> That's fine.
According to your statement above, that should be a problem!!! The
vector is assigned from two different processes, so it should not be ok
then.
>
>> In the second case, the 2 elements of the vector "still_ok" are
>> assigned in the same process, but with the use of a procedure, it works.
>
>
> Same thing using a procedure.
No, not same thing, this time it is from a single process, so it should
and it is fine.
>
>> But oddly enough, in the third case, "not_ok" does not work. This time
>> the 2 elements are also assign by the procedure, but from different
>> processes. I was expecting it to just work fine as well and I do not
>> know the reasons why it does not.
>
>
> Two non-'Z' drivers on the same signal.
Ok, but then why does the first case (signal "ok") works fine? It should
not, it is driven from 2 processes as well!?
Re: Procedures and array element assigment from different processes.
Seb wrote:
> Ok, but then why does the first case (signal "ok") works fine? It should
> not, it is driven from 2 processes as well!?
If you move your architecture-scoped procedure into
the scope of each process, modelsim will catch
the driver problem:
** Error: vector_splicing.vhd(43):
No feasible entries for subprogram 'assign'.
Passing drive signals from multiple processes
to an architecture-scoped procedure is a risky business.
It is up to the designer not to pass signals
owned by another process.
If you break this rule, you get run-time 'U's
instead of an error message.
Re: Procedures and array element assigment from different processes.
Mike Treseler wrote:
> If you move your architecture-scoped procedure into
> the scope of each process, modelsim will catch
> the driver problem:
Ok, fair enoug, but not let's go back to the simple case:
process( clk )
begin
if rising_edge( clk ) then
ok(0) <= '0';
end if;
end process;
process( clk )
begin
if rising_edge( clk ) then
ok(1) <= '1';
end if;
end process;
Surely that should not work either. signal "ok" has two drivers, I
should get 'U'. Why does it work? Is that due to the simulator
implementation? (It even works when ok is decalred as std_ulogic_vector)
Unfortunately, I often drive a vector (but different elements of it)
from different processes generated by generate statements:
gen: generate for i in 0 to NB
process(clk)
begin
....
sig(i) <=
So I really should move away from that, no?
Often it is easy to replace the generate by a for loop inside the
process, but when it also uses variables, it is not that easy.
Re: Procedures and array element assigment from different processes.
Seb wrote:
> Ok, fair enoug, but not let's go back to the simple case:
> process( clk )
> begin
> if rising_edge( clk ) then
> ok(0) <= '0';
> end if;
> end process;
> process( clk )
> begin
> if rising_edge( clk ) then
> ok(1) <= '1';
> end if;
> end process;
>
> Surely that should not work either. signal "ok" has two drivers, I
> should get 'U'. Why does it work?
Because the drivers all agree to resolve
to '1' or '0' in this example.
A smart tool will notice this and treat the
case as a single combined process.
I expect that some tools are not as smart.
combined: process( clk )
begin
if rising_edge( clk ) then
ok(0) <= '0';
ok(1) <= '1';
end if;
end process combined;
Try View, Dataflow in modelsim to see this.
> It even works when ok is decalred as std_ulogic_vector
This is because the case is treated
as a virtual single process by Modelsim.
> Unfortunately, I often drive a vector (but different elements of it)
> from different processes generated by generate statements:
> gen: generate for i in 0 to NB
> process(clk)
> begin
> ....
> sig(i) <=
>
> So I really should move away from that, no?
You might consider it for future designs.
Anything that can done by generating processes
can also be done procedurally in a single process.
> Often it is easy to replace the generate by a for loop inside the
> process, but when it also uses variables, it is not that easy.
Re: Procedures and array element assigment from different processes.
Mike Treseler wrote:
> Seb wrote:
>
>> Ok, fair enoug, but not let's go back to the simple case:
>> process( clk )
>> begin
>> if rising_edge( clk ) then
>> ok(0) <= '0';
>> end if;
>> end process;
>> process( clk )
>> begin
>> if rising_edge( clk ) then
>> ok(1) <= '1';
>> end if;
>> end process;
>>
>> Surely that should not work either. signal "ok" has two drivers, I
>> should get 'U'. Why does it work?
>
I've lost track of the original post :-( but you might also want to look
up the Longest Static Prefix section of the VHDL FAQ, e.g.
which I think is the same reference someone else gave above.
In the example above, only one driver is created from each element
of the vector because the index of the signal elements is static, so
the tool creates one driver in the first process on ok(0), and one
driver in the second process on ok(1).
If, however, you had something like
process(clk)
begin
if rising_edge(clk) then
ok(0) <= '0';
end if;
end process;
process(clk)
begin
if rising_edge(clk) then
for i in 1 to 1 loop
ok(i) <= '1';
end loop;
end if;
end process;
then the second process would also create a driver on ok(0), because
for loops are considered non-static by VHDL. Hence the longest static
prefix is "ok", and the second process creates drivers on all elements
of "ok".
<snip>
>> Unfortunately, I often drive a vector (but different elements of it)
>> from different processes generated by generate statements:
>> gen: generate for i in 0 to NB
>> process(clk)
>> begin
>> ....
>> sig(i) <=
>>
>> So I really should move away from that, no?
>
>
Using generate is fine, because then you only create drivers on the
specific elements you drive within the generate. The example I gave
above would work without multiple drivers if you wrote
process(clk)
begin
if rising_edge(clk) then
ok(0) <= '0';
end if;
end process;
g1: for i in 1 to 1 generate
process(clk)
begin
if rising_edge(clk) then
ok(i) <= '1';
end if;
end process;
end generate g1;
because then the generate contents are statically elaborated, so
only one driver is created on ok(1).
So I would say that sometimes you have to use generate to avoid
creating multiple drivers on elements of a signal.
> You might consider it for future designs.
> Anything that can done by generating processes
> can also be done procedurally in a single process.
>
I would disagree with this Mike. You can't create multiple drivers
on a signal using a single process, a signal process pair only
creates one driver. For instance
g2: for i in 0 to 7 generate
process(inp, EN)
begin
if EN = '1' then
o <= inp(i);
else
o <= 'Z';
end if;
end process;
end generate g2;
cannot be done in a single procedural process because you could only
create one single driver on "o" using one process.
Of course everyone avoids internal tristates, so in practise what you
say is pretty well always true!
Re: Procedures and array element assigment from different processes.
Thanks for these ansewers, very interesting.
So I guess the same is true for records (i.e each concurrent statement
that executes has a separate driver for the longest static prefix of
each signal that is target of a signal assignment statement within the
concurrent statement..) So all the different fields of a record should
be assigned in a single process. If so, that make the use of records far
less attractive.
Re: Procedures and array element assigment from different processes.
Thanks very much for your answer Alan, it is very clear now, and it also
answers my question about records! (i.e. it's fine with records)
Alan Fitch wrote:
> I've lost track of the original post :-( but you might also want
I was surprised by the fact that in the following code, the 3 vectors
did not behave the same.
Seb.
=====
library ieee;
use ieee.std_logic_1164.all;
entity vector_splicing is
end vector_splicing;
architecture one of vector_splicing is
signal ok, still_ok, not_ok : std_logic_vector(1 downto 0);
signal clk : std_logic := '1';
procedure assign(signal d: inout std_logic_vector; i: in integer;
v: in std_logic) is
begin
d(i) <= v;
end assign;
begin
clk <= not clk after 5 ns;
process( clk )
begin
if rising_edge( clk ) then
ok(0) <= '0';
assign(still_ok, 0, '0');
assign(still_ok, 1, '1');
assign(not_ok, 0, '0');
end if;
end process;
process( clk )
begin
if rising_edge( clk ) then
ok(1) <= '1';
assign(not_ok, 1, '1');
end if;
end process;
Re: Procedures and array element assigment from different processes.
Alan Fitch wrote:
> I've lost track of the original post :-( but you might also want to look
> up the Longest Static Prefix section of the VHDL FAQ, e.g.
> http://www.eda.org/comp.lang.vhdl/FAQ1.html#drivers
> which I think is the same reference someone else gave above.
Yes. I gave the reference, but your example of the
"non-static" 1 to 1 loop really clarified the
words for me.
>> Anything that can done by generating processes
>> can also be done procedurally in a single process.
> I would disagree with this Mike. You can't create multiple drivers
> on a signal using a single process.
I stand corrected.
In the future, I will avoid the word "anything" almost always
Seb's original question concerned avoiding multiple
drivers while concatenating vector segments. My
point was that using a single process might
make his job easier.
> Of course everyone avoids internal tristates, so in practise what you
> say is pretty well always true!
Thanks Alan for the illuminating post and kind words.
Thanks to Seb for the interesting problem.