Wie könnte ein einfacher Aufbau aussehen, um Metastabilität darzustellen? Ein Eingangssignal wird auf ein Flipflop ffS eingelesen und der Ausgang dieses ffS parallel auf 2 Flipflops (ffA und ffB) eingetaktet. Die Ausgänge dieser beiden Flipflops werden auf Gleichheit des eingetakteten Signals untersucht und bei unterschiedlichen Werten ein Zähler hochgezählt, der dann auf LEDs ausgegeben wird.
Falls die beiden ffA und ffB die gleichen Werte einlesen, wird auch am Ende der Schieberegisterkette immer der selbe Wert herauskommen, und der Zähler wird nicht hochzählen.
Wenn aber die beiden ffA und ffB unterschiedliche Werte einlesen, weil das ffS metastabile Zustände annimmt, dann wird der Zähler Werte ungleich 0 anzeigen. In der Verhaltenssimulation kann ein solcher Fehler nicht gefunden werden.
Und dazu die VHDL-Beschreibung
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity Metastable is Port ( clk : in STD_LOGIC; inp : in STD_LOGIC; leds : out STD_LOGIC_VECTOR (7 downto 0)); end Metastable; architecture Behavioral of Metastable is signal ffS : std_logic := '0'; signal ffA : std_logic := '0'; signal ffB : std_logic := '0'; signal cnt : unsigned(7 downto 0) := (others=>'0'); begin process begin wait until rising_edge(clk); ffS <= inp; -- Sync-Flipflop ffA <= ffS; ffB <= ffS; end process; process begin wait until rising_edge(clk); if (ffA /= ffB) then cnt <= cnt+1; end if; end process; leds <= std_logic_vector(cnt); end Behavioral;
Allerdings ergibt sich mit den Standardeinstellungen folgendes Ergebnis:
INFO:Xst:2261 - The FF/Latch <ffA_3> in Unit <Metastable> is equivalent to the following FF/Latch, which will be removed : <ffB_3>
WARNING:Xst:1896 - Due to other FF/Latch trimming, FF/Latch <cnt_7> has a constant value of 0 in block <Metastable>.
WARNING:Xst:2677 - Node <sr1_0> of sequential type is unconnected in block <Metastable>.
# Counters : 1
8-bit up counter : 1
# Registers : 1
Flip-Flops : 1
# Xors : 1
1-bit xor2 : 1
Und quasi als Ausrufezeichen:
Clock Information: No clock signals found in this design
Die Synthese hat also erkannt, dass beide Flipflops ffA und ffB das selbe machen. Sie hat eines der beiden Register herausoptimiert und dann ermittelt, dass der Vergleicher überflüssig, und damit der Ausgangswert für die LEDs immer 0 ist.
Also muß erst mal das Wegoptimieren des Schieberegisters unterbunden werden.
Der Versuch, das Attribut KEEP auf die Schieberegister anzuwenden, funktioniert nicht.
Erst das Ändern der Syntheseoption --> Xilinx Specific Options --> Equivalent Register Removal auf unchecked ergibt dieses Ergenbis:
# Registers : 11
Flip-Flops : 11
Erst mit dieser Einstellung werden auch tatsächlich 3 Flipflops und der 8-Bit-Zähler implementiert.
Mit diesem Aufbau wird erkennbar, dass bei handelsüblichen Taktfrequenzen (<200MHz) der Zähler nichts zu tun hat. Es werden keine metastabilen Zustände erkannt. Bis zur jeweils nächsten Taktflanke hat sich am Ausgang des ffS ein stabiler Pegel eingestellt.
Erst bei sehr hohen Taktfrequenzen (>300MHz) zählt der Zähler cnt ab und zu hoch. Xilinx sagt in der AppNote XAPP094 dazu, dass aktuelle FFs in FPGAs sehr schnell sind und sich Metastabilität erst bei sehr hohen Taktfrequenzen bemerkbar machen kann.
Wer jetzt aber meint, externe Signale gar nicht mehr einsynchronisieren zu müssen, geht auf dem Holzweg. Denn was sich durchaus signifikant bemerkbar macht, sind Laufzeitunterschiede im Routing eines Signals. Hier lassen wir das Synchronisierungs-FF einfach mal weg
architecture Behavioral of Metastable is signal ffA : std_logic := '0'; signal ffB : std_logic := '0'; signal cnt : unsigned(7 downto 0) := (others=>'0'); begin process begin wait until rising_edge(clk); ffA <= inp; ffB <= inp; end process; process begin wait until rising_edge(clk); if (ffA /= ffB) then cnt <= cnt+1; end if; end process; leds <= std_logic_vector(cnt); end Behavioral;
Und mit dieser Implementation ist dann in der realen Hardware zu sehen, dass der Zähler bei Änderungen des Signals inp doch recht oft hochzählt. Es wird also, obwohl beide Schieberegister das selbe Eingangssignal erhalten, manchmal ein unterschiedlicher Pegel erkannt. Dies kann leicht anhand des Schaltplans erkannt werden:
Jetz kann natürlich wer sagen: dann mache ich sowas einfach nicht! Er wird dann aber von einem Mechanismus namens "Register Duplication" eingeholt, bei dem die FPGA Toolchain Register automatisch verdoppelt, wenn die nachfolgende Belastung für ein einzelnes Flipflop zu hoch werden würde.
Und wenn die Schaltung jetzt nicht so einfach wäre, sondern z.B. eine Statemachine oder ein Zähler, wo so ein externes Signal an jedes Speicherelement führt, dann würden diese Flipflops ab und zu ein unterschiedliches Eingangssignal sehen und entsprechend falsch reagieren. Dazu näheres und ein anschauliches Beispiel im Beitrag State-Machine mit asynchronem Eingang.
Peter Alfke, ein alter Xilinx-Haudegen, hat dazu mal einen legendären Newsgroupbeitrag verfasst:
A spectre is haunting this newsgroup, the spectre of metastability.
Zu deutsch:
Ein Gespenst geht in diesem Forum um. Das Gespenst "Metastabilität".
Fazit: Weil Metastabilität ein statistischer Prozess ist und eigentlich 1 Flipflop schon reichen würde, aber Ingenieure gerne 100% Sicherheit einkalkulieren, gilt
Jedes asynchrone Signal sollte über mindestens zwei Flipflops eingetaktet werden.