diff --git a/jtag/include/Makefile.am b/jtag/include/Makefile.am index 92674243..6d88be30 100644 --- a/jtag/include/Makefile.am +++ b/jtag/include/Makefile.am @@ -39,4 +39,5 @@ noinst_HEADERS = \ bssignal.h \ state.h \ jtag.h \ - tap.h + tap.h \ + fclock.h diff --git a/jtag/include/cable.h b/jtag/include/cable.h index 07edb91e..24ecbf6b 100644 --- a/jtag/include/cable.h +++ b/jtag/include/cable.h @@ -64,7 +64,8 @@ int cable_get_tdo( cable_t *cable ); int cable_set_trst( cable_t *cable, int trst ); int cable_get_trst( cable_t *cable ); -extern uint32_t frequency; +void cable_set_frequency( cable_t *cable, uint32_t frequency ); +uint32_t cable_get_frequency( cable_t *cable ); void cable_wait( void ); extern cable_driver_t *cable_drivers[]; diff --git a/jtag/include/fclock.h b/jtag/include/fclock.h new file mode 100644 index 00000000..be589dbf --- /dev/null +++ b/jtag/include/fclock.h @@ -0,0 +1,47 @@ +/* + * fclock.h + * + * Copyright (C) 2005 Hein Roehrig + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + + +#ifndef FCLOCK_H +#define FCLOCK_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* return real time in seconds starting at some arbitrary point in + time*/ +long double frealtime(); + +/* return the CPU time used by this process (seconds) */ +long double fcputime(); + + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/jtag/src/Makefile.am b/jtag/src/Makefile.am index bc8b4a20..ff67b4d6 100644 --- a/jtag/src/Makefile.am +++ b/jtag/src/Makefile.am @@ -63,6 +63,7 @@ jtag_LDADD = \ -L../libbrux -lbrux \ -Lbus -lbus \ -Lsvf -lsvf \ + -lrt \ -lm \ @LIBINTL@ diff --git a/jtag/src/cmd/frequency.c b/jtag/src/cmd/frequency.c index ffab4bf1..af235f4d 100644 --- a/jtag/src/cmd/frequency.c +++ b/jtag/src/cmd/frequency.c @@ -27,6 +27,7 @@ #include #include "cable.h" +#include "jtag.h" #include "cmd.h" @@ -36,7 +37,7 @@ cmd_frequency_run( char *params[] ) unsigned int freq; if (cmd_params( params ) == 1) { - printf( _("Current TCK frequency is %u Hz\n"), frequency ); + printf( _("Current TCK frequency is %u Hz\n"), cable_get_frequency(chain->cable) ); return 1; } @@ -47,7 +48,7 @@ cmd_frequency_run( char *params[] ) return -1; printf( _("Setting TCK frequency to %u Hz\n"), freq ); - frequency = freq; + cable_set_frequency(chain->cable, freq); return 1; } diff --git a/jtag/src/lib/Makefile.am b/jtag/src/lib/Makefile.am index 77641384..ea264f79 100644 --- a/jtag/src/lib/Makefile.am +++ b/jtag/src/lib/Makefile.am @@ -27,4 +27,5 @@ noinst_LIBRARIES = libjtaglib.a libjtaglib_a_SOURCES = \ getdelim.c \ - getline.c + getline.c \ + fclock.c diff --git a/jtag/src/lib/fclock.c b/jtag/src/lib/fclock.c new file mode 100644 index 00000000..5bd06ade --- /dev/null +++ b/jtag/src/lib/fclock.c @@ -0,0 +1,86 @@ +/* + * fclock.c + * + * Copyright (C) 2005 Hein Roehrig + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#define _ISOC99_SOURCE +#define _POSIX_C_SOURCE 199309L +#include +#include +#include +#include +#include +#include +#include + + +#ifndef CLK_TCK +static clock_t CLK_TCK = 0; +static void set_clk_tck(void) __attribute__ ((constructor)); +static void set_clk_tck(void) +{ + long v = sysconf(_SC_CLK_TCK); + if (v == -1) { + perror("sysconf(_SC_CLK_TCK)"); + exit(EXIT_FAILURE); + } + CLK_TCK = v; +} +#endif + + +long double +frealtime() +{ + long double result; +#ifdef _POSIX_TIMERS + struct timespec t; + if (clock_gettime(CLOCK_REALTIME, &t)==-1) { + perror("frealtime (clock_gettime)"); + exit(EXIT_FAILURE); + } + result = (long double)t.tv_sec + (long double)t.tv_nsec*(long double)1e-9; +#else + struct tms t; + clock_t c=times(&t); + if (c==(clock_t)-1) { + perror("frealtime (times)"); + exit(EXIT_FAILURE); + } + result = (long double)c/CLK_TCK; +#endif + assert(isnormal(result)); + assert(result > 0); + return result; +} + + +long double +fcputime() +{ + struct tms t; + clock_t c=times(&t); + if (c==(clock_t)-1) { + perror("fcputime (times)"); + exit(EXIT_FAILURE); + } + return ((long double)t.tms_utime+t.tms_stime)/CLK_TCK; +} + diff --git a/jtag/src/tap/cable.c b/jtag/src/tap/cable.c index fc0344ed..c1ed5682 100644 --- a/jtag/src/tap/cable.c +++ b/jtag/src/tap/cable.c @@ -28,7 +28,11 @@ #include #include #include +#include +#include +#include "fclock.h" +#include "jtag.h" #include "cable.h" extern cable_driver_t arcom_cable_driver; @@ -43,8 +47,6 @@ extern cable_driver_t triton_cable_driver; extern cable_driver_t wiggler_cable_driver; extern cable_driver_t wiggler2_cable_driver; -uint32_t frequency = 0; - cable_driver_t *cable_drivers[] = { &arcom_cable_driver, &byteblaster_cable_driver, @@ -102,17 +104,88 @@ cable_get_trst( cable_t *cable ) return cable->driver->get_trst( cable ); } +static uint32_t delay = 0; +static uint32_t frequency = 0; + +void +cable_set_frequency( cable_t *cable, uint32_t new_frequency ) +{ + if (new_frequency == 0) { + delay = 0; + frequency = 0; + } else { + const double tolerance = 0.1; + uint32_t loops; + + printf("requested frequency %u, now calibrating delay loop\n", new_frequency); + + if (delay == 0) { + delay = 1000; + loops = 10000; + } else { + loops = 3 * frequency; + } + + while (1) { + uint32_t i, new_delay; + long double start, end, real_frequency; + + start = frealtime(); + for (i = 0; i < loops; ++i) { + chain_clock(chain, 0, 0); + } + end = frealtime(); + + assert(end > start); + real_frequency = (long double)loops / (end - start); + printf("new real frequency %Lg, delay %u\n", + real_frequency, delay); + + loops = 3 * fmax(real_frequency, new_frequency); + new_delay = (long double)delay * real_frequency / new_frequency; + + if (real_frequency >= (1.0 - tolerance)*new_frequency) { + if (real_frequency <= (1.0 + tolerance)*new_frequency) { + break; + } + if (new_delay > delay) { + delay = new_delay; + } else { + delay++; + } + } else { + if (new_delay < delay) { + delay = new_delay; + } else { + delay--; + } + if (delay == 0) { + printf("operating without delay\n"); + break; + } + } + } + + frequency = new_frequency; + } +} + +uint32_t +cable_get_frequency( cable_t *cable ) +{ + return frequency; +} + void cable_wait( void ) { - useconds_t s; + int i; + volatile int j; - if (!frequency) + if (delay == 0) return; - s = 1000000 / frequency / 2; - if (s == 0) - s = 1; - - usleep( s ); + for (i = 0; i < delay; ++i) { + j = i; + } }