Generador de reloj Verilog
Los relojes son fundamentales para construir circuitos digitales, ya que permiten sincronizar diferentes bloques 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 y la fase del reloj en relación con otros relojes.
Período de reloj
La frecuencia indica cuántos ciclos se pueden encontrar en un determinado período de tiempo. Y, por lo tanto, el período del reloj es el tiempo necesario para completar 1 ciclo.
Ciclo de trabajo del reloj
La cantidad de tiempo que el reloj está alto en comparación con su período de tiempo define el ciclo de trabajo.
Fase de reloj
Si un ciclo de un reloj se puede ver como un círculo completo con 360 grados, otro reloj se puede colocar relativamente en un lugar diferente en el círculo que ocupa una fase diferente. Por ejemplo, se puede decir que otro reloj del mismo período de tiempo que se desplaza a la derecha 1/4 de su período tiene una diferencia de fase de 90 grados.
Generador de reloj Verilog
Se requiere que las simulaciones operen en una escala de tiempo dada que tiene una precisión limitada según lo especificado por la directiva de escala de tiempo. Por lo tanto, es importante que la precisión de la escala de tiempo 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á de 1,5625 ns, para lo cual una precisión de escala de tiempo de 1 ps no será suficiente porque hay un punto extra que representar. Por lo tanto, la simulación redondeará el último dígito para que encaje en la precisión de la escala de tiempo de 3 puntos. ¡Esto aumentará el período del reloj a 1,563, lo que en realidad representa 639795 kHz!
El siguiente módulo generador de reloj Verilog tiene tres parámetros para ajustar las tres propiedades diferentes como se discutió anteriormente. El módulo tiene una habilitación de entrada que permite deshabilitar y habilitar el reloj según se requiera. Cuando varios relojes están controlados por una señal de habilitación común, se pueden sincronizar con relativa facilidad.
`timescale 1ns/1ps
module clock_gen ( input enable,
output reg clk);
parameter FREQ = 100000; // in kHZ
parameter PHASE = 0; // in degrees
parameter DUTY = 50; // in percentage
real clk_pd = 1.0/(FREQ * 1e3) * 1e9; // convert to 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
// Initialize variables to zero
initial begin
clk <= 0;
start_clk <= 0;
end
// When clock is enabled, delay driving the clock to one in order
// to achieve the phase effect. start_dly is configured to the
// correct delay for the configured phase. When enable is 0,
// allow enough time to complete the current clock period
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
// Achieve duty cycle by a skewed clock on/off time and let this
// run as long as the clocks are turned on.
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
Banco de pruebas con diferentes frecuencias de reloj
module tb;
wire clk1;
wire clk2;
wire clk3;
wire 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
Banco de pruebas con diferentes fases de reloj
module tb;
wire clk1;
wire 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
Banco de pruebas con diferentes ciclos de trabajo
module tb;
wire clk1;
wire clk2;
wire clk3;
wire 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 habilitar para iniciar/detener relojes
La siguiente forma de onda muestra que los relojes se detienen cuando la habilitación es baja y los relojes se inician cuando la habilitación es alta.
Verilog