00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <math.h>
00011 #include "edtinc.h"
00012
00013 #include "edt_vco.h"
00014 #include <assert.h>
00015
00016 static int loops = 0;
00017
00018 typedef struct _target
00019 {
00020 double target;
00021 double actual;
00022
00023 edt_pll *pll;
00024
00025 int hits;
00026 int finished;
00027 }target_struct;
00028
00029 #define freq_calc(n,m,v,r,h,l,x,xtal) ((n * v * xtal) / (m * r * h * l * x * 2))
00030
00031
00032
00033
00034 static int factors[64 * 256 + 1];
00035
00036 static int factorsfilled = 0;
00037
00038 static void
00039 fill_factors()
00040
00041 {
00042 int l;
00043 int x;
00044 int product;
00045 int lshift;
00046
00047
00048
00049 memset(&factors[0], 0, sizeof(factors));
00050
00051 for (l = 1; l <= 64; l++)
00052 {
00053 product = l;
00054 lshift = (l << 16);
00055
00056 for (x = 1; x <= 256; x++)
00057 {
00058
00059 factors[product] = lshift | x;
00060
00061 product += l;
00062 }
00063 }
00064
00065 factorsfilled = 1;
00066 }
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 static void
00077 div_out(int h, int r, int n, int v, int m,
00078 double xtal,
00079 double vco,
00080 double ref,
00081 double av_out,
00082 target_struct *targ)
00083 {
00084 int val;
00085 double oddclkout;
00086 double serialclk;
00087 double xl;
00088 int minx = 1;
00089 int maxx = 64 * 256;
00090
00091
00092
00093 oddclkout = av_out / h;
00094
00095
00096
00097 xl = oddclkout / (targ->target * 2);
00098
00099 minx = (int) xl - 1;
00100 if (minx < 1)
00101 minx = 1;
00102 maxx = (int) xl + 1;
00103
00104 if (maxx > 64 * 256)
00105 maxx = 64 * 256;
00106
00107 for (val = minx; val <= maxx; val++)
00108 {
00109
00110 if (val == 1 || ((oddclkout <= F_LOW) && factors[val]))
00111
00112 {
00113 serialclk = oddclkout / (val * 2);
00114
00115
00116
00117
00118
00119
00120
00121 if ((targ->hits == 0) ||
00122 (fabs(targ->actual - targ->target) > fabs(serialclk - targ->target)))
00123 {
00124
00125 targ->actual = serialclk;
00126 targ->pll->m = m;
00127 targ->pll->n = n;
00128 targ->pll->v = v;
00129 targ->pll->r = r;
00130 targ->pll->h = h;
00131
00132 targ->pll->l = (factors[val] >> 16);
00133 targ->pll->x = (factors[val] & 0xffff);
00134
00135 targ->hits++;
00136
00137 if (targ->actual == targ->target)
00138 targ->finished = 1;
00139
00140 #if 0
00141 printf("vco = %3.5f av9110 out = %3.5f, odd divide out = %3.5f\n",
00142 vco, av_out, oddclkout);
00143 printf("serial clk = %3.5f val = %d (%d, n=%d, v=%d, r=%d, h=%d, l=%d, x=%d)\n"
00144 ,serialclk, val, m, n, v, r, h, targ->pll->l, targ->pll->x);
00145 #endif
00146
00147 }
00148 }
00149
00150 loops++;
00151
00152 }
00153
00154 }
00155
00156
00157
00158
00159
00160
00161 static void
00162 av_outputs(int r, int n, int v, int m,
00163 double xtal,
00164 double vco,
00165 double ref,
00166 target_struct *targ)
00167
00168
00169 {
00170 double av_out = vco / r;
00171
00172 if ((av_out) <= F_XILINX)
00173 {
00174
00175
00176
00177
00178
00179
00180 div_out(1, r, n, v, m, xtal, vco, ref, av_out, targ);
00181 if (targ->finished)
00182 return;
00183
00184 div_out(3, r, n, v, m, xtal, vco, ref, av_out, targ);
00185 if (targ->finished)
00186 return;
00187
00188 div_out(5, r, n, v, m, xtal, vco, ref, av_out, targ);
00189 if (targ->finished)
00190 return;
00191
00192 div_out(7, r, n, v, m, xtal, vco, ref, av_out, targ);
00193 }
00194 }
00195
00196
00197
00198
00199
00200 static void
00201 all_n(int v, int m,
00202 double xtal,
00203 double ref,
00204 target_struct *targ)
00205 {
00206 int n = 3;
00207 double vco;
00208 double vref = v * ref;
00209
00210
00211 vco = vref * 3;
00212 while ((n < 128) && ((vco) <= HI_VCO))
00213 {
00214 if ((vco) >= LOW_VCO)
00215 {
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 av_outputs(1, n, v, m, xtal, vco, ref, targ);
00226 if (targ->finished)
00227 return;
00228 av_outputs(2, n, v, m, xtal, vco, ref, targ);
00229 if (targ->finished)
00230 return;
00231 av_outputs(4, n, v, m, xtal, vco, ref, targ);
00232 if (targ->finished)
00233 return;
00234
00235
00236 if (v != 8)
00237 av_outputs(8, n, v, m, xtal, vco, ref, targ);
00238 if (targ->finished)
00239 return;
00240 }
00241 n++;
00242 vco += vref;
00243 }
00244 }
00245
00246
00247
00248
00249
00250
00251 static void
00252 vcofreq( int m, double xtal, target_struct *targ)
00253
00254 {
00255 double ref;
00256
00257
00258
00259
00260 ref = xtal / m;
00261 all_n(1, m, xtal, ref, targ);
00262 if (targ->finished)
00263 return;
00264 all_n(8, m, xtal, ref, targ);
00265 }
00266
00267 double
00268 edt_find_vco_frequency(EdtDev * edt_p, double target,
00269 double xtal, edt_pll * pll, int verbose)
00270
00271 {
00272
00273 target_struct targ;
00274 edt_pll dummypll;
00275
00276 int m, minm, maxm;
00277
00278
00279 if (!pll)
00280 pll = &dummypll;
00281
00282 edt_dtime();
00283
00284 if (!factorsfilled)
00285 {
00286 fill_factors();
00287 factorsfilled = 1;
00288 }
00289
00290 if (xtal == 0)
00291 {
00292 switch (edt_p->devid)
00293 {
00294 case PCD20_ID:
00295 xtal = XTAL20;
00296 break;
00297 case PDV_ID:
00298 case PDVK_ID:
00299 case PDV44_ID:
00300 case PDVFOI_ID:
00301 case PCD40_ID:
00302 xtal = XTAL40;
00303 break;
00304 case PCD60_ID:
00305 case PGP_ECL_ID:
00306 case PCD_16_ID:
00307 case PSS16_ID:
00308 xtal = XTAL60;
00309 break;
00310 default:
00311 xtal = XTAL20;
00312 fprintf(stderr, "WARNING -- vco set got invalid device ID (%d) -- using 20...?\n", edt_p->devid);
00313
00314 break;
00315
00316 }
00317 }
00318
00319 if ((minm = (int) (xtal / HI_REF)) < 3)
00320 minm = 3;
00321 if ((maxm = (int) (xtal / LOW_REF)) > 127)
00322 maxm = 127;
00323
00324 targ.hits = 0;
00325 targ.finished = 0;
00326 targ.target = target;
00327
00328 targ.pll = pll;
00329
00330 for (m = minm; m <= maxm; m++)
00331 {
00332
00333 vcofreq(m, xtal, &targ);
00334
00335 if (targ.finished)
00336 break;
00337 }
00338
00339 if (verbose)
00340 {
00341 printf("\nClosest frequency to target frequency %3.5f is %3.5f\n",
00342 targ.target, targ.actual);
00343 printf("N=%d, M=%d, V=%d, R=%d, H=%d, L=%d, X=%d, updates=%d loops = %d\n",
00344 pll->n, pll->m, pll->v, pll->r, pll->h, pll->l, pll->x,
00345 targ.hits, loops);
00346 printf("Elapsed: %10.6f seconds\n", edt_dtime());
00347 }
00348
00349 return targ.actual;
00350
00351 }
00352
00353
00354
00355
00356 void
00357 edt_set_pll_clock(EdtDev * edt_p, int ref_xtal, edt_pll * clkset, int verbose)
00358 {
00359 double freq = 0;
00360 double vco = 0;
00361
00362
00363 if (verbose)
00364 {
00365 printf("setting pll clock\n");
00366 printf("clock parameters - \n");
00367 printf("\tAV9110 refernce divide(-M) = %d\n", clkset->m);
00368 printf("\tAV9110 VCO feedback divide(-N) = %d\n", clkset->n);
00369 printf("\tAV9110 VCO feedback prescale divide(-V) = %d\n", clkset->v);
00370 printf("\tAV9110 VCO output divide(-R) = %d\n", clkset->r);
00371 printf("\tXilinx low speed divide(-L) = %d\n", clkset->l);
00372 printf("\tXilinx odd divide(-H) = %d\n", clkset->h);
00373 printf("\tXilinx tclk prescaler(-X) = %d\n", clkset->x);
00374 }
00375 vco = (ref_xtal * clkset->v * clkset->n) / (clkset->m);
00376 if (vco < 45e+06 || vco > 250e+06)
00377 printf("edt_set_pll_clock: VCO FREQUENCY OUT OF RANGE at %g Hz\n", vco);
00378 else if (verbose)
00379 printf("VCO Frequency at %g Hz\n", vco);
00380 freq = vco / (2 * clkset->r * clkset->x * clkset->h * clkset->l);
00381 if (verbose)
00382 printf("setting write unit output clock %g Hertz\n", freq);
00383 edt_set_out_clk(edt_p, clkset);
00384 edt_set_funct_bit(edt_p, EDT_FUNCT_PLLCLK);
00385 }
00386