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