Diese Seite gehört zu einer Serie von Seiten über Timing. Auf den vorherigen Seiten wurden die Theorie hinter Timing-Berechnungen erklärt, die Taktperioden-Vorgabe besprochen und das Timing-Closure eingeführt. Aber was, wenn Sie es richtig gemacht haben und trotzdem ein Timing-Problem auftritt? Diese Seite versucht, diese Frage zu beantworten.
Einführung
Auf der vorherigen Seite habe ich versucht, Sie davon zu überzeugen, dass es keine einzelne Methode zur Lösung eines Timing-Closure-Problems gibt. Manchmal ist es richtig, sich auf den kritischen Pfad zu konzentrieren, manchmal nicht. Manchmal lässt sich das Problem mit einer einfachen Änderung der Tool-Einstellungen beheben, manchmal ist es viel schwieriger. Es gibt keinen Ersatz dafür, all Ihre Erfahrung und Ihr Urteilsvermögen einzusetzen, um zur eigentlichen Ursache des Problems zu gelangen. Es ist unmöglich, Timing-Closure mit einer Checkliste zusammenzufassen.
Und doch hilft es oft, eine Liste möglicher Strategien zu haben. Auf dieser Seite habe ich daher ein paar Themen gesammelt, über die es sich nachzudenken lohnt, wenn man vor einem Timing-Problem steht. Wenn Sie das hier lesen, weil Sie ein konkretes Timing-Problem lösen müssen, ist es möglich, dass eine dieser Ideen Sie zur Lösung führt. Erwarten Sie aber nicht, dass Ihre Lösung hier genau beschrieben ist.
Beachten Sie auch, dass diese Seitenreihe hier nicht endet. Ich habe mich entschieden, das Timing-Closure vor vielen anderen Themen zu besprechen, und zwar der Motivation wegen. Die Informationen auf den späteren Seiten sind jedoch ebenfalls relevant.
Aus demselben Grund wird die Besprechung der I/O-Timing-Vorgaben auf später verschoben. Vorerst konzentriere ich mich auf Pfade, die innerhalb des FPGAs beginnen und enden.
Hier also ein paar Ideen im Zusammenhang mit dem Timing-Closure.
Idee #1: Das Logikdesign reparieren
Das ist immer die am wenigsten attraktive Lösung. Das gilt insbesondere dann, wenn das Design bereits nachweislich ordnungsgemäß funktioniert. Man möchte etwas, das funktioniert, nicht ändern. Und doch ist der grundlegende Grund für das Problem oft, dass der Verilog-Code nicht gut genug für die geforderte Leistung geschrieben wurde. Eine Änderung im Logikdesign löst das Problem ein für alle Mal, statt mit ständigen Schwierigkeiten kämpfen zu müssen.
Ein paar Vorschläge zum Schreiben schneller Logik gibt es auf der vorherigen Seite. Und es lohnt sich, das zu wiederholen: Denken Sie während des Entwicklungsprozesses immer an das Timing. Timing-Probleme zu beheben ist viel schwieriger, als den Verilog-Code von Anfang an richtig zu schreiben.
Idee #2: Den Fan-out reduzieren
Wenn eine Leitung einen hohen Fan-out hat, steigt die Ausbreitungsverzögerung (propagation delay) aus zwei Hauptgründen:
- Die Kapazität der physischen Leitung ist größer, sodass mehr elektrische Ladung benötigt wird, um den Logikzustand zu ändern.
- Es wird für die Tools schwieriger, eine Verdrahtung mit geringer Verzögerung für alle Ziele der Leitung zu finden: Diese Ziele sind Logikelemente, die in der Logikstruktur verstreut liegen. Je mehr Ziele es gibt, desto schwieriger wird es, das Timing so zu optimieren, dass alle Leitungen eine geringe Verzögerung haben.
Wenn ein synchroner Reset (synchronous reset) im Design verwendet wird, hat dieses Signal wahrscheinlich einen hohen Fan-out. Dieses Thema wird auf einer eigenen Seite behandelt.
Aber jedes Signal, das viele Logikelemente erreicht, kann wegen eines hohen Fan-outs potenziell Timing-Probleme verursachen. Manchmal ist der hohe Fan-out offensichtlich (z.B. bei Clock-Enable-Signalen), manchmal ist er nicht so leicht vorherzusehen. Die FPGA-Tools können in der Regel helfen, indem sie die Leitungen mit den höchsten Fan-outs auflisten.
Es gibt zwei Methoden, um den Fan-out niedrig zu halten:
- Die FPGA-Tools haben eine Grenze für den Fan-out. Wird diese Grenze erreicht, duplizieren die Tools das Register, das die Quelle der Leitung ist. Es ist möglich, diesen Grenzwert für jedes Register mit Synthesizer-Vorgaben zu ändern. Es ist auch möglich, die globale Grenze zu ändern, indem man die Parameter des Synthesizers anpasst.
- Verilog-Code bearbeiten: Das Register mit hohem Fan-out ausdrücklich in mehrere Register vervielfältigen.
Beide Methoden führen offensichtlich zum gleichen Ergebnis: Das Register mit hohem Fan-out wird in mehrere Register aufgeteilt. Wenn das also automatisch von den Tools erledigt werden kann (erste Methode), warum sollte man es dann von Hand tun (zweite Methode)?
Die zweite Methode erfordert mehr Aufwand, hat aber einen wesentlichen Vorteil: Man kann das Register auf sinnvolle Weise vervielfältigen. Denken Sie daran, dass das Ziel nicht nur darin besteht, den Fan-out zu reduzieren. Wichtig ist auch, dass der Ausgang jedes Registers an Logikelemente verteilt wird, die in einer kleinen Region der Logikstruktur liegen. Sonst entstehen wegen der physischen Distanz große Routing-Verzögerungen. Wenn der Verilog-Code also mit Blick auf den Fan-out geschrieben wird, kann man kurze Verbindungen zwischen den Logikelementen sicherstellen. Das wird für ein synchrones Reset-Signal auf einer anderen Seite gezeigt.
Wenn dagegen die FPGA-Tools für die Vervielfältigung der Register zuständig sind, ist das Ergebnis möglicherweise nicht so effizient. Die Verbesserung der Routing-Verzögerung hängt vom Algorithmus ab, der entscheidet, wie jedes vervielfältigte Register verwendet wird. Die Qualität des Ergebnisses hängt davon ab, welches FPGA-Tool verwendet wird.
Beachten Sie, dass der Synthesizer standardmäßig zwei Register, die sich exakt gleich verhalten, automatisch zu einem Register zusammenfasst. Wenn ein Register im Verilog-Code also vervielfältigt wird, ersetzt der Synthesizer alle Kopien durch ein Register. Das gilt oft auch dann, wenn diese äquivalenten Register in verschiedenen Modulen definiert sind. Um das Zusammenfassen zu verhindern, muss diese Funktion ausdrücklich deaktiviert werden. Eine übliche Methode dafür sind Synthese-Attribute wie „dont_touch“, „dont_merge“ oder „keep“.
Idee #3: Die Platzierungsplanung prüfen
Standardmäßig wird die Platzierung der Logikelemente auf der Logikstruktur automatisch von den FPGA-Tools bestimmt (genauer gesagt vom Placer). Es ist jedoch möglich, anzufordern, dass bestimmte Logikelemente in bestimmten Bereichen des FPGAs platziert werden. Man kann auch anfordern, dass ein bestimmtes Logikelement an einer bestimmten Position liegt. Solche Anforderungen nennt man Platzierungsplanung (Floorplanning). Diese Anforderungen werden über Platzierungsvorgaben (placement constraints) ausgedrückt, deren Syntax den Timing-Vorgaben oft ähnelt und die häufig als Tcl-Befehle formuliert werden.
In den meisten Fällen machen Platzierungsvorgaben das Erreichen der Timing-Vorgaben schwieriger. Der erste Grund ist offensichtlich: Wenn die Wahlmöglichkeiten des Placer eingeschränkt sind, können die Ergebnisse nur schlechter sein als ohne Einschränkung. Es gibt aber noch konkretere Gründe:
- Platzierungsplanung kann viel Logik in eine kleine Fläche des FPGAs zwingen. Das kann zu Verdrahtungsüberlastung führen: Die Logikelemente in diesem Bereich benötigen mehr Verdrahtung als üblich. Der Router wird dadurch gezwungen, suboptimale Ressourcen zu verwenden. Das führt zu suboptimalen Routing-Verzögerungen und möglicherweise dazu, dass die Anforderungen nicht erfüllt werden.
- Platzierungsvorgaben können Logikelemente zwingen, weit voneinander entfernt zu liegen, obwohl es besser wäre, sie nahe beieinander zu platzieren. Der Placer wird also daran gehindert, die Logikelemente im Interesse geringerer Routing-Verzögerungen zu verschieben.
- Platzierungsplanung kann Regionen schaffen, die für die Verdrahtung Hindernisse darstellen. Angenommen, die Platzierungsplanung hat ein Gebiet erzeugt, das dicht mit Logikelementen bestückt ist. Die Verdrahtung anderer Logik kann gezwungen sein, dieses überlastete Gebiet zu meiden. Infolgedessen muss diese Verdrahtung einen längeren Weg nehmen, und die Routing-Verzögerung wird größer.
Bei den meisten Designs ist es am besten, auf Platzierungsplanung zu verzichten und dem Placer damit die Freiheit zu geben, die Platzierung der Logikelemente zu optimieren. Es gibt jedoch Fälle, in denen Platzierungsvorgaben üblich sind, zum Beispiel:
- Ein IP-Core (IP core) kann Platzierungsvorgaben für die Logikelemente enthalten, die er erzeugt. Ein IP, das eine PCIe-Schnittstelle implementiert, erzeugt zum Beispiel oft Platzierungsvorgaben, die die Position seiner wichtigsten Komponenten bestimmen: die Transceiver, PLLs und dedizierte PCIe-Hard-IP. Solche Platzierungsvorgaben sind meist notwendig und richtig.
- Das FPGA kann in Regionen aufgeteilt werden, sodass jede Region nur bestimmte Module enthält. Das ist die ursprüngliche Bedeutung von Floorplanning. Die Motivation für eine solche Aufteilung des FPGAs kann sein, dass verschiedene Teams eines Projekts unabhängig arbeiten können.
- Die partielle Rekonfiguration (partial reconfiguration) ist eine Funktion, mit der ein Bitstream in das FPGA geladen werden kann, während es arbeitet, sodass nur ein Teil des FPGAs betroffen ist. Dafür ist Platzierungsplanung erforderlich: Das FPGA wird in Bereiche aufgeteilt, die beim Eintreffen des neuen Bitstreams unberührt bleiben, und in Bereiche, die durch den Bitstream aktualisiert werden.
Im Hinblick auf das Timing-Closure ist es wichtig, Platzierungsvorgaben als potenziellen Grund für Probleme im Blick zu haben. Insbesondere wenn die Routing-Verzögerungen größer sind als erwartet, kann die Ursache darin liegen, dass der Placer die Positionen der Logikelemente nicht optimieren kann. Denken Sie daran, dass Platzierungsplanung sich negativ auf Pfade auswirken kann, die nichts mit den Logikelementen zu tun haben, deren Platzierung eingeschränkt ist.
Idee #4: Die Timing-Vorgaben prüfen
Die Timing-Vorgaben sind entscheidend für den zuverlässigen Betrieb des FPGAs. Deshalb sollten sie vor der Implementierung des Projekts verifiziert werden. Manchmal erweisen sich die Timing-Vorgaben jedoch trotzdem als falsch. Die Fehler können während des Timing-Closure-Prozesses sichtbar werden. Das sollte nicht passieren, aber wenn es passiert, ist es natürlich besser, das Problem zu beheben.
Es gibt eine ganze Seite zum Prüfen von Timing-Vorgaben. Hier bespreche ich nur zwei häufige Fehler, die zu Timing-Closure-Problemen führen können:
- Unnötige Durchsetzung von Timing-Vorgaben auf Pfaden zwischen unabhängigen Takten (unrelated clocks).
- Unnötige Durchsetzung von Timing-Vorgaben auf asynchronen Resets (asynchronous resets).
Zunächst zu den unabhängigen Takten: Das Thema Taktdomänenübergänge (clock domain crossings) wurde weiter oben bereits besprochen. Es gibt mehrere Gründe, warum es wichtig ist, dass die Timing-Vorgaben widerspiegeln, welche Takte zusammenhängende Takte (related clocks) und welche unabhängige Takte sind. Der wichtigste Grund ist die Gewährleistung des ordnungsgemäßen Betriebs der Logik, aber das Timing-Closure ist ebenfalls betroffen: Wenn zwei Takte von den Tools unnötigerweise als zusammenhängende Takte behandelt werden, führt das zu unnötiger Durchsetzung von Timing-Anforderungen auf den Pfaden zwischen diesen beiden Takten. Dadurch verschwenden die Tools ihre Bemühungen an diesen Pfaden auf Kosten jener Pfade, die diese Bemühungen wirklich brauchen.
Die Timing-Vorgabe, die dieses Problem behebt, wird später in dieser Seitenreihe erklärt.
Was asynchrone Resets betrifft: In den meisten Fällen ist es notwendig, Timing-Vorgaben auf Pfaden durchzusetzen, die an einem asynchronen Reset enden. Manchmal besteht dafür jedoch keine Notwendigkeit. Zum Beispiel, wenn garantiert ist, dass der Takt nicht aktiv ist, wenn der Reset inaktiv wird. Eine andere Möglichkeit besteht darin, dass das Flipflop, das den asynchronen Reset empfängt, wie bei einem Taktdomänenübergang einen Schutzmechanismus gegen Timing-Verletzungen hat. In diesen Situationen sind die Bemühungen der Tools, die Timing-Anforderungen zu erfüllen, zwecklos.
Es kann schwierig sein zu erkennen, dass Probleme dieser Art das Erreichen des Timing-Closure erschweren: Manchmal hat der kritische Pfad nichts mit den beiden Takten zu tun, die unnötigerweise als zusammenhängende Takte behandelt werden. Wenn ein asynchroner Reset die Bemühungen der Tools ablenkt, ist das noch schwerer zu erkennen. In solchen Situationen können Versuche, zur Verbesserung des Timings den kritischen Pfad zu bearbeiten, vergeblich sein.
Die Timing-Vorgaben können natürlich auch auf andere Weise falsch sein. Die hier beschriebene Situation ist nur eine Möglichkeit. Ein Timing-Problem kann also eine gute Gelegenheit sein, die Timing-Vorgaben allgemein zu überprüfen.
Idee #5: Einfach noch einmal versuchen
Erinnern Sie sich: Der Platzierungs- und Verdrahtungsprozess (place and route) beginnt damit, die Logikelemente ziemlich willkürlich auf der Logikstruktur zu verteilen. Die Tools versuchen dann, das Timing durch wiederholte Versuche zu verbessern. Der Erfolg dieses Prozesses hängt also von einem gewissen Maß an Glück ab. Es ist auch möglich, dass ein etwas anderes Verhalten des Platzierungs- und Verdrahtungsalgorithmus bessere Ergebnisse liefert, selbst wenn es keine logische Erklärung dafür gibt.
Wenn also die Timing-Vorgaben nicht erfüllt werden und die negative Zeitmarge relativ klein ist (etwa 10–20 % der Gesamtverzögerung), kann es genügen, es einfach noch einmal zu versuchen. Aber ein bloßes erneutes Ausführen der Implementierung wird wahrscheinlich nichts nützen: Die meisten FPGA-Software ist so ausgelegt, dass sie bei denselben Eingaben ihr Ergebnis exakt wiederholt. Es ist also notwendig, vor dem erneuten Lauf etwas zu ändern. Diese Änderung muss nicht mit dem kritischen Pfad zusammenhängen. Es geht nur darum, eine exakte Wiederholung der vorherigen Implementierung zu vermeiden.
In Vivado hat zum Beispiel jeder Durchlauf ein Attribut namens „strategy“. Wie der Name andeutet, steuert dieses Attribut die Strategie, die die Tools während der Implementierung anwenden. Wenn man dieses Attribut ändert, wird die nächste Implementierung garantiert nicht mit der vorherigen identisch sein. Es ist auch möglich, dass eine andere Strategie im Hinblick auf das konkrete Logikdesign sinnvoller ist.
Alle FPGA-Tools bieten ähnliche Möglichkeiten, die Parameter des Implementierungsprozesses zu verändern. Oft kann man einen höheren Aufwand anfordern, um die Ziele des Designs zu erreichen. Manchmal ist ein höherer Aufwand wirklich nötig, aber oft hilft ein höherer Aufwand nur deshalb, weil die Tools dann etwas anderes tun.
Eine weitere Möglichkeit, eine Wiederholung zu vermeiden, sind Änderungen im Verilog-Code. Auch hier muss die Änderung nicht mit dem kritischen Pfad zusammenhängen. Manchmal reicht es, den Namen eines Registers zu ändern, um eine Implementierung zu bekommen, die sich von der vorherigen ausreichend unterscheidet.
Diese Idee kann man auf die Spitze treiben: Es ist möglich, die Implementierung auf mehreren Rechnern parallel laufen zu lassen, wobei jede Implementierung leicht unterschiedliche Parameter hat. Das kann sinnvoll sein, wenn der Preis des FPGAs wichtig ist. In diesem Szenario lohnt es sich, die Rechner hart arbeiten zu lassen, damit die Timing-Vorgaben auf einem billigeren FPGA erreicht werden.
Zusammengefasst stützt sich diese Methode meist auf Glück. Die Erwartungen sollten entsprechend sein: Nochmaliges Versuchen hilft nur, wenn die Tools gelegentlich die Timing-Vorgaben verfehlen. Aber es ist immer besser, das Timing auf andere Weise zu verbessern, wenn möglich.
Idee #6: Ist das FPGA voll?
Es ist recht häufig, dass Timing-Probleme beginnen, wenn der Füllgrad des FPGAs etwa 70 % erreicht. Dafür gibt es drei Hauptgründe:
- Die Logikelemente werden dichter in der Logikstruktur des FPGAs gepackt. Die Freiheit des Placer, das Timing zu verbessern, ist daher stärker eingeschränkt, weil es schwieriger ist, Logikelemente von einem Ort zum anderen zu verschieben. Das führt zu größeren Routing-Verzögerungen.
- Die Menge an Verdrahtung (Routing-Ressourcen) in einem FPGA ist begrenzt. Solange das FPGA relativ leer ist, darf der Router die am besten geeigneten Wege zwischen den Logikelementen wählen. Wenn mehr Logik hinzukommt, führen suboptimale Entscheidungen zu größeren Routing-Verzögerungen.
- Die spezialisierten Logikelemente im FPGA können ausgehen. Die meisten FPGAs haben zum Beispiel Block-RAMs und dedizierte Komponenten für die arithmetische Multiplikation. Wenn diese Ressourcen ausgehen, implementieren die Tools die geforderte Funktionalität mit einfachen Logikelementen (Slices). Das führt oft zu einer großen Anzahl von Logikstufen und damit zu erhöhter Logikverzögerung. Der Füllgrad des FPGAs kann auch schneller als erwartet ansteigen, weil Slices anstelle spezialisierter Logikelemente verwendet werden.
Von den drei oben genannten Gründen hat nur der dritte eine Art von Lösung: Es kann zum Beispiel helfen, manuell festzulegen, welche Logik die Block-RAMs und ähnliche Ressourcen des FPGAs verwendet. Ansonsten ist die einzige Lösung für ein volles FPGA, ein größeres auszuwählen. Das ist aber nicht immer eine Option. Es ist daher wichtig vorauszusehen, dass das Timing-Closure schwieriger wird, je mehr Logik hinzugefügt wird.
Idee #7: Vielleicht brauchen Sie ein anderes FPGA?
Manchmal bleibt keine andere Wahl, als zuzugeben, dass das FPGA der Aufgabe nicht gewachsen ist. Wenn dasselbe FPGA in einer höheren Geschwindigkeitsklasse verfügbar ist, kann die Lösung darin bestehen, auf ein schnelleres FPGA aufzurüsten. Diese Entscheidung erhöht natürlich die Anschaffungskosten, kann aber noch eine weitere, weniger erwartete Folge haben: Es könnte zu einer Verknappung der FPGAs mit der höheren Geschwindigkeitsklasse kommen. Selbst wenn diese schnelleren FPGAs zu einem bestimmten Zeitpunkt reichlich verfügbar sind, verschwinden schnellere FPGAs in der Regel als erste vom Markt, wenn die Nachfrage das Angebot übersteigt.
Das ist ganz natürlich: Die schnelleren FPGAs sind diejenigen, die die Tests besser bestanden haben, und sie können immer anstelle der langsameren FPGAs verwendet werden. Manchmal gelingt es dem Hersteller nicht, die schnelleren FPGAs zu produzieren, und manchmal gibt es einen großen Abnehmer, der alles kauft, womit er arbeiten kann.
Wenn Sie also an einem Produkt arbeiten, das über einen langen Zeitraum in Serie produziert werden soll, bevorzugen Sie immer die niedrigste Geschwindigkeitsklasse, mit der Ihr Design arbeiten kann. Das gilt auch dann, wenn Geld keine Rolle spielt.
Eine ganz andere Art der Aufrüstung ist die Wahl eines FPGAs aus einer neueren FPGA-Familie. Oder vielleicht ein FPGA eines anderen Herstellers. Diese Änderung ist drastischer, sollte aber in Betracht gezogen werden, wenn das Projekt noch in einem frühen Stadium ist. Wir neigen alle dazu, uns in die Werkzeuge und Komponenten zu verlieben, die wir kennen. Aber wenn sich alles zu vertraut anfühlt, ist es ein guter Zeitpunkt, sich nach Alternativen umzusehen.
Erfahrene FPGA-Ingenieure wissen jedoch, dass die Wahl eines brandneuen FPGAs und seiner Werkzeuge ein riskantes Glücksspiel ist. Aber oft gibt es eine ziemlich etablierte Alternative, die deutlich besser ist als die derzeitige FPGA-Wahl. In einer solchen Situation ist es besser, die Komfortzone zu verlassen und etwas Neues auszuprobieren.
Idee #8: Den Temperaturbereich einschränken
Es gibt einen Grund, warum ich diese Möglichkeit fast ans Ende gestellt habe: Sie ist die unschönste Lösung von allen. Aber manchmal bleibt keine andere Wahl.
Standardmäßig garantiert die Durchsetzung der Timing-Vorgaben durch die Tools, dass das FPGA über den gesamten im Datenblatt definierten Temperaturbereich zuverlässig arbeitet. Einige FPGA-Tools erlauben es, für ein Projekt einen anderen Temperaturbereich zu wählen (zum Beispiel hat Quartus dafür ein Attribut namens „MAX_CORE_JUNCTION_TEMP“). Damit kann man den Tools mitteilen, dass der volle Temperaturbereich nicht unterstützt werden muss.
Allgemein gesprochen nehmen die Verzögerungen der Logikelemente in FPGAs mit steigender Temperatur zu. Wenn die maximale Temperatur gesenkt wird, sind die Werte der Verzögerungen in den Timing-Berechnungen kleiner. Dadurch fällt es den Tools leichter, tsetup-Anforderungen zu erfüllen. Manchmal ist das der einzige Weg, die Tools die Timing-Vorgaben erreichen zu lassen.
Es ist wichtig, die Risiken dieser Methode zu verstehen. Beachten Sie insbesondere, dass wir von der Sperrschichttemperatur (junction temperature) sprechen. Mit anderen Worten: Das ist die Temperatur auf dem Silizium des FPGAs, nicht die Umgebungstemperatur.
Wenn die maximale Temperatur also 85 °C beträgt, bedeutet das nicht, dass das FPGA in einem Ofen mit dieser Temperatur arbeitet. Diese Temperatur kann auch bei Raumtemperatur (25 °C) erreicht werden, insbesondere wenn sich kein Kühlkörper auf dem FPGA befindet. Zwischen der Temperatur an der Sperrschicht und der Umgebungstemperatur gibt es immer eine Differenz. Die Größe dieser Differenz hängt von der Leistungsaufnahme des FPGAs und von der Kühllösung ab.
Wenn Sie an einem kommerziellen Produkt arbeiten, sollten Sie sich bewusst sein, dass die Umgebungstemperatur des FPGAs deutlich über der Raumtemperatur liegen kann. Insbesondere wenn das FPGA in einem Gehäuse mit schlechter Luftzirkulation sitzt, kann die Temperatur im Inneren des Gehäuses deutlich über der Außentemperatur liegen. Erschwerend kommt hinzu, dass die meisten elektronischen Produkte bei einer Temperatur zwischen etwa 0 °C und 40 °C funktionieren sollen (diese Zahlen sind von Produkt zu Produkt unterschiedlich). Wenn das Endprodukt also bei der höchsten Temperatur getestet wird und das FPGA im Gehäuse des Produkts sitzt: Wie hoch ist dann die Temperatur an der Sperrschicht? Genau diese Frage muss man stellen. Die Timing-Berechnungen müssen auf dieser Temperatur (oder einer höheren) basieren.
Mit anderen Worten: Wenn Sie die maximale Temperatur senken, um die Timing-Vorgaben zu erreichen, und im Labor alles einwandfrei funktioniert, bedeutet das nichts. Zur Erinnerung: Was Timing-Vorgaben betrifft, bedeutet es immer nichts, dass das FPGA-Design im Labor funktioniert. Aber die Senkung der maximalen Temperatur ist in dieser Hinsicht noch schlimmer. Das gedankenlose Einschränken des Temperaturbereichs kann eine Einladung zu ernsthaften Problemen sein: Der finale Test des Produkts vor der Produktion, der bei der höchsten Temperatur durchgeführt wird, kann fehlschlagen, und es wird unmöglich sein, die Timing-Vorgaben zu erreichen, wenn der Temperaturbereich korrigiert wird. Der einzige Weg, dieses Problem zu lösen, wird sein, das FPGA-Design von Grund auf neu zu schreiben.
Bevor Sie also den Temperaturbereich im Interesse des Timing-Closure ändern, stellen Sie sicher, dass das sicher ist: Führen Sie eine gründliche Bewertung des Temperaturbereichs an der Sperrschicht unter allen möglichen Betriebsbedingungen durch.
Beachten Sie, dass es unmöglich ist, den Temperaturbereich über die Standardeinstellung hinaus zu erweitern, indem man die Parameter der Implementierung ändert. Der Standard-Temperaturbereich der Tools ist immer derselbe wie im Datenblatt angegeben. Es ist also nicht möglich, einen zuverlässigen Betrieb des FPGAs über diesen Standard-Temperaturbereich hinaus zu garantieren.
Idee #9: Nicht ausgerichtete zusammenhängende Takte
Das ist eine ziemlich spezielle Situation und auch ein wenig schwer zu verstehen. Deshalb habe ich dieses Thema ans Ende gestellt.
Angenommen, es gibt einen Taktdomänenübergang zwischen zwei zusammenhängenden Takten, die nicht ausgerichtet sind. Mit anderen Worten: Die beiden Takte werden von demselben Referenztakt abgeleitet, aber es gibt keinen Mechanismus, der den Taktversatz (clock skew) zwischen diesen Takten steuert.
Infolgedessen fällt es den Tools schwerer, die Timing-Anforderungen von Pfaden zwischen diesen beiden Takten zu erfüllen. Es gibt zwei mögliche Arten von Schwierigkeiten: (Zur Erinnerung: tsetup und thold wurden früher erklärt)
- Wenn der Takt wegen des Taktversatzes später am ersten Flipflop ankommt: Dann bleibt weniger Zeit, bis die nächste Taktflanke das zweite Flipflop erreicht. Es ist also schwieriger, die tsetup-Anforderung zu erfüllen.
- Wenn der Takt wegen des Taktversatzes früher am ersten Flipflop ankommt: Das erste Flipflop aktualisiert seinen Ausgang dann, bevor dieselbe Taktflanke das zweite Flipflop erreicht hat. Dadurch kann die thold-Anforderung am zweiten Flipflop verletzt werden. Die Tools verhindern das, indem sie die Verdrahtung des Pfads künstlich verlängern. Das kann dazu führen, dass die tsetup-Anforderung verfehlt wird. Es ist auch eine Verschwendung von Routing-Ressourcen.
Es ist wichtig zu beachten, dass es auf Kosten der Optimierung anderer Pfade gehen kann, wenn die Tools mehr als gewöhnlich arbeiten müssen, um diese Schwierigkeiten zu überwinden.
Aber nicht ausgerichtete zusammenhängende Takte sind kein Fehler, und manchmal sind sie unvermeidlich. Diese Situation bedeutet nur, dass die Tools härter arbeiten müssen. Wenn die Timing-Vorgaben erreicht werden, gibt es kein Problem mit dem Design. Das sollte jedoch nach Möglichkeit vermieden werden, wenn dies mit vertretbarem Aufwand möglich ist.
Beachten Sie, dass sich der in „Idee #4“ oben erwähnte Fehler davon unterscheidet, auch wenn beide Fehler es den Tools unnötig schwer machen und beide mit dem Taktdomänenübergang zu tun haben.
Die beste Lösung für eine Situation mit nicht ausgerichteten zusammenhängenden Takten ist, diese Takte auszurichten. Das geschieht normalerweise durch das Hinzufügen einer PLL oder das Hinzufügen eines Taktausgangs zu einer vorhandenen PLL. Das Ziel ist, dass beide fraglichen Takte Ausgänge derselben PLL sind.
Eine weitere mögliche Lösung ist, die Takte als unabhängige Takte zu behandeln. Das erfordert sowohl eine Änderung im Logikdesign selbst als auch eine Änderung der Timing-Vorgaben. Es kann sich lohnen, wenn das nicht zu schwierig ist. Mehr zu diesem Thema später.
Wir sehen uns nun ein Beispiel für einen Taktdomänenübergang zwischen zusammenhängenden Takten an, die nicht ausgerichtet sind.
wire pll_clk;
reg [24:0] result;
reg [11:0] x, y, x1, y1;
clk_wiz_0 pll_i
(.clk_in1(clk),
.clk_out1(pll_clk));
always @(posedge clk)
begin
x1 <= x;
y1 <= y;
end
always @(posedge pll_clk)
result <= x1 * y1;
Beachten Sie, dass es eine PLL (clk_wiz_0) gibt. Diese PLL verwendet @clk als Referenztakt, dessen Frequenz 250 MHz beträgt. Es ist dieselbe PLL, die im Beispiel oben auf einer vorherigen Seite gezeigt wurde. Die Frequenz von @pll_clk beträgt 125 MHz.
Der wichtige Teil dieses Beispiels ist der Taktdomänenübergang zwischen zwei zusammenhängenden Takten (@clk und @pll_clk). Da nur @pll_clk von der PLL erzeugt wird, sind diese beiden Takte nicht ausgerichtet. Es gibt also einen Taktversatz auf den Pfaden zu @result (von @x1 und @y1). Trotz dieses Taktversatzes sind die Takte immer noch zusammenhängende Takte, und die Tools werden versuchen, die Timing-Anforderungen zu erfüllen.
Wenn der einzige Grund für die Verwendung von @clk die Notwendigkeit eines Takts mit 250 MHz ist, besteht die richtige Lösung darin, mit der PLL einen weiteren Takt zu erzeugen. Es ist keine Verschwendung von Ressourcen, einen Takt mit derselben Frequenz wie der Referenztakt zu erzeugen. Im Gegenteil: Dadurch erspart man den Tools viel Mühe. Es gibt nur einen guten Grund, @clk direkt wie im Beispiel zu verwenden: wenn die Logik, die @clk verwendet, arbeiten muss, bevor die PLL brauchbare Takte erzeugt.
Der von Vivado erzeugte Timing-Report ist folgender. In diesem speziellen Fall gab es nur ein Problem mit der tsetup-Anforderung.
Slack (VIOLATED) : -1.456ns (required time - arrival time) Source: x1_reg[7]/C (rising edge-triggered cell FDRE clocked by clk {rise@0.000ns fall@2.000ns period=4.000ns}) Destination: result_reg/DSP_OUTPUT_INST/ALU_OUT[10] (rising edge-triggered cell DSP_OUTPUT clocked by clk_out1_clk_wiz_0 {rise@0.000ns fall@4.000ns period=8.000ns}) Path Group: clk_out1_clk_wiz_0 Path Type: Setup (Max at Slow Process Corner) Requirement: 4.000ns (clk_out1_clk_wiz_0 rise@8.000ns - clk rise@4.000ns) Data Path Delay: 3.012ns (logic 2.677ns (88.878%) route 0.335ns (11.122%)) Logic Levels: 5 (DSP_A_B_DATA=1 DSP_ALU=1 DSP_M_DATA=1 DSP_MULTIPLIER=1 DSP_PREADD_DATA=1) Clock Path Skew: -2.192ns (DCD - SCD + CPR) Destination Clock Delay (DCD): 0.998ns = ( 8.998 - 8.000 ) Source Clock Delay (SCD): 3.202ns = ( 7.202 - 4.000 ) Clock Pessimism Removal (CPR): 0.012ns Clock Uncertainty: 0.148ns ((TSJ^2 + DJ^2)^1/2) / 2 + PE Total System Jitter (TSJ): 0.071ns Discrete Jitter (DJ): 0.103ns Phase Error (PE): 0.086ns Clock Net Delay (Source): 1.414ns (routing 0.002ns, distribution 1.412ns) Clock Net Delay (Destination): 1.184ns (routing 0.002ns, distribution 1.182ns) Clock Domain Crossing: Inter clock paths are considered valid unless explicitly excluded by timing constraints such as set_clock_groups or set_false_path. Location Delay type Incr(ns) Path(ns) Netlist Resource(s) ------------------------------------------------------------------- ------------------- (clock clk rise edge) 4.000 4.000 r AG12 0.000 4.000 r clk (IN) net (fo=0) 0.000 4.000 clk_IBUF_inst/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.738 4.738 r clk_IBUF_inst/INBUF_INST/O net (fo=1, routed) 0.105 4.843 clk_IBUF_inst/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.049 4.892 r clk_IBUF_inst/IBUFCTRL_INST/O net (fo=1, routed) 0.795 5.687 clk_IBUF BUFGCE_X1Y2 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.101 5.788 r clk_IBUF_BUFG_inst/O X2Y0 (CLOCK_ROOT) net (fo=62, routed) 1.414 7.202 clk_IBUF_BUFGCE SLICE_X52Y45 FDRE r x1_reg[7]/C ------------------------------------------------------------------- ------------------- SLICE_X52Y45 FDRE (Prop_HFF_SLICEM_C_Q) 0.138 7.340 f x1_reg[7]/Q net (fo=1, routed) 0.335 7.675 result_reg/A[7] DSP48E2_X8Y18 DSP_A_B_DATA (Prop_DSP_A_B_DATA_DSP48E2_A[7]_A2_DATA[7]) 0.396 8.071 r result_reg/DSP_A_B_DATA_INST/A2_DATA[7] net (fo=1, routed) 0.000 8.071 result_reg/DSP_A_B_DATA.A2_DATA<7> DSP48E2_X8Y18 DSP_PREADD_DATA (Prop_DSP_PREADD_DATA_DSP48E2_A2_DATA[7]_A2A1[7]) 0.182 8.253 r result_reg/DSP_PREADD_DATA_INST/A2A1[7] net (fo=1, routed) 0.000 8.253 result_reg/DSP_PREADD_DATA.A2A1<7> DSP48E2_X8Y18 DSP_MULTIPLIER (Prop_DSP_MULTIPLIER_DSP48E2_A2A1[7]_U[10]) 0.994 9.247 f result_reg/DSP_MULTIPLIER_INST/U[10] net (fo=1, routed) 0.000 9.247 result_reg/DSP_MULTIPLIER.U<10> DSP48E2_X8Y18 DSP_M_DATA (Prop_DSP_M_DATA_DSP48E2_U[10]_U_DATA[10]) 0.164 9.411 r result_reg/DSP_M_DATA_INST/U_DATA[10] net (fo=1, routed) 0.000 9.411 result_reg/DSP_M_DATA.U_DATA<10> DSP48E2_X8Y18 DSP_ALU (Prop_DSP_ALU_DSP48E2_U_DATA[10]_ALU_OUT[10]) 0.803 10.214 r result_reg/DSP_ALU_INST/ALU_OUT[10] net (fo=1, routed) 0.000 10.214 result_reg/DSP_ALU.ALU_OUT<10> DSP48E2_X8Y18 DSP_OUTPUT r result_reg/DSP_OUTPUT_INST/ALU_OUT[10] ------------------------------------------------------------------- ------------------- (clock clk_out1_clk_wiz_0 rise edge) 8.000 8.000 r BUFGCE_X1Y2 BUFGCE 0.000 8.000 r clk_IBUF_BUFG_inst/O net (fo=62, routed) 1.078 9.078 pll_i/inst/clk_in1 MMCME3_ADV_X1Y0 MMCME3_ADV (Prop_MMCME3_ADV_CLKIN1_CLKOUT0) -1.777 7.301 r pll_i/inst/mmcme3_adv_inst/CLKOUT0 net (fo=1, routed) 0.422 7.723 pll_i/inst/clk_out1_clk_wiz_0 BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.091 7.814 r pll_i/inst/clkout1_buf/O X2Y0 (CLOCK_ROOT) net (fo=6, routed) 1.184 8.998 result_reg/CLK DSP48E2_X8Y18 DSP_OUTPUT r result_reg/DSP_OUTPUT_INST/CLK clock pessimism 0.012 9.010 clock uncertainty -0.148 8.862 DSP48E2_X8Y18 DSP_OUTPUT (Setup_DSP_OUTPUT_DSP48E2_CLK_ALU_OUT[10]) -0.104 8.758 result_reg/DSP_OUTPUT_INST ------------------------------------------------------------------- required time 8.758 arrival time -10.214 ------------------------------------------------------------------- slack -1.456
Dieser Report zeigt, dass die Tools die Timing-Vorgaben nicht erreicht haben. Der gezeigte Pfad beginnt mit der steigenden Flanke von @clk bei 4 ns und endet mit der steigenden Flanke von @pll_clk bei 8 ns. Das Problem ist die Zeit, die der Takt am Eingangspin braucht, um den Takteingangspin des ersten Flipflops zu erreichen: 3,2 ns. Die Ankunftszeit dieser Taktflanke ist also 7,2 ns.
@pll_clk wird jedoch von der PLL erzeugt, dieser Takt ist also am Eingangspin von @clk ausgerichtet. Die Verzögerung beträgt daher nur 1,0 ns. Die Ankunftszeit von @pll_clk am zweiten Flipflop ist also 9,0 ns. Die Zeit, die für den Datenpfad bleibt, beträgt daher 9,0 – 7,2 = 1,8 ns (ungefähr, wegen der Clock-Uncertainty usw.). Das reicht für eine arithmetische Multiplikation nicht aus, selbst wenn die dedizierte Recheneinheit verwendet wird. Daher konnten die Timing-Anforderungen nicht erfüllt werden.
In diesem Beispiel kommt der Takt wegen des Taktversatzes also spät am ersten Flipflop an. Das führt dazu, dass die tsetup-Anforderung nicht erfüllt wird.
Beachten Sie, dass das durch Manipulation der Ausrichtung von @pll_clk gelöst werden kann. Der Referenztakt der PLL kann zum Beispiel der Ausgang des globalen Taktpuffers sein, der @clk verteilt. Es ist auch möglich, die Phasenverschiebung der PLL zu definieren, um eine bessere Ausrichtung zu erreichen. Das sind jedoch Lösungen, die nur als letztes Mittel eingesetzt werden sollten.
Zusammenfassung
Noch einmal: Das waren nur ein paar Ideen, die beim Lösen eines Timing-Closure-Problems helfen können. Leider kann das Lösen eines solchen Problems viel mehr erfordern. Tatsächlich gibt es im Bereich der FPGAs kein einziges Thema, das nicht irgendwie mit dem Timing-Closure zu tun hat.
Wie bereits erwähnt, ist die beste Strategie, das Logikdesign von Anfang an sorgfältig zu schreiben. Der beste Weg, Timing-Closure anzugehen, ist, es zu vermeiden.
Bis zu diesem Punkt hat diese Seitenreihe das Timing besprochen, aber nicht viel über Timing-Vorgaben gesagt. Das wird sich jetzt ändern: Ab der nächsten Seite wird die Diskussion technischer.