Menu

Timescale y retardos en Verilog: controlando el tiempo de simulación

Cómo la directiva `timescale establece la unidad de #delay, las reglas para combinar unidades distintas entre archivos y cómo los retardos interactúan con la lógica sincronizada por reloj.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

Qué significa "tiempo" en Verilog

Verilog no tiene una noción incorporada de segundos. El simulador avanza "unidades de tiempo" - ticks enteros arbitrarios - y tu código usa #N para esperar N de ellos. La directiva `timescale es lo que mapea esos ticks a tiempo real.

`timescale 1ns / 1ps

module test;
    initial begin
        $display("t = %0t", $time);   // 0
        #5;
        $display("t = %0t", $time);   // 5 ns
        #1.5;
        $display("t = %0t", $time);   // 6500 ps (or 6.5 ns)
        $finish;
    end
endmodule

Dos parámetros:

  • Unidad (primer número): qué significa #1. 1ns dice que un tick es un nanosegundo.
  • Precisión (segundo número): con qué grado de finura sigue la simulación el tiempo dentro de esa unidad. 1ps dice que los retardos fraccionarios se redondean a picosegundos.

La precisión no puede ser más gruesa que la unidad (1ps / 1ns es ilegal). Opciones comunes:

  • 1ns / 1ps - el estándar de facto. Todo en nanosegundos, precisión sub-nanosegundo para cualquier retardo de puerta.
  • 1ps / 1ps - cuando modelas circuitos extremadamente rápidos o cuando cada retardo es sub-nanosegundo.
  • 1us / 1ns - para simulaciones lentas a escala embebida (tiempos de byte de UART, protocolos lentos).

Dónde ponerlo

`timescale es una directiva de compilador, no una construcción de nivel de módulo. Va en la parte superior de un archivo, antes de cualquier module:

`timescale 1ns / 1ps

module foo(...);
    // ...
endmodule

Su ámbito es "desde este punto en adelante en el orden de compilación, hasta el siguiente `timescale o el final de la compilación". Eso tiene una implicación sutil: un archivo sin un `timescale explícito hereda lo que sea que el archivo compilado previamente declaró, lo que depende del orden en que el compilador lee los archivos. Evita la sorpresa: pon `timescale en la parte superior de cada archivo.

El editor del navegador en estos docs establece un timescale por defecto por ti (típicamente 1ns / 1ps), que es por lo que los ejemplos en docs anteriores funcionaron sin declarar uno. En un proyecto real serías explícito.

#delay en la práctica

Tras `timescale 1ns / 1ps:

#5            // wait 5 ns
#100          // wait 100 ns
#1.5          // wait 1.5 ns (precision allows it)
#0.001        // wait 1 ps (just barely above precision)
#0            // zero-delay; useful for ordering events at the same time

Dentro de un bloque initial o always, #N bloquea el flujo procedural durante N unidades de tiempo. El simulador pausa este bloque (otros bloques concurrentes siguen corriendo) y reanuda tras el retardo.

Puedes prefijar una asignación con un retardo:

#10 a = 1;        // wait 10 ns, then assign
data <= #2 new_value;   // schedule the non-blocking assignment 2 ns from now

La primera forma es la habitual de los testbenches. La segunda (non-blocking con retardo) se usa en simulación a nivel de puerta para modelar retardo de propagación.

Generar un reloj

El patrón clásico:

`timescale 1ns / 1ps

module test;
    reg clk = 0;
    always #5 clk = ~clk;
    // ...
endmodule

Con timescale 1ns / 1ps, #5 es 5 ns. El reloj conmuta cada 5 ns, dando un periodo de 10 ns - un reloj de 100 MHz. Para cambiar la frecuencia, cambia el retardo:

Medio periodoPeriodoFrecuencia
#12 ns500 MHz
#2.55 ns200 MHz
#510 ns100 MHz
#1020 ns50 MHz
#2550 ns20 MHz
#50100 ns10 MHz

