aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClaire Wolf <clifford@clifford.at>2020-03-30 13:55:23 +0200
committerGitHub <noreply@github.com>2020-03-30 13:55:23 +0200
commitd1cee1d4ae545fdca995cd656ef52d8923aa77e9 (patch)
treeeec0f8fe9ba4bd89862a85079f1a9903b77c5216
parentd38852b48d17f2a0eba1ed68e681a84899920271 (diff)
parentc1d49fe58b8538aa2228d5de35ba939906e111b9 (diff)
downloadicestorm-d1cee1d4ae545fdca995cd656ef52d8923aa77e9.tar.gz
icestorm-d1cee1d4ae545fdca995cd656ef52d8923aa77e9.tar.bz2
icestorm-d1cee1d4ae545fdca995cd656ef52d8923aa77e9.zip
Merge pull request #245 from SmallRoomLabs/iteratePLL
icepll: Add iteration over list of frequencies for best solution
-rw-r--r--icepll/icepll.cc207
1 files changed, 153 insertions, 54 deletions
diff --git a/icepll/icepll.cc b/icepll/icepll.cc
index f9ebecf..a2db72f 100644
--- a/icepll/icepll.cc
+++ b/icepll/icepll.cc
@@ -51,6 +51,14 @@ void help(const char *cmd)
printf(" -S\n");
printf(" Disable SIMPLE feedback path mode\n");
printf("\n");
+ printf(" -b\n");
+ printf(" Find best input frequency for desired PLL Output frequency\n");
+ printf(" using the normally stocked oscillators at Mouser\n");
+ printf("\n");
+ printf(" -B <filename>\n");
+ printf(" Find best input frequency for desired PLL Output frequency\n");
+ printf(" using frequencies read from <filename>\n");
+ printf("\n");
printf(" -f <filename>\n");
printf(" Save PLL configuration as Verilog to file\n");
printf(" If <filename> is - then the Verilog is written to stdout.\n");
@@ -67,6 +75,119 @@ void help(const char *cmd)
exit(1);
}
+bool analyze(
+ bool simple_feedback, double f_pllin, double f_pllout,
+ double *best_fout, int *best_divr, int *best_divf, int *best_divq
+ )
+{
+ bool found_something = false;
+ *best_fout = 0;
+ *best_divr = 0;
+ *best_divf = 0;
+ *best_divq = 0;
+
+ int divf_max = simple_feedback ? 127 : 63;
+ // The documentation in the iCE40 PLL Usage Guide incorrectly lists the
+ // maximum value of DIVF as 63, when it is only limited to 63 when using
+ // feedback modes other that SIMPLE.
+
+ if (f_pllin < 10 || f_pllin > 133) {
+ fprintf(stderr, "Error: PLL input frequency %.3f MHz is outside range 10 MHz - 133 MHz!\n", f_pllin);
+ exit(1);
+ }
+
+ if (f_pllout < 16 || f_pllout > 275) {
+ fprintf(stderr, "Error: PLL output frequency %.3f MHz is outside range 16 MHz - 275 MHz!\n", f_pllout);
+ exit(1);
+ }
+
+ for (int divr = 0; divr <= 15; divr++)
+ {
+ double f_pfd = f_pllin / (divr + 1);
+ if (f_pfd < 10 || f_pfd > 133) continue;
+
+ for (int divf = 0; divf <= divf_max; divf++)
+ {
+ if (simple_feedback)
+ {
+ double f_vco = f_pfd * (divf + 1);
+ if (f_vco < 533 || f_vco > 1066) continue;
+
+ for (int divq = 1; divq <= 6; divq++)
+ {
+ double fout = f_vco * exp2(-divq);
+
+ if (fabs(fout - f_pllout) < fabs(*best_fout - f_pllout) || !found_something) {
+ *best_fout = fout;
+ *best_divr = divr;
+ *best_divf = divf;
+ *best_divq = divq;
+ found_something = true;
+ }
+ }
+ }
+ else
+ {
+ for (int divq = 1; divq <= 6; divq++)
+ {
+ double f_vco = f_pfd * (divf + 1) * exp2(divq);
+ if (f_vco < 533 || f_vco > 1066) continue;
+
+ double fout = f_vco * exp2(-divq);
+
+ if (fabs(fout - f_pllout) < fabs(*best_fout - f_pllout) || !found_something) {
+ *best_fout = fout;
+ *best_divr = divr;
+ *best_divf = divf;
+ *best_divq = divq;
+ found_something = true;
+ }
+ }
+ }
+ }
+ }
+
+ return found_something;
+}
+
+ // Table of frequencies to test in "best" mode defaults to ABRACOM Crystal
+ // oscillators "Normally stocked" at Mouser
+ double freq_table[100] =
+ {
+ 10, 11.0592, 11.2896, 11.7846, 12, 12.288, 12.352, 12.5, 13, 13.5, 13.6, 14.31818, 14.7456, 15, 16, 16.384, 17.2032, 18.432, 19.2, 19.44, 19.6608,
+ 20, 24, 24.576, 25, 26, 27, 27.12, 28.63636, 28.9, 29.4912,
+ 30, 32, 32.768, 33, 33.206, 33.333, 35.328, 36, 37.03, 37.4, 38.4, 38.88,
+ 40, 40.95, 40.97, 44, 44.736, 48,
+ 50, 54, 57.692,
+ 60, 64, 65, 66, 66.666, 68,
+ 70, 72, 75, 76.8,
+ 80, 80.92,
+ 92.16, 96, 98.304,
+ 100, 104, 106.25, 108,
+ 114.285,
+ 120, 122.88, 125,
+ 0
+ };
+
+void readfreqfile(const char *filename) {
+ FILE *f;
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ fprintf(stderr, "Error: Can't open file %s!\n",filename);
+ exit(1);
+ }
+
+ // Clear and overwrite the default values in the table
+ memset(freq_table, 0, sizeof(freq_table));
+ int i = 0;
+ double freq=0;
+ while((i < sizeof(freq_table)/sizeof(double)) && (fscanf(f, "%lf", &freq) > 0))
+ {
+ freq_table[i++] = freq;
+ }
+ fclose(f);
+}
+
int main(int argc, char **argv)
{
#ifdef __EMSCRIPTEN__
@@ -88,10 +209,12 @@ int main(int argc, char **argv)
bool file_stdout = false;
const char* module_name = NULL;
bool save_as_module = false;
+ bool best_mode = false;
+ const char* freqfile = NULL;
bool quiet = false;
int opt;
- while ((opt = getopt(argc, argv, "i:o:Smf:n:q")) != -1)
+ while ((opt = getopt(argc, argv, "i:o:Smf:n:bB:q")) != -1)
{
switch (opt)
{
@@ -113,6 +236,13 @@ int main(int argc, char **argv)
case 'n':
module_name = optarg;
break;
+ case 'b':
+ best_mode = true;
+ break;
+ case 'B':
+ best_mode = true;
+ freqfile = optarg;
+ break;
case 'q':
quiet = true;
break;
@@ -137,68 +267,37 @@ int main(int argc, char **argv)
quiet = true;
}
+ if (freqfile) {
+ readfreqfile(freqfile);
+ }
+
bool found_something = false;
double best_fout = 0;
int best_divr = 0;
int best_divf = 0;
int best_divq = 0;
- // The documentation in the iCE40 PLL Usage Guide incorrectly lists the
- // maximum value of DIVF as 63, when it is only limited to 63 when using
- // feedback modes other that SIMPLE.
- int divf_max = simple_feedback ? 127 : 63;
-
- if (f_pllin < 10 || f_pllin > 133) {
- fprintf(stderr, "Error: PLL input frequency %.3f MHz is outside range 10 MHz - 133 MHz!\n", f_pllin);
- exit(1);
- }
-
- if (f_pllout < 16 || f_pllout > 275) {
- fprintf(stderr, "Error: PLL output frequency %.3f MHz is outside range 16 MHz - 275 MHz!\n", f_pllout);
- exit(1);
- }
-
- for (int divr = 0; divr <= 15; divr++)
- {
- double f_pfd = f_pllin / (divr + 1);
- if (f_pfd < 10 || f_pfd > 133) continue;
-
- for (int divf = 0; divf <= divf_max; divf++)
+ if (!best_mode) {
+ // Use only specified input frequency
+ found_something = analyze(simple_feedback, f_pllin, f_pllout, &best_fout, &best_divr, &best_divf, &best_divq);
+ } else {
+ // Iterate over all standard crystal frequencies and select the best
+ for (int i = 0; freq_table[i]>0.0 ; i++)
{
- if (simple_feedback)
- {
- double f_vco = f_pfd * (divf + 1);
- if (f_vco < 533 || f_vco > 1066) continue;
-
- for (int divq = 1; divq <= 6; divq++)
- {
- double fout = f_vco * exp2(-divq);
-
- if (fabs(fout - f_pllout) < fabs(best_fout - f_pllout) || !found_something) {
- best_fout = fout;
- best_divr = divr;
- best_divf = divf;
- best_divq = divq;
- found_something = true;
- }
- }
- }
- else
+ double fout = 0;
+ int divr = 0;
+ int divf = 0;
+ int divq = 0;
+ if (analyze(simple_feedback, freq_table[i], f_pllout, &fout, &divr, &divf, &divq))
{
- for (int divq = 1; divq <= 6; divq++)
+ found_something = true;
+ if (abs(fout - f_pllout) < abs(best_fout - f_pllout))
{
- double f_vco = f_pfd * (divf + 1) * exp2(divq);
- if (f_vco < 533 || f_vco > 1066) continue;
-
- double fout = f_vco * exp2(-divq);
-
- if (fabs(fout - f_pllout) < fabs(best_fout - f_pllout) || !found_something) {
- best_fout = fout;
- best_divr = divr;
- best_divf = divf;
- best_divq = divq;
- found_something = true;
- }
+ f_pllin = freq_table[i];
+ best_fout = fout;
+ best_divr = divr;
+ best_divf = divf;
+ best_divq = divq;
}
}
}