00001
00002
00003 #include "edtinc.h"
00004 #include "edt_ss_vco.h"
00005
00006 #include <assert.h>
00007
00008 #include <math.h>
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #define HIGH_VCO_307 400000000
00020 #define LOW_VCO_ics307 55000000
00021 #define MIN_RDW_FREQ 200000
00022
00023 static int test_loops = 0;
00024
00025 typedef struct _target_ics307
00026 {
00027 double target;
00028 double actual;
00029
00030 edt_pll *pll;
00031
00032
00033 int hits;
00034 int finished;
00035 } target_ics307;
00036
00037
00038 void
00039 print_ics307_parameters(double target, double actual, double reference, edt_pll * pll)
00040
00041 {
00042
00043 double check;
00044
00045
00046 printf("ICS 307 computations for reference frequency %f\n", reference);
00047
00048 printf("\nClosest frequency to target frequency %3.5f is %3.5f\n",
00049 target, actual);
00050 printf("Parameters VDW=%d, RDW=%d, OD=%d, LX=%d\n",
00051 pll->VDW, pll->RDW, pll->OD,pll->x);
00052
00053 check = reference * (pll->VDW + 8) / ((pll->RDW + 2) * pll->OD * (pll->x+1));
00054
00055 if (pll->l)
00056 {
00057
00058
00059 check *= 2;
00060
00061 printf("\n--- Note this requires a bitfile which supports no final divide by 2!!! ---\n\n");
00062
00063 printf("Computations:\nF = Ref * 2 * (VDW+8) / ((RDW+2) * (OD) * (LX+1))\n");
00064
00065 printf("%3.5f = %3.5f * 2 * (%d+8) / ((%d+2) * (%d) * (%d))\n",
00066 actual, reference, pll->VDW, pll->RDW, pll->OD, pll->x+1);
00067
00068 }
00069 else
00070 {
00071
00072 printf("Computations:\nF = Ref * 2 * (VDW+8) / ((RDW+2) * (OD) * (LX+1) * 2)\n");
00073
00074 printf("%3.5f = %3.5f * 2 * (%d+8) / ((%d+2) * (%d) * (%d) * 2)\n",
00075 actual, reference, pll->VDW, pll->RDW, pll->OD, pll->x+1);
00076
00077
00078 }
00079
00080 printf("Check = %3.5f\n", check);
00081
00082 }
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 static void
00093 div_out_ics307(int h, int vdw, int rdw, int od, double xtal, double av_out,
00094 target_ics307 * targ,
00095 int lastdivide)
00096
00097 {
00098 int val;
00099 double oddclkout;
00100 double serialclk;
00101 int minx = 1;
00102 int maxx = 64 * 256;
00103
00104 int divider = lastdivide;
00105
00106
00107 oddclkout = av_out / h;
00108
00109
00110
00111 if (lastdivide)
00112 {
00113 double xl;
00114
00115 xl = oddclkout / (targ->target * lastdivide);
00116
00117 minx = (int) xl - 1;
00118 if (minx < 1)
00119 minx = 1;
00120 maxx = (int) xl + 1;
00121
00122 if (maxx > 64 * 256)
00123 maxx = 64 * 256;
00124
00125 }
00126 else
00127 {
00128 minx = maxx = 1;
00129 divider = 1;
00130 }
00131
00132 for (val = minx; val <= maxx; val++)
00133 {
00134
00135 if (val == 1 || ((oddclkout <= F_SS_LOW)))
00136
00137 {
00138 serialclk = oddclkout / (val * divider);
00139
00140 if ((targ->hits == 0) ||
00141 (fabs(targ->actual - targ->target) > fabs(serialclk - targ->target)))
00142 {
00143
00144 targ->actual = serialclk;
00145 targ->pll->VDW = vdw;
00146 targ->pll->RDW = rdw;
00147 targ->pll->OD = od;
00148 targ->pll->h = h;
00149
00150
00151
00152 targ->pll->x = val-1;
00153
00154 targ->hits++;
00155
00156 if (targ->actual == targ->target)
00157 targ->finished = 1;
00158
00159 }
00160 }
00161
00162 test_loops++;
00163
00164 }
00165
00166 }
00167
00168
00169
00170
00171
00172
00173 static void
00174 av_outputs_ics307(int vdw, int rdw, int od, double xtal,
00175 double av_out, target_ics307 * targ,
00176 int last_divide)
00177
00178 {
00179 if ((av_out) <= F_XILINX_307)
00180 {
00181
00182
00183
00184
00185
00186
00187 div_out_ics307(1, vdw, rdw, od, xtal, av_out, targ, last_divide);
00188
00189 }
00190 }
00191
00192
00193
00194
00195
00196
00197 static void
00198 all_vdw_ics307(int od, double xtal, double ref, target_ics307 * targ,
00199 int last_divide)
00200
00201 {
00202 int vdw = 4;
00203 int rdw;
00204 double vco;
00205 double vref;
00206
00207 double workref;
00208
00209 int max_rdw = (int) (xtal / MIN_RDW_FREQ) - 2;
00210
00211 vref = (vdw + 8) * xtal;
00212
00213 while ((vdw < 511) && (2 * (vref / 128) <= HIGH_VCO_307))
00214 {
00215 vref = (vdw + 8) * xtal;
00216
00217
00218
00219
00220
00221
00222
00223
00224 workref = 2 * vref;
00225
00226 for (rdw = 1; rdw < max_rdw; rdw++)
00227 {
00228
00229 vco = workref / (double) (rdw + 2);
00230
00231 if ((vco) >= LOW_VCO_ics307)
00232 {
00233 if (vco <= HIGH_VCO_307)
00234 {
00235 vco /= od;
00236
00237 av_outputs_ics307(vdw, rdw, od, xtal, vco, targ, last_divide);
00238 }
00239 }
00240 else
00241 break;
00242
00243 if (targ->finished)
00244 return;
00245 }
00246
00247
00248 vdw++;
00249
00250 }
00251 }
00252
00253
00254
00255
00256
00257
00258 static void
00259 calc_vco_freq_ics307(double xtal, target_ics307 * targ, int last_divide)
00260
00261 {
00262 double ref;
00263 int od;
00264
00265
00266
00267
00268
00269 printf("\ncalc vco freq last_divide = %d\n", last_divide);
00270
00271 for (od = 2; od <= 10; od++)
00272 {
00273 if (od != 9)
00274 {
00275
00276 ref = xtal * 2 / od;
00277
00278 all_vdw_ics307(od, xtal, ref, targ, last_divide);
00279
00280 if (targ->finished)
00281 return;
00282
00283 }
00284 }
00285
00286 }
00287
00288 double
00289 edt_find_ss_vco_frequency(EdtDev * edt_p, double target,
00290 double xtal, edt_pll * pll, int verbose, int nodivide)
00291
00292 {
00293
00294 target_ics307 targ;
00295
00296 edt_pll dummypll;
00297
00298 int minm, maxm;
00299 int div_value;
00300
00301
00302
00303 if (!pll)
00304 pll = &dummypll;
00305
00306 edt_dtime();
00307
00308
00309 if (xtal == 0)
00310 {
00311 switch (edt_p->devid)
00312 {
00313 case PSS16_ID:
00314 case PSS4_ID:
00315 case PGS16_ID:
00316 case PGS4_ID:
00317 xtal = XTAL_SS;
00318 break;
00319
00320 default:
00321 xtal = XTAL_SS;
00322 fprintf(stderr, "WARNING -- SS vco set requires ICS307 PLL and PCISSgot invalid device ID (%d) -- using %f...?\n", edt_p->devid, XTAL_SS);
00323
00324 break;
00325
00326 }
00327 }
00328
00329
00330
00331
00332
00333
00334
00335 minm = 4;
00336 maxm = 511;
00337
00338 memset(&targ, 0, sizeof(targ));
00339
00340 targ.actual = 0;
00341 targ.hits = 0;
00342 targ.finished = 0;
00343 targ.target = target;
00344 targ.actual = 0;
00345
00346 targ.pll = pll;
00347
00348 switch (nodivide)
00349 {
00350 case 0:
00351 div_value = 2;
00352 break;
00353 case 1:
00354 div_value = 1;
00355 break;
00356 case 2:
00357 div_value = 0;
00358 break;
00359 }
00360
00361
00362 targ.pll->l = nodivide;
00363
00364 calc_vco_freq_ics307(xtal, &targ, div_value);
00365
00366 if (verbose)
00367 {
00368 print_ics307_parameters(targ.target, targ.actual, xtal, pll);
00369 printf("Elapsed: %10.6f seconds\n", edt_dtime());
00370 }
00371 else
00372 printf("Closest frequency to target frequency %3.5f is %3.5f\n",
00373 targ.target, targ.actual);
00374
00375 return targ.actual;
00376
00377 }
00378
00379
00380 double
00381 edt_find_vco_frequency_ics307(EdtDev * edt_p, double target,
00382 double xtal, edt_pll * pll, int verbose)
00383
00384 {
00385 return edt_find_ss_vco_frequency(edt_p,target,xtal, pll, verbose,0);
00386 }
00387
00388 double
00389 edt_find_vco_frequency_ics307_nodivide(EdtDev * edt_p, double target,
00390 double xtal, edt_pll * pll, int verbose)
00391
00392 {
00393 return edt_find_ss_vco_frequency(edt_p,target,xtal, pll, verbose,1);
00394 }
00395
00396 double
00397 edt_find_vco_frequency_ics307_raw(EdtDev * edt_p, double target,
00398 double xtal, edt_pll * pll, int verbose)
00399
00400 {
00401 return edt_find_ss_vco_frequency(edt_p,target,xtal, pll, verbose,2);
00402 }
00403
00404
00405
00406
00407 double
00408 edt_set_frequency_ics307(EdtDev * edt_p,
00409 double ref_xtal,
00410 double target,
00411 int clock_channel,
00412 int finaldivide)
00413 {
00414 double freq = 0;
00415
00416
00417 edt_pll clkset;
00418
00419 freq = edt_find_ss_vco_frequency(edt_p, target, ref_xtal, &clkset,
00420 FALSE, finaldivide);
00421
00422 if (freq > 0)
00423 edt_set_out_clk_ics307(edt_p, &clkset, clock_channel);
00424
00425 return freq;
00426
00427 }
00428
00429
00430
00431
00432 double
00433 edt_set_frequency_fcipcd(EdtDev * edt_p,
00434 double target)
00435 {
00436 double freq = 0;
00437 int clock_channel = 0;
00438 edt_pll clkset;
00439 double ref_xtal = XTAL_SS;
00440
00441 freq = edt_find_ss_vco_frequency(edt_p, target, ref_xtal, &clkset,
00442 FALSE, 2);
00443
00444 if (freq > 0)
00445 edt_set_out_clk_ics307(edt_p, &clkset, clock_channel);
00446
00447 return freq;
00448
00449 }
00450
00451
00452
00453
00454
00455 static void
00456 shift_ics307(EdtDev * edt_p, u_int data, u_int numbits)
00457 {
00458
00459
00460
00461 while (numbits)
00462 {
00463
00464
00465 if ((data >> (numbits - 1)) & 0x01)
00466 {
00467 edt_reg_or(edt_p, EDT_SS_PLL_CTL, EDT_SS_PLL_DATA);
00468
00469
00470
00471 }
00472 else
00473 {
00474 edt_reg_and(edt_p, EDT_SS_PLL_CTL, ~EDT_SS_PLL_DATA);
00475
00476
00477
00478 }
00479
00480
00481 edt_reg_or(edt_p, EDT_SS_PLL_CTL, EDT_SS_PLL_CLK);
00482 edt_reg_and(edt_p, EDT_SS_PLL_CTL, ~EDT_SS_PLL_CLK);
00483
00484 numbits--;
00485 }
00486
00487
00488
00489 }
00490
00491
00492
00493
00494
00495
00496
00497 static int SFromCLK1[11] = {-1, -1, 1, 6, 3, 4, 7, 5, 2, -1, 0};
00498
00499
00500
00501
00502
00503 #define ICS307_CAP_TTL_CLK2 0x06
00504
00505
00506 void
00507 edt_set_out_clk_ics307(EdtDev * edt_p, edt_pll * clk_data, int clock_channel)
00508 {
00509 unsigned short opt_e = 0;
00510
00511 u_int out_scale;
00512 u_int ref_scale;
00513
00514 u_int clk1_divide;
00515
00516 u_int strobe_bit;
00517
00518
00519
00520
00521 if (clk_data->l != 2)
00522 {
00523
00524 if (clk_data->l)
00525 opt_e = 0xffff;
00526 else
00527 opt_e = (clk_data->x) << EDT_X_DIVN_SHFT;
00528
00529 switch (clock_channel)
00530 {
00531 case 0:
00532 out_scale = EDT_SS_PLL0_CLK;
00533 ref_scale = EDT_SS_PLL0_X;
00534 break;
00535
00536 case 1:
00537 out_scale = EDT_SS_PLL1_CLK;
00538 ref_scale = EDT_SS_PLL1_X;
00539 break;
00540 case 2:
00541 out_scale = EDT_SS_PLL2_CLK;
00542 ref_scale = EDT_SS_PLL2_X;
00543 break;
00544 case 3:
00545 out_scale = EDT_SS_PLL3_CLK;
00546 ref_scale = EDT_SS_PLL3_X;
00547 break;
00548 default:
00549 assert(0);
00550 }
00551
00552 edt_reg_write(edt_p, out_scale, opt_e & 0xff);
00553 edt_reg_write(edt_p, ref_scale, opt_e >> 8);
00554
00555 }
00556
00557
00558
00559
00560
00561 shift_ics307(edt_p, ICS307_CAP_TTL_CLK2, 5);
00562
00563 clk1_divide = SFromCLK1[clk_data->OD];
00564
00565 shift_ics307(edt_p, clk1_divide, 3);
00566
00567 shift_ics307(edt_p, clk_data->VDW, 9);
00568 shift_ics307(edt_p, clk_data->RDW, 7);
00569
00570 printf("Programming value %x\n",
00571 (5 << 19) | (clk1_divide<< 16) | (clk_data->VDW << 7) | (clk_data->RDW));
00572
00573 switch (clock_channel)
00574 {
00575 case 0:
00576 strobe_bit = EDT_SS_PLL_STROBE0;
00577 break;
00578 case 1:
00579 strobe_bit = EDT_SS_PLL_STROBE1;
00580 break;
00581 case 2:
00582 strobe_bit = EDT_SS_PLL_STROBE2;
00583 break;
00584 case 3:
00585 strobe_bit = EDT_SS_PLL_STROBE3;
00586 break;
00587 default:
00588 assert(0);
00589 }
00590 edt_reg_or(edt_p, EDT_SS_PLL_CTL, strobe_bit);
00591 edt_reg_and(edt_p, EDT_SS_PLL_CTL, ~strobe_bit);
00592
00593 }
00594