1 /*
2  * $Id$
3  *
4  * Copyright (C) 2003 ETC s.r.o.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19  * 02111-1307, USA.
20  *
21  * Written by Marcel Telka <marcel@telka.sk>, 2003.
22  *
23  */
24 
25 #include <sysdep.h>
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31 #include <math.h>
32 
33 #include <urjtag/cable.h>
34 #include <urjtag/parport.h>
35 #include <urjtag/chain.h>
36 #include <urjtag/fclock.h>
37 
38 #include "generic.h"
39 
40 #include <urjtag/cmd.h>
41 
42 static void
print_vector(urj_log_level_t ll,int len,char * vec)43 print_vector (urj_log_level_t ll, int len, char *vec)
44 {
45     int i;
46     for (i = 0; i < len; i++)
47         urj_log (ll, "%c", vec[i] ? '1' : '0');
48 }
49 
50 
51 void
urj_tap_cable_generic_disconnect(urj_cable_t * cable)52 urj_tap_cable_generic_disconnect (urj_cable_t *cable)
53 {
54     urj_tap_cable_done (cable);
55     urj_tap_chain_disconnect (cable->chain);
56     cable->chain = NULL;
57 }
58 
59 int
urj_tap_cable_generic_transfer(urj_cable_t * cable,int len,const char * in,char * out)60 urj_tap_cable_generic_transfer (urj_cable_t *cable, int len, const char *in,
61                                 char *out)
62 {
63     int i;
64 
65     if (out)
66         for (i = 0; i < len; i++)
67         {
68             out[i] = cable->driver->get_tdo (cable);
69             cable->driver->clock (cable, 0, in[i], 1);
70         }
71     else
72         for (i = 0; i < len; i++)
73         {
74             cable->driver->clock (cable, 0, in[i], 1);
75         }
76 
77     return i;
78 }
79 
80 int
urj_tap_cable_generic_get_signal(urj_cable_t * cable,urj_pod_sigsel_t sig)81 urj_tap_cable_generic_get_signal (urj_cable_t *cable, urj_pod_sigsel_t sig)
82 {
83     return (((PARAM_SIGNALS (cable)) & sig) != 0) ? 1 : 0;
84 }
85 
86 static int
do_one_queued_action(urj_cable_t * cable)87 do_one_queued_action (urj_cable_t *cable)
88 {
89     int i;
90 
91     urj_log (URJ_LOG_LEVEL_DEBUG, "do_one_queued\n");
92 
93     if ((i = urj_tap_cable_get_queue_item (cable, &cable->todo)) >= 0)
94     {
95         int j;
96 
97         if (cable->done.num_items >= cable->done.max_items)
98         {
99             if (cable->todo.data[i].action == URJ_TAP_CABLE_GET_TDO
100                 || cable->todo.data[i].action == URJ_TAP_CABLE_GET_SIGNAL
101                 || cable->todo.data[i].action == URJ_TAP_CABLE_TRANSFER)
102             {
103                 urj_error_set (URJ_ERROR_OUT_OF_BOUNDS,
104                                _("No space in cable activity results queue"));
105                 urj_tap_cable_purge_queue (&cable->done, 1);
106                 /* @@@@ RFHH shouldn't we bail out? */
107             }
108         }
109 
110         switch (cable->todo.data[i].action)
111         {
112         case URJ_TAP_CABLE_CLOCK:
113             cable->driver->clock (cable,
114                                   cable->todo.data[i].arg.clock.tms,
115                                   cable->todo.data[i].arg.clock.tdi,
116                                   cable->todo.data[i].arg.clock.n);
117             break;
118         case URJ_TAP_CABLE_SET_SIGNAL:
119             urj_tap_cable_set_signal (cable,
120                                       cable->todo.data[i].arg.value.sig,
121                                       cable->todo.data[i].arg.value.val);
122             break;
123         case URJ_TAP_CABLE_TRANSFER:
124             {
125                 /* @@@@ RFHH check result */
126                 int r = cable->driver->transfer (cable,
127                                                  cable->todo.data[i].arg.
128                                                  transfer.len,
129                                                  cable->todo.data[i].arg.
130                                                  transfer.in,
131                                                  cable->todo.data[i].arg.
132                                                  transfer.out);
133 
134                 free (cable->todo.data[i].arg.transfer.in);
135                 if (cable->todo.data[i].arg.transfer.out != NULL)
136                 {
137                     /* @@@@ RFHH check result */
138                     j = urj_tap_cable_add_queue_item (cable, &cable->done);
139                     urj_log (URJ_LOG_LEVEL_DEBUG,
140                              "add result from transfer to %p.%d (out=%p)\n",
141                              &cable->done, j,
142                              cable->todo.data[i].arg.transfer.out);
143                     cable->done.data[j].action = URJ_TAP_CABLE_TRANSFER;
144                     cable->done.data[j].arg.xferred.len =
145                         cable->todo.data[i].arg.transfer.len;
146                     cable->done.data[j].arg.xferred.res = r;
147                     cable->done.data[j].arg.xferred.out =
148                         cable->todo.data[i].arg.transfer.out;
149                 }
150                 break;
151             }
152         case URJ_TAP_CABLE_GET_TDO:
153             /* @@@@ RFHH check result */
154             j = urj_tap_cable_add_queue_item (cable, &cable->done);
155             urj_log (URJ_LOG_LEVEL_DEBUG,
156                      "add result from get_tdo to %p.%d\n", &cable->done, j);
157             cable->done.data[j].action = URJ_TAP_CABLE_GET_TDO;
158             cable->done.data[j].arg.value.val =
159                 cable->driver->get_tdo (cable);
160             break;
161         case URJ_TAP_CABLE_GET_SIGNAL:
162             /* @@@@ RFHH check result */
163             j = urj_tap_cable_add_queue_item (cable, &cable->done);
164             urj_log (URJ_LOG_LEVEL_DEBUG,
165                      "add result from get_signal to %p.%d\n", &cable->done,
166                      j);
167             cable->done.data[j].action = URJ_TAP_CABLE_GET_SIGNAL;
168             cable->done.data[j].arg.value.sig =
169                 cable->todo.data[i].arg.value.sig;
170             cable->done.data[j].arg.value.val =
171                 cable->driver->get_signal (cable,
172                                            cable->todo.data[i].arg.value.sig);
173             break;
174         case URJ_TAP_CABLE_CLOCK_COMPACT: /* Turn off GCC warning */
175             break;
176         }
177         urj_log (URJ_LOG_LEVEL_DEBUG, "do_one_queued done\n");
178 
179         return 1;
180     }
181     urj_log (URJ_LOG_LEVEL_DEBUG, "do_one_queued abort\n");
182 
183     return 0;
184 }
185 
186 void
urj_tap_cable_generic_flush_one_by_one(urj_cable_t * cable,urj_cable_flush_amount_t how_much)187 urj_tap_cable_generic_flush_one_by_one (urj_cable_t *cable,
188                                         urj_cable_flush_amount_t how_much)
189 {
190     /* This will flush always, even if how_much == URJ_TAP_CABLE_OPTIONALLY,
191      * because there is no reason to let the queue grow */
192 
193     while (do_one_queued_action (cable));
194 }
195 
196 void
urj_tap_cable_generic_flush_using_transfer(urj_cable_t * cable,urj_cable_flush_amount_t how_much)197 urj_tap_cable_generic_flush_using_transfer (urj_cable_t *cable,
198                                             urj_cable_flush_amount_t how_much)
199 {
200     int i, j, n;
201     char *in, *out;
202 
203     if (how_much == URJ_TAP_CABLE_OPTIONALLY)
204         return;
205 
206     if (cable->todo.num_items == 0)
207         return;
208 
209     do
210     {
211         int r, bits = 0, tdo = 0, savbits;
212 
213         urj_log (URJ_LOG_LEVEL_DETAIL, "flush(%d)\n", cable->todo.num_items);
214 
215         /* Combine as much as possible into transfer() */
216 
217         /* Step 1: Count clocks. Can do only clock(TMS=0), get_tdo, transfer */
218 
219         for (i = cable->todo.next_item, n = 0; n < cable->todo.num_items; n++)
220         {
221             if (cable->todo.data[i].action != URJ_TAP_CABLE_CLOCK
222                 && cable->todo.data[i].action != URJ_TAP_CABLE_TRANSFER
223                 && cable->todo.data[i].action != URJ_TAP_CABLE_GET_TDO)
224             {
225                 urj_log (URJ_LOG_LEVEL_DETAIL,
226                          "cutoff at n=%d because action unsuitable for transfer\n",
227                          n);
228                 break;
229             }
230             if (cable->todo.data[i].action == URJ_TAP_CABLE_CLOCK
231                 && cable->todo.data[i].arg.clock.tms != 0)
232             {
233                 urj_log (URJ_LOG_LEVEL_DETAIL,
234                          "cutoff at n=%d because clock.tms=1 is unsuitable for transfer\n",
235                          n);
236                 break;
237             }
238             if (cable->todo.data[i].action == URJ_TAP_CABLE_CLOCK)
239             {
240                 int k = cable->todo.data[i].arg.clock.n;
241                 urj_log (URJ_LOG_LEVEL_DETAIL, "%d clock(s)\n", k);
242                 bits += k;
243             }
244             else if (cable->todo.data[i].action == URJ_TAP_CABLE_TRANSFER)
245             {
246                 int k = cable->todo.data[i].arg.transfer.len;
247                 urj_log (URJ_LOG_LEVEL_DETAIL, "%d transfer\n", k);
248                 bits += k;
249             }
250             i++;
251             if (i >= cable->todo.max_items)
252                 i = 0;
253         }
254 
255         urj_log (URJ_LOG_LEVEL_DETAIL, "%d combined into one (%d bits)\n",
256                  n, bits);
257 
258         savbits = bits;
259 
260         if (bits == 0 || n <= 1)
261         {
262             do_one_queued_action (cable);
263         }
264         else
265         {
266             /* Step 2: Combine into single transfer. */
267 
268             in = malloc (bits);
269             out = malloc (bits);
270 
271             if (in == NULL || out == NULL)
272             {
273                 /* @@@@ RFHH free(NULL) is correct */
274                 if (in != NULL)
275                     free (in);
276                 if (out != NULL)
277                     free (out);
278                 urj_tap_cable_generic_flush_one_by_one (cable, how_much);
279                 break;
280             }
281 
282             for (j = 0, bits = 0, i = cable->todo.next_item; j < n; j++)
283             {
284                 if (cable->todo.data[i].action == URJ_TAP_CABLE_CLOCK)
285                 {
286                     int k;
287                     for (k = 0; k < cable->todo.data[i].arg.clock.n; k++)
288                         in[bits++] = cable->todo.data[i].arg.clock.tdi;
289                 }
290                 else if (cable->todo.data[i].action == URJ_TAP_CABLE_TRANSFER)
291                 {
292                     int len = cable->todo.data[i].arg.transfer.len;
293                     if (len > 0)
294                     {
295                         memcpy (in + bits,
296                                 cable->todo.data[i].arg.transfer.in, len);
297                         bits += len;
298                     }
299                 }
300                 i++;
301                 if (i >= cable->todo.max_items)
302                     i = 0;
303             }
304 
305             /* Step 3: Do the transfer */
306 
307             /* @@@@ RFHH check result */
308             r = cable->driver->transfer (cable, bits, in, out);
309             urj_log (URJ_LOG_LEVEL_DETAIL, "in: ");
310             print_vector (URJ_LOG_LEVEL_DETAIL, bits, in);
311             urj_log (URJ_LOG_LEVEL_DETAIL, "\n");
312             // @@@@ RFHH here always: out != NULL
313             if (out)
314             {
315                 urj_log (URJ_LOG_LEVEL_DETAIL, "out: ");
316                 print_vector (URJ_LOG_LEVEL_DETAIL, bits, out);
317                 urj_log (URJ_LOG_LEVEL_DETAIL, "\n");
318             }
319 
320             /* Step 4: Pick results from transfer */
321 
322             for (j = 0, bits = 0, i = cable->todo.next_item; j < n; j++)
323             {
324                 if (cable->todo.data[i].action == URJ_TAP_CABLE_CLOCK)
325                 {
326                     int k;
327                     for (k = 0; k < cable->todo.data[i].arg.clock.n; k++)
328                         tdo = out[bits++];
329                 }
330                 else if (cable->todo.data[i].action == URJ_TAP_CABLE_GET_TDO)
331                 {
332                     int c = urj_tap_cable_add_queue_item (cable,
333                                                           &cable->done);
334                     urj_log (URJ_LOG_LEVEL_DETAIL,
335                              "add result from transfer to %p.%d\n",
336                              &cable->done, c);
337                     cable->done.data[c].action = URJ_TAP_CABLE_GET_TDO;
338                     if (bits < savbits)
339                         tdo = out[bits];
340                     else
341                         tdo = cable->driver->get_tdo(cable);
342                     cable->done.data[c].arg.value.val = tdo;
343                 }
344                 else if (cable->todo.data[i].action == URJ_TAP_CABLE_TRANSFER)
345                 {
346                     char *p = cable->todo.data[i].arg.transfer.out;
347                     int len = cable->todo.data[i].arg.transfer.len;
348                     free (cable->todo.data[i].arg.transfer.in);
349                     if (p != NULL)
350                     {
351                         int c = urj_tap_cable_add_queue_item (cable,
352                                                               &cable->done);
353                         urj_log (URJ_LOG_LEVEL_DETAIL,
354                                  "add result from transfer to %p.%d\n",
355                                  &cable->done, c);
356                         cable->done.data[c].action = URJ_TAP_CABLE_TRANSFER;
357                         cable->done.data[c].arg.xferred.len = len;
358                         cable->done.data[c].arg.xferred.res = r;
359                         cable->done.data[c].arg.xferred.out = p;
360                         if (len > 0)
361                             memcpy (p, out + bits, len);
362                     }
363                     if (len > 0)
364                         bits += len;
365                     if (bits > 0)
366                         tdo = out[bits - 1];
367                 }
368                 i++;
369                 if (i >= cable->todo.max_items)
370                     i = 0;
371             }
372 
373             cable->todo.next_item = i;
374             cable->todo.num_items -= n;
375 
376             free (in);
377             free (out);
378         }
379     }
380     while (cable->todo.num_items > 0);
381 }
382 
383 void
urj_tap_cable_generic_set_frequency(urj_cable_t * cable,uint32_t new_frequency)384 urj_tap_cable_generic_set_frequency (urj_cable_t *cable,
385                                      uint32_t new_frequency)
386 {
387     if (new_frequency == 0)
388     {
389         cable->delay = 0;
390         cable->frequency = 0;
391     }
392     else
393     {
394         const double tolerance = 0.1;
395         uint32_t loops = 2048;
396         uint32_t delay = cable->delay;
397         uint32_t frequency = cable->frequency;
398 
399         if (new_frequency > (1.0 - tolerance) * frequency &&
400             new_frequency < (1.0 + tolerance) * frequency)
401             return;
402 
403         urj_log (URJ_LOG_LEVEL_NORMAL,
404                  "requested frequency %lu, now calibrating delay loop\n",
405                 (long unsigned) new_frequency);
406 
407         while (1)
408         {
409             uint32_t i, new_delay;
410             long double start, end, real_frequency;
411 
412             cable->delay = delay;
413             start = urj_lib_frealtime ();
414             for (i = 0; i < loops; ++i)
415             {
416                 cable->driver->clock (cable, 0, 0, 1);
417             }
418             end = urj_lib_frealtime ();
419 
420             if (end < start)
421             {
422                 urj_log (URJ_LOG_LEVEL_ERROR,
423                          _("calibration error, wall clock is not monotonically increasing\n"));
424                 break;
425             }
426             if (end == start)
427             {
428                 /* retry with higher loop count
429                    if the timer is not fine grained enough */
430                 loops *= 2;
431                 continue;
432             }
433             real_frequency = (long double) loops / (end - start);
434             urj_log (URJ_LOG_LEVEL_NORMAL,
435                      "new real frequency %Lg, delay %lu\n",
436                      real_frequency, (long unsigned) delay);
437 
438             new_delay = (long double) delay *real_frequency / new_frequency;
439 
440             if (real_frequency >= (1.0 - tolerance) * new_frequency)
441             {
442                 if (real_frequency <= (1.0 + tolerance) * new_frequency)
443                 {
444                     frequency = real_frequency;
445                     break;
446                 }
447                 if (new_delay > delay)
448                 {
449                     delay = new_delay;
450                 }
451                 else
452                 {
453                     delay++;
454                 }
455 
456             }
457             else
458             {
459                 if (delay == 0)
460                 {
461                     urj_log (URJ_LOG_LEVEL_NORMAL, "operating without delay\n");
462                     frequency = real_frequency;
463                     break;
464                 }
465 
466                 if (new_delay < delay)
467                 {
468                     delay = new_delay;
469                 }
470                 else
471                 {
472                     if (delay > 0)
473                         delay--;
474                 }
475             }
476         }
477 
478         urj_log (URJ_LOG_LEVEL_NORMAL, "done\n");
479 
480         cable->delay = delay;
481         cable->frequency = frequency;
482     }
483 }
484