On 31 Jan 2005 09:33:49 -0800,
[email protected]
(Dave) wrote:
>I am implementing a state machine in a FPGA using VHDL.
>Several states are determined by 4 external event inputs (falling
>edge) which occur asynchronously to the 25MHz FPGA clock (I might need
>to increase to 50MHz). The events occur at random intervals of 10us or
>more.
>
>I have a couple questions which someone may be able to guide me on:
>
>1) Should I have a synchroniser (2-stage shift reg) at each of the 4
>event inputs before being sampled by the state machine
Yes, absolutely, unless you have an astonishingly cunning state
machine design...
> to avoid meta-stability problems?
AARGH, no, that's not the reason.
Saddle-up the old warhorse, and back in to battle once again...
Most people who *think* they have a problem with metastability,
don't. Instead they probably have a problem with input hazards.
OK, so what's an input hazard? It's any situation where an
asynchronous input can affect more than one flip-flop.
If this asynch input should change painfully close to a clock
edge, you will of course get setup/hold violations on the flops.
This in itself rarely causes a problem, because each flop
individually will either respond to the changed input or it
won't. The problem happens when one of the flops DOES respond,
and the other DOESN'T. When this happens you get an internal
state change that was not expected. It will almost certainly
screw up the sequencing of your state machine, and it will
quite likely send it off into the weeds.
Note that, in describing this problem, I have made no appeal
whatever to the idea of metastability. Each flip-flop
individually is behaving quite perfectly; it's just that
the collection of two flip-flops appears to behave inconsistently
because of the asynchronous input.
The problem is completely (yes, I really mean completely) solved
by registering the offending input in just one flip-flop.
The output of this resynchronising flop is then fed to your
state machine. Given that the input is asynchronous, a one-
clock delay in responding to it is unlikely to be a show-
stopper.
If you are both clever and lucky, you may be able to design
your state machine so that only one of its state bits is
affected by any input change. However, it is brain-
numbingly difficult to do this in the face of complicated
changes to the state machine as its design evolves, and
when synthesis tools are inclined to re-code state
vector values arbitrarily as an "optimisation". So it's
almost always better, in practice, to register the
asynchronous inputs before they get anywhere near your
state machine. Especially when you have multiple asynch
inputs to worry about.
Metastability is a much less likely culprit. Metastability
means that one individual flop misbehaves because its D input
changes at an inopportune moment, so that the internal
logic of the flop gets confused about whether to settle at
1 or 0. The flop's clock-to-output delay then becomes much
longer than its specified value. This effect, of course,
CAN happen on my single resynchronising flop, and CAN cause
trouble if its clock-to-output delay is thereby pushed out
to about a clock period; should this happen, the supposedly
resynchronised signal can itself appear to be asynchronous and
can therefore cause an input hazard on the state machine.
A second resynch flip-flop will dramatically reduce the risk
of this problem, at the expense of one more cycle of latency.
Figures published here by Peter Alfke and others suggest that
in your case, with a slow-ish clock and relatively infrequent
transitions of the asynchronous input, the risk of this
genuine metastability is so small that you can ignore it -
but you MUST either do the sums, or else be just a little
paranoid and add the extra flop in any case.
>2) I'm using the following VHDL code to detect a falling edge on the
>event inputs. Is there a better way?
>
>process( clk, ev1, ev2, ev3, ev4, reset)
Oh flippin' 'eck, what are you doing putting asynch
inputs into the sensitivity list of a clocked process?
> variable prev_ev1: std_logic;
> variable got_ev1: boolean;
>
> <variables for other events omitted>
>
> begin
> if (reset = '1') then -- reset the event states
> prev_ev1 := event;
> got_ev1 := false;
> elsif (rising_edge(clk)) then
> if (event = '0') then -- event signal is low
> if (prev_ev1 = '1') then
> got_ev1 := true; -- falling edge detected
> end if;
> prev_ev1 = '0'
> else
> prev_ev1 = '1';
> end if;
>
> <repeat edge detection for the other events>
>
> <process 'got_ev' flags in state machine & reset them>
> end if;
>end process;
Yeah, something like that. Don't reset the flags inside
the state machine. Reset them at the top of the clocked
process, so that they become purely combinational flags.
Effectively you've created a shift register with
an and gate sensing a change across its final stage.
It's sometimes easier to roll this edge detection
into the state machine (don't go into your "wait for fall" state
until you've detected "input high"). Depends on what you're
doing in the state machine. Once again, given that you have
multiple inputs, I suspect the scheme you outline is as good
as you'll get - and it's easy to understand.
>Any advice welcome!
Finally, please DON'T do anything that depends on
simultaneity of two or more of the external asynchronous
inputs - you simply can't rely on that, given that they
are asynchronous relative to your clock. The best you
can do is to identify when two or more inputs change
within one or two sampling clocks of each other.
Alternatively, if you're very lucky you may have an
external signal that indicates when the four inputs
are stable and therefore it's safe to sample them.
HTH
--
Jonathan Bromley, Consultant
DOULOS - Developing Design Know-how
VHDL, Verilog, SystemC, Perl, Tcl/Tk, Verification, Project Services
Doulos Ltd. Church Hatch, 22 Market Place, Ringwood, BH24 1AW, UK
Tel: +44 (0)1425 471223 mail:
[email protected]
Fax: +44 (0)1425 471573 Web:
http://www.doulos.com
The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.