Menu

Verilog Timescale e Delays: Controlando o tempo de simulação

Como a diretiva timescale define a unidade de #delay`, as regras para combinar unidades diferentes entre arquivos e como delays interagem com lógica clocked.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

O que "tempo" significa em Verilog

Verilog não tem uma noção embutida de segundos. O simulador avança "unidades de tempo" - ticks inteiros arbitrários - e seu código usa #N para esperar N delas. A diretiva `timescale é o que mapeia esses ticks para tempo 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 (ou 6.5 ns)
        $finish;
    end
endmodule

Dois parâmetros:

  • Unidade (primeiro número): o que #1 significa. 1ns diz que um tick é um nanossegundo.
  • Precisão (segundo número): com que finura a simulação rastreia tempo dentro daquela unidade. 1ps diz que delays fracionários são arredondados para picossegundos.

A precisão não pode ser mais grossa que a unidade (1ps / 1ns é ilegal). Escolhas comuns:

  • 1ns / 1ps - o padrão de fato. Tudo em nanossegundos, precisão sub-nanossegundo para qualquer delay de gate.
  • 1ps / 1ps - quando se modela circuitos extremamente rápidos ou quando cada delay é sub-nanossegundo.
  • 1us / 1ns - para simulações lentas, em escala embarcada (tempos de byte UART, protocolos lentos).

Onde colocá-la

`timescale é uma diretiva de compilador, não uma construção de nível de module. Vai bem no topo de um arquivo, antes de qualquer module:

`timescale 1ns / 1ps

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

Seu escopo é "deste ponto em diante na ordem de compilação, até o próximo `timescale ou fim da compilação". Isso tem uma implicação sutil: um arquivo sem `timescale explícito herda o que o arquivo previamente compilado declarou, o que depende da ordem em que o compilador lê os arquivos. Evite a surpresa: coloque `timescale no topo de cada arquivo.

O editor do navegador nestes docs define um timescale padrão para você (tipicamente 1ns / 1ps), que é por isso que os exemplos em docs anteriores funcionaram sem declarar um. Em um projeto real você seria explícito.

#delay na prática

Depois de `timescale 1ns / 1ps:

#5            // espera 5 ns
#100          // espera 100 ns
#1.5          // espera 1.5 ns (precisao permite)
#0.001        // espera 1 ps (so um pouco acima da precisao)
#0            // delay zero; util para ordenar eventos no mesmo tempo

Dentro de um bloco initial ou always, #N bloqueia o fluxo procedural por N unidades de tempo. O simulador pausa este bloco (outros blocos concorrentes continuam rodando) e retoma depois do delay.

Você pode prefixar uma atribuição com um delay:

#10 a = 1;        // espera 10 ns, depois atribui
data <= #2 new_value;   // agenda a non-blocking assignment 2 ns no futuro

A primeira forma é o feijão com arroz do testbench. A segunda (non-blocking com delay) é usada em simulação no nível de gate para modelar delay de propagação.

Gerando um clock

O padrão clássico:

`timescale 1ns / 1ps

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

Com timescale 1ns / 1ps, #5 é 5 ns. O clock alterna a cada 5 ns, dando um período de 10 ns - um clock de 100 MHz. Para mudar a frequência, mude o delay:

Meio-períodoPeríodoFrequência
#12 ns500 MHz
#2.55 ns200 MHz
#510 ns100 MHz
#1020 ns50 MHz
#2550 ns20 MHz
#50100 ns10 MHz

