Meta test

From Hamsterworks Wiki!

Jump to: navigation, search

This FPGA Project is a little experiment to see if metastability really does occur. I want to see it with my own eyes!

Contents

Project 1

Can I prove that just buffering an external switch isn't enough? Not yet a test for true metasability, but can be a cause of errors in your design. The input is passed to eight registers, and this is tested to see if they all have the same values. If not, we have a problem...

Here is the technology level view, confirming that the input signal goes to eight different flip-flops:

Meta test1.png

You can just see the input buffer on the left, which should eliminate any issues with rise times and so on.

meta_test.vhd

----------------------------------------------------------------------------------
-- Engineer: Mike Field <hamster@snap.net.nz>
-- 
-- Description: Stage one in a project to test for metastability 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
Library UNISIM;
use UNISIM.vcomponents.all;

entity meta_test is
    Port ( clk : in  STD_LOGIC;
           testsig : in  STD_LOGIC;
           leds : out  STD_LOGIC_VECTOR (7 downto 0));
end meta_test;

architecture Behavioral of meta_test is
   signal s   : std_logic_vector(7 downto 0);
   signal ss   : std_logic_vector(7 downto 0);
   
   signal ctr : unsigned(7 downto 0);
begin
   leds <= std_logic_vector(ctr);

FF_A : FDRSE generic map ( INIT => '0')  port map ( Q => s(0), C => clk, CE => '1', D => testsig, R => '0', S => '0');
FF_B : FDRSE generic map ( INIT => '0')  port map ( Q => s(1), C => clk, CE => '1', D => testsig, R => '0', S => '0');
FF_C : FDRSE generic map ( INIT => '0')  port map ( Q => s(2), C => clk, CE => '1', D => testsig, R => '0', S => '0');
FF_D : FDRSE generic map ( INIT => '0')  port map ( Q => s(3), C => clk, CE => '1', D => testsig, R => '0', S => '0');
FF_E : FDRSE generic map ( INIT => '0')  port map ( Q => s(4), C => clk, CE => '1', D => testsig, R => '0', S => '0');
FF_F : FDRSE generic map ( INIT => '0')  port map ( Q => s(5), C => clk, CE => '1', D => testsig, R => '0', S => '0');
FF_G : FDRSE generic map ( INIT => '0')  port map ( Q => s(6), C => clk, CE => '1', D => testsig, R => '0', S => '0');
FF_H : FDRSE generic map ( INIT => '0')  port map ( Q => s(7), C => clk, CE => '1', D => testsig, R => '0', S => '0');

process(clk)
   begin
      if rising_edge(clk) then
         -- detect if a error has occurred
         case ss is 
            when "00000000" =>
               ctr <= ctr;
            when "11111111" =>
               ctr <= ctr;
            when others => ctr <= ctr+1;
         end case;
         -- Second stage of a serialisers
         ss <= s;
      end if;
   end process;   
end Behavioral;

meta_test.ucf

Here is the UCF file for the Papilio One + LogicStart megawung:


#Created by Constraints Editor (xc3s250e-vq100-4) - 2012/10/02
NET "clk" TNM_NET = clk;
TIMESPEC TS_clk = PERIOD "clk" 31.25 ns HIGH 50%;

NET LEDs(7) LOC = "P5"  | IOSTANDARD=LVTTL;
NET LEDs(6) LOC = "P9"  | IOSTANDARD=LVTTL;
NET LEDs(5) LOC = "P10" | IOSTANDARD=LVTTL;
NET LEDs(4) LOC = "P11" | IOSTANDARD=LVTTL;
NET LEDs(3) LOC = "P12" | IOSTANDARD=LVTTL;
NET LEDs(2) LOC = "P15" | IOSTANDARD=LVTTL;
NET LEDs(1) LOC = "P16" | IOSTANDARD=LVTTL;
NET LEDs(0) LOC = "P17" | IOSTANDARD=LVTTL;

NET testsig LOC = "P4"  | IOSTANDARD=LVTTL; # Rightmost switch

NET "clk" LOC="P89" | IOSTANDARD=LVTTL | PERIOD=31.25ns;

Routing delays

The difference in path delays is most probably the determining factor in how likely a mismatch is to occur. This info can be picked up in the FPGA Editor, if you view the net's properties and tick the "Show pin delays" on the "Pins" tab:

Path timings.png

Project 2

In project two I'll merge the eight input flip-flops (FF_A through FF_H) into a single flip-flop. This will stop any faults from occurring, unless that flip-flop is driven into a metastable state. To get that to happen I'm going to need to pump a lot of signal transitions through it, each with slightly varying phase alignment.

Here is the updated technology schematic, showing how the test signal feeds into one flip-flop, and then into 8 synchronizers:

Meta test2.png

meta_test2.vhd

----------------------------------------------------------------------------------
-- Engineer: Mike Field <hamster@snap.net.nz>
-- 
-- Description: Stage one in a project to test for metastability 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
Library UNISIM;
use UNISIM.vcomponents.all;

