01signal.com

La restricción del periodo de reloj y los objetos de reloj

Esta página pertenece a una serie de páginas sobre temporización (timing). Las páginas anteriores explicaron la teoría que hay detrás de los cálculos de temporización, analizaron la restricción del periodo de reloj y mostraron los principios del cierre de temporización (timing closure). Ahora toca empezar con los detalles técnicos de las restricciones de temporización (timing constraints).

El significado de create_clock como comando Tcl

Las páginas anteriores han girado en torno a esta restricción de temporización:

create_clock -period 4 -name clk [get_ports clk]

He evitado deliberadamente hablar de la sintaxis de esta línea hasta ahora. Así que es hora de explicar qué significa realmente.

Esta restricción de temporización está escrita en formato SDC (Synopsys Design Constraints), el formato más común para restricciones de temporización. Vivado y Quartus usan este formato, así como varias otras herramientas de FPGA.

Un archivo SDC es, en esencia, un guion (script) escrito en Tcl. Por tanto, el contenido de un archivo SDC es un pequeño programa de ordenador, y no solo un conjunto de información. Sin embargo, las capacidades de un archivo SDC como guion están limitadas a un pequeño subconjunto de comandos pensados para escribir restricciones: no todo lo que está permitido en un guion Tcl puede hacerse en un archivo SDC.

El comando create_clock se utiliza para definir una restricción de temporización. Pero, de hecho, este comando le dice a las herramientas de FPGA que creen un nuevo objeto de reloj. Y la palabra «objeto» significa lo que suele significar en ingeniería del software. El nuevo objeto de reloj es, por tanto, algo que se guarda en la memoria del intérprete de Tcl como un objeto con sus propias propiedades.

Por ejemplo, la parte del comando create_clock que dice «-name clk» asigna el valor «clk» a la propiedad llamada «name». Recuerda, de una de las páginas anteriores, que este nombre se usaba en los informes de temporización: el nombre «clk» aparecía junto con los caminos de temporización (paths) que se calculaban gracias a esta restricción (o, más exactamente, gracias a este objeto de reloj).

Más adelante, vimos que había otros nombres de relojes, por ejemplo clk_out1_clk_wiz_1 y clk_out2_clk_wiz_1. Estos eran, de hecho, nombres de otros objetos de reloj creados automáticamente por las herramientas.

Hay un comando Tcl para enumerar todos los relojes: get_clocks. Así que, con el ejemplo de dos relojes de la página anterior, esta es una sesión en la consola Tcl de Vivado:

> get_clocks
clk clkfbout_clk_wiz_1 clk_out1_clk_wiz_1 clk_out2_clk_wiz_1

get_clocks y comandos similares se explican con más detalle en la página siguiente.

También es posible ver las propiedades de estos objetos. No hace falta entender todas esas propiedades: lo muestro solo para dejar claro que un reloj es un objeto. Personalmente, nunca he tenido necesidad de manipular directamente ninguna propiedad de un objeto.

> 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

Lo importante es darse cuenta de que create_clock solo crea un objeto. Los parámetros de ese comando solo determinan cómo establecer las propiedades de ese objeto. Por ejemplo, la parte que dice «-period 4» (en la restricción que he mostrado repetidamente) solo significa que cierta propiedad llamada «PERIOD» debe tener el valor 4.

Por si quieres probar estos comandos Tcl tú mismo, ten en cuenta que hay diferencias entre las herramientas de FPGA.

En Vivado, estos comandos solo pueden usarse después de abrir el diseño implementado.

En Quartus, primero abre el analizador de temporización TimeQuest, y luego haz clic en Create Timing Netlist, Read SDC File y Update Timing Netlist. Después prueba algunos comandos en la consola Tcl, por ejemplo:

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

El significado de la palabra «reloj»

Cuando las herramientas de FPGA usan la palabra «reloj», normalmente significa un objeto de reloj, y no la señal física dentro de la FPGA. Esto es especialmente cierto en los informes de temporización.

Recuerda que en la página anterior usé varias veces el término «relojes teóricos». De hecho, esos son objetos de reloj. En el informe de temporización se les llama «relojes», pero su uso en el análisis de tiempos indica que son solo contenedores de información.

Entonces, ¿cuál es la conexión entre esos objetos de reloj y las señales reales? Ya hemos visto los nombres de los objetos de reloj en el análisis de tiempos. ¿Cómo funciona todo esto en conjunto?

Cuando las herramientas realizan el análisis estático de tiempos del diseño, se examinan todos los caminos (paths). Si un camino comienza en un flip-flop, las herramientas examinan la señal (es decir, la red) conectada a la entrada de reloj del flip-flop: ¿hay algún objeto de reloj relacionado con esa señal? Por ejemplo, cuando la señal es @clk, el objeto de reloj correspondiente es el que recibió el nombre «clk» con el comando create_clock. Tras encontrar el objeto de reloj pertinente, las herramientas pueden recuperar la información necesaria de las propiedades de ese objeto.

Lo mismo ocurre con el flip-flop al final del camino. Así que ahora las herramientas tienen los dos objetos de reloj que corresponden al camino. Con la información de esos objetos, las herramientas realizan el análisis de tiempos.

Y, por supuesto, el mismo procedimiento se aplica a cualquier elemento secuencial, no solo a los flip-flops.

