Newbie question: using asynchronous signals.

P

Paul Marciano

Guest
Hello. A quick question from a beginner.

I've read that in order to use asynchronous signals in synchronous
logic, they must be passed through a couple of registers in order to
reduce metastability.

So you can't write:

@(posedge clk)
sync_reg <= async_source;

Instead, something like (ignoring reset):

reg [1:0] buf;

@(posedge clk)
begin
buf <= { buf[0], async_source };
sync_reg <= buf[1];
end


Does the same rule apply to signals used only in conditional clauses?
For example, is it ok to write:

reg [7:0] cnt;

always @(posedge clk)
if (async_signal)
cnt <= cnt + 1;


Or must async_signal be synchronized here too? I think the answer is
that it must be synchronized, but please advise.


Thanks,
Paul.
 
The signal must be synchronized. The problems you'll see these days are
less related to metastability and more related to just when the async signal
arrives. In your counter example, the enable may be routed to all the
counter bits. Imagine what result you'd get if that signal was "valid" in
only some of your registers. Your signal has to have a single point that
says it's valid or it isn't. That single point should be synchronous to
your clock to allow proper setup time for the event that it drives.

Note also for your example that an async enable might be caught more than
once or might not be caught at all depending on the pulse width versus your
clock frequency.

Conditional operators are just like the rest of the signals in your design;
the logic can be distributed, reusing the condition signal at multiple
destinations.



"Paul Marciano" <pm940@yahoo.com> wrote in message
news:1127411323.582268.137000@z14g2000cwz.googlegroups.com...
Hello. A quick question from a beginner.

I've read that in order to use asynchronous signals in synchronous
logic, they must be passed through a couple of registers in order to
reduce metastability.

So you can't write:

@(posedge clk)
sync_reg <= async_source;

Instead, something like (ignoring reset):

reg [1:0] buf;

@(posedge clk)
begin
buf <= { buf[0], async_source };
sync_reg <= buf[1];
end


Does the same rule apply to signals used only in conditional clauses?
For example, is it ok to write:

reg [7:0] cnt;

always @(posedge clk)
if (async_signal)
cnt <= cnt + 1;


Or must async_signal be synchronized here too? I think the answer is
that it must be synchronized, but please advise.


Thanks,
Paul.
 
Paul Marciano wrote:
Hello. A quick question from a beginner.

I've read that in order to use asynchronous signals in synchronous
logic, they must be passed through a couple of registers in order to
reduce metastability.
The answer depends. If you just want to register some kind of
asynchronous event, you will probably pass it through a glitch-filter in
the first place, in that case you don't need meta-stability filter.

If you don't care about glitches or are using analog filters, then the
answer is maybe. If the registered signal is only driving more than one
logic gate, then you'd need a meta-stability filter.

For large amount of data with wide buses, using asynchronous FIFO is
much better.

You normall don't want to synchronize the asynchronous reset if you want
instantaneous response. However, you should at least synchronize the
trailing edge of the asynchronous reset to reduce meta-stability issues.
 
John/Jason,

Thanks for the replies.

I want to build a simple pulse counter. The pulses run at 0 - 5kHz
(50% duty cycle) and my FPGA clock runs around 30MHz. This is my
attempt, shifting the asynchronous pulse source signal (a_sig) through
a shift register for synchronization. Synchronous reset.

module pulse(
input clk,
input reset,
input a_sig,
output reg [15:0] cnt);

reg [2:0] s_sig;

wire pos_sig = s_sig[2] & ~s_sig[1];

always @(posedge clk)
if (!reset)
s_sig <= 3'b0;
else
s_sig <= { s_sig[1:0], a_sig };

always @(posedge clk)
if (!reset)
cnt <= 16'h0000;
else if (pos_sig)
cnt <= cnt + 1;

endmodule

Pretty straight forward, and seems to work in simulation.


Is this minimal, or would an experienced designer do it differently?

Thanks,
Paul.
 
Change the combinatorial enable to a register. Metastability will *rarely*
cut down on the slack for the s_sig[0] to pos_sig propagation delay. Adding
another register or a shorter timing constraint to the s_sig[0]-to-pos_sig
path can reduce your synchronization failure from once every million years
to once every 10 trillion if you'd like to go that extra step.

reg [1:0] s_sig;
reg pos_sig;
always @(posedge clk)
if( !reset )
begin
s_sig <= 2'h3; // no count after reset if a_sig already high
pos_sig <= 1'b0;
cnt <= 16'h0000;
end
else
begin
s_sig <= { s_sig[0], a_sig };
pos_sig <= ~s_sig[1] & s_sig[0]; // rising edge
if (pos_sig) cnt <= cnt + 16'h1;
end

It's just the way I'd do it, not the only right way.


"Paul Marciano" <pm940@yahoo.com> wrote in message
news:1127425295.381656.216510@g43g2000cwa.googlegroups.com...
John/Jason,

Thanks for the replies.

I want to build a simple pulse counter. The pulses run at 0 - 5kHz
(50% duty cycle) and my FPGA clock runs around 30MHz. This is my
attempt, shifting the asynchronous pulse source signal (a_sig) through
a shift register for synchronization. Synchronous reset.

module pulse(
input clk,
input reset,
input a_sig,
output reg [15:0] cnt);

reg [2:0] s_sig;

wire pos_sig = s_sig[2] & ~s_sig[1];

always @(posedge clk)
if (!reset)
s_sig <= 3'b0;
else
s_sig <= { s_sig[1:0], a_sig };

always @(posedge clk)
if (!reset)
cnt <= 16'h0000;
else if (pos_sig)
cnt <= cnt + 1;

endmodule

Pretty straight forward, and seems to work in simulation.


Is this minimal, or would an experienced designer do it differently?

Thanks,
Paul.
 
Paul,

You don't have to worry about meta-stability in this situation. Even if
it occurs on a rising edge, you have the following two possibilities:

1. The new value appears at 0
2. The new value appears at 1

Either way the edge detector will see it, only in the first case it will
see it one cycle late, which is no problem for you.

The only thing that I would change is to use two flipflops only. You
don't need another flipflop. Also if you are using negative reset, it's
better to name the signal reset_n or something like that. You will see
the benefit of this when you have a large project.

reg [1:0] s_sig;
reg [15:0] cnt;

always @ (posedge clk)
if (~reset)
s_sig[1:0] = 2'b11;
else
s_sig[1:0] = {s_sig[0], a_sig};

always @ (posedge clk)
if (~reset)
cnt = 16'b0;
else if (s_sig[0] & ~s_sig[1])
cnt = cnt + 1'b1;

~Jason

Paul Marciano wrote:
John/Jason,

Thanks for the replies.

I want to build a simple pulse counter. The pulses run at 0 - 5kHz
(50% duty cycle) and my FPGA clock runs around 30MHz. This is my
attempt, shifting the asynchronous pulse source signal (a_sig) through
a shift register for synchronization. Synchronous reset.

module pulse(
input clk,
input reset,
input a_sig,
output reg [15:0] cnt);

reg [2:0] s_sig;

wire pos_sig = s_sig[2] & ~s_sig[1];

always @(posedge clk)
if (!reset)
s_sig <= 3'b0;
else
s_sig <= { s_sig[1:0], a_sig };

always @(posedge clk)
if (!reset)
cnt <= 16'h0000;
else if (pos_sig)
cnt <= cnt + 1;

endmodule

Pretty straight forward, and seems to work in simulation.


Is this minimal, or would an experienced designer do it differently?

Thanks,
Paul.
 
John/Jason,

Thanks again for the help!

Regards,
Paul.
 

Welcome to EDABoard.com

Sponsor

Back
Top