Skip to content

Instantly share code, notes, and snippets.

@sgherbst
Created January 30, 2020 13:30
Show Gist options
  • Select an option

  • Save sgherbst/9c8d3ed7b09074e6e145c0db58d2e3d0 to your computer and use it in GitHub Desktop.

Select an option

Save sgherbst/9c8d3ed7b09074e6e145c0db58d2e3d0 to your computer and use it in GitHub Desktop.
SystemVerilog PLL Simulation
// run simulation with xrun pll.sv +access+rw
// view results with simvision
`timescale 1s / 1fs
module ringosc (
input real vdd,
output logic out
);
// YOUR CODE HERE
endmodule
module ctrl (
input real in,
input clk,
input rst,
output real out
);
// YOUR CODE HERE
endmodule
module freqdiv #(
parameter integer N=20
) (
input in,
output var out=1'b0
);
integer count=0;
always @(posedge in) begin
if (count==(N/2)-1) begin
out <= ~out;
count <= 0;
end else begin
out <= out;
count <= count+1;
end
end
endmodule
module phasecmp #(
parameter real tau=1e-9
) (
input clk1,
input clk2,
output real out
);
// generate up/down signals for a phase/frequency comparator
logic up, dn;
assign #(1e-12*1s) clr = up & dn;
always @(posedge clk2 or posedge clr) begin
if (clr == 1'b1) begin
up <= 1'b0;
end else begin
up <= 1'b1;
end
end
always @(posedge clk1 or posedge clr) begin
if (clr == 1'b1) begin
dn <= 1'b0;
end else begin
dn <= 1'b1;
end
end
// apply filter to up-dn signal
real dt;
real filt_state=0.0;
real last_inpt=0.0;
real last_time=0.0;
always @(up or dn) begin
dt = $realtime - last_time;
filt_state = filt_state*$exp(-dt/tau) + last_inpt*(1.0-$exp(-dt/tau));
last_inpt = (up===1'b1 ? 1.0 : 0.0) - (dn===1'b1 ? 1.0 : 0.0);
last_time = $realtime;
end
assign out = filt_state;
endmodule
module pll (
input clkin,
output clkout,
input rst
);
real vdd;
ringosc ringosc_i (
.vdd(vdd),
.out(clkout)
);
logic divo;
freqdiv freqdiv_i (
.in(clkout),
.out(divo)
);
real phmeas;
phasecmp phasecmp_i (
.clk1(divo),
.clk2(clkin),
.out(phmeas)
);
ctrl ctrl_i (
.in(phmeas),
.clk(clkin),
.rst(rst),
.out(vdd)
);
endmodule
module tb;
localparam real ref_freq=1e9;
logic clkin, rst, clkout;
always begin
clkin = 1'b0;
#(0.5/ref_freq*1s);
clkin = 1'b1;
#(0.5/ref_freq*1s);
end
pll pll_i (
.clkin(clkin),
.clkout(clkout),
.rst(rst)
);
real tdiff, last_time;
task meas_freq;
@(posedge clkout);
last_time = $realtime;
@(posedge clkout);
tdiff = $realtime - last_time;
$display("Frequency of clkout at t=%0.1e: %0.3f GHz", $realtime, 1e-9/tdiff);
endtask
always begin
#(1e-6);
meas_freq();
end
initial begin
// setup
$shm_open("waves.shm");
$shm_probe("AS");
// initialize reset
rst = 1'b1;
#(3e-9*1s);
rst = 1'b0;
// run simulation
#(10e-6*1s);
$finish;
end
endmodule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment