mirror of https://github.com/YosysHQ/icestorm.git
Merge pull request #245 from SmallRoomLabs/iteratePLL
icepll: Add iteration over list of frequencies for best solution
This commit is contained in:
commit
d1cee1d4ae
267
icepll/icepll.cc
267
icepll/icepll.cc
|
|
@ -51,6 +51,14 @@ void help(const char *cmd)
|
||||||
printf(" -S\n");
|
printf(" -S\n");
|
||||||
printf(" Disable SIMPLE feedback path mode\n");
|
printf(" Disable SIMPLE feedback path mode\n");
|
||||||
printf("\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(" -f <filename>\n");
|
||||||
printf(" Save PLL configuration as Verilog to file\n");
|
printf(" Save PLL configuration as Verilog to file\n");
|
||||||
printf(" If <filename> is - then the Verilog is written to stdout.\n");
|
printf(" If <filename> is - then the Verilog is written to stdout.\n");
|
||||||
|
|
@ -67,86 +75,21 @@ void help(const char *cmd)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
bool analyze(
|
||||||
|
bool simple_feedback, double f_pllin, double f_pllout,
|
||||||
|
double *best_fout, int *best_divr, int *best_divf, int *best_divq
|
||||||
|
)
|
||||||
{
|
{
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
EM_ASM(
|
|
||||||
if (ENVIRONMENT_IS_NODE)
|
|
||||||
{
|
|
||||||
FS.mkdir('/hostcwd');
|
|
||||||
FS.mount(NODEFS, { root: '.' }, '/hostcwd');
|
|
||||||
FS.mkdir('/hostfs');
|
|
||||||
FS.mount(NODEFS, { root: '/' }, '/hostfs');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
double f_pllin = 12;
|
|
||||||
double f_pllout = 60;
|
|
||||||
bool simple_feedback = true;
|
|
||||||
const char* filename = NULL;
|
|
||||||
bool file_stdout = false;
|
|
||||||
const char* module_name = NULL;
|
|
||||||
bool save_as_module = false;
|
|
||||||
bool quiet = false;
|
|
||||||
|
|
||||||
int opt;
|
|
||||||
while ((opt = getopt(argc, argv, "i:o:Smf:n:q")) != -1)
|
|
||||||
{
|
|
||||||
switch (opt)
|
|
||||||
{
|
|
||||||
case 'i':
|
|
||||||
f_pllin = atof(optarg);
|
|
||||||
break;
|
|
||||||
case 'o':
|
|
||||||
f_pllout = atof(optarg);
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
simple_feedback = false;
|
|
||||||
break;
|
|
||||||
case 'm':
|
|
||||||
save_as_module = true;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
filename = optarg;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
module_name = optarg;
|
|
||||||
break;
|
|
||||||
case 'q':
|
|
||||||
quiet = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
help(argv[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (optind != argc)
|
|
||||||
help(argv[0]);
|
|
||||||
|
|
||||||
// Shall save as module, but no filename was given.
|
|
||||||
// Write to stdout.
|
|
||||||
if (save_as_module && filename == NULL)
|
|
||||||
filename = "-";
|
|
||||||
|
|
||||||
// If filename is "-", then use stdout as output stream.
|
|
||||||
// That implies quiet mode.
|
|
||||||
if (filename != NULL && strcmp(filename, "-") == 0)
|
|
||||||
{
|
|
||||||
file_stdout = true;
|
|
||||||
quiet = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool found_something = false;
|
bool found_something = false;
|
||||||
double best_fout = 0;
|
*best_fout = 0;
|
||||||
int best_divr = 0;
|
*best_divr = 0;
|
||||||
int best_divf = 0;
|
*best_divf = 0;
|
||||||
int best_divq = 0;
|
*best_divq = 0;
|
||||||
|
|
||||||
|
int divf_max = simple_feedback ? 127 : 63;
|
||||||
// The documentation in the iCE40 PLL Usage Guide incorrectly lists the
|
// 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
|
// maximum value of DIVF as 63, when it is only limited to 63 when using
|
||||||
// feedback modes other that SIMPLE.
|
// feedback modes other that SIMPLE.
|
||||||
int divf_max = simple_feedback ? 127 : 63;
|
|
||||||
|
|
||||||
if (f_pllin < 10 || f_pllin > 133) {
|
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);
|
fprintf(stderr, "Error: PLL input frequency %.3f MHz is outside range 10 MHz - 133 MHz!\n", f_pllin);
|
||||||
|
|
@ -174,11 +117,11 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
double fout = f_vco * exp2(-divq);
|
double fout = f_vco * exp2(-divq);
|
||||||
|
|
||||||
if (fabs(fout - f_pllout) < fabs(best_fout - f_pllout) || !found_something) {
|
if (fabs(fout - f_pllout) < fabs(*best_fout - f_pllout) || !found_something) {
|
||||||
best_fout = fout;
|
*best_fout = fout;
|
||||||
best_divr = divr;
|
*best_divr = divr;
|
||||||
best_divf = divf;
|
*best_divf = divf;
|
||||||
best_divq = divq;
|
*best_divq = divq;
|
||||||
found_something = true;
|
found_something = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -192,11 +135,11 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
double fout = f_vco * exp2(-divq);
|
double fout = f_vco * exp2(-divq);
|
||||||
|
|
||||||
if (fabs(fout - f_pllout) < fabs(best_fout - f_pllout) || !found_something) {
|
if (fabs(fout - f_pllout) < fabs(*best_fout - f_pllout) || !found_something) {
|
||||||
best_fout = fout;
|
*best_fout = fout;
|
||||||
best_divr = divr;
|
*best_divr = divr;
|
||||||
best_divf = divf;
|
*best_divf = divf;
|
||||||
best_divq = divq;
|
*best_divq = divq;
|
||||||
found_something = true;
|
found_something = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -204,6 +147,162 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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__
|
||||||
|
EM_ASM(
|
||||||
|
if (ENVIRONMENT_IS_NODE)
|
||||||
|
{
|
||||||
|
FS.mkdir('/hostcwd');
|
||||||
|
FS.mount(NODEFS, { root: '.' }, '/hostcwd');
|
||||||
|
FS.mkdir('/hostfs');
|
||||||
|
FS.mount(NODEFS, { root: '/' }, '/hostfs');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
double f_pllin = 12;
|
||||||
|
double f_pllout = 60;
|
||||||
|
bool simple_feedback = true;
|
||||||
|
const char* filename = NULL;
|
||||||
|
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:bB:q")) != -1)
|
||||||
|
{
|
||||||
|
switch (opt)
|
||||||
|
{
|
||||||
|
case 'i':
|
||||||
|
f_pllin = atof(optarg);
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
f_pllout = atof(optarg);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
simple_feedback = false;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
save_as_module = true;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
filename = optarg;
|
||||||
|
break;
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
help(argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind != argc)
|
||||||
|
help(argv[0]);
|
||||||
|
|
||||||
|
// Shall save as module, but no filename was given.
|
||||||
|
// Write to stdout.
|
||||||
|
if (save_as_module && filename == NULL)
|
||||||
|
filename = "-";
|
||||||
|
|
||||||
|
// If filename is "-", then use stdout as output stream.
|
||||||
|
// That implies quiet mode.
|
||||||
|
if (filename != NULL && strcmp(filename, "-") == 0)
|
||||||
|
{
|
||||||
|
file_stdout = true;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
found_something = true;
|
||||||
|
if (abs(fout - f_pllout) < abs(best_fout - f_pllout))
|
||||||
|
{
|
||||||
|
f_pllin = freq_table[i];
|
||||||
|
best_fout = fout;
|
||||||
|
best_divr = divr;
|
||||||
|
best_divf = divf;
|
||||||
|
best_divq = divq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double f_pfd = f_pllin / (best_divr + 1);;
|
double f_pfd = f_pllin / (best_divr + 1);;
|
||||||
double f_vco = f_pfd * (best_divf + 1);
|
double f_vco = f_pfd * (best_divf + 1);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue