01signal.com

La contrainte de période d’horloge et les objets d’horloge

Cette page fait partie d’une série de pages consacrée au timing. Les pages précédentes ont expliqué la théorie derrière les calculs de timing, abordé la contrainte de période d’horloge et présenté les principes de la convergence temporelle (timing closure). Il est maintenant temps d’entrer dans les détails techniques des contraintes temporelles (timing constraints).

La signification de create_clock en tant que commande Tcl

Les pages précédentes ont toutes tourné autour de cette contrainte temporelle :

create_clock -period 4 -name clk [get_ports clk]

J’ai délibérément attendu jusqu’à présent pour discuter de la syntaxe de cette ligne. Il est donc temps d’expliquer ce qu’elle signifie vraiment.

Cette contrainte temporelle est écrite au format SDC (Synopsys Design Constraints), qui est le format le plus courant pour les contraintes temporelles (timing constraints). Vivado et Quartus utilisent ce format, ainsi que plusieurs autres outils FPGA.

Un fichier SDC est essentiellement un script (script) écrit en Tcl. Le contenu d’un fichier SDC est donc un petit programme informatique, et pas seulement un ensemble d’informations. Cela dit, les possibilités d’un fichier SDC en tant que script se limitent à un petit sous-ensemble de commandes destinées à écrire des contraintes : tout ce qui est autorisé dans un script Tcl ne l’est pas dans un fichier SDC.

La commande create_clock sert à définir une contrainte temporelle. Mais en réalité, cette commande demande aux outils FPGA de créer un objet d’horloge (clock object). Et le mot « objet » a ici son sens habituel en génie logiciel. Le nouvel objet d’horloge est donc quelque chose qui est stocké dans la mémoire de l’interpréteur Tcl comme un objet possédant ses propres propriétés.

Par exemple, la partie « -name clk » de la commande create_clock donne la valeur « clk » à la propriété appelée « name ». Rappelons, d’après l’une des pages précédentes, que ce nom apparaissait dans les rapports de timing : le nom « clk » accompagnait les chemins de timing calculés à cause de cette contrainte (ou plus précisément, à cause de cet objet d’horloge).

Plus loin, nous avons vu d’autres noms d’horloges, par exemple clk_out1_clk_wiz_1 et clk_out2_clk_wiz_1. C’étaient en réalité les noms d’autres objets d’horloge, créés automatiquement par les outils.

Il existe une commande Tcl pour lister toutes les horloges : get_clocks. Avec l’exemple à deux horloges de la page précédente, voici une session sur la console Tcl de Vivado :

> get_clocks
clk clkfbout_clk_wiz_1 clk_out1_clk_wiz_1 clk_out2_clk_wiz_1

get_clocks et les commandes analogues sont expliquées plus en détail sur la page suivante.

Il est aussi possible de consulter les propriétés de ces objets. Il n’est pas nécessaire de comprendre toutes ces propriétés : je les montre simplement pour illustrer qu’une horloge est un objet. Personnellement, je n’ai jamais eu besoin de manipuler directement une propriété d’objet.

> report_property [get_clocks clk]
Property           Type     Read-only  Value
CLASS              string   true       clock
INPUT_JITTER       double   true       0.040
IS_GENERATED       bool     true       0
IS_PROPAGATED      bool     true       1
IS_USER_GENERATED  bool     true       0
IS_VIRTUAL         bool     true       0
NAME               string   true       clk
PERIOD             double   true       4.000
SOURCE_PINS        string*  true       clk
SYSTEM_JITTER      double   true       0.050
WAVEFORM           double*  true       0.000 2.000

> report_property [get_clocks clk_out1_clk_wiz_1]
Property           Type     Read-only  Value
CLASS              string   true       clock
EDGES              int*     true       1 2 3
EDGE_SHIFT         double*  true       0.000 2.000 4.000
INPUT_JITTER       double   true       0.000
IS_GENERATED       bool     true       1
IS_INVERTED        bool     true       0
IS_PROPAGATED      bool     true       1
IS_RENAMED         bool     true       0
IS_USER_GENERATED  bool     true       0
IS_VIRTUAL         bool     true       0
MASTER_CLOCK       clock    true       clk
NAME               string   true       clk_out1_clk_wiz_1
PERIOD             double   true       8.000
SOURCE             pin      true       pll_i/inst/mmcme3_adv_inst/CLKIN1
SOURCE_PINS        string*  true       pll_i/inst/mmcme3_adv_inst/CLKOUT0
SYSTEM_JITTER      double   true       0.050
WAVEFORM           double*  true       0.000 4.000

L’important est de comprendre que create_clock se contente de créer un objet. Les paramètres de cette commande ne font que déterminer comment régler les propriétés de cet objet. Par exemple, la partie « -period 4 » (dans la contrainte que j’ai montrée à plusieurs reprises) signifie simplement qu’une propriété appelée « PERIOD » doit avoir la valeur 4.

