Strange signal non-assignment

Discussion in 'VHDL' started by Andy Peters, Mar 2, 2010.

  1. Andy Peters

    Andy Peters Guest

    Here's an odd one. Following is a stripped-down test entity which has
    two shift registers, one "good" and one "bad." I ginned this up
    because a colleague wrote some code that uses the latter and it showed
    a strange simulation result.

    ---- code here:
    library ieee;
    use ieee.std_logic_1164.all;

    entity shift_test is
    end entity shift_test;

    architecture test of shift_test is

    signal gSysClk : std_logic := '1'; -- the clock
    signal aReset : std_logic := '1'; -- async reset
    signal sReset : std_logic; -- sync reset

    signal srStart : std_logic := '0'; -- start shift
    signal srStop : std_logic := '0';

    signal goodSR : std_logic_vector(7 downto 0);
    signal badSR : std_logic_vector(7 downto 0);

    begin -- architecture test

    bit0 : process (gSysClk) is
    begin -- process bit0
    if rising_edge(gSysClk) then
    if gReset = '1' then
    goodSR(0) <= '0';
    badSR(0) <= '0';
    elsif srStart = '1' then
    goodSR(0) <= '1';
    badSR(0) <= '1';
    elsif srStop = '1' then
    goodSR(0) <= '0';
    badSR(0) <= '0';
    end if;
    end if;
    end process bit0;

    shifters : process (gSysClk) is
    begin -- process shifters
    if rising_edge(gSysClk) then
    goodSR(goodSR'high downto 1) <= goodSR(goodSR'high - 1
    downto 0);

    badshiftloop : for i in 1 to badSR'high loop
    badSR(i) <= badSR(i-1);
    end loop badshiftloop;
    end if;
    end process shifters;

    -- toggle the start and stop.
    MainTest : process is
    begin -- process MainTest
    wait until sReset = '0';
    wait for 500 NS;
    wait until rising_edge(gSysClk);
    srStart <= '1';
    wait until rising_edge(gSysClk);
    srStart <= '0';
    wait for 500 NS;
    wait until rising_edge(gSysClk);
    srStop <= '1';
    wait until rising_edge(gSysClk);
    srStop <= '0';
    wait until rising_edge(gSysClk);
    wait;
    end process MainTest;

    -- clock:
    gSysClk <= not gSysClk after 100 NS;
    aReset <= '0' after 666 NS;

    SyncReset : process (gSysClk) is
    begin -- process SyncReset
    if rising_edge(gSysClk) then
    sReset <= aReset;
    end if;
    end process SyncReset;

    end architecture test;
    ------- end code

    Basically, we want to expressly set or clear the input to the shift
    register. This is done in the bit0 process, depending on the state of
    srStart and srStop.

    The shifters process never explicitly assigns bit 0 as that is
    ostensibly handled in bit0. The goodSR shift register functions as one
    expects: goodSR(0) is set one clock after srStart and remains true
    until srStop, and the bits shift through properly.

    However, in the badSR, none of the bits are ever assigned ... the
    shift register remains "UUUUUUUU". Looking at the drivers on this
    signal, bit0 is actually assigned a '1' in the bit0 process at the
    correct time, but it also has a driver shown for the shifters process,
    and this driver's value is 'U'. The bit0 process creates a driver for
    goodSR(0) but there is no driver in the shifters process like there is
    for badSR(0). So it's the extra driver in shifters on badSR(0) that is
    overriding the bit0 assignment (one delta cycle later).

    But why is this the case? Why the second driver on the loop but not on
    the simpler assignment? I don't see how the simulator infers a driver
    in shifters on badSR(0) but not goodSR(0) when in neither case is an
    explicit assignment made to either.

    FWIW, I get the same results in ModelSim and in Active-HDL.

    -a
     
    Andy Peters, Mar 2, 2010
    #1
    1. Advertising

  2. Andy Peters

    HT-Lab Guest

    Google for longest static prefix,

    Also see a simpler example here : http://www.ht-lab.com/question.jpg

    Hans
    www.ht-lab.com


    "Andy Peters" <> wrote in message
    news:...
    > Here's an odd one. Following is a stripped-down test entity which has
    > two shift registers, one "good" and one "bad." I ginned this up
    > because a colleague wrote some code that uses the latter and it showed
    > a strange simulation result.
    >
    > ---- code here:
    > library ieee;
    > use ieee.std_logic_1164.all;
    >
    > entity shift_test is
    > end entity shift_test;
    >
    > architecture test of shift_test is
    >
    > signal gSysClk : std_logic := '1'; -- the clock
    > signal aReset : std_logic := '1'; -- async reset
    > signal sReset : std_logic; -- sync reset
    >
    > signal srStart : std_logic := '0'; -- start shift
    > signal srStop : std_logic := '0';
    >
    > signal goodSR : std_logic_vector(7 downto 0);
    > signal badSR : std_logic_vector(7 downto 0);
    >
    > begin -- architecture test
    >
    > bit0 : process (gSysClk) is
    > begin -- process bit0
    > if rising_edge(gSysClk) then
    > if gReset = '1' then
    > goodSR(0) <= '0';
    > badSR(0) <= '0';
    > elsif srStart = '1' then
    > goodSR(0) <= '1';
    > badSR(0) <= '1';
    > elsif srStop = '1' then
    > goodSR(0) <= '0';
    > badSR(0) <= '0';
    > end if;
    > end if;
    > end process bit0;
    >
    > shifters : process (gSysClk) is
    > begin -- process shifters
    > if rising_edge(gSysClk) then
    > goodSR(goodSR'high downto 1) <= goodSR(goodSR'high - 1
    > downto 0);
    >
    > badshiftloop : for i in 1 to badSR'high loop
    > badSR(i) <= badSR(i-1);
    > end loop badshiftloop;
    > end if;
    > end process shifters;
    >
    > -- toggle the start and stop.
    > MainTest : process is
    > begin -- process MainTest
    > wait until sReset = '0';
    > wait for 500 NS;
    > wait until rising_edge(gSysClk);
    > srStart <= '1';
    > wait until rising_edge(gSysClk);
    > srStart <= '0';
    > wait for 500 NS;
    > wait until rising_edge(gSysClk);
    > srStop <= '1';
    > wait until rising_edge(gSysClk);
    > srStop <= '0';
    > wait until rising_edge(gSysClk);
    > wait;
    > end process MainTest;
    >
    > -- clock:
    > gSysClk <= not gSysClk after 100 NS;
    > aReset <= '0' after 666 NS;
    >
    > SyncReset : process (gSysClk) is
    > begin -- process SyncReset
    > if rising_edge(gSysClk) then
    > sReset <= aReset;
    > end if;
    > end process SyncReset;
    >
    > end architecture test;
    > ------- end code
    >
    > Basically, we want to expressly set or clear the input to the shift
    > register. This is done in the bit0 process, depending on the state of
    > srStart and srStop.
    >
    > The shifters process never explicitly assigns bit 0 as that is
    > ostensibly handled in bit0. The goodSR shift register functions as one
    > expects: goodSR(0) is set one clock after srStart and remains true
    > until srStop, and the bits shift through properly.
    >
    > However, in the badSR, none of the bits are ever assigned ... the
    > shift register remains "UUUUUUUU". Looking at the drivers on this
    > signal, bit0 is actually assigned a '1' in the bit0 process at the
    > correct time, but it also has a driver shown for the shifters process,
    > and this driver's value is 'U'. The bit0 process creates a driver for
    > goodSR(0) but there is no driver in the shifters process like there is
    > for badSR(0). So it's the extra driver in shifters on badSR(0) that is
    > overriding the bit0 assignment (one delta cycle later).
    >
    > But why is this the case? Why the second driver on the loop but not on
    > the simpler assignment? I don't see how the simulator infers a driver
    > in shifters on badSR(0) but not goodSR(0) when in neither case is an
    > explicit assignment made to either.
    >
    > FWIW, I get the same results in ModelSim and in Active-HDL.
    >
    > -a
    >
     
    HT-Lab, Mar 2, 2010
    #2
    1. Advertising

  3. HT-Lab wrote:
    > Google for longest static prefix,
    >
    > Also see a simpler example here : http://www.ht-lab.com/question.jpg
    >
    > Hans
    > www.ht-lab.com
    >


    Well,
    I googled it and tried to understand;
    - Longest static prefix of goodSR in process shifters is 7 downto 1
    since it is defined explicitly, hence no driver for goodSR(0) in that
    process.
    - L.S.P. of badSR is all elements of badSR since it is indexed by
    variable (not static) and therefore all elements gets assigned a driver
    in that process.

    Then we have 2 drivers on badSR(0) of type std_logic. Since process
    shifters does not explicitly assign any value to badSR(0) it will drive
    it with the value it had at the delta time the process is executed.
    Since the signal is initialized with 'U', and 'U' will always win the
    resolution, process bit0 will never be able to force any other value on
    the signal.

    Does that make sense? Hopefully, I got it right and learned something
    new today!
     
    Magne Munkejord, Mar 2, 2010
    #3
  4. Magne Munkejord wrote:

    > HT-Lab wrote:
    >> Google for longest static prefix,
    >>
    >> Also see a simpler example here : http://www.ht-lab.com/question.jpg
    >>
    >> Hans
    >> www.ht-lab.com
    >>

    >
    > Well,
    > I googled it and tried to understand;
    > - Longest static prefix of goodSR in process shifters is 7 downto 1
    > since it is defined explicitly, hence no driver for goodSR(0) in that
    > process.
    > - L.S.P. of badSR is all elements of badSR since it is indexed by
    > variable (not static) and therefore all elements gets assigned a driver
    > in that process.
    >
    > Then we have 2 drivers on badSR(0) of type std_logic. Since process
    > shifters does not explicitly assign any value to badSR(0) it will drive
    > it with the value it had at the delta time the process is executed.


    I think this sentence is not correct, or at least I do not understand it
    completely.

    The thing is: if a process creates a driver for a signal, the initial value
    of the driver is 'U' for a std_logic (or in general: the left-most value of
    the type). This is so from time zero and delta zero, and it remains so to
    the end of the simulation if there is not a signal assignment. This happens
    with badSR(0) in process shifters.

    A driver is a permanent thing. It is not only active at the moment a value
    is assigned to a signal. The assignment just changes the value of the
    driver.

    The actual value of a signal with a resolved type (here: std_logic) is
    determined by the resolution function of std_logic. That function receives
    the value of all drivers and returns the resulting value. In case of
    std_logic, 'U' wins over any other value. So badSR(0) wil remain 'U' for
    ever.

    > Since the signal is initialized with 'U', and 'U' will always win the
    > resolution, process bit0 will never be able to force any other value on
    > the signal.
    >
    > Does that make sense?


    Yes, absolutely.

    > Hopefully, I got it right and learned something new today!


    What I would like to add: I do not see any reason to have two processes in
    the example of the OP. It has been said in this news group before (and
    rightfully so): limit the number of processes. Having multiple processes
    makes debugging harder. This is my experience as well.

    --
    Paul Uiterlinden
    www.aimvalley.nl
    e-mail addres: remove the not.
     
    Paul Uiterlinden, Mar 2, 2010
    #4
  5. Andy Peters

    rickman Guest

    On Mar 2, 7:28 am, Paul Uiterlinden <> wrote:
    >
    > What I would like to add: I do not see any reason to have two processes in
    > the example of the OP. It has been said in this news group before (and
    > rightfully so): limit the number of processes. Having multiple processes
    > makes debugging harder. This is my experience as well.


    That makes sense to me. At least, I would not put the assignment of
    bit 0 in a separate process. Instead I might separately define the
    input to bit 0. That could be done either in a process or a
    concurrent assignment. I often do that when the logic expressed in an
    if-then tree would cloud the rest of the structure of the register
    process.

    Rick
     
    rickman, Mar 2, 2010
    #5
  6. Andy Peters

    Andy Peters Guest

    On Mar 2, 3:19 am, Magne Munkejord <> wrote:
    > HT-Lab wrote:
    > > Google for longest static prefix,

    >
    > > Also see a simpler example here :http://www.ht-lab.com/question.jpg

    >
    > > Hans
    > >www.ht-lab.com

    >
    > Well,
    > I googled it and tried to understand;


    > - L.S.P. of badSR is all elements of badSR since it is indexed by
    > variable (not static) and therefore all elements gets assigned a driver
    > in that process.


    Ahhhh, got it.

    > Then we have 2 drivers on badSR(0) of type std_logic. Since process
    > shifters does not explicitly assign any value to badSR(0) it will drive
    > it with the value it had at the delta time the process is executed.
    > Since the signal is initialized with 'U', and 'U' will always win the
    > resolution, process bit0 will never be able to force any other value on
    > the signal.


    Yes, this seems like it's exactly the problem. I've never run into
    this because I always use the non-loop construct for the shift
    register, and I would have put the bit 0 assignment in the same
    process.

    File this under "really dusty corners of VHDL."

    -a
     
    Andy Peters, Mar 2, 2010
    #6
  7. Paul Uiterlinden wrote:
    > Magne Munkejord wrote:
    >
    >> HT-Lab wrote:
    >>> Google for longest static prefix,
    >>>
    >>> Also see a simpler example here : http://www.ht-lab.com/question.jpg
    >>>
    >>> Hans
    >>> www.ht-lab.com
    >>>

    >> Well,
    >> I googled it and tried to understand;
    >> - Longest static prefix of goodSR in process shifters is 7 downto 1
    >> since it is defined explicitly, hence no driver for goodSR(0) in that
    >> process.
    >> - L.S.P. of badSR is all elements of badSR since it is indexed by
    >> variable (not static) and therefore all elements gets assigned a driver
    >> in that process.
    >>
    >> Then we have 2 drivers on badSR(0) of type std_logic. Since process
    >> shifters does not explicitly assign any value to badSR(0) it will drive
    >> it with the value it had at the delta time the process is executed.

    >
    > I think this sentence is not correct, or at least I do not understand it
    > completely.

    Yes, it was badly written and not very accurate, in some way incorrect.
    What I meant to say is that VHDL will explicitly assign a value to a
    signal it has a driver for, even if no such signal assignment exists in
    the code or are not executed due to conditional constructs. In this case
    badSR(0) was initialized to 'U' (the default) so it is equivalent to
    badSR(0) <= 'U' until the process assigns another value to it (which it
    doesn't).
    If badSR(0) was initialized to 'Z', the signal would resolve to the
    value driven by process bit0. But the driver for process shifter would
    still be 'Z'.

    >
    > The thing is: if a process creates a driver for a signal, the initial value
    > of the driver is 'U' for a std_logic (or in general: the left-most value of
    > the type). This is so from time zero and delta zero, and it remains so to
    > the end of the simulation if there is not a signal assignment. This happens
    > with badSR(0) in process shifters.


    I am sure you know, but it can be initialized to another value when the
    signal is declared. If
    signal badSR : std_logic_vector(7 downto 0) := (others => '1');
    then I assume all drivers for the signal(s) will be initialized to '1'?

    >
    > A driver is a permanent thing. It is not only active at the moment a value
    > is assigned to a signal. The assignment just changes the value of the
    > driver.
    >
    > The actual value of a signal with a resolved type (here: std_logic) is
    > determined by the resolution function of std_logic. That function receives
    > the value of all drivers and returns the resulting value. In case of
    > std_logic, 'U' wins over any other value. So badSR(0) wil remain 'U' for
    > ever.
    >
    >> Since the signal is initialized with 'U', and 'U' will always win the
    >> resolution, process bit0 will never be able to force any other value on
    >> the signal.
    >>
    >> Does that make sense?

    >
    > Yes, absolutely.
    >
    >> Hopefully, I got it right and learned something new today!

    >
    > What I would like to add: I do not see any reason to have two processes in
    > the example of the OP. It has been said in this news group before (and
    > rightfully so): limit the number of processes. Having multiple processes
    > makes debugging harder. This is my experience as well.
    >
     
    Magne Munkejord, Mar 2, 2010
    #7
  8. Andy Peters

    Andy Guest

    On Mar 2, 6:53 am, rickman <> wrote:
    > On Mar 2, 7:28 am, Paul Uiterlinden <> wrote:
    >
    >
    >
    > > What I would like to add: I do not see any reason to have two processes in
    > > the example of the OP. It has been said in this news group before (and
    > > rightfully so): limit the number of processes. Having multiple processes
    > > makes debugging harder. This is my experience as well.

    >
    > That makes sense to me.  At least, I would not put the assignment of
    > bit 0 in a separate process.  Instead I might separately define the
    > input to bit 0.  That could be done either in a process or a
    > concurrent assignment.  I often do that when the logic expressed in an
    > if-then tree would cloud the rest of the structure of the register
    > process.
    >
    > Rick


    I agree. This is one of those cases where using a variable to capture
    combinatorial logic in a clocked process makes particularly good
    sense. You get the separation of a separate process or concurrent
    assignment, with the simulation efficiency and scope control of a
    single process.

    Andy
     
    Andy, Mar 2, 2010
    #8
  9. Magne Munkejord wrote:

    > Paul Uiterlinden wrote:
    >> Magne Munkejord wrote:
    >>
    >>> HT-Lab wrote:
    >>>> Google for longest static prefix,
    >>>>
    >>>> Also see a simpler example here : http://www.ht-lab.com/question.jpg
    >>>>
    >>>> Hans
    >>>> www.ht-lab.com
    >>>>
    >>> Well,
    >>> I googled it and tried to understand;
    >>> - Longest static prefix of goodSR in process shifters is 7 downto 1
    >>> since it is defined explicitly, hence no driver for goodSR(0) in that
    >>> process.
    >>> - L.S.P. of badSR is all elements of badSR since it is indexed by
    >>> variable (not static) and therefore all elements gets assigned a driver
    >>> in that process.
    >>>
    >>> Then we have 2 drivers on badSR(0) of type std_logic. Since process
    >>> shifters does not explicitly assign any value to badSR(0) it will drive
    >>> it with the value it had at the delta time the process is executed.

    >>
    >> I think this sentence is not correct, or at least I do not understand it
    >> completely.

    > Yes, it was badly written and not very accurate, in some way incorrect.
    > What I meant to say is that VHDL will explicitly assign a value to a
    > signal it has a driver for, even if no such signal assignment exists in
    > the code or are not executed due to conditional constructs. In this case
    > badSR(0) was initialized to 'U' (the default) so it is equivalent to
    > badSR(0) <= 'U' until the process assigns another value to it (which it
    > doesn't).
    > If badSR(0) was initialized to 'Z', the signal would resolve to the
    > value driven by process bit0. But the driver for process shifter would
    > still be 'Z'.
    >
    >>
    >> The thing is: if a process creates a driver for a signal, the initial
    >> value of the driver is 'U' for a std_logic (or in general: the left-most
    >> value of the type). This is so from time zero and delta zero, and it
    >> remains so to the end of the simulation if there is not a signal
    >> assignment. This happens with badSR(0) in process shifters.

    >
    > I am sure you know, but it can be initialized to another value when the
    > signal is declared. If
    > signal badSR : std_logic_vector(7 downto 0) := (others => '1');
    > then I assume all drivers for the signal(s) will be initialized to '1'?


    Good question (sorry for the late answer).

    My initial though was: yes.
    Then I started thinking and doubt set in.
    So time for a little experiment:

    ENTITY sig_init_val IS
    END ENTITY sig_init_val;

    LIBRARY ieee;
    USE ieee.std_logic_1164.ALL;

    ARCHITECTURE arch OF sig_init_val IS
    SIGNAL s : std_logic := '1';
    BEGIN
    driver1: PROCESS IS
    BEGIN
    WAIT FOR 1 ns;
    s <= '0';
    WAIT;
    END PROCESS driver1;

    driver2: PROCESS IS
    BEGIN
    WAIT FOR 2 ns;
    s <= '0';
    WAIT;
    END PROCESS driver2;

    mon_s: PROCESS(s) IS
    BEGIN
    REPORT "s = " & std_logic'IMAGE(s) & ".";
    END PROCESS mon_s;
    END ARCHITECTURE arch;


    The outcome of this is:

    # ** Note: s = '1'.
    # Time: 0 ps Iteration: 0 Instance: /sig_init_val
    # ** Note: s = 'X'.
    # Time: 1 ns Iteration: 1 Instance: /sig_init_val
    # ** Note: s = '0'.
    # Time: 2 ns Iteration: 1 Instance: /sig_init_val

    So the signal starts at '1' at time=0 ns, delta=0. Then it goes to 'X' at
    time=1 ns, delta=1. Finally it goes to '1' at time=2 ns, delta=1.

    Perhaps the surprising part is the transition at 1 ns to 'X'. So driving a
    value in the future (1 ns later) has an effect now (at 1 ns).

    The explanation of course is that both processes create a driver for signal
    s. The initial value of both drivers is '1', as you already suspected.

    At 1 ns driver1 changes value to '0', while driver2 stay unchanged at '1'.
    Hence the resulting 'X'

    At 2 ns driver2 changes value to '0', so now both driving values are '0'.
    Hence the transition to '0'.

    Ahh, I love it when theory and practice coincide. ;-)

    --
    Paul Uiterlinden
    www.aimvalley.nl
    e-mail addres: remove the not.
     
    Paul Uiterlinden, Mar 10, 2010
    #9
    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. Michael Pronath
    Replies:
    1
    Views:
    1,183
    Diez B. Roggisch
    Jan 3, 2005
  2. Jack Orenstein

    threading.Thread vs. signal.signal

    Jack Orenstein, Sep 18, 2005, in forum: Python
    Replies:
    0
    Views:
    472
    Jack Orenstein
    Sep 18, 2005
  3. Weng Tianxiang
    Replies:
    2
    Views:
    664
    Jonathan Bromley
    Jan 30, 2007
  4. Nicolas Moreau
    Replies:
    9
    Views:
    3,199
  5. dibacco73
    Replies:
    1
    Views:
    661
    joris
    Feb 12, 2009
Loading...

Share This Page