entity meta_test2 is
    Port ( clk32 : in  STD_LOGIC;
           testsig : in  STD_LOGIC;
           leds : out  STD_LOGIC_VECTOR (7 downto 0));
end meta_test2;

architecture Behavioral of meta_test2 is
   signal latched : std_logic := '0';
   signal s       : std_logic_vector(7 downto 0);
   signal ss      : std_logic_vector(7 downto 0);   
   signal ctr     : unsigned(7 downto 0);
   signal clk     : std_logic := '0';
   signal clkn    : std_logic := '0';
   signal errored : std_logic := '0';
   
   COMPONENT clocking
   PORT(
      CLKIN_IN : IN std_logic;          
      CLKFX_OUT : OUT std_logic;
      CLKFX180_OUT : OUT std_logic;
      CLKIN_IBUFG_OUT : OUT std_logic;
      CLK0_OUT : OUT std_logic
      );
   END COMPONENT;

begin
   leds <= std_logic_vector(ctr);
   Inst_clocking: clocking PORT MAP(
      CLKIN_IN => clk32,
      CLKFX_OUT => clk,
      CLKFX180_OUT => clkn,
      CLKIN_IBUFG_OUT => open,
      CLK0_OUT => open
   );

--   latched <=testsig;
FF_L : FDRSE generic map ( INIT => '0')  port map ( Q => latched, C => clkn, CE => '1', D => testsig, R => '0', S => '0');
   
FF_A : FDRSE generic map ( INIT => '0')  port map ( Q => s(0), C => clk, CE => '1', D => latched, R => '0', S => '0');
FF_B : FDRSE generic map ( INIT => '0')  port map ( Q => s(1), C => clk, CE => '1', D => latched, R => '0', S => '0');
FF_C : FDRSE generic map ( INIT => '0')  port map ( Q => s(2), C => clk, CE => '1', D => latched, R => '0', S => '0');
FF_D : FDRSE generic map ( INIT => '0')  port map ( Q => s(3), C => clk, CE => '1', D => latched, R => '0', S => '0');
FF_E : FDRSE generic map ( INIT => '0')  port map ( Q => s(4), C => clk, CE => '1', D => latched, R => '0', S => '0');
FF_F : FDRSE generic map ( INIT => '0')  port map ( Q => s(5), C => clk, CE => '1', D => latched, R => '0', S => '0');
FF_G : FDRSE generic map ( INIT => '0')  port map ( Q => s(6), C => clk, CE => '1', D => latched, R => '0', S => '0');
FF_H : FDRSE generic map ( INIT => '0')  port map ( Q => s(7), C => clk, CE => '1', D => latched, R => '0', S => '0');

process(clk)
   begin
      if rising_edge(clk) then
         if errored = '1' then
            ctr <= ctr+1;
         end if;

         -- detect if a error has occurred
         case ss is 
            when "00000000" =>
               errored <= '0';
            when "11111111" =>
               errored <= '0';
            when others => 
               errored <= '1';
         end case;
         -- Second stage of a serialisers
         ss <= s;
      end if;
   end process;   
end Behavioral;

papilio.ucf

With these location constraints on the flip-flops, pin delays are spread between around 0.5ns to 1.25ns.

NET "clk32" TNM_NET = clk32;
TIMESPEC TS_clk32 = PERIOD "clk32" 31.25 ns HIGH 50%;
NET "clk32" LOC="P89" | IOSTANDARD=LVTTL | PERIOD=31.25ns;

NET testsig LOC = "P17" ;
NET LEDs(7) LOC = "P58" ;
NET LEDs(6) LOC = "P54" ;
NET LEDs(5) LOC = "P41" ;
NET LEDs(4) LOC = "P36" ;
NET LEDs(3) LOC = "P34" ;
NET LEDs(2) LOC = "P32" ;
NET LEDs(1) LOC = "P25" ;
NET LEDs(0) LOC = "P22" ;
INST "ff_l" LOC = "SLICE_X24Y9";
INST "ff_a" LOC = "SLICE_X25Y10";
INST "ff_b" LOC = "SLICE_X25Y12";
INST "ff_c" LOC = "SLICE_X25Y14";
INST "ff_d" LOC = "SLICE_X25Y16";
INST "ff_e" LOC = "SLICE_X25Y18";
INST "ff_f" LOC = "SLICE_X25Y20";
INST "ff_g" LOC = "SLICE_X25Y22";
INST "ff_h" LOC = "SLICE_X25Y24";

Findings

The last project detects an error about once every 15 minutes - that is a one in 45,000,000,000 transitions of test_signal. To put that in a human perspective, if you pushed a button once every second, and it generated 20 bounces per press it will take on average 70 years before a metastable error occurred. However, if you have a million units in the field, this equates to about 40 faults per day.

When working at very high speeds the errors are much more likely to occur is far higher, and likewise at lower speeds errors are much less likely. The exact likelihood of an error depends on many things, not only the performance characteristics of the logic, but also routing delays and the 'spread' of routing delays within the design. Because of this it the same logical design can have different MTBF numbers each time it is implemented, even in the same device.

Personal tools