Si vous voulez essayer ces commandes Tcl vous-même, notez qu’il existe des différences entre les outils FPGA.

Dans Vivado, ces commandes ne peuvent être utilisées qu’après avoir ouvert l’implémentation terminée (Implemented Design).

Dans Quartus, ouvrez d’abord l’analyseur de timing TimeQuest, puis cliquez sur Create Timing Netlist, Read SDC File et Update Timing Netlist. Essayez ensuite quelques commandes sur la console Tcl, par exemple :

> join [ query_collection -all [ get_clocks ] ] "\n"
> get_clock_info -waveform [get_clocks clk]

Le sens du mot « horloge »

Lorsque les outils FPGA emploient le mot « clock », il s’agit généralement d’un objet d’horloge, et non du signal physique présent dans le FPGA. C’est particulièrement vrai dans les rapports de timing.

Rappelons, d’après la page précédente, que j’ai employé plusieurs fois l’expression « horloges théoriques ». Ce sont en réalité des objets d’horloge. Elles sont appelées « clocks » dans le rapport de timing, mais leur rôle dans l’analyse indique qu’elles ne sont que des contenants d’informations.

Quel est donc le lien entre ces objets d’horloge et les signaux réels ? Nous avons déjà vu les noms des objets d’horloge dans l’analyse de timing. Comment tout cela s’articule-t-il ?

Lorsque les outils effectuent l’analyse statique du timing du design, tous les chemins (paths) sont examinés. Si un chemin commence par une bascule, les outils examinent le signal (c’est-à-dire le fil, net) connecté à l’entrée d’horloge de la bascule : existe-t-il un objet d’horloge associé à ce signal ? Par exemple, lorsque le signal est @clk, l’objet d’horloge associé est celui qui a reçu le nom « clk » par la commande create_clock. Une fois l’objet trouvé, les outils peuvent extraire de ses propriétés les informations nécessaires.

La même chose se produit avec la bascule à l’extrémité du chemin. Les outils ont alors les deux objets d’horloge correspondant au chemin. Grâce aux informations de ces objets, ils effectuent l’analyse de timing.

Et bien sûr, la même procédure vaut pour tout élément séquentiel, pas seulement pour les bascules.

Pourquoi est-il important de comprendre cela ? Entre autres, parce que le rapport de timing contient parfois un message d’erreur indiquant qu’il y a des registres sans horloge. En général, cela ne signifie pas qu’une bascule n’a rien de connecté à son entrée d’horloge. Cela signifie plutôt que les outils n’ont trouvé aucun objet d’horloge lié à cette entrée. Autrement dit, ils n’ont trouvé aucune information sur l’horloge de cette bascule. Le problème ne vient donc généralement pas de la conception logique, mais d’une contrainte temporelle manquante (ou mal écrite).

Il vaut la peine de le répéter : quand un rapport de timing mentionne « clock », cela ne veut pas dire qu’il existe un signal portant ce nom dans le design, mais qu’un objet d’horloge a été créé avec ce nom. Comment savoir à quel signal cela correspond ? C’est le sujet suivant.

À qui est cette horloge ?

Ce qui rend le rapport de timing difficile à lire tient aussi aux noms des horloges. La plupart des signaux d’horloge d’un design sont créés par une PLL, et nous avons déjà vu que le nom qui apparaît dans le rapport peut être peu parlant. La plupart des outils FPGA permettent de renommer les objets d’horloge en ajoutant des commandes au fichier SDC, mais ce n’est pas fait dans la plupart des projets. Et la règle d’or n° 4 recommande d’éviter ce qui est spécifique à votre projet.

Le problème des noms devient encore plus délicat lorsque la source de l’horloge est un bloc IP — un cœur IP (IP core), par exemple un émetteur-récepteur Gigabit, un bloc PCIe ou un cœur de processeur sur puce. Dans ce cas, le nom de l’horloge en dit souvent très peu sur sa provenance ou sur ce à quoi elle se rapporte.

Alors, comment résoudre ce problème ? Commençons par la situation la plus simple : lorsque le nom de l’horloge provient de la commande create_clock de notre propre fichier SDC. Voici une fois de plus la même contrainte temporelle :

create_clock -period 4 -name clk [get_ports clk]

La dernière partie de cette commande, « [get_ports clk] », utilise une particularité du langage Tcl : les crochets indiquent qu’il faut exécuter le contenu comme une commande Tcl, puis utiliser le résultat de cette commande à la place des crochets.

La commande get_ports recherche un port d’entrée-sortie nommé « clk ». Son résultat est l’objet qui représente ce port. Dans la commande create_clock ci-dessus, cet objet est donc passé en argument à la commande. C’est ainsi que create_clock établit le lien entre l’objet d’horloge et un signal réel.

Notez que le nom du port et celui de l’objet sont tous deux « clk ». Rien n’oblige à ce qu’ils soient identiques, mais il est recommandé qu’ils le soient : le nom de l’objet apparaît dans les rapports de timing. Le nom du port est donc généralement le meilleur choix.

