Procedures and array element assigment from different processes.

Discussion in 'VHDL' started by Seb, Mar 11, 2005.

  1. Seb

    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;
     
    Seb, Mar 11, 2005
    #1
    1. Advertising

  2. Seb

    Neo Guest

    I think there is a race condition imposed by your two clocked processes
    calling the same procedure.
     
    Neo, Mar 14, 2005
    #2
    1. Advertising

  3. 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
     
    Mike Treseler, Mar 14, 2005
    #3
  4. Seb

    Seb Guest

    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.
     
    Seb, Mar 15, 2005
    #4
  5. 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
     
    Mike Treseler, Mar 15, 2005
    #5
  6. Seb

    Seb Guest

    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, Mar 15, 2005
    #6
  7. 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
     
    Mike Treseler, Mar 15, 2005
    #7
  8. Seb

    Seb Guest

    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.
     
    Seb, Mar 16, 2005
    #8
  9. 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, Mar 16, 2005
    #9
  10. Seb

    Alan Fitch Guest

    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
     
    Alan Fitch, Mar 17, 2005
    #10
  11. Seb

    Seb Guest

    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.
     
    Seb, Mar 17, 2005
    #11
  12. Seb

    Seb Guest

    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;
    ======
     
    Seb, Mar 17, 2005
    #12
  13. 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
     
    Mike Treseler, Mar 17, 2005
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dean Mitchell
    Replies:
    4
    Views:
    387
    Attila Feher
    Aug 27, 2003
  2. Thomas Philips
    Replies:
    4
    Views:
    376
    Duncan Booth
    Jun 22, 2004
  3. Adrian
    Replies:
    10
    Views:
    511
    Robert Bauck Hamar
    Dec 5, 2006
  4. mreister
    Replies:
    1
    Views:
    676
    jeppe
    Sep 12, 2008
  5. Godspeed

    Iterators and Assigment

    Godspeed, Feb 28, 2006, in forum: Ruby
    Replies:
    3
    Views:
    90
    Godspeed
    Mar 1, 2006
Loading...

Share This Page