Motivation
Irgendwo am Ende des Reports, den der Synthesizer von ISE (xst) erzeugt, steht etwas über die maximale Frequenz, zusammen mit einer groben Darstellung des langsamsten Pfads (englisch: path). Das ist eine recht nette Sache, besonders wenn man versucht, ein bestimmtes Modul zu optimieren. Nach einer Synthese mit Vivado wird eine solche Zahl nicht angegeben. Möglicherweise, weil die Leute bei Xilinx dachten, dass diese „maximale Frequenz“ irreführend sein könnte. Wenn das so ist, hatten sie dafür zwei gute Gründe:
- Eine „maximale Frequenz“ gibt es nicht wirklich: Die Tools achten auf die Timing-Vorgaben (englisch: timing constraints) und tun ihr Bestes, um diese zu erfüllen. Kurz gesagt: Eine bestimmte Frequenz bekommt man unter Umständen nur dann, wenn man sie auch verlangt.
- In einem typischen Design gibt es viele Takte mit unterschiedlichen Frequenzen. Der langsamste Pfad kann durchaus zu einem Takt gehören, der ohnehin langsam ist.
Trotzdem ist es manchmal nützlich, eine Vorstellung davon zu bekommen, wo man steht, bevor man sich auf den Kreuzweg einer vollständigen Implementierung begibt.
Wie man es in Vivado macht
Zuallererst: Setze die Timing-Vorgaben so, wie es deinen Erwartungen entspricht. Oder zumindest so, dass klar ist, welcher Takt wichtig ist und welcher langsam sein darf. Danach führst du eine Synthese des Designs durch.
Nachdem die Synthese erfolgreich abgeschlossen wurde, öffnest du das synthetisierte Design (Klick auf „Open Synthesized Design“ in der linken Leiste oder mit dem Tcl-Befehl „open_run synth_1“).
Gib im Tcl-Fenster den Befehl
report_timing_summary -file mytiming.rpt
ein. Dadurch wird ein vollständiger Timing-Report nach der Synthese in die Datei mytiming.rpt geschrieben. Ein einfaches „report_timing_summary“ gibt den Report auf der Konsole aus.
Unter „Synthesized Design“ in der linken Leiste gibt es auch die Option „Report Timing Summary“. Ich persönlich finde es aber schwierig, die relevanten Informationen aus dem Report zu ziehen, wenn man ihn über die grafische Oberfläche aufruft.
Den Report lesen
REGEL #1: Der Synthese-Report ist nicht mehr als eine grobe Schätzung. Die Routing-Verzögerungen sind reine Vermutungen. Es kann Timing-Verletzungen melden, obwohl die Implementierung hinterher problemlos gelingt. Und es kann alles in Ordnung melden, obwohl die Implementierung grandios scheitert (insbesondere dann, wenn die Logikauslastung des FPGAs nahe 100 % liegt).
Nun zur Praxis: Das Erste, was man sich anschaut, ist die Taktübersicht (Clock Summary) und die Intra-Clock-Tabelle, um herauszufinden, welchen Namen Vivado welchem Takt gegeben hat. Zum Beispiel:
------------------------------------------------------------------------------------------------
| Clock Summary
| -------------
------------------------------------------------------------------------------------------------
Clock Waveform(ns) Period(ns) Frequency(MHz)
----- ------------ ---------- --------------
clk_fpga_1 {0.000 5.000} 10.000 100.000
gclk {0.000 4.000} 8.000 125.000
audio_mclk_OBUF {0.000 41.667} 83.333 12.000
clk_fb {0.000 20.000} 40.000 25.000
vga_clk_ins/clk_fb {0.000 20.000} 40.000 25.000
vga_clk_ins/clkout0 {0.000 1.538} 3.077 325.000
vga_clk_ins/clkout1 {0.000 7.692} 15.385 65.000
vga_clk_ins/clkout2 {0.000 7.692} 15.385 65.000
------------------------------------------------------------------------------------------------
| Intra Clock Table
| -----------------
------------------------------------------------------------------------------------------------
Clock WNS(ns) TNS(ns) TNS Failing Endpoints TNS Total Endpoints WHS(ns) THS(ns) THS Failing Endpoints THS Total Endpoints WPWS(ns) TPWS(ns) TPWS Failing Endpoints TPWS Total Endpoints
----- ------- ------- --------------------- ------------------- ------- ------- --------------------- ------------------- -------- -------- ---------------------- --------------------
clk_fpga_1 3.791 0.000 0 12474 0.135 0.000 0 12474 3.750 0.000 0 5021
gclk 6.751 0.000 0 2
audio_mclk_OBUF 76.667 0.000 0 1
clk_fb 12.633 0.000 0 2
vga_clk_ins/clk_fb 38.751 0.000 0 2
vga_clk_ins/clkout0 1.410 0.000 0 10
vga_clk_ins/clkout1 10.747 0.000 0 215 -0.029 -0.229 8 215 6.712 0.000 0 195
vga_clk_ins/clkout2 3.990 0.000 0 415 0.135 0.000 0 415 7.192 0.000 0 211
Falls die in der Clock Summary aufgeführten Taktfrequenzen (die ja aus den Timing-Vorgaben abgeleitet sind) nicht helfen, einen Takt mit einem Namen zu verbinden, dann hilft die Spalte „TNS Total Endpoints“ der einzelnen Takte in der Intra-Clock-Tabelle weiter, um herauszufinden, welcher Takt welcher ist. Sobald man den Namen des interessierenden Takts gefunden hat, sucht man in der Datei nach diesem Namen und findet etwa Folgendes:
Max Delay Paths -------------------------------------------------------------------------------------- Slack (MET) : 3.791ns (required time - arrival time) Source: xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_offset_limit_1/C (rising edge-triggered cell FDRE clocked by clk_fpga_1 {rise@0.000ns fall@5.000ns period=10.000ns}) Destination: xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_end_offset_0/D (rising edge-triggered cell FDRE clocked by clk_fpga_1 {rise@0.000ns fall@5.000ns period=10.000ns}) Path Group: clk_fpga_1 Path Type: Setup (Max at Slow Process Corner) Requirement: 10.000ns (clk_fpga_1 rise@10.000ns - clk_fpga_1 rise@0.000ns) Data Path Delay: 6.077ns (logic 2.346ns (38.605%) route 3.731ns (61.395%)) Logic Levels: 8 (CARRY4=3 LUT3=1 LUT4=1 LUT6=3) Clock Path Skew: -0.040ns (DCD - SCD + CPR) Destination Clock Delay (DCD): 0.851ns = ( 10.851 - 10.000 ) Source Clock Delay (SCD): 0.901ns Clock Pessimism Removal (CPR): 0.010ns Clock Uncertainty: 0.154ns ((TSJ^2 + TIJ^2)^1/2 + DJ) / 2 + PE Total System Jitter (TSJ): 0.071ns Total Input Jitter (TIJ): 0.300ns Discrete Jitter (DJ): 0.000ns Phase Error (PE): 0.000ns Location Delay type Incr(ns) Path(ns) Netlist Resource(s) ------------------------------------------------------------------- ------------------- (clock clk_fpga_1 rise edge) 0.000 0.000 r PS7 0.000 0.000 r xillybus_ins/system_i/vivado_system_i/processing_system7_0/inst/PS7_i/FCLKCLK[1] net (fo=1, unplaced) 0.000 0.000 xillybus_ins/system_i/vivado_system_i/processing_system7_0/inst/n_707_PS7_i BUFG (Prop_bufg_I_O) 0.101 0.101 r xillybus_ins/system_i/vivado_system_i/processing_system7_0/inst/buffer_fclk_clk_1.FCLK_CLK_1_BUFG/O net (fo=5023, unplaced) 0.800 0.901 xillybus_ins/xillybus_core_ins/bus_clk_w r xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_offset_limit_1/C ------------------------------------------------------------------- ------------------- FDRE (Prop_fdre_C_Q) 0.496 1.397 f xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_offset_limit_1/Q net (fo=5, unplaced) 0.834 2.231 xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_offset_limit[1] LUT4 (Prop_lut4_I0_O) 0.289 2.520 r xillybus_ins/xillybus_core_ins/unitw_1_ins/Mcompar_n0037_lutdi/O net (fo=1, unplaced) 0.000 2.520 xillybus_ins/xillybus_core_ins/unitw_1_ins/Mcompar_n0037_lutdi CARRY4 (Prop_carry4_DI[0]_CO[3]) 0.553 3.073 r xillybus_ins/xillybus_core_ins/unitw_1_ins/Mcompar_n0037_cy[0]_CARRY4/CO[3] net (fo=1, unplaced) 0.000 3.073 xillybus_ins/xillybus_core_ins/unitw_1_ins/Mcompar_n0037_cy[3] CARRY4 (Prop_carry4_CI_CO[3]) 0.114 3.187 r xillybus_ins/xillybus_core_ins/unitw_1_ins/Mcompar_n0037_cy[4]_CARRY4/CO[3] net (fo=3, unplaced) 0.936 4.123 xillybus_ins/xillybus_core_ins/unitw_1_ins/Mcompar_n0037_cy[7] LUT6 (Prop_lut6_I4_O) 0.124 4.247 f xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_wr_request_condition/O net (fo=7, unplaced) 0.480 4.727 xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_wr_request_condition LUT3 (Prop_lut3_I2_O) 0.124 4.851 r xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_flush_condition_unitw_1_wr_request_condition_AND_179_o3_lut/O net (fo=1, unplaced) 0.000 4.851 xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_flush_condition_unitw_1_wr_request_condition_AND_179_o3_lut CARRY4 (Prop_carry4_S[2]_CO[3]) 0.398 5.249 f xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_flush_condition_unitw_1_wr_request_condition_AND_179_o2_cy_CARRY4/CO[3] net (fo=21, unplaced) 0.979 6.228 xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_flush_condition_unitw_1_wr_request_condition_AND_179_o LUT6 (Prop_lut6_I5_O) 0.124 6.352 r xillybus_ins/xillybus_core_ins/unitw_1_ins/_n03401/O net (fo=15, unplaced) 0.502 6.854 xillybus_ins/xillybus_core_ins/unitw_1_ins/_n0340 LUT6 (Prop_lut6_I5_O) 0.124 6.978 r xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_end_offset_0_rstpot/O net (fo=1, unplaced) 0.000 6.978 xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_end_offset_0_rstpot FDRE r xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_end_offset_0/D ------------------------------------------------------------------- ------------------- (clock clk_fpga_1 rise edge) 10.000 10.000 r PS7 0.000 10.000 r xillybus_ins/system_i/vivado_system_i/processing_system7_0/inst/PS7_i/FCLKCLK[1] net (fo=1, unplaced) 0.000 10.000 xillybus_ins/system_i/vivado_system_i/processing_system7_0/inst/n_707_PS7_i BUFG (Prop_bufg_I_O) 0.091 10.091 r xillybus_ins/system_i/vivado_system_i/processing_system7_0/inst/buffer_fclk_clk_1.FCLK_CLK_1_BUFG/O net (fo=5023, unplaced) 0.760 10.851 xillybus_ins/xillybus_core_ins/bus_clk_w r xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_end_offset_0/C clock pessimism 0.010 10.861 clock uncertainty -0.154 10.707 FDRE (Setup_fdre_C_D) 0.062 10.769 xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_end_offset_0 ------------------------------------------------------------------- required time 10.769 arrival time -6.978 ------------------------------------------------------------------- slack 3.791
Das ist ein ziemlich unübersichtlicher Text, aber die wichtigsten Elemente sind hier rot markiert.
Bevor du Schlüsse daraus ziehst, stelle sicher, dass du den richtigen Teil ansiehst:
- Es muss der Abschnitt Max Delay Paths sein. Der Abschnitt mit den Minimal-Pfaden ist nützlich, um Hold-Verletzungen zu finden, hat aber keinen Einfluss auf die maximale Frequenz.
- Es ist der richtige Takt. Im Beispiel oben ist das clk_fpga_1. Die Zeile Requirement nennt nicht nur die Vorgabe, die für diesen Takt gilt (10 ns = 100 MHz), sondern auch, dass der Pfad von einer steigenden Flanke von clk_fpga_1 bis zur nächsten steigenden Flanke läuft.
Wenn das erledigt ist, schauen wir uns an, was wir haben: Die Anforderung betrug 10 ns, und der Slack (englisch: slack; die Zeitmarge) betrug 3,791 ns (man beachte: positiv). Das bedeutet, wir hätten eine um 3,791 ns kürzere Taktperiode verlangen können, und es wäre trotzdem in Ordnung gewesen. Die angeforderte Taktperiode hätte also 10 – 3,791 = 6,209 ns betragen können; das entspricht etwa 161 MHz.
Die kurze Antwort auf die Frage nach dem „maximalen Takt“ für clk_fpga_1 lautet also 161 MHz. Aber denk daran: Dieser Wert kann sich ändern, wenn sich die Timing-Vorgaben ändern.
Und noch ein letzter Hinweis: Die Data Path Delay zeigt uns, was diesen schlechtesten Pfad langsam oder schnell gemacht hat. Wie viel Verzögerung auf die Logik entfällt und wie viel auf die (geschätzten) Routing-Verzögerungen. Das macht auch der darauffolgende detaillierte Verzögerungsreport. Wenn du einen detaillierteren Report möchtest, kannst du beim Anfordern des Timing-Reports die Option „-nworst“ verwenden, damit mehrere Worst-Case-Pfade aufgelistet werden. Das kann helfen, Timing-Probleme zu lösen.