Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Industrial programming >> Verilog

Generador de reloj en Verilog: Guía de diseño e implementación

Los relojes son fundamentales para construir circuitos digitales ya que permiten que diferentes bloques estén en sincronía entre sí.

Propiedades de un reloj

Las propiedades clave de un reloj digital son su frecuencia que determina el período de reloj, su ciclo de trabajo (duty cycle) y la fase del reloj en relación con otros relojes.

Período de reloj

La frecuencia indica cuántos ciclos pueden encontrarse en un cierto período de tiempo. Y por tanto el período de reloj es el tiempo tomado para completar 1 ciclo.

Ciclo de trabajo

La cantidad de tiempo que el reloj está en alto comparado con su período define el ciclo de trabajo.

Fase del reloj

Si un ciclo de un reloj puede verse como un círculo completo con 360 grados, otro reloj puede colocarse relativamente en un lugar diferente en el círculo que ocupa una fase diferente. Por ejemplo, otro reloj del mismo período que se desplaza a la derecha por 1/4 de su período puede decirse que está a 90 grados en diferencia de fase.

Generador de reloj en Verilog

Las simulaciones requieren operar en un timescale dado que tiene una precisión limitada como se especifica por la directiva timescale. Por tanto es importante que la precisión del timescale sea lo suficientemente buena para representar un período de reloj. Por ejemplo, si la frecuencia del reloj se establece en 640000 kHz, entonces su período de reloj será 1.5625 ns para lo cual una precisión de timescale de 1ps no será suficiente porque hay un dígito extra que representar. Por tanto la simulación redondeará el último dígito para ajustarse a la precisión de 3 puntos del timescale. Esto aumentará el período de reloj a 1.563 que en realidad representa 639795 kHz!

El siguiente módulo generador de reloj en Verilog tiene tres parámetros para ajustar las tres propiedades diferentes discutidas arriba. El módulo tiene una entrada enable que permite que el reloj se deshabilite y habilite según sea requerido. Cuando múltiples relojes son controlados por una señal enable común, pueden ser relativamente faseados fácilmente.

`timescale 1ns/1ps
module clock_gen (
  input enable,
  output reg clk
);
  parameter FREQ = 100000; // en kHz
  parameter PHASE = 0;     // en grados
  parameter DUTY = 50;     // en porcentaje

  real clk_pd = 1.0/(FREQ * 1e3) * 1e9; // convertir a 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

  // Inicializar variables a cero
  initial begin
    clk <= 0;
    start_clk <= 0;
  end

  // Cuando el reloj está habilitado, retrasar el manejo del reloj a uno para
  // lograr el efecto de fase. start_dly está configurado al
  // retraso correcto para la fase configurada. Cuando enable es 0,
  // permitir suficiente tiempo para completar el período de reloj actual
  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

  // Lograr ciclo de trabajo por tiempo de reloj encendido/apagado sesgado y dejar
  // esto correr mientras los relojes estén encendidos.
  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 con diferentes frecuencias de reloj

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
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 con diferentes fases de reloj

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
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 con diferentes ciclos de trabajo

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
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/detener relojes

La forma de onda abajo muestra que los relojes se detienen cuando enable es bajo y se inician cuando enable se pone alto.

Verilog

  1. Dominar Verilog: Tutorial completo para diseño de circuitos digitales
  2. Dominar la concatenación en Verilog: Guía práctica
  3. Comprender las asignaciones en Verilog: tipos, sintaxis y mejores prácticas
  4. Bloqueante vs. No bloqueante en Verilog: Diferencias clave explicadas
  5. Dominar las funciones en Verilog para diseño RTL eficiente
  6. Comprender las Tasks en Verilog: Funciones vs Tasks, sintaxis y uso
  7. Dominar las funciones matemáticas en Verilog para diseño de hardware eficiente
  8. Dominar $timeformat en Verilog: Control de precisión y visualización
  9. Comprender e imprimir timescales de Verilog en cualquier alcance
  10. Dominando la E/S de Archivos en Verilog: Abrir, Leer, Escribir y Cerrar
  11. Guía para Principiantes de Verilog: Ejemplo Hola Mundo