Process vs concurrent stataments?

P

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 <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
 
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;
 
tx_data &lt;=
(others =&gt; '0') when RESET='0'
else
'0' &amp; DATA_L(IN_WIDTH-1 downto 0) &amp; "0000000"
when rising_edge(SYS_CK_IN)
and (counter mod (SYS_CK_RATIO/2) = 0)
and last_lr_ck = '1'
else
'0' &amp; DATA_R(IN_WIDTH-1 downto 0) &amp; "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) &amp; '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.
 
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 &lt;= 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 &lt;= not last_lr_ck; --commented out...
--what if i'd put here instead of below?
if(last_lr_ck = '1') then
tx_data &lt;= "0" &amp; DATA_R(IN_WIDTH-1 downto 0) &amp; "0000000";
last_lr_ck &lt;= '0';
else
tx_data &lt;= "0" &amp; DATA_L(IN_WIDTH-1 downto 0) &amp; "0000000";
last_lr_ck &lt;= '1';
end if;

else
tx_data &lt;= tx_data(BITXCH-2 downto 0) &amp; '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) &lt;= tx_data(i);
--end loop;

end if;

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

DOUT &lt;= tx_data(BITXCH-1);
SYS_CK_OUT &lt;= SYS_CK_IN;
BIT_CK &lt;= last_bit_ck;
LR_CK &lt;= 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 &lt;= 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 &lt;= 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 &lt;= "0" &amp; DATA_R(IN_WIDTH-1 downto 0) &amp; "0000000";
else
tx_data &lt;= "0" &amp; DATA_L(IN_WIDTH-1 downto 0) &amp; "0000000";
end if;
elsif(last_bit_ck = '1') then --MOD HERE, was 0
tx_data &lt;= tx_data(BITXCH-2 downto 0) &amp; '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 &lt;= (counter + 1) mod (SYS_CK_RATIO/2);
end if;
end process;


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


Thanks,
Primiano Tucci
--
http://www.primianotucci.com/
 
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 &lt;= tx_data(BITXCH-2 downto 0) &amp; '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) &lt;= 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.
 
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
 
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
 
On Tue, 20 Jan 2009 10:06:59 -0800 (PST), Andy wrote:

Most synthesizers also infer a register from this:

q &lt;= d when rising_edge(clk);
[...]
You can add an asynchronous reset assignment to the concurrent
register template, but not multiple clock specifications (or enables
thereof).

q &lt;= '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).
Completely agreed. See my response to the same querant
on comp.arch.fpga where I pointed out that you can use a
function to get arbitrarily complicated next-state logic:

q &lt;= '0' when rst = '1' else FUNC(d,q) when rising_edge(clk);

Of course, this gives rise to yet more unnecessary
firings of the implied sensitivity list (one delta after
the active clock that changes q).
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
On Jan 19, 3:00 am, Tricky &lt;Trickyh...@gmail.com&gt; 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 &lt;= 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 &lt;= '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
 
On Jan 20, 12:19 pm, Jonathan Bromley &lt;jonathan.brom...@MYCOMPANY.com&gt;
wrote:
  q &lt;= '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
 
On Tue, 20 Jan 2009 10:06:59 -0800 (PST), Andy &lt;jonesandy@comcast.net&gt;
wrote:

On Jan 19, 3:00 am, Tricky &lt;Trickyh...@gmail.com&gt; 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 &lt;= 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.
I don't know about most, but certainly XST and Altera (Quartus) also
accept a process with a single "wait for rising_edge(clk)"
(but not inside a for loop!)

process
begin
wait for rising_edge(clk);
if enable then
q &lt;= d;
end if;
end process;

This may have fewer limitations than the concurrent statement. I don't
believe it allows any more generality than the standard approach but it
may sometimes be more concise or readable.

Yes my "enable" is of type boolean. It might be a function...

- Brian
 
Brian
process
begin
wait for rising_edge(clk);
if enable then
q &lt;= d;
end if;
end process;
A minor oops in the code (which you know) but will produce
an confusing error message should the OP tries it.
Wait for is used with time units. What is needed here is:

wait until rising_edge(Clk) ;

-- or in more simplified form:

wait until Clk = '1' ;

Note in the 2nd form, the wait statement only wakes up when
Clk changes (or more generally a signal in the expression).

