Gerador de Relógio Verilog
Os relógios são fundamentais para a construção de circuitos digitais, pois permitem que diferentes blocos estejam sincronizados entre si.
Propriedades de um relógio
As principais propriedades de um relógio digital são sua frequência que determina o período do relógio , seu ciclo de trabalho e a fase do relógio em relação a outros relógios.
Período do Relógio
A frequência indica quantos ciclos podem ser encontrados em um determinado período de tempo. E, portanto, o período do relógio é o tempo necessário para completar 1 ciclo.
Ciclo de trabalho do relógio
A quantidade de tempo em que o relógio está alto em comparação com seu período de tempo define o ciclo de trabalho.
Fase do Relógio
Se um ciclo de um relógio pode ser visto como um círculo completo com 360 graus, outro relógio pode ser colocado relativamente em um lugar diferente no círculo que ocupa uma fase diferente. Por exemplo, outro relógio do mesmo período de tempo que é deslocado para a direita em 1/4 de seu período pode ser dito estar a 90 graus na diferença de fase.
Gerador de relógio Verilog
As simulações são necessárias para operar em uma determinada escala de tempo que tem uma precisão limitada conforme especificado pela diretiva de escala de tempo. Portanto, é importante que a precisão da escala de tempo seja boa o suficiente para representar um período de relógio. Por exemplo, se a frequência do relógio for definida para 640.000 kHz, seu período de relógio será de 1,5625 ns, para o qual uma precisão de escala de tempo de 1ps não será suficiente porque há um ponto extra a ser representado. Portanto, a simulação arredondará o último dígito para caber na precisão da escala de tempo de 3 pontos. Isso aumentará o período do relógio para 1,563, o que na verdade representa 639795 kHz!
O módulo gerador de relógio Verilog a seguir tem três parâmetros para ajustar as três propriedades diferentes, conforme discutido acima. O módulo possui uma habilitação de entrada que permite que o relógio seja desabilitado e habilitado conforme necessário. Quando vários relógios são controlados por um sinal de habilitação comum, eles podem ser divididos em fases com relativa facilidade.
`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
Testbench com diferentes frequências de clock
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
Registro 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 de clock
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
Registro 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 ciclos de trabalho
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
Registro 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 ativar para iniciar/parar relógios
A forma de onda abaixo mostra que os relógios são interrompidos quando a habilitação está baixa e os relógios são iniciados quando a habilitação está definida como alta.
Verilog