I spoke with the layout guy today, and I've once again had to re-evaluate my understanding. Seems like gates don't propagate metastability. Since gates are railed to VCC and GND, and they don't have internal feedback like flip-flops, metastability is unlikely to propagate through them. This includes regular gates, and buffers, and I'm sure other stuff too.
This means that metastable oscillation is pretty unlikely. Unless of course the output of one flip flop is tied back to its input without going through buffers, or gates.
I guess the only likely issue with metastable flops is the uncertainty of the output. Oh well. I'd still be careful.
Tuesday, June 14, 2011
Sunday, June 12, 2011
Metastability - what logic and research has led me to believe
A long time ago I began learning about hardware design. This was at a time when I was primarily doing software development. Without formal training, I was relying on the explanations of others, logic, and experimentation. It has been years, and I've advanced quite a ways.
When I started designing, the ideas of synchronization were explained to me. Always double or triple sample signals from external sources, or from other clock domains. As it was explained to me, each flop reduced the chances of metastability by a very large factor. 2 samples were considered enough to lower the chances of metastaibility to almost nothing. 3 flops were even better.
As I got more experience, I got used to only using 2 flops to move between clock domains, or to bring an external signal in. But what was really going on?
There are 2 reasons for synchronization flops.
1. Metastable oscillation. This requires an explanation of metastability.
Metastability is a state whereby a flip-flop will sample an input signal on a clock edge, but the input signal is in a state of transition. This is a common situation when sampling from another clock domain or from an external signal. When a flip-flop samples an input signal that is not stable high or stable low, the flip-flop's output is undefined. Suffice it to say that an undefined output means that the output does not rise or fall as would be expected. The output wavers and takes a while to settle in one state or another.
A metastable flop will settle after a while. The assumed time it takes for a metastable flop to settle is a complete clock period. While a flop-flop is metastable, any flop sampling the metastable flop's output could also go metastable.
A second synchronization flop guarantees a full clock period of time for the output of the first metastable synchronization flop to settle and arrive at the second synchronization flop. As a rule of synchronization, there can be no combinatorial logic between the first and second flops.
Metastable oscillations can occur if there is a path whereby metastability can loop around. This can occur with a single flop, or with a sequence of flops. The simplest example of metastable oscillation can be with one flop. A single flop whose input comes from a mux that has a select signal to choose between an external signal and the flop's own output is prone to metastable oscillation. The flop can be used to sample an input signal, and then hold that value using the select of the input mux. But since the output of this flop is driven back to it's input using a mux, there may not be enough time for the output to settle before it is sampled back into itself.
2. Indeterminate input. When an output from another clock domain or an external signal is input into multiple flops at the same time, there is no guarantee that each flop will settle with the same input value. There are also the risks of metastability propagating through the sampling flops.
Wednesday, June 1, 2011
Can you guess why multicycle constraints are problematic?
As I have been suffering with synthesis tools that don't analyze clock domains during synthesis, I realized a new aspect to this problem. Have you ever designed a module that uses a multicycle path? Well it can cause you real headaches if you're not careful. Imagine this code:
entity demo_module is
port (
clk : in std_logic;
rstn : in std_logic;
sel : in std_logic;
inputa : in std_logic_vector(7 downto 0);
inputb : in std_logic_vector(7 downto 0);
output : out std_logic_vector(7 downto 0)
);
end entity;
architecture rtl of demo_module is
signal sel_input : std_logic_vector(7 downto 0);
signal input_d : std_logic_vector(7 downto 0);
begin
process(sel, inputa, inputb)
begin
if(sel = '0') then
sel_input <= inputa;
else
sel_input <= inputb;
end if;
end process;
process(clk, rstn)
begin
if(rstn = '0') then
input_d <= (others => '0');
output <= (others => '0');
elsif(clk'event and clk = '1') then
input_d <= sel_input;
output <= sel_input xor input_d;
end if;
end process;
end rtl;
I'm doing nothing complex here. Using sel to select which of the inputs I'm gonna sample and then output the xor of.
Now let's say that it takes 2 cycles to change inputa or inputb, and I make sure that sel only switches every other cycle. This should be valid. Here's where the problem with synthesis tools come in to play. Synthesis tools can use any method they choose for implementing the sel mux. They do not have to use an actual mux. This could be done using a combination of gates / complex gates. What this means is that even when sel is stable on inputa, a change on inputb can cause a glitch (and vice versa). This is unimportant when inputa and inputb are guaranteed to change within a clock, but this is of vital importance when you want to use a multicycle constraint. The fact that inputa and inputb take more than one cycle to change means that at the clock edge when sel doesn't change (and sel is STABLE), inputa / inputb can be changing and thereby cause a glitch on the output of the muxing process (when done without a mux). This will then create an incorrect read of input_d (the sampled value).
Beware!
entity demo_module is
port (
clk : in std_logic;
rstn : in std_logic;
sel : in std_logic;
inputa : in std_logic_vector(7 downto 0);
inputb : in std_logic_vector(7 downto 0);
output : out std_logic_vector(7 downto 0)
);
end entity;
architecture rtl of demo_module is
signal sel_input : std_logic_vector(7 downto 0);
signal input_d : std_logic_vector(7 downto 0);
begin
process(sel, inputa, inputb)
begin
if(sel = '0') then
sel_input <= inputa;
else
sel_input <= inputb;
end if;
end process;
process(clk, rstn)
begin
if(rstn = '0') then
input_d <= (others => '0');
output <= (others => '0');
elsif(clk'event and clk = '1') then
input_d <= sel_input;
output <= sel_input xor input_d;
end if;
end process;
end rtl;
I'm doing nothing complex here. Using sel to select which of the inputs I'm gonna sample and then output the xor of.
Now let's say that it takes 2 cycles to change inputa or inputb, and I make sure that sel only switches every other cycle. This should be valid. Here's where the problem with synthesis tools come in to play. Synthesis tools can use any method they choose for implementing the sel mux. They do not have to use an actual mux. This could be done using a combination of gates / complex gates. What this means is that even when sel is stable on inputa, a change on inputb can cause a glitch (and vice versa). This is unimportant when inputa and inputb are guaranteed to change within a clock, but this is of vital importance when you want to use a multicycle constraint. The fact that inputa and inputb take more than one cycle to change means that at the clock edge when sel doesn't change (and sel is STABLE), inputa / inputb can be changing and thereby cause a glitch on the output of the muxing process (when done without a mux). This will then create an incorrect read of input_d (the sampled value).
Beware!
Subscribe to:
Posts (Atom)