synchronization of state machine between clocks

Guest
Hi,

There are two clocks in my design. On the main clock, a state machine
runs. It is encoded as a type (leaving the decision on the exact
encoding to the synthesizer). I want to set a signal on "enable" when
the machine is in a certain state, so I do:

if reset
...
elsif rising_edge(clk1) then
if machine_state = active then
my_enable <= '1';
else
my_enable <= '0';
end if;
end if;

This works fine, of course. But suppose I have another enable signal,
which should depend on the same event but works with a different
clock. How do I synchronize the state of the machine between the two
clocks ? At the moment I do a process:

if reset
...
elsif rising_edge(clk2) then
my_enable_sync <= my_enable;
my_enable2 <= my_enable_sync;
end if;

This works, because I know that the "Active" state is very long and
I'm not sensitive to exact timing. This double FF ensures no
metastability and correct syncing of my_enable to the clk2 domain.

Questions:

1) Is this a valid way to accomplish my goal ?
2) What is a faster / tighter way to do this synchronization, if I
care about every clock cycle ?

10x
R
 
On Nov 25, 6:09 am, richard.melik...@gmail.com wrote:

1) Is this a valid way to accomplish my goal ?
2) What is a faster / tighter way to do this synchronization, if I
care about every clock cycle ?

10x
R
It's very common. This makes it mostly valid :) Read the literature
on metastability, it's all probabilities. One flop gets you the
biggest bang for th buck. I tend to be paranoid and flop more than
once, but this costs you delay.

It also depends on the relative clock rates. One gotcha is that if you
assume that the pulse in the sending domain is a certain number of
clocks wide, it may not be so on the other side. In particular, single
pulse "events" may get deleted or stretched.

Also, make sure you use the flopped output in *exactly* one place, and
make sure you decorate it with do-not-replicate and do-not-retime
attributes. Otherwise the synthesizer may introduce all kinds of
problems when signals reconverge after undergoing a statistically
distributed and unequal number of clock delays at each crossing.

Another fairly common approach is to build a hand-shake (an SR-flop
idea), possibly with intervening metastability flops, which guarantees
to hold the signal until seen properly at the other side. You can
couple this with edge-detctors to get single clock wide pulse ouputs.
This lets you cross from slow to fast clocks safely but again, can
cost delays.

If you need absolute speed (like in a CPU pipeline), and are willing
to do some serious work to achieve it, look at some of the neat ideas
in the paper "Efficient Self-Timed Interfaces for Crossing Clock
Domains" by Chakraborty and Greenstreet:

http://www.cs.utah.edu/classes/cs6943/papers/async2003.pdf

These techniques may be easier to implement in ASIC than FPGA, though.
I'm sure there are a thousand other neat ideas out there, too.

Best regards,

- Kenn
 
richard.melikson@gmail.com schrieb:

if reset
...
elsif rising_edge(clk2) then
my_enable_sync <= my_enable;
my_enable2 <= my_enable_sync;
end if;

This works, because I know that the "Active" state is very long and
I'm not sensitive to exact timing. This double FF ensures no
metastability and correct syncing of my_enable to the clk2 domain.

Questions:

1) Is this a valid way to accomplish my goal ?
2) What is a faster / tighter way to do this synchronization, if I
care about every clock cycle ?
Synchronisation of asynchronous processes can be done by detecting a one
bit signal change. With this method you can avoid in many situations
that the duration of the synchronisation signal could become too short.
I would never use a pulse to synchronise between two clock domains.

-- trigger process 2 from process 1, clock domain #1:
if have_to_trigger_proc2 then
trigger_proc2 <= not trigger_proc2;
end if;

-- detect trigger from process 1 in process 2, clock domain #2:
trigger_proc2_sync <= trigger_proc2; -- synchronise signal from proc1
trigger_proc2_sync_old <= trigger_proc2_sync;

if trigger_proc2_sync /= trigger_proc2_sync_old then
...
end if;

You have to care about that the trigger signals in both processes have
the same reset value.

Best regards

Wolfgang Grafen
 

Welcome to EDABoard.com

Sponsor

Back
Top