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