Motivation
Quelque part en bas du rapport généré par le synthétiseur (synthesizer) d’ISE (xst), on trouve la fréquence maximale, accompagnée d’un aperçu du chemin (path) le plus lent. C’est une fonctionnalité plutôt sympathique, notamment lorsqu’on cherche à optimiser un module particulier. Vivado ne fournit pas une telle valeur après une synthèse, sans doute parce que les gens de chez Xilinx ont estimé que cette « fréquence maximale » pouvait être trompeuse. Si c’est le cas, ils avaient deux bonnes raisons pour cela :
- La « fréquence maximale » n’existe pas : les outils se plient aux contraintes temporelles (timing constraints) et font de leur mieux en conséquence. En clair, vous n’obtiendrez pas une certaine fréquence si vous ne la demandez pas.
- Dans une conception typique, il y a plusieurs horloges à des fréquences différentes. Le chemin le plus lent peut très bien appartenir à une horloge qui est de toute façon lente.
Et pourtant, il est parfois utile d’avoir une idée de la situation avant le chemin de croix d’une implémentation complète.
Comment faire dans Vivado
Tout d’abord : définissez les contraintes temporelles conformément à vos attentes. Ou du moins, d’une manière qui indique clairement quelle horloge est importante, et laquelle peut être lente. Ensuite, effectuez une synthèse du projet.
Une fois la synthèse terminée avec succès, ouvrez la conception synthétisée (en cliquant sur « Open Synthesized Design » dans la barre de gauche, ou avec la commande Tcl « open_run synth_1 »).
Dans la fenêtre Tcl, tapez la commande
report_timing_summary -file mytiming.rpt
qui écrit un rapport d’analyse temporelle complet après synthèse dans mytiming.rpt. La simple commande « report_timing_summary » l’affiche dans la console.
L’option « Report Timing Summary » existe aussi sous « Synthesized Design » dans la barre de gauche, mais je trouve difficile d’extraire des informations du rapport avec l’interface graphique.
Lecture du rapport
RÈGLE N°1 : le rapport de synthèse n’est qu’une estimation grossière. Les délais de routage sont des suppositions. Il peut signaler des violations temporelles là où l’implémentation réussira quand même, et il peut annoncer que tout va bien là où l’implémentation échouera de façon spectaculaire (en particulier lorsque le taux d’utilisation de la logique du FPGA approche les 100 %).
Passons aux choses sérieuses : la première chose à examiner est le résumé des horloges (Clock Summary) et le tableau Intra Clock Table, et à comprendre comment Vivado a nommé chaque horloge. Par exemple :
------------------------------------------------------------------------------------------------
| 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
Si les fréquences listées dans le Clock Summary (qui découlent des contraintes temporelles) ne suffisent pas à associer une horloge à un nom, la colonne TNS Total Endpoints de chaque horloge dans l’Intra Clock Table aide à identifier quelle horloge est laquelle. Une fois le nom de l’horloge qui vous intéresse trouvé, recherchez ce nom dans le fichier et vous tomberez sur quelque chose comme ceci :
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
Ce rapport est plutôt touffu, mais les éléments clés sont marqués en rouge.
Avant de tirer des conclusions, assurez-vous d’avoir sous les yeux la bonne partie :
- Il s’agit de la section des chemins à délai max (Max Delay Paths). La section des chemins minimums est utile pour repérer les violations de temps de maintien (hold time), mais elle n’a aucun effet sur la fréquence maximale.
- C’est la bonne horloge. Dans l’exemple ci-dessus, il s’agit de clk_fpga_1. La ligne Requirement (exigence) indique non seulement la contrainte donnée pour cette horloge (10 ns = 100 MHz), mais aussi qu’elle court d’un front montant de clk_fpga_1 au front montant suivant.
Une fois cela fait, voyons ce que nous avons : l’exigence était de 10 ns et la marge (slack) de 3,791 ns (notez qu’elle est positive). Cela signifie que nous aurions pu demander une période d’horloge plus courte de 3,791 ns, et tout aurait été encore correct. La période d’horloge demandée aurait donc pu être de 10 – 3,791 = 6,209 ns, soit environ 161 MHz.
La réponse courte à la question de la « fréquence maximale » pour clk_fpga_1 est donc 161 MHz. Mais rappelez-vous que cette valeur peut changer si les contraintes changent.
Et une dernière remarque : le délai du chemin de données (Data Path Delay) nous renseigne sur ce qui rend ce chemin le plus défavorable (worst path) lent ou rapide. Quelle part du délai est due à la logique, et quelle part aux délais de routage (estimés). Le rapport de détail qui suit donne aussi cette information. Pour un rapport plus détaillé, pensez à utiliser l’option « -nworst » lorsque vous demandez le rapport d’analyse temporelle, afin que quelques chemins dans le pire cas (worst-case paths) soient listés. Cela peut aider à résoudre les problèmes temporels.