Esta página es la última de una serie de páginas sobre temporización (timing). Las páginas anteriores explicaron la teoría de los cálculos de temporización, mostraron cómo escribir varias restricciones de temporización (timing constraints) y analizaron los principios del cierre de temporización (timing closure).
Introducción
Con bastante frecuencia, la táctica de desarrollo con FPGA consiste en añadir funcionalidad, arreglar lo que no funciona y repetir. Es fácil descuidar las partes del diseño que posiblemente sean incorrectas pero que, sin embargo, no plantean un problema visible.
Es crucial entender que un diseño para FPGA puede funcionar perfectamente aunque las restricciones de temporización se apliquen incorrectamente e incluso aunque no se cumplan: el uso correcto de las restricciones es uno de los componentes clave para garantizar el funcionamiento estable y correcto de la FPGA. Y sin embargo, descuidar este tema no significa necesariamente un fallo inmediato. Más bien, una temporización inadecuada puede llevar a fallos ocasionales que pueden resultar muy desconcertantes.
Esta página resume y reitera muchas de las sugerencias de esta serie de páginas sobre restricciones de temporización. El propósito es destacar algunos temas que conviene tener presentes cuando se buscan problemas derivados de una temporización inadecuada. Sería deseable tener la sabiduría de revisar estos temas ocasionalmente por su propio bien, pero en la vida real la mayoría de nosotros lo hacemos para resolver un problema que parece un poco brujería.
Lee tu informe de temporización
Todas las herramientas de diseño para FPGA generan informes de temporización. La razón más habitual por la que los abrimos es cuando las herramientas no consiguen cumplir las restricciones: ahí es donde se encuentran los caminos (paths) que fallan y, con suerte, se puede deducir qué hacer con ellos.
Sin embargo, hay otra razón no menos importante para examinar los informes: verificar que las herramientas interpretan las restricciones tal y como se pretendía y, por tanto, que las aplican correctamente. Es un buen hábito hacer esta comprobación de vez en cuando, en particular después de añadir restricciones nuevas.
Dado que cada herramienta de diseño para FPGA produce estos informes con estructuras y formatos distintos, no es posible detallar exactamente qué significa cada parte de cada informe. Por ello, esta página expone los principios, que son comunes a todas las herramientas. En cuanto a los formatos y capacidades de tus propios informes, de todos modos es buena idea dedicar tiempo a conocerlos.
Otra posible ventaja de repasar el informe de temporización es que puede revelar un uso incorrecto de la lógica. Por ejemplo, si el diseño incluye lógica asíncrona mal utilizada o depende de relojes a los que no se pueden aplicar restricciones, ello puede hacerse evidente en el informe: al ser imposible aplicar restricciones a esta lógica, puede aparecer en el informe como caminos sin restricciones (unconstrained paths).
Por otra parte, merece la pena mencionar que las IP (IP cores) incluidas en el diseño a menudo aportan sus propias restricciones de temporización, que las herramientas añaden a las que tú proporcionas. Normalmente no merece la pena revisar los caminos relacionados con esas restricciones, pero sí pueden añadir bastante peso al informe.
Caminos internos sin restricciones
A efectos de esta discusión, un elemento síncrono es un flip-flop, una block RAM, un registro de desplazamiento (shift register) o cualquier otro elemento lógico que muestrea su entrada de datos y/o cambia su salida de datos en el flanco de subida o de bajada de un reloj.
Todos los caminos que van desde la salida de datos de un elemento síncrono hasta la entrada de datos de otro elemento síncrono deben estar temporizados, es decir, sujetos a restricciones de temporización. La única excepción se da cuando la posibilidad de una violación de temporización se maneja adecuadamente en el elemento síncrono de destino, como ocurre con los dominios de reloj no relacionados.
En otras palabras, el camino hacia cualquier elemento síncrono debe estar temporizado, salvo que exista un mecanismo explícito de resincronización que compense el hecho de que las herramientas de diseño no asumen ninguna responsabilidad de muestrear la señal de entrada de manera predecible.
A veces basta con una restricción de temporización de una sola línea que defina el reloj de referencia, y las herramientas de FPGA se encargan del resto. En otros casos se necesita algo más. En situaciones realmente malas, algunos caminos internos quedan sin restricciones por error. Hay varias razones posibles, entre otras:
- Olvidar añadir una restricción de temporización.
- Un camino se define erróneamente como camino falso (false path).
- Un camino cruza de un dominio de reloj a otro entre relojes relacionados (related clocks), pero las herramientas los tratan como relojes no relacionados (unrelated clocks) (más sobre esto abajo).
- La restricción de temporización no se propaga a través de un elemento de recursos de reloj. Por ejemplo, si el reloj de referencia se conecta a una PLL de la FPGA, la restricción suele definirse en el pin de entrada de la FPGA. Entonces se espera que las herramientas creen restricciones automáticamente para los relojes de salida de la PLL. Normalmente lo hacen, pero a veces hay sorpresas.
- El reloj se genera con lógica (por ejemplo, con un divisor de frecuencia implementado en el tejido lógico) y no está cubierto explícitamente por una restricción.
Las herramientas de diseño para FPGA permiten generar informes de temporización que enumeran los caminos sin restricciones, es decir, los caminos para los que no se aplicó ninguna restricción. En principio, esta lista debería estar vacía: los caminos que no necesitan restricciones deben definirse explícitamente como caminos falsos en el archivo de restricciones. Tales restricciones no cambian nada funcionalmente en los caminos que de todos modos no estaban temporizados, pero permiten mantener vacía la lista de caminos sin restricciones en el informe. Así resulta fácil detectar caminos que se han quedado fuera sin querer. Además, como el número de caminos en esa lista es limitado, los caminos que definitivamente no deberían estar pueden quedar ocultos, porque en su lugar aparecen caminos inocuos.
Desgraciadamente, en algunos informes de temporización, la sección de caminos sin restricciones también puede incluir caminos que no tienen por qué estar cubiertos por restricciones. Por ejemplo, el camino desde la salida de un buffer de reloj hasta la entrada de otro recurso de reloj. Como resultado, el informe puede enumerar muchísimos caminos como sin restricciones y, sin embargo, todo es perfectamente normal. Esto hace algo más difícil deducir la situación a partir del informe, pero no es un problema real, ya que esos caminos suelen aparecer en una sección separada de los que terminan en la entrada de datos de un flip-flop o en otro elemento síncrono. Así que todo se reduce a leer el informe con atención y a fijarse en qué significa cada grupo de caminos enumerados.
El informe que se genera por defecto a veces no es lo bastante detallado para contener esta información. Cualquier herramienta razonable permite crear un informe de temporización bajo demanda que enumere los caminos sin restricciones, y elegir cuántos caminos listar para cada grupo (10 es un número razonable, aunque las listas relevantes deberían estar completamente vacías).
Caminos entre dominios de reloj
Es necesario aplicar restricciones a los caminos internos que son síncronos con relojes distintos en su origen y en su destino, si esos relojes son relojes relacionados (related clocks) (o, más exactamente, si la lógica los trata como tales). De lo contrario, no deberían aplicarse, ya que esa restricción innecesaria puede desperdiciar recursos de enrutado de alta calidad y posiblemente provocar el incumplimiento de las restricciones. Ver esta página sobre relojes relacionados frente a relojes no relacionados (unrelated clocks).
Cada conjunto de herramientas tiene su propia manera de decidir automáticamente si considera que una pareja de relojes es relacionada. Las herramientas que usan sintaxis SDC en sus archivos de restricciones (por ejemplo, Vivado y Quartus) tienen un comando set_clock_groups, que permite definir grupos de relojes relacionados y no relacionados. También hay otros métodos para orientar a las herramientas sobre este asunto, en particular mediante restricciones de camino falso.
Así que la pregunta es cómo comprobar si las herramientas consideran los relojes como relacionados o no. La respuesta, desgraciadamente, es que cada conjunto de herramientas tiene una forma distinta. Vivado, por ejemplo, tiene un Clock Interaction Report, con un diagrama de colores que muestra la situación para cada pareja de relojes:
- Los caminos de un reloj a otro se han temporizado (es decir, los relojes se consideran relojes relacionados).
- Los caminos de un reloj a otro no se han temporizado («User Ignored Paths»).
- Solo se han temporizado algunos de los caminos.
Alternativamente, se pueden usar informes de temporización a medida, limitados a ciertos grupos de caminos, para investigar esta cuestión. Los caminos pueden seleccionarse según los relojes implicados. Eso puede hacerse seleccionando caminos que comiencen en elementos lógicos síncronos con un reloj y terminen en otro reloj. También puede ser útil examinar específicamente los grupos de caminos que se sabe que intervienen en cruces de dominios de reloj (clock domain crossing).
Aunque pueda ser difícil, es crucial hacer una revisión completa de sobre qué cruces de dominios de reloj aplican las herramientas las restricciones y si son correctos. Al mismo tiempo, es una oportunidad para revisar si el diseño lógico tiene la lógica de resincronización donde hace falta. Es fácil acabar con un cruce de dominios de reloj inseguro por confusión sobre qué reloj se usa con cada señal.
Es importante hacer esta revisión teniendo en cuenta la naturaleza de cada reloj. Por ejemplo, si dos relojes de osciladores distintos tienen la misma frecuencia prevista y, por tanto, una definición similar en el archivo de restricciones, las herramientas podrían considerarlos erróneamente como relacionados y calcular la temporización en los caminos que van de un reloj al otro. Aplicar restricciones a esos caminos no tiene sentido, ya que no hay garantía alguna sobre las relaciones de fase entre los dos relojes. Por sí solas, las restricciones innecesarias solo dificultan que las herramientas cumplan la temporización, lo cual puede ser bastante inofensivo. El problema real es que el informe de temporización puede inducirnos a pensar que los relojes son en realidad relojes relacionados. Así que con solo mirar las restricciones y los informes, los caminos entre ellos pueden parecer seguros (es decir, que no necesitan protección contra violaciones de temporización) cuando en realidad no lo son: los dos relojes no tienen nada en común, salvo aproximadamente la misma frecuencia. La única manera de evitar errores de este tipo es entender cómo se genera cada reloj.
Caminos externos sin restricciones
Siempre deben aplicarse restricciones de temporización a los caminos que comienzan en pines de E/S o terminan en pines de E/S. Hay una página aparte que explica cómo hacerlo. La única excepción son los pines de entrada de reloj y los pines con interfaz especial, p. ej. transceptores Gigabit, pines conectados directamente a un procesador integrado en el silicio de la FPGA, etc. Si la interfaz es muy lenta, también puede perdonarse no definir restricciones. Por ejemplo, con LED, pulsadores e incluso líneas I2C. Pero es mucho mejor asignar restricciones de camino falso a esos pines, porque así la lista de pines de E/S sin restricciones del informe se mantiene vacía.
Muchas veces puede parecer absurdo aplicar restricciones a caminos externos. Por ejemplo, si hay varios pines de salida síncronos con el mismo reloj y la temporización correcta queda garantizada por el hecho de que todos conmutan simultáneamente. Una forma habitual de implementar esa conmutación simultánea es usar el registro IOB (IOB register). Este flip-flop ofrece el mejor retardo de reloj a salida posible y, además, una desviación (skew) impresionantemente baja entre los pines de salida.
Este es, sin embargo, un buen ejemplo de cuándo son importantes las restricciones de temporización en los pines de salida: manteniendo las restricciones ajustadas, se garantiza una baja desviación entre esos pines. Cuando se usa el registro IOB, unas restricciones estrictas pueden ser una forma de obligar a las herramientas a usar ese flip-flop, o de asegurarse de que, si no lo hacen, no pase desapercibido: si las herramientas no colocan el flip-flop como se desea, la temporización falla.
Por razones similares, también deben aplicarse restricciones estrictas a los pines de entrada.
Al usar restricciones de temporización con el objetivo de lograr una baja desviación entre varios pines, es importante no limitarse a restringir los pines de E/S hasta que el margen (slack) notificado sea casi cero, sino comprobar además que exigir una temporización más estricta produzca un incumplimiento de la restricción. Esto se debe a que el camino de la señal de E/S puede contener líneas de retardo opcionales que las herramientas pueden utilizar de forma contraintuitiva. Por ejemplo, el Quartus de Intel FPGA puede añadir cierto retardo en el camino de entrada si hay excedente de presupuesto de temporización. Que las herramientas elijan hacerlo puede no ser ni deseado ni esperado.
Caminos falsos incorrectos y temporización relajada en exceso
A veces se aplican restricciones de temporización, pero son demasiado permisivas. Esto es mucho más difícil de detectar, porque los caminos correspondientes sí están temporizados, solo que con el requisito equivocado.
Hay varias razones posibles para este tipo de contratiempos, entre otras:
- Las restricciones de camino falso se aplican por accidente a caminos a los que no deberían, casi siempre por un error en la expresión que define qué elementos lógicos cubren.
- Lo mismo ocurre con otras restricciones específicas, por ejemplo, unos requisitos de temporización incorrectos para caminos multicycle (multi-cycle paths).
- El valor que define la magnitud temporal deseada está mal especificado en la restricción.
- Las herramientas de diseño para FPGA hacen una mala pasada. Por ejemplo, el Quartus de Intel FPGA puede asignar una frecuencia de reloj incorrecta a algunos caminos a menos que la sentencia «derive_pll_clocks» aparezca en el archivo SDC.
No hay ninguna receta sencilla para detectar problemas de este tipo. Leer el informe de temporización de arriba abajo con atención es sin duda una buena idea; sin embargo, aunque el informe muestre 10 caminos por grupo, no hay garantía de que los caminos problemáticos aparezcan ahí. Ni tampoco entre cualquier otro número de caminos mostrados.
Otra forma de abordar esto es revisar las restricciones de temporización tal como están escritas. Como las restricciones SDC se escriben en Tcl, es posible evaluar como expresiones Tcl las expresiones que seleccionan los elementos lógicos (con «from» y «to») en el archivo de restricciones, y leer la lista de puntos extremos.
Así que si, por ejemplo, esta línea aparece en un archivo .xdc de Vivado:
set_false_path -to [ get_pins -hier -filter {name =~ */pclk_i1_bufgctrl.pclk_i1/S*} ]
se puede abrir el diseño implementado y enumerar los destinos a los que se aplican los caminos falsos:
puts [join [ get_pins -hier -filter {name =~ */pclk_i1_bufgctrl.pclk_i1/S*} ] "\n" ]
Los comandos Tcl («puts» y «join») hacen que cada elemento aparezca en una fila separada, de modo que la salida sea fácil de leer (aunque pueda ser muy larga).
Este tipo de revisión de las restricciones es importante, pero también es difícil, porque exige pensar de verdad.
Resumen
Asegurarse de que las herramientas imponen los límites de temporización correctos en los distintos caminos es una tarea delicada. Es una combinación de saber exactamente qué significan las sentencias de restricción y saber cómo revisar los informes de temporización para aumentar las posibilidades de detectar errores.
Pero, por encima de todo, se trata de tener la autodisciplina de comprobar y volver a comprobar el diseño, en particular cuando parece que funciona bien.