Il est aussi possible d’utiliser des objets de type fil (net) ou broche (pin) pour identifier un signal. C’est courant dans les contraintes temporelles générées automatiquement pour le compte de blocs IP — de cœurs IP (IP cores). En revanche, si vous ressentez le besoin de le faire dans vos propres contraintes, il y a de bonnes chances que vous fassiez quelque chose de travers.

Ainsi, lorsqu’une commande create_clock est utilisée dans un fichier SDC, il est facile de dire à quel signal l’objet d’horloge se rapporte. Mais qu’en est-il des objets d’horloge créés automatiquement par les outils ?

Dans ce cas, le meilleur moyen de reconnaître l’horloge est de regarder le rapport de timing. Par exemple, quel objet d’horloge est associé à @pll_clk_8 dans l’exemple de la page précédente ? Un moyen simple est de faire une recherche textuelle dans le rapport. En cherchant « pll_clk_8 », on trouve le passage suivant :

Location          Delay type                Incr(ns)  Path(ns)    Netlist Resource(s)
--------------------------------------------------------------  -------------------
                  (clock clk_out1_clk_wiz_1 rise edge)
                                              16.000    16.000
AG12                                           0.000    16.000  clk (IN)
                  net (fo=0)                   0.000    16.000  pll_i/inst/clkin1_ibuf/I
AG12              INBUF (Prop_INBUF_HRIO_PAD_O)
                                               0.738    16.738  pll_i/inst/clkin1_ibuf/INBUF_INST/O
                  net (fo=1, routed)           0.105    16.843  pll_i/inst/clkin1_ibuf/OUT
AG12              IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O)
                                               0.049    16.892  pll_i/inst/clkin1_ibuf/IBUFCTRL_INST/O
                  net (fo=1, routed)           0.975    17.867  pll_i/inst/clk_in1_clk_wiz_1
MMCME3_ADV_X1Y0   MMCME3_ADV (Prop_MMCME3_ADV_CLKIN1_CLKOUT0)
                                              -4.438    13.429  pll_i/inst/mmcme3_adv_inst/CLKOUT0
                  net (fo=1, routed)           0.501    13.930  pll_i/inst/clk_out1_clk_wiz_1
BUFGCE_X1Y1       BUFGCE (Prop_BUFCE_BUFGCE_I_O)
                                               0.101    14.031  pll_i/inst/clkout1_buf/O
X2Y0 (CLOCK_ROOT) net (fo=1, routed)           1.369    15.400  pll_clk_8
SLICE_X49Y58      FDRE                                          foo_reg_reg/C

C’est le chemin d’horloge source (source clock path) pour clk_out1_clk_wiz_1, et voilà la réponse à la question.

Une autre méthode consiste à obtenir l’information par une commande Tcl. La manière exacte de procéder varie d’un outil FPGA à l’autre. Dans Vivado, la commande suivante peut être utilisée après avoir ouvert l’implémentation terminée :

> get_clocks -of_objects [ get_nets pll_clk_8 ]
clk_out1_clk_wiz_1

Cette méthode exige de connaître le nom du fil (net). Parfois c’est aussi simple que dans cet exemple, parfois il faut d’abord trouver ce nom. Les outils FPGA offrent généralement un moyen de le faire par l’interface graphique. Des commandes Tcl peuvent aussi être employées.

En fait, j’espère que ces quelques exemples en Tcl vous ont convaincu de l’importance de savoir travailler correctement en Tcl. C’est précisément le sujet de la page suivante.

L’importance d’utiliser get_port

Dans l’exemple ci-dessus, la commande create_clock s’appuie sur get_port pour relier l’objet d’horloge à une broche d’entrée physique. Comme mentionné plus haut, ce lien est nécessaire pour savoir quels éléments logiques sont reliés à cette horloge (ou aux horloges qui en sont dérivées).

Mais get_port n’est pas la seule possibilité. On peut, par exemple, se référer à la broche de sortie d’un buffer d’horloge global. Quelque chose comme :

create_clock -name clk -period 4 [get_pins my_BUFG_inst/O]

La différence est que les outils considèrent la broche de sortie du buffer d’horloge global comme l’origine de l’horloge. Autrement dit, le calcul des chemins d’horloge commence à cette position. Le premier front d’horloge à cette origine a lieu à 0 ns ; cette broche de sortie devient donc la référence de temps.

C’est une contrainte temporelle légale, mais elle présente deux inconvénients importants :

Il faut donc toujours utiliser get_port lorsque c’est possible. Dans le cas contraire, le timing de l’horloge doit être considéré comme inconnu par rapport à tout ce qui n’est pas elle-même.


Dans cette page, beaucoup de commandes Tcl ont été présentées, mais sans être expliquées convenablement. La page suivante comble cette lacune.

Cette page a été traduite de l’anglais par une machine. En cas de doute, veuillez vous reporter au texte original
Copyright © 2021-2026. All rights reserved. (dcc38493)