01signal.com

Strategien für das Timing-Closure

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:

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:

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:

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:

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:

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:

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)

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.

Diese Seite wurde maschinell aus dem Englischen übersetzt. Im Zweifelsfall siehe den Originaltext.
Copyright © 2021-2026. All rights reserved. (dcc38493)