Forum
 lwzunique Community Member Offline Posts: 38 how to make sdm based fractional pll's transient simulation more accurate? Oct 24th, 2019, 7:24pm   Hi,everyone!the problem is as following:1. this fractional pll is based on veriloga. all blocks are veriloga model.2. charge pump current is Icp=16uA, VCO gain kvco=100Mhz, LPF ’s C1=36pf, R1=100K, C2=3.6pf，R3=65K,C3=1pf。3.when doing transient simulation，after pll locked， using freq function in viva calculator to measure the vco’s frequency, the frequency‘s fluctuation is about 200khz peak to peak, and the center frequency is 4.8G.it should have fluctuation, but isn't  this value  too large? which magnitude should this fluctuation shouldbe？if the magnitude is about 10khz or less, what's wrong with my model. the model is as below: PFD code： Code:````include "constants.vams" `include "disciplines.vams" module PFD_V1_VA (ref_clk, fb_clk, up_out, down_out); inout ref_clk, fb_clk, up_out, down_out; electrical ref_clk, fb_clk, up_out, down_out; parameter real vdd=3.3, ttol=10f, ttime=0.2n ; integer state; // state=1 for down, -1 for up real td_up, td_down ; /* analog begin @(cross( V(ref_clk) - vdd/2 , 1 , ttol )) begin state = state - 1; if(V(up_out)>vdd/2) td_up=480p; else td_up=1005p; if(V(down_out)vdd/2) td_up=480p; else td_up=1005p; if(V(down_out) 1 ) state = 1 ; if ( state < -1 ) state = -1; V(down_out) <+ transition( (state + 1)/2*vdd , td_down , ttime ); V(up_out) <+ transition( (state - 1)/2*vdd+vdd , td_up , ttime ); end */ analog begin @(cross( V(ref_clk) - vdd/2 , 1 , ttol )) begin if(state<1) state = state + 1; end @(cross( V(fb_clk) - vdd/2 , 1 , ttol )) begin if(state>-1) state = state - 1; end V(up_out) <+ transition( (state==1)?1.2:0 , 0 , 10p ); V(down_out) <+ transition( (state==-1)?1.2:0 , 0 , 10p ); end endmodule ```CP code： Code:````include "constants.vams" `include "disciplines.vams" module CP_VA(up,down,iout); input up,down; output iout; electrical up,down,iout; parameter Vhigh=1 from[0:inf); parameter Vlow=0 from[0:inf); parameter Vtrans=0.5; parameter vp_h=1.2; parameter vp_l=0; /* real iuptemp,idowntemp,chargecurrent; analog begin  chargecurrent=50u;  iuptemp=(V(up)>Vtrans)?1:0;  idowntemp=(V(down)>Vtrans)?-1:0;  I(iout)<+ -iuptemp*chargecurrent-idowntemp*chargecurrent;  end endmodule */ real iuptemp,idowntemp,chargecurrentdown,chargecurrentup; analog begin  if(V(iout)>(vp_l+200m))     chargecurrentdown=16u;  if(V(iout)>vp_l && V(iout)<=(vp_l+200m) )     chargecurrentdown=V(iout)*80u;  if(V(iout)<=vp_l)     chargecurrentdown=0;   if(V(iout)<(vp_h-200m))     chargecurrentup=16u;  if(V(iout)>=(vp_h-200m) && V(iout)=vp_h)     chargecurrentup=0; /*  iuptemp=(V(up)>Vtrans)?1:0;  idowntemp=(V(down)>Vtrans)?-1:0; */ @(cross(V(up)-Vtrans,1)) iuptemp=1; @(cross(V(up)-Vtrans,-1)) iuptemp=0; @(cross(V(down)-Vtrans,1)) iuptemp=-1; @(cross(V(down)-Vtrans,-1)) iuptemp=0;  I(iout)<+ -iuptemp*chargecurrentup-idowntemp*chargecurrentdown;     end endmodule ```VCO code： Code:````include "constants.vams" `include "disciplines.vams" module VCO_BITS_TP_FD_VA(loopin,tp,bits,freqout); input loopin,tp; input [3:0] bits; output freqout; electrical loopin,tp; electrical [3:0] bits; electrical freqout; parameter vhigh=1.2; parameter vlow=0; parameter vtrans=(vhigh+vlow)/2; real tempbits; real freq; real fmax; real fmin; real vmax; real vmin; real initial_freq; real space; real kvco; real gain; analog begin kvco=100M; initial_freq=4720M; space=20M; vmax=800m; vmin=400m; tempbits=0; tempbits=tempbits+((V(bits[3])>vtrans)?1:0)*8; tempbits=tempbits+((V(bits[2])>vtrans)?1:0)*4; tempbits=tempbits+((V(bits[1])>vtrans)?1:0)*2; tempbits=tempbits+((V(bits[0])>vtrans)?1:0)*1; case(tempbits) 0,1,2,3 : gain=1.6M; 4,5,6,7: gain=1.8M; 8,9,10,11:gain=2M; 12,13,14,15:gain=2.4M; default gain=1.6M; endcase fmin=initial_freq+tempbits*space; fmax=initial_freq+(vmax-vmin)*kvco+tempbits*space; freq=(V(loopin)-vmin)*kvco+fmin+(V(tp)-0.6)*gain; if (freq > fmax) freq = fmax; if (freq < fmin) freq = fmin; //\$bound_step(1/(freq*100)); V(freqout) <+   freq/1e6; end endmodule ```freq to sin wave conversion code： Code:````include "constants.vams" `include "disciplines.vams" `define PI  3.14159265358979323846264338327950288419716939937511 module FREQ2VOL_V1_VA(vin, rst, vout); input vin, rst; output vout; electrical vin, rst, vout; parameter real amp=0.6; parameter integer steps_per_period=32; parameter real vco_gain=1e6; real phase, inst_freq, phase_modulus; analog begin if(V(rst)>0.6) begin inst_freq=1e6; phase_modulus=1e-3; end else begin inst_freq=vco_gain*V(vin); phase_modulus=1; end \$bound_step(1.0 / (steps_per_period*inst_freq)); phase=idtmod(inst_freq, 0, phase_modulus); V(vout) <+ 0.6+amp*sin(2*`PI*phase-`PI); end endmodule ```DIVIDER code： Code:```// VerilogA for nb1820_t55lp_lwz_v01, DIV_VAR_FD_VA, veriloga `include "constants.vams" `include "disciplines.vams" module DIV_VAR_FD_VA(ratio,freqin,freqout); input freqin,ratio; output freqout; electrical freqin,ratio, freqout; real tempratio; analog begin    tempratio=2*V(ratio);        V(freqout) <+ V(freqin)/tempratio; end endmodule ``` Back to top IP Logged
 lwzunique Community Member Offline Posts: 38 Re: how to make sdm based fractional pll's transient simulation more accurate? Reply #1 - Oct 24th, 2019, 7:29pm   mash code： Code:````include "constants.h" `include "discipline.h" module MASH_VA(fset, cp, f, f_av); output f; output f_av; input cp; input fset; electrical f; electrical cp; electrical f_av; electrical fset; parameter integer BIT = 8; parameter real vtrans = 0.5; parameter real outOffset = 0;   integer out_value;   real av_out_value;   integer sum1, sum3, sum2;   integer sum1_d, sum2_d, sum3_d;   integer c1, c2, c3;   integer c3_d;   integer c2c3, c2c3_d;   integer c1c2c3;   integer j, n,  m , k;   real unconverted;   real vref;   real halfref;   integer vd[0:BIT-1];   integer w[0:BIT-1];   analog begin @(initial_step ) begin    for ( j = 0; j <= BIT-1 ; j=j+1 ) begin    w[j] = 1;  end  for ( j = 1; j <= BIT-1 ; j=j+1 ) begin     for ( n = 1; n <= j; n=n+1 ) begin w[j] = 2*w[j];     end  end  for ( j = 0; j <= BIT-1 ; j=j+1 ) begin   //  \$strobe("w[%d]=%d\n",j,w[j]);  end  vref = 1.0;  halfref = vref / 2;  out_value = 0;  av_out_value = 0;  n = 1;  m = 1;  for ( j = 1; j <= BIT ; j=j+1 ) begin    m = m * 2;  end    k = 0;  if ( k >= m ) begin     \$strobe("k must be less than 2^%d", BIT);     \$finish;  end    c1 = 0;  c2 = 0;  c3 = 0;  sum1 = 0;  sum2 = 0;  sum3 = 0;  sum1_d =0;  sum2_d =0;  sum3_d =0;  c3_d = 0;  c2c3 = 0;  c2c3_d = 0;  c1c2c3 = 0; end sum1 = k + sum1_d; sum2 = sum1_d + sum2_d; sum3 = sum2_d + sum3_d; if ( sum1 >= m ) begin c1 = 1; sum1 = sum1 - m; end else begin c1 = 0; end if ( sum2 >= m ) begin c2 = 1; sum2 = sum2 - m; end else begin c2 = 0; end if ( sum3 >= m ) begin c3 = 1; sum3 = sum3 - m; end else begin c3 = 0; end c2c3 = c2 + c3 - c3_d; c1c2c3 = c1 + c2c3 - c2c3_d; out_value = c1c2c3; @(cross(V(cp)-vtrans, 1, 10f, cp.potential.abstol) ) begin  n = n + 1;  // update k , it is input analogue to digital  unconverted = V(fset);  for (j = (BIT-1); j >= 0 ; j = j - 1) begin     vd[j] = 0;     if (unconverted >= halfref) begin  vd[j] = 1;  unconverted = unconverted - halfref;     end else begin  vd[j] = 0;     end     unconverted = unconverted * 2;  end  k = 0;  for ( j = 0; j <= BIT-1 ; j=j+1 ) begin    k = k + vd[j]*w[j];  end   // \$strobe("k=%d\n",k);  av_out_value = av_out_value + out_value;  sum1_d = sum1;  sum2_d = sum2;  sum3_d = sum3;  c3_d = c3;  c2c3_d = c2c3; end V(f) <+ out_value + outOffset; V(f_av) <+ outOffset + av_out_value/n;   end ``` Back to top « Last Edit: Oct 25th, 2019, 12:33am by lwzunique »     IP Logged