Si quieres un medio periodo fraccionario (#2.5), tu precisión necesita soportarlo - la precisión 1ps maneja cualquier cosa hasta 0.001 ns, así que cualquier frecuencia razonable está bien.

Mezclar timescales entre archivos

Un diseño real tiene muchos archivos, y pueden declarar timescales distintos. El simulador usa el timescale propio de cada archivo para interpretar los retardos en ese archivo. Si module_a.v dice `timescale 1ns / 1ps y usa #5, eso son 5 ns. Si module_b.v dice `timescale 1us / 1ns y usa #5, eso son 5 us.

Esto es mayormente invisible porque el simulador presenta un eje de tiempo global de todos modos - pero significa que el mismo #N en dos archivos puede significar cosas tremendamente distintas. La solución: elige un timescale (el estándar de la industria es 1ns / 1ps) y ponlo en la parte superior de cada archivo. No los mezcles.

Los retardos no son sintetizables

Punto crucial: #delay solo existe para simulación. La herramienta de síntesis lee:

// In synthesizable RTL - WRONG
always @(posedge clk) begin
    out <= #2 in;
end

…y o bien ignora el #2 (la mayoría de las herramientas) o rechaza la construcción (linters más estrictos). El timing del hardware real lo determinan el reloj y el retardo de propagación de las puertas - ambos invisibles para el código fuente.

La regla: usa # solo en testbenches. El RTL sintetizable no tiene retardos #. Si te encuentras queriendo un retardo en código sintetizable, en realidad quieres un contador que decrementa con el reloj - así es como espera el hardware real.

$time vs $realtime

Dos maneras de leer el tiempo de simulación actual:

  • $time devuelve un entero de 64 bits en unidades de la unidad del timescale actual.
  • $realtime devuelve un real en unidades de la unidad del timescale actual, pero con precisión completa.

Para logging de testbench, $time casi siempre es suficiente. Recurre a $realtime solo cuando necesites precisión sub-tick en sentencias de impresión.

Consejos prácticos

  • Declara siempre `timescale en la parte superior de cada archivo. 1ns / 1ps es el valor por defecto seguro.
  • Usa #delay solo en testbenches. Trata su ausencia en código sintetizable como una regla estática.
  • Adapta los periodos de reloj a tu frecuencia objetivo. Si estás simulando un diseño de 50 MHz, usa un periodo de reloj de 20 ns - periodos mal emparejados pueden enmascarar bugs sensibles al timing.
  • Para estímulos contados por ciclos, usa @(posedge clk) en vez de #. Es robusto frente a cambios en el periodo del reloj.

Qué viene a continuación

Ya has visto cada doc de estos tutoriales de Verilog. Desde los fundamentos del lenguaje (wire vs reg, módulos, operadores), pasando por bloques procedurales y control de flujo, hasta diseño síncrono y máquinas de estados, y finalmente las herramientas de testbench que demuestran que todo funciona. Hora de construir algo - el playground al lado de estos docs es el mismo simulador que hemos estado usando todo el rato, listo para cualquier módulo que esbozes.

Preguntas frecuentes

¿Qué significa `timescale 1ns / 1ps en Verilog?

Le dice al simulador: 'una unidad de tiempo en este archivo es un nanosegundo, y los tiempos se siguen con precisión de picosegundo.' Tras esa directiva, #5 espera 5 ns, #1.5 espera 1.5 ns (redondeado a picosegundos), y $time se reporta en nanosegundos. El primer número es la unidad; el segundo es la precisión.

¿Necesito `timescale en cada archivo Verilog?

Buena práctica: sí. El ámbito de la directiva termina en el siguiente `timescale o en el final de la compilación, así que los archivos sin uno heredan lo que sea que el archivo compilado previamente declarara. Eso hace el timing no determinista entre builds. Pon `timescale 1ns / 1ps en la parte superior de cada archivo fuente - es la convención más común - y nunca tendrás una sorpresa.

¿Qué significa #5 en Verilog?

#5 avanza el tiempo de simulación en 5 unidades de tiempo. La unidad viene de la directiva `timescale activa. Con `timescale 1ns / 1ps, #5 es 5 nanosegundos. Con `timescale 1us / 1ns, #5 es 5 microsegundos. El número puede ser fraccionario - #1.5 funciona si tu precisión es más fina que la unidad.

¿Es sintetizable #delay en Verilog?

No. #delay solo afecta a la simulación - la herramienta de síntesis lo ignora o lo rechaza. El timing del hardware real viene de la señal de reloj y del retardo de propagación de las puertas, no de sentencias #. Usa # libremente en testbenches; nunca lo escribas en RTL sintetizable.

Ilustración de los lenguajes de programación de Coddy

Aprende a programar con Coddy

Comenzar