aboutsummaryrefslogtreecommitdiffstats
path: root/icepll
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2016-01-04 19:31:17 +0100
committerClifford Wolf <clifford@clifford.at>2016-01-04 19:31:17 +0100
commitbf660412e88c0645d002d4daa2586152552e05f1 (patch)
tree9d042a62ce72e6b4e60f20e20498cd637be69af9 /icepll
parent75421c016f02ffe0b95b470896a2f9799716922a (diff)
downloadicestorm-bf660412e88c0645d002d4daa2586152552e05f1.tar.gz
icestorm-bf660412e88c0645d002d4daa2586152552e05f1.tar.bz2
icestorm-bf660412e88c0645d002d4daa2586152552e05f1.zip
Added "icepll" PLL parameters calculator
Diffstat (limited to 'icepll')
-rw-r--r--icepll/.gitignore3
-rw-r--r--icepll/Makefile22
-rw-r--r--icepll/icepll.cc174
3 files changed, 199 insertions, 0 deletions
diff --git a/icepll/.gitignore b/icepll/.gitignore
new file mode 100644
index 0000000..385a169
--- /dev/null
+++ b/icepll/.gitignore
@@ -0,0 +1,3 @@
+icepll
+icepll.o
+icepll.d
diff --git a/icepll/Makefile b/icepll/Makefile
new file mode 100644
index 0000000..9a190f6
--- /dev/null
+++ b/icepll/Makefile
@@ -0,0 +1,22 @@
+include ../config.mk
+LDLIBS = -lm -lstdc++
+CXXFLAGS = -MD -O0 -ggdb -Wall -std=c++11 -I/usr/local/include
+
+all: icepll
+
+icepll: icepll.o
+
+install: all
+ mkdir -p $(DESTDIR)$(PREFIX)/bin
+ cp icepll $(DESTDIR)$(PREFIX)/bin/icepll
+
+uninstall:
+ rm -f $(DESTDIR)$(PREFIX)/bin/icepll
+
+clean:
+ rm -f icepll *.o *.d
+
+-include *.d
+
+.PHONY: all install uninstall clean
+
diff --git a/icepll/icepll.cc b/icepll/icepll.cc
new file mode 100644
index 0000000..261cf0a
--- /dev/null
+++ b/icepll/icepll.cc
@@ -0,0 +1,174 @@
+//
+// Copyright (C) 2015 Clifford Wolf <clifford@clifford.at>
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+
+const char *binstr(int v, int n)
+{
+ static char buffer[16];
+ char *p = buffer;
+
+ for (int i = n-1; i >= 0; i--)
+ *(p++) = ((v >> i) & 1) ? '1' : '0';
+ *(p++) = 0;
+
+ return buffer;
+}
+
+void help(const char *cmd)
+{
+ printf("\n");
+ printf("Usage: %s [options]\n", cmd);
+ printf("\n");
+ printf(" -i <input_freq_mhz>\n");
+ printf(" PLL Input Frequency (default: 12 MHz)\n");
+ printf("\n");
+ printf(" -o <output_freq_mhz>\n");
+ printf(" PLL Output Frequency (default: 60 MHz)\n");
+ printf("\n");
+ printf(" -S\n");
+ printf(" Disable SIMPLE feedback path mode\n");
+ printf("\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ double f_pllin = 12;
+ double f_pllout = 60;
+ bool simple_feedback = true;
+
+ int opt;
+ while ((opt = getopt(argc, argv, "i:o:S")) != -1)
+ {
+ switch (opt)
+ {
+ case 'i':
+ f_pllin = atof(optarg);
+ break;
+ case 'o':
+ f_pllout = atof(optarg);
+ break;
+ case 'S':
+ simple_feedback = false;
+ break;
+ default:
+ help(argv[0]);
+ }
+ }
+
+ if (optind != argc)
+ help(argv[0]);
+
+ bool found_something = false;
+ double best_fout = 0;
+ int best_divr = 0;
+ int best_divf = 0;
+ int best_divq = 0;
+
+ if (f_pllin < 10 || f_pllin > 133) {
+ fprintf(stderr, "Error: PLL input freqency %.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 freqency %.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 <= 127; 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;
+ }
+ }
+ }
+ }
+ }
+
+ double f_pfd = f_pllin / (best_divr + 1);;
+ double f_vco = f_pfd * (best_divf + 1);
+
+ if (!simple_feedback)
+ f_vco *= exp2(best_divq);
+
+ if (!found_something) {
+ fprintf(stderr, "Error: No valid configuration found!\n");
+ exit(1);
+ }
+
+ printf("\n");
+
+ printf("F_PLLIN: %8.3f MHz (given)\n", f_pllin);
+ printf("F_PLLOUT: %8.3f MHz (requested)\n", f_pllout);
+ printf("F_PLLOUT: %8.3f MHz (achieved)\n", best_fout);
+
+ printf("\n");
+
+ printf("FEEDBACK: %s\n", simple_feedback ? "SIMPLE" : "NON_SIMPLE");
+ printf("F_PFD: %8.3f MHz\n", f_pfd);
+ printf("F_VCO: %8.3f MHz\n", f_vco);
+
+ printf("\n");
+
+ printf("DIVR: %2d (4'b%s)\n", best_divr, binstr(best_divr, 4));
+ printf("DIVF: %2d (7'b%s)\n", best_divf, binstr(best_divf, 7));
+ printf("DIVQ: %2d (3'b%s)\n", best_divq, binstr(best_divq, 3));
+
+ printf("\n");
+
+ return 0;
+}