Process vs concurrent stataments?

P

p.tucci

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
 
Joined
Mar 10, 2008
Messages
348
Reaction score
0
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
 
T

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

Tricky

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

p.tucci

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
 
T

Tricky

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

p.tucci

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

p.tucci

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
 
A

Andy

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
 
A

Andy

  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
 
D

Dave

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,738
Latest member
JinaMacvit

Latest Threads

Top