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 \timescaleo 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 \timescaleactiva. Con`timescale 1ns / 1ps, #5es 5 nanosegundos. Con`timescale 1us / 1ns, #5es 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.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR