Procedures and array element assigment from different proces

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.

Thanks for your responses Mike.

Seb.
 
S

Seb

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

end one;
 
I think there is a race condition imposed by your two clocked processes
calling the same procedure.
 
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;

-- Mike Treseler
 
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.

Seb.
 
Mike Treseler wrote:
Your processes are both writing to the same signals.
Seb wrote:
Yes, but to differents elements of the array!
That's still a problem. If you drive one bit,
the process has a driver on the whole object.
http://www.eda.org/comp.lang.vhdl/FAQ1.html#drivers

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?
That's how vhdl works.
But it's not really a problem.
You can do a lot with one processs.
http://home.comcast.net/~mike_treseler/uart.vhd
for example.

-- Mike Treseler
 
Thanks for your response Mike,

Mike Treseler wrote:
That's still a problem. If you drive one bit,
the process has a driver on the whole object.
http://www.eda.org/comp.lang.vhdl/FAQ1.html#drivers
Ok, fair enough.


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!?


Seb.
 
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.

-- Mike Treseler
 
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.
Also consider array types instead of loops.

Thanks for your responses Mike.
You are welcome.

-- Mike Treseler
 
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.

http://www.eda.org/comp.lang.vhdl/FAQ1.html#drivers

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!

regards
Alan
--
Alan Fitch
Doulos Ltd
http://www.doulos.com
 
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.

Seb.
 
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;

end one;
======
 
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.

-- Mike Treseler
 

Welcome to EDABoard.com

Sponsor

Back
Top