/*
File : vco.v
Creator : Ozgur Cobanoglu
Institute : Univ. & INFN of Turin, VLSI Group
Versions : v0, 22-03-2007, OC, initial version
v1, 26-03-2007, OC, probe is added
Information : This is a Voltage Controlled Oscillator module that
corresponds to the actual transistor level schematic.
Frequency as a function of control voltage, the control
curve of the VCO, is parametrized and the parameters
for all 15 corners have been included in the model.
The following table lists the possible corners settable :
Corner Meaning (C_T_V)
0 1_m20_132
1 1_125_108
2 1_25_120
3 2_m20_132
4 2_125_108
5 2_25_120
6 3_m20_132
7 3_125_108
8 3_25_120
9 4_m20_132
10 4_125_108
11 4_25_120
12 5_m20_132
13 5_125_108
14 5_25_120
Meaning has the format as the following :
C_T_V -> C = "fixed_cor_sw" parameter in the file "design.scs"
T = temperature in Celcius (m stands for minus)
V = value of Vdd potential - 108 is 1.08V
120 is 1.20V
132 is 1.32V
Warnings : 1 - Parameters extracted are schematic level but not post-layout (for now)
2 - Duty cycle variation due to different corners is also included
but the duty cycle error is the one @ 4.32GHz. This value is
used for all the tuning range within a specific corner, since the
vco is expected to stay locked @ 4.32GHz during the operation.
That is, it changes with the corner but not with the frequency.
3 - Random jitter is also included but the parameter does not depend
on any simulation; I set it to -5ps> DutyCycleError = width_a-width_b
//
// Extracted from analog simulations for all the corners @4.32GHz.
//
real dutyCycleError0, dutyCycleError1, dutyCycleError2, dutyCycleError3;
real dutyCycleError4, dutyCycleError5, dutyCycleError6, dutyCycleError7;
real dutyCycleError8, dutyCycleError9, dutyCycleError10, dutyCycleError11;
real dutyCycleError12, dutyCycleError13, dutyCycleError14;
real dutyCycleError;
real randomJitter, riseJitter, fallJitter;
// File handles
integer data_probe_vco;
initial begin
data_probe_vco = $fopen("data_probe_vco.dat");
VCOout = 1'b1; // Initial values
ClkRef = 1'b1;
freq = 4.32; // Nominal value = 40MHz*108bits in GHz
phaseErrorLimit = 12500; // in ps
range4corner0_first = 0.40; range4corner0_last = 0.69; // in units of V
range4corner1_first = 0.35; range4corner1_last = 0.69;
range4corner2_first = 0.41; range4corner2_last = 0.69;
range4corner3_first = 0.35; range4corner3_last = 0.69;
range4corner4_first = 0.35; range4corner4_last = 0.69;
range4corner5_first = 0.35; range4corner5_last = 0.69;
range4corner6_first = 0.45; range4corner6_last = 0.69;
range4corner7_first = 0.35; range4corner7_last = 0.69;
range4corner8_first = 0.45; range4corner8_last = 0.69;
range4corner9_first = 0.40; range4corner9_last = 0.69;
range4corner10_first = 0.35; range4corner10_last = 0.69;
range4corner11_first = 0.40; range4corner11_last = 0.69;
range4corner12_first = 0.40; range4corner12_last = 0.69;
range4corner13_first = 0.35; range4corner13_last = 0.69;
range4corner14_first = 0.45; range4corner14_last = 0.69;
dutyCycleError0 = -17.07; // in units of ps,
dutyCycleError1 = -14.63; // The errors originate from the D2S conversion.
dutyCycleError2 = -11.57; // Diff. VCO has an error of 0 but the conversion
dutyCycleError3 = -10.64; // introduces an inherent mismatch :(
dutyCycleError4 = -10.62;
dutyCycleError5 = -8.36;
dutyCycleError6 = -20.89;
dutyCycleError7 = -18.57;
dutyCycleError8 = -15.62;
dutyCycleError9 = -17.68;
dutyCycleError10 = -16.95;
dutyCycleError11 = -14.31;
dutyCycleError12 = -13.47;
dutyCycleError13 = -13.14;
dutyCycleError14 = -10.19;
randomJitter = 5.0; // This is put by hand; it is not extracted from somewhere.
// Analog simulation confirmation is needed for this number
// jitter will be between randomJitter*1ps and -randomJitter*1ps.
end
always #(500.0/freq) ClkRef=~ClkRef; // Ideal VCO output, for comparison
always begin
riseJitter = randomJitter*($random/2147483647.0); // randomJitter is in units of ps
fallJitter = randomJitter*($random/2147483647.0); // RAND_MAX=2147483647.0
if (VCOout) #(500.0/freq+dutyCycleError/2.0+fallJitter) VCOout = ~VCOout;
if (~VCOout) #(500.0/freq-dutyCycleError/2.0+riseJitter) VCOout = ~VCOout;
end
always @(Corner or Vctrl) begin
vctrl = Vctrl/1000.0; // Vctrl is provided in mV and is converted to V internally
if (Corner < 0 || Corner > 14) begin
// See the module header; these are the corners defined at the GBT meeting
$display("\nERROR : Parameter covers the following range : 0 < Corner < 14");
$display(" : But it is %0d\n", Corner);
$finish;
end
if (Corner == 0) begin
if (vctrl < range4corner0_first || vctrl > range4corner0_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner0_first, range4corner0_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -1.64755e+12;
a1 = 1.63633e+13;
a2 = -6.09447e+13;
a3 = 9.30479e+13;
a4 = 1.0;
a5 = -1.78625e+14;
a6 = 2.08998e+14;
a7 = -7.78976e+13;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError0;
end
if (Corner == 1) begin
if (vctrl < range4corner1_first || vctrl > range4corner1_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner1_first, range4corner1_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -1.96339e+11;
a1 = 2.3548e+12;
a2 = -1.05071e+13;
a3 = 1.90366e+13;
a4 = 1.0;
a5 = -4.88713e+13;
a6 = 6.44957e+13;
a7 = -2.67123e+13;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError1;
end
if (Corner == 2) begin
if (vctrl < range4corner2_first || vctrl > range4corner2_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner2_first, range4corner2_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -1.67135e+12;
a1 = 1.66546e+13;
a2 = -6.24674e+13;
a3 = 9.62895e+13;
a4 = 1.0;
a5 = -1.8859e+14;
a6 = 2.22189e+14;
a7 = -8.30578e+13;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError2;
end
if (Corner == 3) begin
if (vctrl < range4corner3_first || vctrl > range4corner3_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner3_first, range4corner3_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -8.84239e+11;
a1 = 9.34504e+12;
a2 = -3.68236e+13;
a3 = 5.90848e+13;
a4 = 1.0;
a5 = -1.22403e+14;
a6 = 1.47435e+14;
a7 = -5.63281e+13;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError3;
end
if (Corner == 4) begin
if (vctrl < range4corner4_first || vctrl > range4corner4_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner4_first, range4corner4_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -3.28339e+11;
a1 = 3.71686e+12;
a2 = -1.58844e+13;
a3 = 2.79465e+13;
a4 = 1.0;
a5 = -6.98794e+13;
a6 = 9.2005e+13;
a7 = -3.8199e+13;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError4;
end
if (Corner == 5) begin
if (vctrl < range4corner5_first || vctrl > range4corner5_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner5_first, range4corner5_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -4.26844e+11;
a1 = 4.65299e+12;
a2 = -1.8865e+13;
a3 = 3.09673e+13;
a4 = 1.0;
a5 = -6.4872e+13;
a6 = 7.70123e+13;
a7 = -2.85788e+13;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError5;
end
if (Corner == 6) begin
if (vctrl < range4corner6_first || vctrl > range4corner6_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner6_first, range4corner6_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -2.82467e+12;
a1 = 2.63845e+13;
a2 = -9.28682e+13;
a3 = 1.34739e+14;
a4 = 1.0;
a5 = -2.37991e+14;
a6 = 2.69431e+14;
a7 = -9.76987e+13;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError6;
end
if (Corner == 7) begin
if (vctrl < range4corner7_first || vctrl > range4corner7_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner7_first, range4corner7_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -4.0105e+11;
a1 = 4.45248e+12;
a2 = -1.85535e+13;
a3 = 3.16676e+13;
a4 = 1.0;
a5 = -7.47891e+13;
a6 = 9.60308e+13;
a7 = -3.89678e+13;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError7;
end
if (Corner == 8) begin
if (vctrl < range4corner8_first || vctrl > range4corner8_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner8_first, range4corner8_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -5.06732e+12;
a1 = 4.74842e+13;
a2 = -1.68313e+14;
a3 = 2.4665e+14;
a4 = 1.0;
a5 = -4.46044e+14;
a6 = 5.09852e+14;
a7 = -1.85892e+14;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError8;
end
if (Corner == 9) begin
if (vctrl < range4corner9_first || vctrl > range4corner9_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner9_first, range4corner9_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -1.69171e+12;
a1 = 1.69177e+13;
a2 = -6.33133e+13;
a3 = 9.68736e+13;
a4 = 1.0;
a5 = -1.84644e+14;
a6 = 2.13675e+14;
a7 = -7.83143e+13;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError9;
end
if (Corner == 10) begin
if (vctrl < range4corner10_first || vctrl > range4corner10_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner10_first, range4corner10_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -3.8952e+11;
a1 = 4.48161e+12;
a2 = -1.94013e+13;
a3 = 3.44686e+13;
a4 = 1.0;
a5 = -8.80116e+13;
a6 = 1.17219e+14;
a7 = -4.92413e+13;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError10;
end
if (Corner == 11) begin
if (vctrl < range4corner11_first || vctrl > range4corner11_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner11_first, range4corner11_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -1.87541e+12;
a1 = 1.91533e+13;
a2 = -7.36782e+13;
a3 = 1.16561e+14;
a4 = 1.0;
a5 = -2.41005e+14;
a6 = 2.91967e+14;
a7 = -1.12263e+14;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError11;
end
if (Corner == 12) begin
if (vctrl < range4corner12_first || vctrl > range4corner12_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner12_first, range4corner12_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -1.06011e+12;
a1 = 1.02543e+13;
a2 = -3.71704e+13;
a3 = 5.52033e+13;
a4 = 1.0;
a5 = -1.00427e+14;
a6 = 1.14948e+14;
a7 = -4.21795e+13;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError12;
end
if (Corner == 13) begin
if (vctrl < range4corner13_first || vctrl > range4corner13_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner13_first, range4corner13_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -3.12334e+11;
a1 = 3.46581e+12;
a2 = -1.44348e+13;
a3 = 2.46106e+13;
a4 = 1.0;
a5 = -5.74841e+13;
a6 = 7.31251e+13;
a7 = -2.93451e+13;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError13;
end
if (Corner == 14) begin
if (vctrl < range4corner14_first || vctrl > range4corner14_last) begin
// Parameter extraction has been performed for a range but not between 0 to Vdd
// This is the proper operation range of the VCO
$display("\nERROR : Parameter covers the following range : %0f mV < Vctrl < %0f mV",
range4corner14_first, range4corner14_last);
$display(" : for Corner=%0d, but it is %0d\n", Corner, Vctrl);
$finish;
end
a0 = -3.39792e+12;
a1 = 3.18654e+13;
a2 = -1.1307e+14 ;
a3 = 1.65853e+14;
a4 = 1.0;
a5 = -2.99961e+14;
a6 = 3.42665e+14;
a7 = -1.24852e+14;
a8 = 1.0;
a9 = 1.0;
dutyCycleError=dutyCycleError14;
end
// Fit polinomial for the control curve that produces the frequency
// at which the VCO oscillates; frequency error is almost zero.
freq = (a0 +
a1 * vctrl +
a2 * vctrl*vctrl +
a3 * vctrl*vctrl*vctrl +
a4 * vctrl*vctrl*vctrl*vctrl +
a5 * vctrl*vctrl*vctrl*vctrl*vctrl +
a6 * vctrl*vctrl*vctrl*vctrl*vctrl*vctrl +
a7 * vctrl*vctrl*vctrl*vctrl*vctrl*vctrl*vctrl +
a8 * vctrl*vctrl*vctrl*vctrl*vctrl*vctrl*vctrl*vctrl +
a9 * vctrl*vctrl*vctrl*vctrl*vctrl*vctrl*vctrl*vctrl*vctrl) / 1.0e9;
end
// This is the probe module collecting statistics related to VCO functioning,
// The output is always produced and visualized by a ROOT script having a similar
// name with the data file in the same directory
probe_vco probe(data_probe_vco, ClkRef, VCOout, phaseErrorLimit);
endmodule