Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial programming >> Verilog

Gerador de Clock Verilog: Guia de Design e Implementação

Clocks são fundamentais para circuitos digitais pois permitem diferentes blocos ficarem sincronizados.

Propriedades de um Clock

Propriedades-chave: frequência (determina período do clock), duty cycle e fase do clock em relação a outros clocks.

Período do Clock

Frequência indica quantos ciclos em certo período. Período = tempo para completar 1 ciclo.

Duty Cycle do Clock

Tempo que clock fica alto comparado ao período define duty cycle.

Fase do Clock

Se um ciclo = círculo completo (360°), outro clock pode estar em fase diferente. Ex: clock mesmo período deslocado 1/4 do período = 90° de diferença de fase.

Gerador de Clock Verilog

Simulações operam em timescale com precisão limitada. Importante que precisão represente período do clock. Ex: frequência 640000 kHz → período 1.5625ns; precisão 1ps não basta (precisa 4 casas decimais). Simulação arredonda último dígito para 3 casas → período 1.563ns = 639795 kHz!

Módulo gerador abaixo tem três parâmetros para ajustar as propriedades. Entrada enable permite habilitar/desabilitar clock. Múltiplos clocks com enable comum podem ser faseados relativamente.

`timescale 1ns/1ps

module clock_gen (
  input enable,
  output reg clk
);
  parameter FREQ = 100000; // em kHz
  parameter PHASE = 0;     // em graus
  parameter DUTY = 50;     // em porcentagem
  
  real clk_pd = 1.0/(FREQ * 1e3) * 1e9; // converte para ns
  real clk_on = DUTY/100.0 * clk_pd;
  real clk_off = (100.0 - DUTY)/100.0 * clk_pd;
  real quarter = clk_pd/4;
  real start_dly = quarter * PHASE/90;
  reg start_clk;
  
  initial begin
    $display("FREQ = %0d kHz", FREQ);
    $display("PHASE = %0d deg", PHASE);
    $display("DUTY = %0d %%", DUTY);
    $display("PERIOD = %0.3f ns", clk_pd);
    $display("CLK_ON = %0.3f ns", clk_on);
    $display("CLK_OFF = %0.3f ns", clk_off);
    $display("QUARTER = %0.3f ns", quarter);
    $display("START_DLY = %0.3f ns", start_dly);
  end
  
  // Inicializa variáveis
  initial begin
    clk <= 0;
    start_clk <= 0;
  end
  
  // Quando clock habilitado, atrasa acionamento para efeito de fase
  always @ (posedge enable or negedge enable) begin
    if (enable) begin
      #(start_dly) start_clk = 1;
    end else begin
      #(start_dly) start_clk = 0;
    end
  end
  
  // Duty cycle por tempo assimétrico de clock on/off
  always @(posedge start_clk) begin
    if (start_clk) begin
      clk = 1;
      while (start_clk) begin
        #(clk_on) clk = 0;
        #(clk_off) clk = 1;
      end
      clk = 0;
    end
  end
endmodule

Testbench com diferentes frequências

module tb;
  wire clk1, clk2, clk3, clk4;
  reg enable;
  reg [7:0] dly;
  
  clock_gen u0(enable, clk1);
  clock_gen #(.FREQ(200000)) u1(enable, clk2);
  clock_gen #(.FREQ(400000)) u2(enable, clk3);
  clock_gen #(.FREQ(800000)) u3(enable, clk4);
  
  initial begin
    enable <= 0;
    for (int i = 0; i < 10; i= i+1) begin
      dly = $random; #(dly) enable <= ~enable;
      $display("i=%0d dly=%0d", i, dly); #50;
    end
    #50 $finish;
  end
endmodule

Log de Simulação

xcelium> run
FREQ = 100000 kHz PHASE = 0 deg DUTY = 50 %
PERIOD = 10.000 ns CLK_ON = 5.000 ns CLK_OFF = 5.000 ns
QUARTER = 2.500 ns START_DLY = 0.000 ns
FREQ = 200000 kHz PHASE = 0 deg DUTY = 50 %
PERIOD = 5.000 ns CLK_ON = 2.500 ns CLK_OFF = 2.500 ns
QUARTER = 1.250 ns START_DLY = 0.000 ns
FREQ = 400000 kHz PHASE = 0 deg DUTY = 50 %
PERIOD = 2.500 ns CLK_ON = 1.250 ns CLK_OFF = 1.250 ns
QUARTER = 0.625 ns START_DLY = 0.000 ns
FREQ = 800000 kHz PHASE = 0 deg DUTY = 50 %
PERIOD = 1.250 ns CLK_ON = 0.625 ns CLK_OFF = 0.625 ns
QUARTER = 0.312 ns START_DLY = 0.000 ns
i=0 dly=36 i=1 dly=129 i=2 dly=9 i=3 dly=99
i=4 dly=13 i=5 dly=141 i=6 dly=101 i=7 dly=18 i=8 dly=1 i=9 dly=13
Simulation complete via $finish(1) at time 1110 NS + 0

Testbench com diferentes fases

module tb;
  wire clk1, clk2;
  reg enable;
  reg [7:0] dly;
  
  clock_gen u0(enable, clk1);
  clock_gen #(.FREQ(50000), .PHASE(90)) u1(enable, clk2);
  
  initial begin
    enable <= 0;
    for (int i = 0; i < 10; i=i+1) begin
      dly = $random; #(dly) enable <= ~enable;
      $display("i=%0d dly=%0d", i, dly);
    end
    #50 $finish;
  end
endmodule

Log de Simulação

xcelium> run
FREQ = 100000 kHz PHASE = 0 deg DUTY = 50 %
PERIOD = 10.000 ns CLK_ON = 5.000 ns CLK_OFF = 5.000 ns
QUARTER = 2.500 ns START_DLY = 0.000 ns
FREQ = 100000 kHz PHASE = 90 deg DUTY = 50 %
PERIOD = 10.000 ns CLK_ON = 5.000 ns CLK_OFF = 5.000 ns
QUARTER = 2.500 ns START_DLY = 2.500 ns
FREQ = 100000 kHz PHASE = 180 deg DUTY = 50 %
PERIOD = 10.000 ns CLK_ON = 5.000 ns CLK_OFF = 5.000 ns
QUARTER = 2.500 ns START_DLY = 5.000 ns
FREQ = 100000 kHz PHASE = 270 deg DUTY = 50 %
PERIOD = 10.000 ns CLK_ON = 5.000 ns CLK_OFF = 5.000 ns
QUARTER = 2.500 ns START_DLY = 7.500 ns
i=0 dly=36 i=1 dly=129 i=2 dly=9 i=3 dly=99 i=4 dly=13
i=5 dly=141 i=6 dly=101 i=7 dly=18 i=8 dly=1 i=9 dly=13
Simulation complete via $finish(1) at time 1110 NS + 0

Testbench com diferentes duty cycles

module tb;
  wire clk1, clk2, clk3, clk4;
  reg enable;
  reg [7:0] dly;
  
  clock_gen u0(enable, clk1);
  clock_gen #(.DUTY(25)) u1(enable, clk2);
  clock_gen #(.DUTY(75)) u2(enable, clk3);
  clock_gen #(.DUTY(90)) u3(enable, clk4);
  
  initial begin
    enable <= 0;
    for (int i = 0; i < 10; i= i+1) begin
      dly = $random; #(dly) enable <= ~enable;
      $display("i=%0d dly=%0d", i, dly); #50;
    end
    #50 $finish;
  end
endmodule

Log de Simulação

xcelium> run
FREQ = 100000 kHz PHASE = 0 deg DUTY = 50 %
PERIOD = 10.000 ns CLK_ON = 5.000 ns CLK_OFF = 5.000 ns
QUARTER = 2.500 ns START_DLY = 0.000 ns
FREQ = 100000 kHz PHASE = 0 deg DUTY = 25 %
PERIOD = 10.000 ns CLK_ON = 2.500 ns CLK_OFF = 7.500 ns
QUARTER = 2.500 ns START_DLY = 0.000 ns
FREQ = 100000 kHz PHASE = 0 deg DUTY = 75 %
PERIOD = 10.000 ns CLK_ON = 7.500 ns CLK_OFF = 2.500 ns
QUARTER = 2.500 ns START_DLY = 0.000 ns
FREQ = 100000 kHz PHASE = 0 deg DUTY = 90 %
PERIOD = 10.000 ns CLK_ON = 9.000 ns CLK_OFF = 1.000 ns
QUARTER = 2.500 ns START_DLY = 0.000 ns
i=0 dly=36 i=1 dly=129 i=2 dly=9 i=3 dly=99 i=4 dly=13
i=5 dly=141 i=6 dly=101 i=7 dly=18 i=8 dly=1 i=9 dly=13
Simulation complete via $finish(1) at time 1110 NS + 0

Alternar enable para iniciar/parar clocks

Waveform mostra clocks parados quando enable=low e iniciados quando enable=high.

Verilog

  1. Domine o Verilog: Tutorial Completo para Projeto de Circuitos Digitais
  2. Dominando Concatenação Verilog: Guia Prático
  3. Entendendo Atribuições em Verilog: Tipos, Sintaxe e Boas Práticas
  4. Verilog Blocking vs Non-Blocking: Diferenças Essenciais Explicadas
  5. Dominando Funções em Verilog para Design RTL Eficiente
  6. Entendendo Tasks em Verilog: Funções vs Tasks, Sintaxe e Uso
  7. Dominando Funções Matemáticas do Verilog para Design de Hardware Eficiente
  8. Dominando $timeformat do Verilog: Precisão e Controle de Exibição
  9. Entendendo e Imprimindo Timescales do Verilog em Qualquer Escopo
  10. Dominando I/O de Arquivos em Verilog: Abrir, Ler, Escrever e Fechar