The downside to this form is it does not support asynchronous resets
(at least not in an easy, reasonable form).

The one I use most is the one Tricky posted:
sync_proc : process(clk, reset)
begin
if reset = '1' then
--async reset
elsif rising_edge(clk) then
if sync_reset = '1' then
--sync reset
elsif enable = '1' then
--put synchronous code here.
end if;
end if;
end process;

WRT reset which Tricky posted some preferences, I don't think
it is as simple as he does, so see my follow up post to Tricky's
post.

Cheers,
Jim
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jim Lewis SynthWorks VHDL Training http://www.synthworks.com

A bird in the hand may be worth two in the bush,
but it sure makes it hard to type.
 
Tricky
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;
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.

With a static device (fuse programmed or ASIC), asynchronous reset can
stabilize some outputs before clock starts which is sometimes important
in safety critical applications.
On a dynamically loaded FPGA (most Xilinx and Altera) this is a mute
point as the clock has to be running before the FPGA loads and it
is not reset until after the device is loaded.

Synchronous reset has better immunity to noise
on the reset input, which can be important in any application.
This can be mitigated depending on the reset synchronization
style.

Every reset input to every clock domain (for synchronous or
asynchronous reset) needs a reset synchronization circuit.
This is discussed in the Cliff Cummings paper:
http://www.sunburst-design.com/papers/CummingsSNUG2002SJ_Resets.pdf
For synchronous resets and asynchronous ones on a dynamically
loaded device, I double register reset before propagating it
out to the flip-flops in the chip.

What do people think of Xilinx's position to not use reset, but
instead use the device load to reset the chip?
One of my concerns is that it leads to a design that is difficult
to port to other technologies.

To allow easy IP generation, it seems like we would benefit from
portable tool commands that allow us to change the reset style of
a device between synchronous, asynchronous, and reset during load.
Then code either synchronous or asynchronous reset as you prefer
and allow the tool to convert it.

Cheers,
Jim
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jim Lewis SynthWorks VHDL Training http://www.synthworks.com

A bird in the hand may be worth two in the bush,
but it sure makes it hard to type.
 
On Jan 21, 12:27 pm, Jim Lewis &lt;j...@synthworks.com&gt; 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
 
On Wed, 21 Jan 2009 08:50:21 -0800, Jim Lewis &lt;jim@synthworks.com&gt;
wrote:

Brian
process
begin
wait for rising_edge(clk);

A minor oops in the code (which you know) but will produce
an confusing error message should the OP tries it.
Wait for is used with time units. What is needed here is:

wait until rising_edge(Clk) ;
Thanks for the correction; you're right of course.
(Work machine != internet machine)

- Brian
wait until Clk = '1' ;

Note in the 2nd form, the wait statement only wakes up when
Clk changes (or more generally a signal in the expression).
ah; I expect you could fool it in sim by alternating 'H' and '1' but
practically you are right...

The downside to this form is it does not support asynchronous resets
(at least not in an easy, reasonable form).
Which is why I ducked that issue in the example!
And in practice, yes, I normally use the example below.

The one I use most is the one Tricky posted:
sync_proc : process(clk, reset)
begin
if reset = '1' then
--async reset
elsif rising_edge(clk) then
if sync_reset = '1' then
--sync reset
elsif enable = '1' then
--put synchronous code here.
end if;
end if;
end process;
Thanks,
- Brian
 
Brian,
wait until rising_edge(Clk) ;
. . .
wait until Clk = '1' ;

Note in the 2nd form, the wait statement only wakes up when
Clk changes (or more generally a signal in the expression).

ah; I expect you could fool it in sim by alternating 'H' and '1' but
practically you are right...
Yes you can fool it, however, if I want to check clock, I can
check it once with:
assert (Clk = '1' or Clk = '0') report "Bad value on Clk" severity error ;

OTOH, I tend to use rising_edge(Clk) in all applications due to
its readability. Hopefully the compiler people are smart
enough to optimize the code so that rising_edge is at least
as fast as the other alternatives.

I like to call rising_edge a "valley girl" check :) -
you want to be for-sure for-sure that clk rose.

Cheers,
Jim
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jim Lewis SynthWorks VHDL Training http://www.synthworks.com

A bird in the hand may be worth two in the bush,
but it sure makes it hard to type.
 

Welcome to EDABoard.com

Sponsor

Back
Top