Générateur d'horloge Verilog
Les horloges sont fondamentales pour la construction de circuits numériques car elles permettent à différents blocs d'être synchronisés les uns avec les autres.
Propriétés d'une horloge
Les principales propriétés d'une horloge numérique sont sa fréquence qui détermine la période d'horloge , son cycle de service et la phase d'horloge par rapport aux autres horloges.
Période d'horloge
La fréquence indique combien de cycles peuvent être trouvés dans une certaine période de temps. Et par conséquent, la période d'horloge est le temps nécessaire pour terminer 1 cycle.
Cycle d'utilisation de l'horloge
La durée pendant laquelle l'horloge est élevée par rapport à sa période de temps définit le rapport cyclique.
Phase d'horloge
Si un cycle d'une horloge peut être considéré comme un cercle complet avec 360 degrés, une autre horloge peut être relativement placée à un endroit différent dans le cercle qui occupe une phase différente. Par exemple, une autre horloge de la même période qui est décalée vers la droite d'1/4 de sa période peut être considérée comme ayant une différence de phase de 90 degrés.
Générateur d'horloge Verilog
Les simulations doivent fonctionner sur une échelle de temps donnée qui a une précision limitée comme spécifié par la directive sur les échelles de temps. Il est donc important que la précision de l'échelle de temps soit suffisamment bonne pour représenter une période d'horloge. Par exemple, si la fréquence de l'horloge est fixée à 640000 kHz, alors sa période d'horloge sera de 1,5625 ns pour laquelle une précision d'échelle de temps de 1ps ne suffira pas car il y a un point supplémentaire à représenter. Par conséquent, la simulation arrondira le dernier chiffre pour s'adapter à la précision de l'échelle de temps à 3 points. Cela augmentera la période d'horloge à 1,563, ce qui représente en fait 639795 kHz !
Le module générateur d'horloge Verilog suivant a trois paramètres pour ajuster les trois propriétés différentes comme indiqué ci-dessus. Le module dispose d'une entrée d'activation qui permet de désactiver et d'activer l'horloge selon les besoins. Lorsque plusieurs horloges sont contrôlées par un signal d'activation commun, elles peuvent être mises en phase relativement facilement.
`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
Banc de test avec différentes fréquences d'horloge
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
Journal de simulation 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
Banc de test avec différentes phases d'horloge
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
Journal de simulation 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
Banc de test avec différents cycles de service
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
Journal de simulation 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
Activer/Désactiver pour démarrer/arrêter les horloges
La forme d'onde ci-dessous montre que les horloges sont arrêtées lorsque l'activation est faible et les horloges sont démarrées lorsque l'activation est définie sur haut.
Verilog