¿Por qué es importante entender esto? Entre otras razones, porque a veces aparece en el informe de temporización un mensaje de error que dice que hay registros sin reloj. Normalmente, eso no significa que haya un flip-flop con la entrada de reloj desconectada. Más bien significa que las herramientas no encontraron ningún objeto de reloj relacionado con esa entrada de reloj. En otras palabras, las herramientas no encontraron ninguna información sobre la entrada de reloj de ese flip-flop. Así que el problema no suele estar en el diseño lógico, sino que falta una restricción de temporización (o está mal escrita).

Vale la pena repetirlo: cuando en un informe de temporización pone «reloj», no significa que haya una señal con ese nombre en el diseño lógico, sino que se ha creado un objeto de reloj con ese nombre. ¿Cómo sabemos a qué señal corresponde? Ese es el siguiente tema.

¿De qué señal es este reloj?

Una de las cosas que hacen difícil de leer el informe de temporización son los nombres de los relojes. La mayoría de las señales de reloj de un diseño lógico las crea una PLL, y ya hemos visto que el nombre que aparece en el informe puede ser de poca ayuda. La mayoría de las herramientas de FPGA permiten renombrar los objetos de reloj añadiendo comandos al archivo SDC, pero en la mayoría de los proyectos no se hace. Y la Regla de Oro n.º 4 es abstenerse de hacer cosas que sean especiales para tu proyecto.

El problema con los nombres se vuelve aún más difícil cuando el origen del reloj es un bloque de IP (IP core) (por ejemplo, un transceptor Gigabit, un bloque PCIe o un núcleo de procesador integrado en el chip). En ese caso, el nombre del reloj suele decir muy poco sobre de dónde viene y con qué se relaciona.

Entonces, ¿cómo se resuelve este problema? Empecemos por la situación más sencilla: cuando el nombre del reloj proviene del comando create_clock de nuestro propio archivo SDC. Esta es, una vez más, la misma restricción de temporización:

create_clock -period 4 -name clk [get_ports clk]

La última parte de este comando es «[get_ports clk]». En el lenguaje Tcl, los corchetes significan que hay que ejecutar el contenido de los corchetes como un comando Tcl y usar el resultado de ese comando en lugar de esos corchetes.

El comando get_ports busca un puerto de E/S llamado «clk». El resultado de este comando es el objeto que representa a ese puerto. Así que en el comando create_clock anterior, ese objeto es un argumento de ese comando. De esta manera, create_clock establece la conexión entre el objeto de reloj y una señal real.

Observa que tanto el nombre del puerto como el nombre del objeto son «clk». No es necesario que coincidan, pero se recomienda que así sea: el nombre del objeto aparece en los informes de temporización. Por tanto, el nombre del puerto suele ser la mejor elección.

También es posible usar objetos de red (net) y objetos de pin como identificador de una señal. Esto es habitual en las restricciones de temporización generadas automáticamente en nombre de bloques de IP (IP core). Sin embargo, si sientes la necesidad de hacerlo en tus propias restricciones, hay muchas posibilidades de que estés haciendo algo mal.

Así que si se ha usado un comando create_clock en un archivo SDC, es fácil saber a qué señal corresponde el objeto de reloj. Pero, ¿qué pasa con los objetos de reloj creados automáticamente por las herramientas?

En ese caso, la mejor manera de reconocer el reloj es mirar el informe de temporización. Por ejemplo, ¿qué objeto de reloj está relacionado con @pll_clk_8 en el ejemplo de la página anterior? Una forma sencilla de averiguarlo es hacer una búsqueda de texto en el informe. Buscando «pll_clk_8», se encuentra la siguiente parte:

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

Este es el camino del reloj de origen (Source Clock Path) de clk_out1_clk_wiz_1, y ahí está la respuesta a la pregunta.

Otro método es obtener la información con un comando Tcl. Cómo hacerlo exactamente difiere de una herramienta de FPGA a otra. En Vivado, se puede usar un comando como el siguiente después de abrir el diseño implementado:

> get_clocks -of_objects [ get_nets pll_clk_8 ]
clk_out1_clk_wiz_1

Este método requiere saber el nombre de la red (net). A veces es tan sencillo como en este ejemplo, y a veces requiere encontrar el nombre de la red. Las herramientas de FPGA suelen ofrecer una manera de hacerlo con la interfaz gráfica. También se pueden usar comandos Tcl para ese fin.

De hecho, espero que los pocos ejemplos con Tcl te hayan convencido de la importancia de saber trabajar bien con Tcl. De eso trata la página siguiente.

La importancia de usar get_port

En el ejemplo anterior, el comando create_clock se apoya en get_port para hacer la conexión entre el objeto de reloj y un pin físico de entrada. Como se ha dicho antes, esta conexión es necesaria para saber qué elementos lógicos están conectados a este reloj (o a los relojes generados a partir de él).

Pero usar get_port no es la única posibilidad. Por ejemplo, también es posible referirse al pin de salida de un buffer global de reloj. Algo así:

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

La diferencia es que las herramientas consideran que el pin de salida del buffer global de reloj es el origen del reloj. En otras palabras, el cálculo de los caminos del reloj comienza desde esa posición. El primer flanco en ese origen se produce en 0 ns, así que ese pin de salida se convierte en la referencia temporal.

Esta es una restricción de temporización legal, pero tiene dos importantes inconvenientes:

Por tanto, siempre que sea posible se debe usar get_port. De lo contrario, la temporización del reloj debe considerarse desconocida en relación con cualquier cosa que no sea él mismo.


En esta página se han presentado muchos comandos Tcl, pero sin explicarlos adecuadamente. La página siguiente llena ese vacío.

Esta página se ha traducido del inglés mediante traducción automática. En caso de duda, consulta el texto original.
Copyright © 2021-2026. All rights reserved. (dcc38493)