Esta página pertenece a una serie de páginas sobre temporización.
Acerca de esta página
Es imposible realizar correctamente la temporización sin conocer algunos conceptos básicos del diseño lógico. Esta página explica unos conceptos fundamentales, que constituyen la base del resto de la serie.
Todo lo que se explica a continuación se enseña en los cursos académicos de diseño lógico. Sin embargo, no todo el que trabaja con FPGAs ha cursado una asignatura de este tipo, e incluso quienes la han cursado no recuerdan necesariamente todo. Esta página pretende rellenar las lagunas que puedan existir.
Siéntete libre de saltarte las secciones que ya conozcas, pero aun así se recomienda leer la página entera, aunque solo sea por encima. Las últimas secciones son especialmente importantes para entender las páginas siguientes de la serie.
Un breve repaso
Antes de entrar en los conceptos relacionados con la temporización, haré un breve repaso de algunos términos relevantes del diseño lógico. Si alguno de estos términos no se conoce ya, te sugiero que te familiarices con él antes de continuar con esta página.
En primer lugar, la lógica combinacional (combinatorial logic). Este término se utiliza para describir elementos como las puertas lógicas: puerta AND, puerta OR, puerta NOT, etc. Estos elementos lógicos se consideran lógica combinacional porque no tienen memoria. En otras palabras, su comportamiento no depende de lo que haya ocurrido en el pasado. El valor presente en la salida de estos elementos depende solo de los valores en las entradas.
Un tipo importante de lógica combinacional es la tabla de consulta (LUT). Se trata de un elemento lógico multiuso que implementa cualquier función lógica dependiente de un número de entradas. La LUT es importante porque se utiliza para casi toda la lógica combinacional dentro de una FPGA. Las LUT de una FPGA se implementan como ROM asíncronas (es decir, memorias ROM sin reloj): las entradas se tratan como la dirección de los datos almacenados en la LUT. La salida suele estar formada por uno o dos bits.
El número de entradas de estas LUT es de 4 o 6 en casi todas las FPGAs del mercado, así que el número de celdas de memoria de cada LUT es de 16 o 64.
El siguiente término importante es la lógica secuencial. Esta incluye biestables (flip-flops), memorias RAM síncronas y muchos otros bloques básicos que requieren un reloj para funcionar. Todos estos elementos lógicos se activan como reacción a un cambio concreto del reloj. Entre esos momentos de actividad, los elementos secuenciales ignoran sus entradas, conservan su estado interno y no cambian sus salidas.
Por ejemplo, los elementos lógicos disparados por flanco positivo se activan cuando el reloj cambia de bajo a alto, es decir, en un flanco de subida del reloj. Del mismo modo, los elementos disparados por flanco negativo se activan cuando el reloj cambia de alto a bajo, es decir, en un flanco de bajada. También hay elementos lógicos que se activan con ambos flancos, pero se utilizan casi exclusivamente para el muestreo (sampling) de señales de E/S o para generarlas.
Todos los elementos secuenciales tienen algún tipo de memoria. Esto se deduce directamente del hecho de que no cambian su salida hasta que llega un flanco de reloj. Algunos elementos secuenciales tienen la cantidad mínima de memoria, exactamente un bit por cada salida. Otros elementos secuenciales tienen más memoria, por ejemplo los registros de desplazamiento y las memorias RAM.
Para hablar de temporización, solo hay dos hechos importantes: la entrada se muestrea únicamente en conjunción con un flanco de reloj, y la salida cambia casi solo como consecuencia de un flanco de reloj. Solo hay una excepción: algunos elementos secuenciales tienen una entrada de reset asíncrono (asynchronous reset). Cuando esta entrada está activa (nivel alto o bajo, según el elemento), el estado interno del elemento secuencial cambia de inmediato a un valor predefinido, sin tener en cuenta el reloj. Como resultado, algunas de sus salidas o todas cambian también inmediatamente a un valor conocido.
En una FPGA, algunos elementos secuenciales tienen reset asíncrono y otros no. El reset asíncrono es la única entrada asíncrona posible en casi todos los elementos secuenciales de una FPGA. Esto es así aunque la teoría del diseño lógico contempla elementos con múltiples entradas asíncronas, por ejemplo el biestable S-R.
De aquí en adelante, hablaré de biestables
Para simplificar, supondré que todos los elementos secuenciales son biestables disparados por flanco positivo, es decir, biestables que responden a un flanco de subida del reloj. Dicho de otro modo, todos los elementos secuenciales se representarán aquí mediante biestables. Estos biestables responden a sus entradas y actualizan sus salidas solo cuando el reloj cambia de bajo a alto.
Así es más fácil entender la temporización, y la discusión sobre el biestable se generaliza fácilmente a cualquier otro elemento secuencial.
Establecimiento y retención
Para asegurar que un biestable funcione de forma correcta y fiable, sus entradas deben ser estables (es decir, no cambiar de valor) de acuerdo con dos requisitos de temporización:
- La entrada debe permanecer estable durante un periodo de tiempo antes del flanco de reloj. Este intervalo se denomina tiempo de establecimiento (setup time) y se representa como tsu.
- La entrada debe permanecer estable durante un periodo de tiempo después del flanco de reloj. Este intervalo se denomina tiempo de retención (hold time) y se representa como thold.
El dibujo anterior muestra el significado de tsu y thold: no se permite que la entrada D cambie de valor dentro del periodo marcado en amarillo. En este ejemplo, D cambia de alto a bajo con una temporización legal, es decir, fuera de ese periodo amarillo.
Una forma de entender estos dos parámetros de temporización es esta: resulta bastante evidente que, si una entrada de un biestable cambia exactamente a la vez que el flanco de reloj, no queda claro si el biestable tratará esa entrada como alta o baja. ¿Qué debería elegir? ¿El estado justo antes del flanco o el posterior?
Entonces podemos preguntarnos qué significa que la entrada cambie “exactamente a la vez” que el flanco. ¿Cuán exacto es eso? Los dos parámetros, tsu y thold, definen a qué distancia del flanco de reloj es seguro cambiar el valor de la entrada. Estos parámetros están definidos para todos los elementos secuenciales con el mismo significado.
Es importante señalar que, si se incumple este requisito de temporización, la consecuencia puede ser mucho peor que simplemente que la salida del biestable sea aleatoria después del flanco. Estas son las dos razones principales:
- En algunos casos, las herramientas de diseño para FPGA duplican automáticamente biestables del diseño lógico durante la implementación del proyecto, en particular para reducir el fan-out. Al hacer esto, una parte de la lógica que depende del valor de este biestable se conecta a un biestable, y otra parte de la lógica se conecta al segundo biestable. Esto es correcto siempre que ambos biestables tengan la misma salida en todo momento. Pero si se violan los requisitos de temporización (tsu y thold), cada uno de estos dos biestables puede tener un valor distinto en su salida.
- Un biestable puede caer en un estado de metaestabilidad (metastability) si se violan los requisitos de temporización. En ese estado, la salida del biestable no es ni alta ni baja durante un breve instante. Puedes encontrar más información sobre la metaestabilidad y sus consecuencias adversas en esta página.
Tiempo de reloj a salida
El tercer parámetro de temporización definido para todos los elementos secuenciales es el tiempo de reloj a salida (clock-to-output), que tiene varios símbolos habituales, por ejemplo tcko, tco, tC_Q, etc. Este parámetro no es un requisito, sino que indica cuándo se garantiza que la salida (Q) del elemento secuencial es válida. Más concretamente, cuánto tiempo después del flanco de reloj es válida la salida (véase el diagrama de tiempos anterior).
De hecho, hay dos parámetros al respecto:
- El tiempo de reloj a salida máximo: cuánto tiempo tarda la salida en ser válida después de un flanco de reloj.
- El tiempo de reloj a salida mínimo: durante cuánto tiempo se garantiza que la salida permanece sin cambios después de un flanco de reloj.
Casi siempre solo interesa el tiempo de reloj a salida máximo, así que cuando este parámetro aparece en una hoja de datos, casi con seguridad se trata del valor máximo.
Nótese que, si se violan los requisitos de temporización del biestable (tsu y thold), no hay garantía de cuándo será estable la salida. En ese caso, el tiempo de reloj a salida máximo no tiene sentido, debido a la posibilidad de que el biestable permanezca un breve instante en un estado indefinido (metaestabilidad).
tsu y thold pueden ser negativos
Aunque el dibujo anterior muestra tsu y thold positivos, es posible que uno de estos parámetros tenga un valor negativo. De hecho, esto ocurre a menudo con los biestables dentro de las FPGAs.
Por ejemplo, un tsu negativo significa que los datos no tienen que estar estables cuando llega el flanco de reloj. Más bien, los datos deben haber alcanzado su valor estable ligeramente después del flanco de reloj. Pero tsu sigue limitando cuánto después del flanco se permite.
Del mismo modo, un thold negativo permite que los datos cambien antes del flanco de reloj. Una vez más, sigue existiendo un límite sobre cuánto antes se permite, y esto queda reflejado en thold.
Sin embargo, como tsu y thold pueden ser negativos, es teóricamente posible definir requisitos de temporización que no tengan sentido.
Para explicarlo, definamos tsamp como el instante real en el que el biestable muestrea su entrada. tsamp no se conoce de antemano, pero la definición de tsu nos dice que -tsu < tsamp. En otras palabras, el biestable muestrea su entrada después de que los datos se hayan estabilizado tras un cambio, que es lo que garantiza tsu. Por el mismo principio, tsamp < thold: el muestreo debe ocurrir antes de que los datos puedan cambiar como respuesta a un flanco de reloj. Combinando ambas cosas tenemos -tsu < tsamp < thold, o simplemente -tsu < thold. Esto debe cumplirse para cualquier par de tsu y thold.
Así que tsu o thold pueden ser negativos siempre que se cumpla esta condición. Pero ambos no pueden ser negativos a la vez.
El tiempo de reloj a salida siempre es positivo: un biestable no puede reaccionar a un flanco de reloj antes de que este haya llegado. En cambio, nótese que el hecho de que tsamp pueda ser negativo no implica que el muestreo haya tenido lugar antes del flanco de reloj. Más bien, esto puede ocurrir debido a un retardo en la señal de datos.
Retardo de propagación
El dibujo anterior muestra una conexión sencilla entre dos biestables con una LUT en medio. Para simplificar, supongamos que la salida de la LUT depende solo de I1. Por ejemplo, esa lógica podría ser el resultado del siguiente código Verilog, de modo que la LUT implementa una puerta NOT:
always @(posedge clk)
begin
foo_reg <= foo; // FF1 = foo_reg
bar <= !foo_reg; // FF2 = bar
end
Nótese que ambos biestables están conectados al mismo reloj. ¿Cuál es la frecuencia máxima de este reloj?
Para responder a esta pregunta falta un dato: ¿cuánto tiempo transcurre desde que la salida de FF1 tiene un valor estable hasta que la entrada de FF2 tiene un valor estable? A este tiempo lo llamaremos tpd (retardo de propagación, propagation delay).
Nótese que el término retardo de propagación se refiere siempre a un segmento concreto de lógica combinacional. Es importante definir explícitamente a qué segmento se refiere. Por ejemplo, también se puede definir como retardo de propagación el tiempo desde I1 de la LUT hasta la O de esa misma LUT (de su entrada a su salida). Este retardo probablemente sea distinto de la definición anterior de tpd.
En particular, en una FPGA hay un retardo de interconexión entre la salida de FF1 y la entrada de la LUT. Así que, en la práctica, la Q de FF1 no es el mismo punto que la I1 de la LUT, y la señal tarda un tiempo en propagarse entre ambos puntos.
Debido a esta ambigüedad, es raro ver el símbolo tpd en las hojas de datos de las FPGAs. Y cuando en esas hojas se indica un retardo de propagación, normalmente se explica explícitamente el significado exacto del parámetro.
Más adelante volveré sobre la frecuencia máxima del reloj.
La ruta
Es difícil dar una definición concisa de ruta (path), pero ya hemos visto un ejemplo. Más arriba he definido tpd como el retardo de propagación entre la Q de FF1 y la D de FF2. Ese tpd se refiere a un escenario concreto: FF1 cambia su valor; el valor actualizado llega a la LUT; la LUT cambia su salida; y por último el valor actualizado llega a FF2. Esta secuencia de eventos comienza con el cambio de una única señal (la salida de FF1) y termina cuando la señal en otro punto distinto (la entrada de FF2) es estable.
Así pues, tpd se define como el retardo de propagación de la ruta desde la Q de FF1 hasta la D de FF2, o, para abreviar, la ruta de FF1 a FF2.
La ruta está formada por todos los elementos que aportan un retardo desde el principio de la secuencia hasta su fin. Hay dos tipos de elementos en la ruta:
- Elementos de lógica combinacional, que contribuyen al retardo porque los circuitos electrónicos tardan cierto tiempo en actualizar las señales en sus salidas. A esto se le suele llamar retardo lógico. En el ejemplo anterior, la LUT es un elemento de este tipo.
- Conexiones (routing). Se trata simplemente de los cables que unen los elementos lógicos. Estos segmentos contribuyen al retardo porque la señal tarda un tiempo en desplazarse por el espacio, y también porque un cambio de tensión implica cargar condensadores a lo largo del recorrido.
El propósito de una ruta es calcular su retardo de propagación. A continuación se muestra cómo se utiliza el resultado de este cálculo.
A menudo una ruta representa un experimento teórico en el que cambia la salida de un biestable y se sigue un recorrido concreto hasta la entrada de otro biestable. En este experimento teórico se pone en marcha un cronómetro imaginario cuando cambia la salida del primer biestable. Cuando cambia la entrada del segundo biestable, se detiene el cronómetro.
Este experimento teórico ayuda a responder si el tiempo que marca el cronómetro es demasiado largo, lo que significaría que se ha violado el requisito de tsu. Una segunda cuestión es si ese tiempo es demasiado corto, con lo que se habría violado thold.
Nótese que el recorrido de una ruta incluye solo cableado y lógica combinacional. Por tanto, el tiempo que tarda la señal en estabilizarse en el destino depende únicamente de los elementos de lógica combinacional y de las conexiones a lo largo de la ruta. No importa cuándo se realice este experimento teórico; el resultado siempre es el mismo.
En un diseño real de FPGA, cada biestable suele tener muchas rutas que llegan a su entrada y muchas rutas que comienzan en su salida. De hecho, también puede haber más de una ruta entre un par de biestables. Aun así, los cálculos de temporización siempre se hacen suponiendo que solo un biestable ha cambiado su salida, y que todo lo que sucede en la lógica de la FPGA es consecuencia directa de ese cambio. El número de rutas que se calculan en un diseño de FPGA puede ser enorme, pero, por supuesto, el software lo hace automáticamente.
Un análisis sencillo de temporización estática
A modo de demostración, haré un análisis sencillo de temporización del ejemplo anterior con dos biestables. El tema de las restricciones de temporización (timing constraints) se tratará más adelante, pero por ahora supongamos que @clk tiene una frecuencia de 250 MHz (4 ns) y que está conectado directamente a la lógica (es decir, sin PLL, lo cual no se recomienda en un diseño real, pero simplifica el análisis de temporización). La restricción de temporización (en estilo SDC) podría ser algo así:
create_clock -period 4.000 -name clk [get_ports clk]
En la siguiente página de esta serie se muestra un ejemplo de análisis de temporización real, pero ese análisis es exacto y, por tanto, contiene muchos detalles que dificultan su comprensión. Así que este es un análisis sencillo que solo demuestra el principio.
El análisis lleva a cabo el experimento teórico mencionado antes: un cronómetro imaginario se pone en marcha con el flanco de subida de @clk. Esta es la cadena de eventos, junto con el retardo (ficticio) que aporta cada uno.
- Tiempo de reloj a salida de FF1 (0,2 ns): el tiempo que tarda la salida (Q) de FF1 en actualizarse con el valor presente en la entrada (D) del biestable.
- Retardo de interconexión hasta I1 (0,3 ns): el tiempo que tarda la señal en viajar desde la salida de FF1 hasta la entrada de la LUT (I1).
- Retardo de propagación de la LUT (0,3 ns): la LUT necesita este tiempo para actualizar su salida (O) después de que cualquiera de sus entradas (en este caso I1) haya cambiado.
- Retardo de interconexión hasta la entrada de FF2 (0,4 ns): el tiempo que tarda la señal en viajar desde la salida de la LUT hasta la entrada de FF2 (D).
El retardo de propagación (tpd) de esta ruta es la suma de todos estos retardos: 0,2 + 0,3 + 0,3 + 0,4 = 1,2 ns. Para el ejemplo, supongamos que el tsu de FF2 es 0,1 ns. Esto significa que la entrada (D) de FF2 debe estar estable 0,1 ns antes del siguiente flanco de subida de @clk. Dicho de otro modo, el tpd máximo permitido es de 4 - 0,1 = 3,9 ns.
Pero tpd es solo 1,2 ns, así que, según este cálculo, la ruta cumple la restricción de temporización con un amplio margen. Este margen se denomina margen temporal (slack) y, en este caso, es de 3,9 - 1,2 = 2,7 ns. Cuando este número aparece en los cálculos de temporización del software, indica si las herramientas lo han tenido difícil para cumplir las restricciones de temporización: si el margen temporal está cerca de cero, suele indicar que el software ha tenido que trabajar duro para que la ruta cumpla los requisitos de temporización.
El retardo de propagación también permite calcular la frecuencia máxima de @clk con la que esta ruta puede cumplir la temporización. tpd es 1,2 ns, y el requisito de tsu implica que el siguiente flanco de subida puede llegar 0,1 ns más tarde. Es decir, debe haber al menos 1,3 ns entre los flancos de subida. Eso supone una frecuencia de unos 769 MHz. Es una frecuencia muy alta, pero es un resultado realista porque la ruta contiene una sola LUT. La lógica real suele ser más complicada, motivo por el cual las frecuencias reales son a menudo mucho más bajas.
Un análisis de temporización estática real realiza exactamente este cálculo, pero eso es solo parte de la historia. La ruta que se ha calculado aquí se denomina ruta de datos en un cálculo real. Sin embargo, un análisis de temporización estática real también tiene en cuenta que el flanco de reloj no llega exactamente a la vez a ambos biestables. Esto se debe a que el retardo desde el búfer de reloj hasta cada uno de estos biestables es ligeramente distinto. La diferencia entre estos retardos se denomina desviación del reloj (clock skew). Además, el tiempo entre cada flanco de reloj no es exactamente el mismo debido a la fluctuación de fase (jitter) del reloj. Estos problemas con el reloj hacen que el cálculo exacto sea más complicado, como se muestra en la siguiente página.
Recuperación y retirada
Si un biestable tiene una entrada de reset asíncrono (¿seguro que quieres eso?), existen requisitos sobre cuándo esta entrada pasa a estar inactiva. Nótese que no importa cuándo se activa el reset, porque el biestable pasará a un estado conocido de todas formas.
Pero cuando el reset se vuelve inactivo, el biestable empieza a ser sensible al reloj. Si esta desactivación del reset ocurre cerca de un flanco de reloj, no está claro si el biestable debe responder a ese flanco. Al igual que tsetup y thold, el reset debe permanecer estable durante un periodo alrededor del flanco de reloj. O, más concretamente:
- El reset no debe cambiar de activo a inactivo durante un periodo de tiempo antes del flanco de reloj. Este intervalo se denomina tiempo de recuperación (recovery time). Es el tiempo que tarda el biestable en recuperarse del reset y quedar listo para un flanco de reloj.
- El reset no debe cambiar de activo a inactivo durante un periodo de tiempo después del flanco de reloj. Este intervalo se denomina tiempo de retirada (removal time).
Estas definiciones son similares a las de tsetup y thold. No es casualidad: el tiempo de recuperación es un tipo especial de tiempo de establecimiento. El análisis de temporización se hace de la misma manera. La única diferencia es que el tiempo de establecimiento debe cumplirse independientemente del valor de la señal de datos. En cambio, el tiempo de recuperación no se exige cuando la señal de reset asíncrono cambia al estado activo. La relación entre el tiempo de retirada y el tiempo de retención es la misma.
Debido a esta similitud, no se hablará más de la recuperación y la retirada. Nótese también que todo lo dicho anteriormente es válido para todas las entradas asíncronas, no solo para el reset asíncrono.
El paradigma RTL y la temporización
El ejemplo anterior con dos biestables es sencillo, pero representa toda la lógica creada con el paradigma RTL: cada ruta comienza en un biestable y termina en un biestable con el mismo reloj (o un reloj relacionado, related clock). La ruta en sí está formada por lógica combinacional y conexiones. En este ejemplo, la lógica combinacional es solo una LUT, pero no hay ninguna diferencia sustancial entre esto y tener varios elementos lógicos en la ruta. La estructura es la misma.
La razón por la que el paradigma RTL es tan importante es que, cuando se utiliza este método, casi todas las rutas de datos tienen esta misma estructura sencilla. Y como el número de rutas en un diseño lógico suele ser enorme, la simplicidad del análisis de temporización ayuda a evitar errores. Entre otras cosas, el hecho de que el análisis de temporización siga un patrón concreto permite leer el informe de temporización y preguntarse si tiene sentido.
Por tanto, en la medida de lo posible, todo debería comenzar en un elemento secuencial y terminar en un elemento secuencial. Esta es una pauta útil tanto al escribir código Verilog como al planificar la estructura general de la lógica.
Esto concluye la breve introducción a la teoría de las restricciones de temporización. Una restricción de periodo de reloj y los informes de temporización asociados se explican en la siguiente página.


