Process vs concurrent stataments?

Discussion in 'VHDL' started by p.tucci, Jan 18, 2009.

  1. p.tucci

    p.tucci Guest

    Hi all,
    I'm a VHDL beginner and I've a trouble with a simple VHDL piece code.

    Writing the same thing in two ways that (appearently to me) seem to be
    the same,
    produce different resuls.

    In one case the code is synthesized, in the other it is not.

    This is the first piece of code, written as a process.
    It is well synthesized:

    sample_parallel_data : process(SYS_CK_IN,RESET) begin
    if(RESET = '0') then
    tx_data <= (others => '0');
    elsif(rising_edge(SYS_CK_IN)) then
    if(counter mod (SYS_CK_RATIO/2) = 0) then
    if(last_lr_ck = '1') then
    tx_data <= "0" & DATA_R
    (IN_WIDTH-1 downto 0) & "0000000";
    else
    tx_data <= "0" & DATA_L
    (IN_WIDTH-1 downto 0) & "0000000";
    end if;
    else
    tx_data <= tx_data(BITXCH-2 downto 0)
    & '0'; --shift data left
    end if;
    end if;
    end process;

    Now there's the some code, written as a concurrent statement... this
    one reports me the error
    "Signal tx_data cannot be synthesized, bad synchronous description."

    tx_data <=
    (others => '0') when RESET='0'
    else
    '0' & DATA_L(IN_WIDTH-1 downto 0) & "0000000"
    when rising_edge(SYS_CK_IN)
    and (counter mod (SYS_CK_RATIO/2) = 0)
    and last_lr_ck = '1'
    else
    '0' & DATA_R(IN_WIDTH-1 downto 0) & "0000000"
    when rising_edge(SYS_CK_IN)
    and (counter mod (SYS_CK_RATIO/2) = 0)
    and last_lr_ck = '0'
    else
    tx_data(BITXCH-2 downto 0) & '0'
    when rising_edge(SYS_CK_IN);


    For both designs:
    tx_data is a signal
    signal signal tx_data : std_logic_vector(BITXCH-1 downto 0);

    DATA_L and DATA_R are two input ports
    DATA_L : in std_logic_vector(IN_WIDTH-1 downto 0);
    DATA_R : in std_logic_vector(IN_WIDTH-1 downto 0);

    BITXCH is a constant = 32
    IN_WIDTH is a constant = 24

    Why are these piece of code different?
    It appear the same thing in my mind !


    Thanks all,
    Primiano Tucci
    --
    http://www.primianotucci.com/
     
    p.tucci, Jan 18, 2009
    #1
    1. Advertising

  2. p.tucci <a t> gmail.com wrote:

    > In one case the code is synthesized, in the other it is not.


    See Mr Bromley in comp.arch.fpga
     
    Mike Treseler, Jan 18, 2009
    #2
    1. Advertising

  3. p.tucci

    jeppe

    Joined:
    Mar 10, 2008
    Messages:
    348
    Location:
    Denmark
    Hi Primiano

    The problem with your concurrent code as follows:
    1) You got more then one Rising_egde( ) statement in the same structure.
    (If you try the same in a process will you fail there as well)
    2) Worse - you specify and else to a Rising_egde statement - this will surely
    give you an error as you can't have a F/F which react on rising_egde and else do ....;

    I never try implement sekvential logic with Concurrent statement - but
    properly can it be done.

    Your welcome
    Jeppe
     
    jeppe, Jan 18, 2009
    #3
  4. p.tucci

    Tricky Guest

    Basically, synthesisers will only recognise the following synchronous
    template:

    sync_proc : process(clk, reset)
    begin
    if reset = '1' then
    --async reset (avoid using if possible)
    elsif rising_edge(clk) then
    if sync_reset = '1' then
    --sync reset prefered
    elsif enable = '1' then
    --put synchronous code here.
    end if;
    end if;
    end process;
     
    Tricky, Jan 19, 2009
    #4
  5. p.tucci

    Tricky Guest


    >
    > tx_data <=
    > (others => '0') when RESET='0'
    > else
    > '0' & DATA_L(IN_WIDTH-1 downto 0) & "0000000"
    > when rising_edge(SYS_CK_IN)
    > and (counter mod (SYS_CK_RATIO/2) = 0)
    > and last_lr_ck = '1'
    > else
    > '0' & DATA_R(IN_WIDTH-1 downto 0) & "0000000"
    > when rising_edge(SYS_CK_IN)
    > and (counter mod (SYS_CK_RATIO/2) = 0)
    > and last_lr_ck = '0'
    > else
    > tx_data(BITXCH-2 downto 0) & '0'
    > when rising_edge(SYS_CK_IN);
    >



    Another reason why this code is bad, is that it becomes sensitive to
    EVERY signal on the RHS of a assignment. To the synthesiser, it looks
    more like a MUX template which you dont actually mean. This code would
    probably work in simulation, but would be much slower than the
    standard template because it's re-evaluating the equations every time
    one of them changes (counter, SYS_CK_IN, RESET, Last_Lr_Ck, tx_data,
    DATA_R, DATA_L), which is not like real hardware. The process version
    only gets re-evaluated when the clock or reset changes.

    Also, although you may find it odd, but the rising_edge/falling_edge
    functions actually use non-synthesisable constructs within them (the
    'LAST_VALUE and 'EVENT attributes).So they can only be recognised
    within the appropriate template.
     
    Tricky, Jan 19, 2009
    #5
  6. p.tucci

    p.tucci Guest

    You were so precise and clear in you answer.
    Indeed, I prefer the process statement too, because it's more
    readable.
    But now I have another question... i've not completely clear the
    semantics of process statemens.

    I'm quite sure that at this point you'll hate me for my "find the
    differece" questions ;)
    but they're a nice way for me to understand VHDL semantics
    So, the big question is (single process or multiple processes?):

    are these two piece of code the same?

    -----------------------------------------------
    ------------- CUT ONE -------------------------
    -----------------------------------------------
    process(SYS_CK_IN)
    begin
    if(rising_edge(SYS_CK_IN)) then
    -- Generate the BIT_CK
    -- every SYS_CK_RATIO / BIT_CK_RATIO System Clock Rising edge
    if( counter mod ((SYS_CK_RATIO / BIT_CK_RATIO) / 2) =
    (SYS_CK_RATIO/2 - 1)) then
    last_bit_ck <= not last_bit_ck;
    end if;

    -- Generate the LR_CK
    -- every SYS_CK_RATIO System Clocks (SYS_CK_RATIO/2 rising edges)
    if( counter mod (SYS_CK_RATIO/2) = 0) then
    --last_lr_ck <= not last_lr_ck; --commented out...
    --what if i'd put here instead of below?
    if(last_lr_ck = '1') then
    tx_data <= "0" & DATA_R(IN_WIDTH-1 downto 0) & "0000000";
    last_lr_ck <= '0';
    else
    tx_data <= "0" & DATA_L(IN_WIDTH-1 downto 0) & "0000000";
    last_lr_ck <= '1';
    end if;

    else
    tx_data <= tx_data(BITXCH-2 downto 0) & '0';
    --Would be this more appropriate?
    --It does not explicit the leading zero
    --but i do not matter about the dirty bit being shifted
    --for i in (BITXCH-2) downto 0 loop
    --tx_data(i+1) <= tx_data(i);
    --end loop;

    end if;

    counter <= counter + 1 mod (SYS_CK_RATIO/2);
    end if;--rising_edge
    end process;

    DOUT <= tx_data(BITXCH-1);
    SYS_CK_OUT <= SYS_CK_IN;
    BIT_CK <= last_bit_ck;
    LR_CK <= last_lr_ck;

    -----------------------------------------------
    ------------- CUT TWO -------------------------
    -----------------------------------------------

    -- Generate the BIT_CK
    -- every SYS_CK_RATIO / BIT_CK_RATIO System Clock Rising edge
    generate_bit_clock : process(SYS_CK_IN) begin
    if(rising_edge(SYS_CK_IN)) then
    if(counter mod ((SYS_CK_RATIO / BIT_CK_RATIO) / 2) = 0) then
    last_bit_ck <= not last_bit_ck;
    end if;
    end if;
    end process;

    -- Generate the LR_CK
    -- every SYS_CK_RATIO System Clocks (SYS_CK_RATIO/2 rising edges)
    generate_lrck_clock : process(SYS_CK_IN) begin
    if(rising_edge(SYS_CK_IN)) then
    if(counter mod (SYS_CK_RATIO/2) = (SYS_CK_RATIO/2 - 1) ) then
    last_lr_ck <= not last_lr_ck;
    end if;
    end if;
    end process;

    -- Sample parallel data
    -- every SYS_CK_RATIO System Clocks (SYS_CK_RATIO/2 rising edges)
    sample_parallel_data : process(SYS_CK_IN) begin
    if(rising_edge(SYS_CK_IN)) then
    if(counter mod (SYS_CK_RATIO/2) = 0) then
    if(last_lr_ck = '1') then
    tx_data <= "0" & DATA_R(IN_WIDTH-1 downto 0) & "0000000";
    else
    tx_data <= "0" & DATA_L(IN_WIDTH-1 downto 0) & "0000000";
    end if;
    elsif(last_bit_ck = '1') then --MOD HERE, was 0
    tx_data <= tx_data(BITXCH-2 downto 0) & '0';
    end if;
    end if;
    end process;

    -- Increment counter every SYS_CK_IN edge
    update_counter : process(SYS_CK_IN) begin
    if(rising_edge(SYS_CK_IN)) then
    counter <= (counter + 1) mod (SYS_CK_RATIO/2);
    end if;
    end process;


    BIT_CK <= last_bit_ck;
    LR_CK <= last_lr_ck;
    DOUT <= tx_data(BITXCH-1);
    SYS_CK_OUT <= SYS_CK_IN;


    Thanks,
    Primiano Tucci
    --
    http://www.primianotucci.com/
     
    p.tucci, Jan 19, 2009
    #6
  7. p.tucci

    Tricky Guest

    The two code sections you have written are now identical, except you
    have separated out each signal into it's own process. Some people like
    this because it specifically defines each register, but it just makes
    the code more wordy. Personally I try and group together stuff into
    fewer processes, trying to get the code to flow from top to bottom
    like you might see on a system diagram from left to right.

    As for this comment:

    tx_data <= tx_data(BITXCH-2 downto 0) & '0';
    --Would be this more appropriate?
    --It does not explicit the leading zero
    --but i do not matter about the dirty bit being shifted

    --for i in (BITXCH-2) downto 0 loop
    --tx_data(i+1) <= tx_data(i);
    --end loop;

    Having ignored bit 0 in simulation it will come up as 'U'. In
    synthesis, it will be connected to '1' or '0', dependent on the
    synthesisors flavour and mood, and might even be set at the fitter
    stage.


    Other things that concern me: you have signals called "BIT_CK",
    "LR_CK", "SYS_CK_OUT". I am concerned you are using these elsewhere in
    the design as clocks, and not enables. if this is for an FPGA be
    warned that logic generated clocks are not very practical, useful or
    safe. Its best to use enables tied into the system clock instead. To
    generate proper system clocks at different speeds, it is best to use a
    PLL or a DCM, and make sure your data crosses the domains correctly,
    normally via a FIFO.
     
    Tricky, Jan 19, 2009
    #7
  8. p.tucci

    p.tucci Guest

    > Other things that concern me: you have signals called "BIT_CK",
    > "LR_CK", "SYS_CK_OUT". I am concerned you are using these elsewhere in
    > the design as clocks, and not enables. if this is for an FPGA be
    > warned that logic generated clocks are not very practical, useful or
    > safe. Its best to use enables tied into the system clock instead. To
    > generate proper system clocks at different speeds, it is best to use a
    > PLL or a DCM, and make sure your data crosses the domains correctly,
    > normally via a FIFO.


    The vhdl is an audio parallel to i2s.
    It takes a System Clock (generated by a PLL, about 6 Mhz) in input and
    parallel data.
    It outputs:
    -A bit clock (that is SYS_CK_IN divided by two)
    -An LRCK clock (taht is SYS_CK_IN divided by 64)
    -A Data output (timed with Bit Clock).

    It sounds interesting the fact of enable the system clock, but, how to
    do it?
    Do you have any examples?

    Thans all for your great support
     
    p.tucci, Jan 19, 2009
    #8
  9. p.tucci

    p.tucci Guest

    Just another thing,
    The SYS_CK_OUT, LRCK and BIT_CK are not used anymore into the design
    but are exported to the output pins of the CPLD (an xc95144xl) that
    will connect to and drive a Digital to Analog Converter
     
    p.tucci, Jan 19, 2009
    #9
  10. p.tucci

    Andy Guest

    On Jan 19, 3:00 am, Tricky <> wrote:
    > Basically, synthesisers will only recognise the following synchronous
    > template:
    >
    > sync_proc : process(clk, reset)
    > begin
    >   if reset = '1' then
    >     --async reset (avoid using if possible)
    >   elsif rising_edge(clk) then
    >     if sync_reset = '1' then
    >       --sync reset prefered
    >     elsif enable = '1' then
    >       --put synchronous code here.
    >     end if;
    >   end if;
    > end process;


    Most synthesizers also infer a register from this:

    q <= d when rising_edge(clk);

    The behavior of this concurrent statement is identical to a clocked
    process. The implied process from this concurrent statement will wake
    up on changes to d, but no assignment will be made. Just like clocked
    processes will wake up on the "other" edge of the clock, but no
    assignments will be made. The only time I use the above is when I need
    a register in between structural elements (entity instantiations).

    You can add an asynchronous reset assignment to the concurrent
    register template, but not multiple clock specifications (or enables
    thereof).

    q <= '0' when rst = '1' else d when rising_edge(clk);

    The problem is, there are no "nested if" capabilities in concurrent
    statements like there are in processes.

    For that matter I'm also not aware of any synthesizers that accept
    multiple "clocked" if statements that control assignments to the same
    signal/variable (which would be the analagous process).

    Andy
     
    Andy, Jan 20, 2009
    #10
  11. p.tucci

    Andy Guest

    On Jan 20, 12:19 pm, Jonathan Bromley <>
    wrote:
    >   q <= '0' when rst = '1' else FUNC(d,q) when rising_edge(clk);


    Yep, that'll work, assuming q is not an output port.

    This is one of those interesting situations where the RTL (in a
    process) can describe a behavior without having to read an output, but
    the implementation must read the output, or a buffered version thereof
    (clock enables are usually done with a multiplexer on the register
    input, with one of the mux inputs being the register's output).

    Andy
     
    Andy, Jan 20, 2009
    #11
  12. p.tucci

    Dave Guest

    On Jan 21, 12:27 pm, Jim Lewis <> wrote:

    > I don't find asynchronous and synchronous reset trade-off as clear
    > cut as this.  Does anyone else have a compiled summary of the
    > whys and why nots of asynchronous vs synchronous resets?
    >
    > Off the top of my head, this is what I consider:
    > Match what the target technology (FPGA or ASIC) does best.
    >    If the technology natively supports asynchronous resets, synchronous
    >    reset will cost you a data path element or part of one in an FPGA (one
    >    input in a LUT based FPGA).  In some cases this will increase both
    >    area and timing.
    >


    --snip--

    I've seen both utilization and timing improve somewhat in Xilinx
    Virtex-4 designs when switching from async to synchronous resets. I'm
    led to believe this is because the sync reset inputs of the flops can
    be used to implement some of the synchronous logic as well, giving the
    synthesizer new optimization opportunities. Synchronous logic
    obviously can't be optimized into an async reset input of a flop.

    Dave
     
    Dave, Jan 21, 2009
    #12
    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. Pep
    Replies:
    6
    Views:
    836
  2. Daniel
    Replies:
    6
    Views:
    773
    Thomas Stanka
    Jan 30, 2008
  3. Arne Vajhøj
    Replies:
    23
    Views:
    884
    Tom Anderson
    Aug 31, 2008
  4. Replies:
    4
    Views:
    835
    Minesh Patel
    Mar 10, 2009
  5. KJ
    Replies:
    4
    Views:
    691
Loading...

Share This Page