Wenn Dinge seltsam werden
FPGAs sind grundsätzlich äußerst zuverlässige Bauelemente. Aber wie jedes Stück Technik funktionieren sie nicht besonders gut, wenn man sie falsch benutzt.
Leider helfen uns die verfügbaren FPGA-Entwicklungswerkzeuge nur wenig dabei, Fehler zu vermeiden. Das führt allzu oft zu unzuverlässigen und unvorhersehbaren Ergebnissen. Genauer gesagt garantieren die FPGA-Werkzeuge einen zuverlässigen Betrieb nur dann, wenn bestimmte Entwurfsregeln eingehalten werden. Dabei wird stillschweigend vorausgesetzt, dass wir wissen, was wir tun. Software-Compiler verweigern die Erzeugung von ausführbarem Code, wenn im Quellcode ein Fehler ist. FPGA-Werkzeuge sagen dagegen nur: „Hier ist dein Bitstrom (bitstream), probier’s aus, wenn du magst. Ach ja, und hier sind 200 Warnungen. Wenn du verstehst, was Warnung #143 bedeutet, verstehst du auch, dass da ein ernstes Problem ist, das behoben werden muss.“
Für Menschen, die mit FPGAs arbeiten, ist es nicht ungewöhnlich, das Gefühl zu bekommen, die Elektronik sei von irgendeiner magischen Kraft besessen, und nichts ergebe mehr einen Sinn. Ein Problem kann auftauchen und wieder verschwinden, nachdem völlig unzusammenhängende Änderungen gemacht wurden, und es ist keine rationale Erklärung in Sicht. So mancher ordentlich ausgebildete Ingenieur neigt dann zu absurden Theorien über FPGAs, nur um dieses merkwürdige Verhalten irgendwie zu erklären.
Das ist der „Black Magic Mode“: Wenn vernünftige Leute nicht mehr daran glauben, dass es für ihr Problem eine rationale Erklärung gibt, und stattdessen nach einer Lösung suchen, die auf Erfahrung basiert. Alles funktioniert einwandfrei, wenn das FPGA richtig kalt ist? Gut, dann montier einen dicken Kühlkörper. Das Problem tritt nur bei manchen Platinen auf und bei anderen nicht? OK, dann test jede Platine und wirf die weg, bei denen es auftritt. Und so weiter.
Wie das aussieht
Hier ist eine unvollständige Liste von Vorfällen, die Ingenieure in einen irrationalen Gemütszustand versetzen können. Es geht immer los mit „Alles funktioniert einwandfrei, außer wenn …“
- … es plötzlich nicht mehr funktioniert, ohne erkennbaren Grund.
- … im Verilog-Code (oder VHDL) oder in den Einstellungen beziehungsweise der Version der FPGA-Werkzeuge eine zufällige, in keinem Zusammenhang stehende Änderung vorgenommen wird.
- … die Klimaanlage an beziehungsweise aus ist.
- … das System bereits eine Weile gelaufen ist beziehungsweise kalt eingeschaltet wird.
- … FPGA-Bauelemente aus einer anderen Produktionscharge verwendet werden.
- … ein anderes Bauteil aus einer anderen Produktionscharge verwendet wird.
- … ich meinen Finger hierher lege / meine Hand darüber halte / den unzusammenhängenden Knopf drücke.
Oft geht damit die Überzeugung einher, die Elektronik selbst sei fehlerhaft und werde ihren Datenblattangaben nicht gerecht. Verschwörungstheorien darüber, dass ein großer Konzern mangelhafte Bauteile ausliefert, sind nicht ungewöhnlich.
Es ist also nicht einfach ein Bug. Bugs können einen zwar in den Wahnsinn treiben, aber sie sind in gewissem Maße reproduzierbar, und sie tauchen bestimmt nicht wegen der Klimaanlage auf und verschwinden wieder. Ich habe noch nie erlebt, dass ein Softwareentwickler einen Bug dem PC selbst angelastet hat (auch wenn das in sehr seltenen Fällen tatsächlich der Grund ist). Fehler in einem FPGA-Design dagegen können durchaus Störungen auf Hardware-Ebene verursachen. Von dort bis dazu, der ganzen Welt die Schuld zu geben, ist es nur ein kurzer Weg.
Es gibt eine logische Erklärung. Wirklich.
Und sie ist in Reichweite. Nicht unbedingt leicht.
Da ich eine ganze Weile als Freiberufler auf diesem Gebiet gearbeitet und solche Situationen gelegentlich behoben habe, glaub mir, wenn ich dir sage: Abgesehen von extrem seltenen Fällen ist das FPGA in Ordnung, und das Problem liegt höchstwahrscheinlich im Bitstrom.
Die schlechte Nachricht ist, dass es oft mehr als einen Fehler im FPGA-Design gibt, und diese Fehler können die Ursache für das sichtbare Problem sein. Folglich kann es eine Menge zu beheben geben. So manches Mal wurde ich gebeten, ein „fast funktionierendes“ FPGA-Design zu reparieren, und musste bald feststellen, dass da die unrealistische Erwartung bestand, dass dieses „kleine Problem“ schnell behoben wird. Ein Design zu stabilisieren bedeutet oft, viel zu arbeiten, ohne sichtbare Fortschritte zu erzielen.
Wie auch immer, es gibt keine Wahl. Auf dieser Seite möchte ich versuchen, das rationale Denken zurückzubringen, unter anderem, indem ich mögliche Gründe für das aufliste, was wie ein Geist in der Elektronik wirkt.
Der beste Weg ist natürlich, diese Situation gar nicht erst entstehen zu lassen. Ein guter Anfang ist, die Golden Rules zu befolgen, die ich auf einer anderen Seite aufgelistet habe.
Warum die Dinge seltsam werden
Nun, die kurze Antwort ist, dass mit dem FPGA-Design etwas nicht stimmt. Und wenn das der Fall ist, gibt es grundsätzlich zwei Möglichkeiten. Die vergleichsweise glückliche Möglichkeit ist eine sichtbare und beständige Funktionsstörung dessen, was das FPGA tun soll. Das ist wie ein Software-Bug: Finden, beheben, nach dem Fix sehen, dass es funktioniert, fertig.
Die weniger glückliche Möglichkeit ist, dass das FPGA funktioniert, aber meist nur durch einen glücklichen Zufall. Wenn sich also irgendwelche Bedingungen ändern, funktioniert das FPGA plötzlich nicht mehr richtig, und vielleicht kehrt es dann wieder zum ordnungsgemäßen Zustand zurück. Aber warum passiert das?
Hier ist der Punkt: Ein FPGA ist ein Stück Elektronik, und als solches gibt es bei der Fertigung Ungenauigkeiten. Noch wichtiger: Wenn sich die Temperatur des Siliziums ändert, ändert sich auch die Geschwindigkeit, mit der die Transistoren ihren Zustand wechseln. Dasselbe gilt für die Geschwindigkeit, mit der sich Signale in der Logikstruktur ausbreiten. Auch Änderungen der Versorgungsspannung beeinflussen, wie schnell die Dinge im FPGA passieren.
Wenn das FPGA also etwas wärmer oder kühler wird, kann ein Signal im Verhältnis zum Takt etwas später oder früher an einem Flip-Flop ankommen. Das allein kann dazu führen, dass das Flip-Flop das Signal verpasst, das es hätte übernehmen sollen – oder dass es genau das Signal übernimmt, das es sonst regelmäßig verpasst. Schon eine lokale Erwärmung des Siliziums kann das auslösen, wenn benachbarte (und möglicherweise nicht verwandte) Logik auf dem Chip weniger oder mehr aktiv wird.
Ebenso haben FPGAs Fertigungsungenauigkeiten. Auch wenn alle FPGAs, die das Werk verlassen, Tests bestanden haben, die sicherstellen, dass sie den Spezifikationen entsprechen, kann das Silizium des einen FPGAs schneller sein als das eines anderen. Deshalb funktioniert ein unsauber erstelltes Logikdesign möglicherweise auf dem einen FPGA und auf dem anderen nicht.
All diese zufälligen Parameter beeinflussen, wann die kleinen Bausteine in der Logikstruktur ihren Zustand ändern. Und dieser Unterschied im Timing kann den Unterschied zwischen einwandfreiem Funktionieren und einer Katastrophe ausmachen. Kleine Abweichungen bei Herstellung, Temperatur und Spannungen können also einen sichtbaren Unterschied bewirken.
Wie kann ein FPGA dann zuverlässig sein? Wenn das FPGA-Design korrekt erstellt ist, sorgen die FPGA-Entwurfswerkzeuge dafür, dass alles immer wie definiert funktioniert – genauer gesagt, auf jedem FPGA, das die Fertigungstests bestanden hat und innerhalb der Datenblattanforderungen betrieben wird. Das heißt: Die Umgebungstemperatur muss im zulässigen Bereich liegen (notfalls mit Kühlung), und an den Pins des FPGAs müssen korrekte Spannungen anliegen.
Wenn die erforderlichen Entwurfsregeln für FPGAs jedoch nicht eingehalten werden, garantieren die Werkzeuge auch keinen ordnungsgemäßen Betrieb. Das bedeutet, dass ausgerechnet die Parameter entscheidend werden, die eigentlich keine Rolle spielen sollten. Die gesamte Platine funktioniert dann und fällt aus, je nach Dingen, die überhaupt nichts zur Sache tun sollten. Es gibt keine Grenze dafür, wie seltsam es werden kann.
Auf die Gefahr hin, mich zu wiederholen, hier ein paar Beispiele:
- Alles kann einwandfrei funktionieren. Dann machst du eine triviale Änderung, startest die Implementierung erneut, lädst den neuen Bitstrom – und zack, kompletter Ausfall. Das liegt meist daran, dass die Logik anders in der Logikstruktur des FPGAs platziert wird, und dasselbe passiert mit den Verbindungen (Routing) zwischen den Logikelementen. Dadurch ändern sich die Signallaufzeiten (propagation delays), und manche Signale, die vorher mit korrektem Timing ihr Ziel erreichten, tun das jetzt nicht mehr.
- Du hast drei identische Platinen: Eine funktioniert perfekt, die zweite nur morgens und die dritte nie. Das liegt wahrscheinlich an kleinen Unterschieden im Silizium der FPGAs. Irgendwo im Design gibt es dann ein Signal, das auf der ersten Platine mit korrektem Timing am Ziel ankommt. Auf der zweiten ist der Spielraum kleiner, sodass eine andere Umgebungstemperatur das FPGA über die Schwelle zwischen Funktionieren und Nichtfunktionieren bringt. Und das dritte FPGA liegt die ganze Zeit auf der falschen Seite dieser Schwelle.
- „Ich schalte dieses Gerät ein, und jenes andere funktioniert nicht mehr – obwohl beide nichts miteinander zu tun haben.“ Das hat oft mit Temperatur zu tun. Selbst wenn die Logik der einen Funktion völlig unabhängig von einer anderen ist, kann ein aktives Logikelement seine Nachbarn aufheizen.
Das ist es wert, immer und immer wieder gesagt zu werden: Wenn das FPGA-Design ordentlich gemacht ist, passiert so etwas nie. Oder zumindest extrem selten. Nur wenigen ist bewusst, wie zuverlässig Elektronik ist, wenn man die Datenblätter liest und befolgt und das FPGA ebenfalls korrekt einsetzt.
Aber ich vermute, diese Predigt kommt für die Leser dieser Seite etwas zu spät – das Problem ist ja bereits da. Deshalb habe ich, basierend auf meiner eigenen Erfahrung, ein paar häufige Gründe für ein scheinbar verhextes FPGA aufgelistet. Wenn du vor einem solchen Problem stehst, ist die Chance gut, dass es einer davon ist.
Grund #1: Timing
Die Werkzeuge sorgen weitgehend für den stabilen Betrieb des FPGAs, indem sie die Timing-Vorgaben (timing constraints) erfüllen, die du ihnen gegeben hast. Das ist der Deal zwischen dir und den Werkzeugen: Du formulierst die Timing-Anforderungen präzise, und die Werkzeuge stellen sicher, dass sie auf jedem verwendeten FPGA eingehalten werden, solange das FPGA innerhalb seines erlaubten Temperatur- und Spannungsbereichs arbeitet.
Es ist nicht ungewöhnlich, dass die Timing-Vorgaben nur aus einer einzigen Bedingung bestehen, die die Frequenz des Referenztakts enthält. Das kann durchaus ausreichen. Wenn du diese Zeile aber bloß aus einem anderen Design kopiert hast und hey, es funktioniert ja, dann ist das ein guter Grund, die Sache zu überprüfen.
Eigentlich geht es darum, das Timing insgesamt korrekt zu machen. Und das ist keine triviale Aufgabe – nicht einmal für den erfahrensten FPGA-Designer. Es bedeutet, dass du dir sicher sein musst, dass jeder einzelne Signalpfad (path) im Design von einer Vorgabe kontrolliert wird, die dafür sorgt, dass das Flip-Flop am Ende das Signal immer korrekt erhält. Ausgenommen sind nur diejenigen Pfade, die keine Einschränkung benötigen.
Als erstes ist also zu prüfen: Hat das Design die Timing-Vorgaben erfüllt? Das ist wirklich grundlegend, aber weil die meisten FPGA-Werkzeuge trotzdem einen Bitstrom erzeugen, können FPGA-Neulinge in genau diese einfache Falle tappen.
Der nächste Schritt ist, die Timing-Vorgaben zu überprüfen. Es gibt eine eigene Seite, die eine solche Überprüfung behandelt. Aber um es kurz zu machen: Verstehst du genau, was die Timing-Vorgaben bedeuten? Ist ihre Bedeutung exakt die richtige? Falls es selektive Timing-Vorgaben gibt – also solche, die gezielt bestimmte Pfade mit Filterbedingungen abdecken – wirken sie tatsächlich auf die richtigen Pfade?
Und dann sollte der Timing-Report sorgfältig gelesen werden. Auch dazu findet sich auf dieser Seite mehr.
Ein weiterer Punkt, den man sich ansehen sollte, sind Taktdomänenübergänge (clock domain crossings). Gibt es Signale, die unsicher von einer Taktdomäne (clock domain) in eine andere wechseln? Das könnte daran liegen, dass nicht sorgfältig beachtet wurde, welche Logik zu welchem Takt gehört. Werden Taktdomänenübergänge nur über die FIFOs gemacht, die von den FPGA-Werkzeugen erzeugt werden? Wenn nicht: Sind die Übergänge korrekt und sicher gemacht?
Grund #2: Nicht ordnungsgemäße Resets
Das scheint vielleicht nicht zusammenzuhängen. Aber wenn der Anfangszustand der Logik nicht sichergestellt ist, kann das sehr wohl zu Black-Magic-Verhalten führen.
Die Regel ist einfach: Wer sich über Resets und das Aufwachen der Logik keine ernsthaften Gedanken gemacht hat, hat es mit hoher Wahrscheinlichkeit falsch gemacht.
Betrachte insbesondere dieses Beispiel:
always @(posedge clk or negedge resetn)
if (!resetn)
the_reg <= 0;
else
the_reg <= [ ... ] ;
Wenn deine Vorstellung von Resets darin besteht, Code wie diesen zu schreiben, ohne dich ausdrücklich darum zu kümmern, was passiert, wenn @resetn deaktiviert wird (in diesem Beispiel also auf High wechselt), solltest du dir unbedingt diese Seite ansehen.
Wie auch immer: Es ist eine gute Idee zu prüfen, ob es überall dort Resets gibt, wo sie hingehören, und ob sie ihre Aufgabe ordentlich erfüllen. Was das bedeutet, wird in einer kurzen Beitragsreihe zu diesem Thema besprochen.
Grund #3: Taktsignale
Die Qualität der Taktsignale ist möglicherweise das am meisten unterschätzte Thema im Digital-Design. Häufig heißt es: „Klar, es wechselt von High auf Low und wieder zurück, nehmen wir das als Takt.“
Die Taktsignale, die für die FPGA-Logik verwendet werden, sollten stabil sein und bezüglich Jitter (jitter) angemessene Eigenschaften besitzen. Nicht weniger wichtig ist eine stabile und zuverlässige physikalische Verbindung des Takts zum FPGA.
Bei einer Anweisung wie dieser
always @(posedge clk)
muss das, was dort als @clk verwendet wird, mit großer Sorgfalt behandelt werden. Idealerweise stammt dieser Takt von einem eigens dafür vorgesehenen Taktgenerator (Oszillator), der einen stabilen Takt mit niedrigem Jitter liefert. Generell ist es besser, diesen externen Takt als Referenztakt an einen PLL anzuschließen, statt ihn direkt an Logik anzulegen. Das gilt auch dann, wenn der PLL die Frequenz des Takts nicht verändert.
Der Grund ist, dass man mit einem PLL den Lock-Detector des PLL überwachen kann. Die Logik, die von diesem Takt abhängt, kann also im Reset gehalten werden, solange der PLL nicht gelockt ist. Dadurch sinkt die Wahrscheinlichkeit für Probleme deutlich, wenn der Referenztakt Stabilitätsprobleme hat (insbesondere direkt nach dem Einschalten).
Ein PLL kann leicht als Störenfried angesehen werden und scheinbar unnötige Resets verursachen, weil er gelegentlich sein Lock verliert. Das kann dann fälschlich dadurch „behoben“ werden, dass man den PLL entfernt und den externen Takt direkt an die Logik anschließt – und plötzlich scheint alles einwandfrei zu funktionieren. In so einem Fall liegt die Wahrscheinlichkeit nahe, dass ein Problem mit dem Referenztakt vorliegt. Den PLL zu entfernen löst das Problem nicht, sondern verschiebt es nur in die Logikstruktur und kann dadurch eine Black-Magic-Situation erzeugen.
Bisher habe ich über Takte von eigens dafür vorgesehenen Oszillatoren gesprochen, was der einfache Fall ist. Bei anderen Quellen wird es schlimmer: Takte, die von einem Prozessor oder einem seiner Peripheriegeräte erzeugt werden, sollte man wenn überhaupt nur mit Vorsicht verwenden. Solche Takte können vom Prozessor kurz angehalten werden oder gelegentlich unzulässige Wellenformen erzeugen. Das kann passieren, wenn Software in die betreffenden Hardware-Register schreibt, vielleicht im Rahmen einer völlig anderen Aufgabe. Solche kurzen Ereignisse sind bei der Untersuchung des Takts mit einem Oszilloskop möglicherweise nicht sichtbar, verursachen aber trotzdem seltsame Störungen.
Eine weitere häufige Fehlerquelle ist der unsaubere Umgang mit einem quellensynchronen Takt (source-synchronous clock). Dabei liefert eine externe Komponente ein Taktsignal und ein oder mehrere Datensignale, sodass die Daten synchron zum Takt sind. Normalerweise dürfen die Datensignale nur mit den steigenden Flanken des Takts (oder nur mit den fallenden) ihren Wert ändern.
Eine übliche, aber ziemlich gefährliche Methode besteht darin, den quellensynchronen Takt direkt mit der Anwendungslogik im FPGA zu verbinden. Ein Teil des Problems besteht darin, dass ein quellensynchroner Takt oft nicht dafür gedacht ist, als durchgehender Takt verwendet zu werden. Er kann daher kurz anhalten oder Störimpulse haben.
Ein weiteres mögliches Problem ist, dass quellensynchrone Schnittstellen häufig über einen physischen Steckverbinder mit dem FPGA verbunden sind, z. B. wenn die Datenquelle eine Kamera ist, die über ein Kabel an der Hauptplatine hängt. Steckverbinder sind zwar normalerweise zuverlässig, aber selbst wenn durch Vibration für eine Nanosekunde der Kontakt unterbrochen wird, kann das ausreichen, um einen unzulässigen Impuls auf dem Taktsignal zu erzeugen. Das kann natürlich auch bei Datensignalen passieren, ist dort aber meist weniger kritisch, insbesondere wenn die Datenquelle eine Kamera ist. Wenn ein solches Taktsignal jedoch direkt mit der Anwendungslogik verbunden ist, kann ein eine Nanosekunde langer Impuls garantiert einiges anrichten.
Die beste Lösung für quellensynchrone Schnittstellen mit Takt und Daten ist es deshalb, sowohl den Takt als auch die Daten wie normale Signale zu behandeln. Dementsprechend werden die Datensignale und der quellensynchrone Takt mit Flip-Flops abgetastet (Sampling), wobei ein deutlich schnellerer, stabiler und sicherer Takt verwendet wird. Am besten geschieht das mit den dedizierten Flip-Flops, die sich direkt neben den I/O-Pins befinden.
Wechselt der quellensynchrone Takt von Low auf High, spiegelt sich das in einer entsprechenden Änderung am Ausgang des Flip-Flops wider, das dieses Signal abtastet. Die steigenden Flanken des quellensynchronen Takts lassen sich also mit synchroner Logik daran erkennen, dass der Ausgang dieses Flip-Flops von Low auf High wechselt. Diese Logik basiert natürlich auf dem schnelleren, stabilen Takt. Wenn sie eine solche steigende Flanke erkennt, markiert sie die Daten als gültig. Mit anderen Worten: Die Ausgänge der Flip-Flops, die die Werte der Dateneingänge enthalten, werden als gültige Daten markiert.
Der klare Vorteil dieser Methode mit 01-Signal-Abtastung (01-signal sampling) ist, dass die FPGA-Logik unabhängig davon, was mit dem Taktsignal passiert, immer auf einem sicheren Takt beruht. Die Logik, die die Flanken erkennt, muss dann angemessen darauf reagieren, falls der quellensynchrone Takt verrücktspielt.
Diese Technik ist bei relativ niedrigen Frequenzen des quellensynchronen Takts möglich (typischerweise bis 200–300 MHz, je nach Geschwindigkeit des FPGAs und ob DDR-Abtastung verwendet wird).
Bei schnelleren Quellen besteht die bevorzugte Lösung darin, einen PLL mit dem Quellentakt zu speisen und den Ausgang des PLL mit der Anwendungslogik zu verwenden. Wie oben erwähnt, sollte die Logik zurückgesetzt werden, wenn der PLL anzeigt, dass er kein Lock hat. Das ist wahrscheinlich auch aus einem anderen Grund die richtige Lösung: Wenn die Frequenz für die soeben beschriebene 01-Signal-Abtastung zu hoch ist, ist die einzige Möglichkeit für ein korrektes Abtasten (sampling) der Signale sehr wahrscheinlich, das Timing über eine Phasenverschiebung des Takts zu finden. Das bedeutet, dass die Logik das Timing automatisch nachstellt, bis bei den abgetasteten Signalen keine Fehler mehr erkannt werden. Diese Technik erfordert ohnehin einen PLL.
Grund #4: Verstoß gegen die Regeln des RTL-Designs
Sauberer Verilog-Code (oder VHDL) für die Synthese muss einige strenge Regeln einhalten, insbesondere das RTL-Paradigma (Register-Transfer-Level). Das bedeutet unter anderem, dass jedes Logikelement, das eine Art Speicher ist (z. B. ein Flip-Flop), seinen Wert nur als Folge einer Taktflanke ändert. Die einzige Ausnahme ist ein asynchroner Reset (asynchronous reset), der nicht irgendein x-beliebiges Signal sein darf.
Wenn ein Synthesewerkzeug (Synthesizer) auf Verilog-Code trifft, der gegen diese Regeln verstößt, versucht es meist hilfsbereit zu sein und erzeugt Logik, die sich möglicherweise anders verhält als in der Simulation. Eine andere Möglichkeit ist, dass das Syntheseergebnis die erwartete Funktion meistens erfüllt, aber zufällig versagen kann.
Betrachten wir zum Beispiel dieses falsche Design für einen Zähler zwischen 0 und 14:
reg [3:0] counter;
wire reset_cnt;
assign reset_cnt = (counter == 15); // This is so wrong!
always @(posedge clk or posedge reset_cnt)
if (reset_cnt)
counter <= 0;
else
counter <= counter + 1;
Der schreckliche Fehler besteht darin, @reset_cnt als asynchronen Reset zu verwenden.
Aber erklären wir zunächst, wie das in der Simulation funktioniert: @counter zählt bei steigenden Flanken von @clk hoch. Wenn @counter jedoch den Wert 15 erreicht, wechselt @reset_cnt auf ’1‘ und setzt @counter asynchron auf Null zurück. Wenn @counter mit @clk abgetastet wird, zeigt er also die Werte 0 bis 14 an, wie gewünscht.
In Hardware könnte das fehlschlagen. Das Problem ist, dass @reset_cnt eine kombinatorische Funktion von @counter ist. Wenn @counter seinen Wert von 7 auf 8 ändert, kann die Logik, die @reset_cnt berechnet, den Wert von @counter kurzzeitig als 15 sehen. Das liegt daran, dass 7 im Binärcode 0111 ist und 8 als 1000 codiert wird. Wenn Bit 3 die kürzeste Signallaufzeit zu der Logik hat, die @reset_cnt berechnet, kann dieses Signal kurzzeitig auf ’1‘ liegen. Infolgedessen zählt @counter manchmal von 0 bis 14 und manchmal von 0 bis 7. Temperatur und andere unzusammenhängende Faktoren können beeinflussen, welche der beiden Varianten man beobachtet.
Diese Erklärung, warum dieses Beispiel falsch ist, ist allerdings stark vereinfacht. Die Werkzeuge haben völlige Freiheit, kombinatorische Logik (combinatorial logic) auf die kreativste Art und Weise zu implementieren, sodass zwischen den Taktflanken praktisch alles passieren kann. Das Einzige, was die Werkzeuge garantieren, ist, dass die Signale entsprechend den Timing-Anforderungen der Flip-Flops am Ziel stabil ankommen (Setup- und Hold-Zeiten).
Solange der Logikentwurf die RTL-Regeln also nicht strikt einhält, können definitiv seltsame Dinge passieren.
Grund #5: Temperatur und Spannungsversorgung
Das ist kein häufiger Grund für Probleme und leicht zu prüfen. Trotzdem können Temperatur und Spannungsversorgung die Wurzel merkwürdiger Fehler sein.
Wenn die Temperatur des Siliziums außerhalb des zulässigen Bereichs liegt, ist natürlich nichts garantiert. Die häufigsten Ursachen sind Überhitzung wegen unzureichender thermischer Auslegung oder Lüfter, die mit Staub zu kämpfen haben.
Bei den Spannungsversorgungen können verschiedenste Gründe zu fehlerhafter Ausgangsspannung führen. Ein einfacher Check mit dem Oszilloskop zeigt oft, ob die Spannung im spezifizierten Bereich liegt. Beachte jedoch, dass die Spannung zu jedem Zeitpunkt in diesem Bereich bleiben muss. Es genügt nicht, dass die mittlere Spannung stimmt: Weder das Rauschen, das Schaltnetzteile immer erzeugen, noch gelegentliche Spitzen dürfen die Grenzen überschreiten.
Beachte außerdem: Auch wenn eine Spitze, die nicht länger als 1 μs dauert, harmlos erscheinen mag, sind das im FPGA zig bis hunderte Taktzyklen. Das ist also eine beträchtliche Zeitspanne, in der das FPGA mit einer falschen Spannung versorgt wird. Miss die Spannung vorzugsweise an den Entkopplungskondensatoren nahe am FPGA, um zu sehen, welche Spannung tatsächlich ankommt. Stelle außerdem den Trigger des Oszilloskops auf die obere und untere Spannungsgrenze ein und achte darauf, dass es nicht auf normale Signalschwankungen reagiert. Kurze Spannungsspitzen sind auf dem Bildschirm des Oszilloskops nicht leicht zu erkennen, aber der Trigger fängt sie ein.
Manchmal sind Probleme mit der Spannungsversorgung eine direkte Folge eines schlechten Platinen-Layouts. Viele Spannungsversorgungsmodule haben einen Mindeststrom, der oft übersehen wird. Wenn diesem Modul nicht mindestens dieser Strom entnommen wird, kann es instabil werden und eine Spannung liefern, die nicht der Spezifikation entspricht – schlimmer noch, es kann gelegentlich zu Schwingungen kommen.
Ein weiterer häufiger Fehler ist der Einsatz eines Schaltnetzteils dort, wo ein Spannungsregler erforderlich ist. Insbesondere gibt es Taktoszillatoren mit geringem Jitter, die eine sehr saubere Versorgung benötigen. Wenn ein solcher Oszillator aus einer verrauschten Spannungsversorgung gespeist wird, schlägt sich dieses Rauschen als Jitter auf dem Taktausgang nieder. Wenn ein Gigabit-Transceiver diesen Takt verwendet (z. B. PCIe, USB 3.x, Glasfaser usw.), führt das oft zu einer unzuverlässigen Datenverbindung.
Wenn DDR-Speicher Teil des Designs sind, wird außerdem eine Referenzspannungsversorgung benötigt. Diese Spannung dient sowohl dem FPGA als auch den DDR-Speichern als Schwellwert zwischen ’0‘ und ’1‘ auf den Leitungen zwischen den beiden Komponenten. Wenn diese Spannung von einem Schaltnetzteil erzeugt wird, ist es wahrscheinlich, dass das Rauschen der Spannungsversorgung es schwerer oder sogar unmöglich macht, Daten fehlerfrei zwischen FPGA und DDR-Speicher zu übertragen.
Grund #6: Soll das ein Witz sein?
Manchmal ist der Grund für die Black-Magic-Situation ein so großer Fehler, dass man sich fragt, wie überhaupt irgendetwas funktionieren konnte. Zum Beispiel, wenn eine Leiterbahn auf der Platine vollständig vom betreffenden FPGA-Pin getrennt ist und das korrekte Signal das FPGA trotzdem erreicht – aufgrund von Übersprechen oder parasitärer Kapazität.
Das passiert besonders gern bei Taktsignalen, weil sie oft über die gesamte Platine geführt werden. Und weil sie periodische Signale sind, haben sie bessere Chancen, das FPGA in einer Qualität zu erreichen, die geradeso gut genug aussieht.
Also: Nimm auf jeden Fall ein Oszilloskop und prüfe alle Takte so nah wie möglich am FPGA. Wenn für den Takt ein AC-Koppelkondensator vorhanden ist, ist das eine gute Messstelle – insbesondere, weil du dabei entdecken kannst, dass der Kondensator fehlt.
Grund #7: Einfach nur Bugs
Oder genauer: Das Design war nie dazu gemacht, zu funktionieren. Niemand hat sich je hingesetzt und durchdacht, wie die Logik ihre Aufgabe zuverlässig erledigen soll. Stattdessen wurde der Code nach und nach durch Ausprobieren entwickelt, teils mit Simulationen, teils mit Hardware. Der Prozess endete, als die Dinge einigermaßen zu funktionieren schienen. Wenn man sich den Code aber ansieht, wirkt es wie ein Wunder, dass er überhaupt lief: Weil er so oft gepatcht wurde, um genau dieses kleine Problem zu beheben, ist es unmöglich, ihm zu folgen – von Änderungen ganz zu schweigen.
Ich habe diesen Grund ans Ende gestellt, weil es sich nicht wirklich um Black Magic handelt. Es ist einfach nur ein sehr lästiger Bug. Trotzdem ist dies der häufigste Grund, warum FPGA-Projekte feststecken.
Wenn du immer noch glaubst, dass das FPGA schuld ist
Manchmal ist es nicht deine Schuld. Möglicherweise gibt es einen Fehler im FPGA selbst oder in der Software des Herstellers. Das kommt viel seltener vor, als man dem FPGA-Hersteller gern die Schuld gibt, aber in seltenen Fällen ist es tatsächlich so.
Der Versuchung, jemand anderem die Schuld zu geben, ist natürlich groß. Tu dir selbst einen Gefallen und beende die Exorzismus-Sitzung nicht mit einer Schuldzuweisung an das FPGA, es sei denn, du hast eines oder beide der folgenden Dinge:
- Einen Errata-Eintrag des Herstellers, der exakt auf deine Situation passt – sowohl bei der Ursache als auch beim Ergebnis. Das kann allerdings etwas schwierig zu beurteilen sein, denn Errata werden gern absichtlich vage formuliert, insbesondere um das Problem als äußerst speziell und selten darzustellen und die Folgen herunterzuspielen. Lass dich nicht dazu verleiten, einen ähnlichen Errata-Eintrag als Übereinstimmung mit deiner Situation zu interpretieren. Es gibt immer irgendeinen Errata-Eintrag, der deinem Fall irgendwie ähnlich ist.
- Einen unbestreitbaren Beweis (smoking gun): Wenn du wiederholt einen bestimmten Fehler auslösen kannst, der exakt erklärt, warum dein Problem aufgetreten ist. Es reicht nicht zu zeigen, dass die Werkzeuge oder das FPGA selbst sich unsinnig verhalten. Du musst es auf ein bestimmtes, wiederholbares fehlerhaftes Logikmuster eingrenzen.
Wenn du die Sache ohne eines davon abschließt und das Problem irgendwie umschiffst, ist die Chance groß, dass du ihm später wiederbegegnest.
Das beste Beispiel, das ich für einen Fehler im FPGA selbst habe, liegt lange zurück und betraf das Hardware-FIFO der Xilinx Virtex-4. Genauer gesagt ein Dual-Clock-FIFO, dessen Steuerlogik direkt in Silizium implementiert war (also nicht in der Logikstruktur).
Der Datenfluss durch dieses FIFO blieb ab und an stehen. Nach einiger Untersuchung stellte sich heraus, dass das FIFO nach einer Weile einwandfreien Betriebs gleichzeitig sein „empty“-Signal (leer) und sein „full“-Signal (voll) aktiv hielt. Das ist ein unzulässiger Zustand, es sei denn, das FIFO wird im Reset gehalten – was nicht der Fall war. Nachdem ich mir also absolut sicher war, dass ich die richtigen Signale beobachtete, schloss ich den Fall mit dem Ergebnis ab, dass es einen Fehler im FIFO des FPGA gibt. Und ich verwendete fortan FIFOs, die in der Logikstruktur implementiert sind.
Ein paar Monate später fand ich einen Errata-Eintrag zu diesen FIFOs, den ich ohne Vorwissen über das Problem wohl nicht verstanden hätte. Aber nachdem ich die Beschreibung sehr sorgfältig gelesen hatte, konnte ich schlussfolgern, dass sie meine Beobachtung bestätigte.
Das war nur ein Beispiel dafür, wie offensichtlich ein Fehler in einem FPGA sein muss, bevor man das Problem getrost als „nicht mein Fehler“ bezeichnen darf.
Zusammenfassung
Wenn das FPGA scheinbar den Naturgesetzen widerspricht, liegt es nahe, Erklärungen anzunehmen, die vom gesunden Menschenverstand abweichen. Es ist aber wichtig, nach einer rationalen Erklärung zu suchen – und diese Erklärung ist oft auch ohne Superkräfte zu finden.
Die Jagd nach dem Grund kann allerdings eine gründliche Überprüfung des Designs erfordern, was nicht unbedingt schlecht ist. So frustrierend eine solche Jagd sein kann, sie kann unabhängig davon erheblich zur Qualität des Designs beitragen.