Se você quer um meio-período fracionário (#2.5), sua precisão precisa suportar isso - precisão 1ps lida com qualquer coisa até 0.001 ns, então qualquer frequência razoável está bem.

Misturando timescales entre arquivos

Um design real tem muitos arquivos, e eles podem declarar timescales diferentes. O simulador usa o timescale de cada arquivo para interpretar os delays naquele arquivo. Se module_a.v diz `timescale 1ns / 1ps e usa #5, isso é 5 ns. Se module_b.v diz `timescale 1us / 1ns e usa #5, isso é 5 us.

Isso é principalmente invisível porque o simulador apresenta um eixo de tempo global independente disso - mas significa que o mesmo #N em dois arquivos pode significar coisas muito diferentes. A correção: escolha um timescale (padrão da indústria é 1ns / 1ps) e coloque no topo de cada arquivo. Não misture.

Delays não são sintetizáveis

Ponto crucial: #delay só existe para simulação. A ferramenta de síntese lê:

// Em RTL sintetizavel - ERRADO
always @(posedge clk) begin
    out <= #2 in;
end

…e ou ignora o #2 (a maioria das ferramentas) ou rejeita a construção (linters mais rigorosos). O timing do hardware real é determinado pelo clock e pelo delay de propagação dos gates - ambos invisíveis ao código fonte.

A regra: use # só em testbenches. RTL sintetizável não tem delays #. Se você se pegar querendo um delay em código sintetizável, na verdade quer um contador que decrementa no clock - é assim que hardware real "espera".

$time vs $realtime

Duas formas de ler o tempo de simulação atual:

  • $time retorna um inteiro de 64 bits em unidades da unidade do timescale atual.
  • $realtime retorna um real em unidades da unidade do timescale atual, mas com precisão completa.

Para logging de testbench, $time é quase sempre o suficiente. Recorra a $realtime apenas quando precisar de precisão sub-tick em declarações de print.

Dicas práticas

  • Sempre declare `timescale no topo de cada arquivo. 1ns / 1ps é o default seguro.
  • Use #delay só em testbenches. Trate sua ausência em código sintetizável como uma regra estática.
  • Combine períodos de clock com sua frequência alvo. Se você está simulando um design de 50 MHz, use um período de clock de 20 ns - períodos mal combinados podem mascarar bugs sensíveis ao timing.
  • Para estímulo contado por ciclos, use @(posedge clk) em vez de #. É robusto contra mudanças no período do clock.

O que vem a seguir

Você agora viu cada doc destes tutoriais Verilog. Dos fundamentos da linguagem (wire vs reg, modules, operadores), passando por blocos procedurais e controle de fluxo, em design síncrono e máquinas de estado, e finalmente o ferramental de testbench que prova que tudo funciona. Hora de construir algo - o playground ao lado destes docs é o mesmo simulador que usamos ao longo de tudo, pronto para o que quer que você esboce.

Perguntas frequentes

O que `timescale 1ns / 1ps significa em Verilog?

Diz ao simulador: 'uma unidade de tempo neste arquivo é um nanossegundo, e tempos são rastreados com precisão de picossegundo'. Depois dessa diretiva, #5 espera 5 ns, #1.5 espera 1.5 ns (arredondado para picossegundos) e $time é reportado em nanossegundos. O primeiro número é a unidade; o segundo é a precisão.

Preciso de `timescale em cada arquivo Verilog?

Boa prática: sim. O escopo da diretiva termina no próximo \timescaleou no fim da compilação, então arquivos sem uma herdam o que o arquivo previamente compilado declarou. Isso torna o timing não-determinístico entre builds. Coloque`timescale 1ns / 1ps` no topo de cada arquivo fonte - é a convenção mais comum - e você nunca terá surpresa.

O que #5 significa em Verilog?

#5 avança o tempo de simulação em 5 unidades de tempo. A unidade vem da diretiva \timescaleativa. Com`timescale 1ns / 1ps, #5é 5 nanossegundos. Com`timescale 1us / 1ns, #5é 5 microssegundos. O número pode ser fracionário -#1.5` funciona se sua precisão é mais fina que a unidade.

#delay é sintetizável em Verilog?

Não. #delay só afeta simulação - a ferramenta de síntese ignora ou rejeita. O timing do hardware real vem do sinal de clock e do delay de propagação dos gates, não de declarações #. Use # livremente em testbenches; nunca escreva em RTL sintetizável.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR