origen_jtag 0.22.2 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/config/application.rb +65 -65
- data/config/boot.rb +24 -24
- data/config/commands.rb +137 -130
- data/config/version.rb +7 -7
- data/lib/origen_jtag/driver.rb +824 -708
- data/lib/origen_jtag/tap_controller.rb +385 -386
- data/lib/origen_jtag.rb +13 -13
- data/lib/origen_jtag_dev/new_style.rb +113 -113
- data/lib/origen_jtag_dev/serial.rb +24 -24
- data/lib/origen_jtag_dev/top_level.rb +94 -94
- data/pattern/chained_devices_test.rb +48 -0
- data/pattern/full_reg_ovly_cap.rb +11 -11
- data/pattern/global_label_test.rb +12 -12
- data/pattern/jtag_workout.rb +230 -230
- data/pattern/rww_test.rb +25 -25
- data/pattern/two_port.rb +49 -49
- data/templates/web/index.md.erb +305 -259
- data/templates/web/layouts/_basic.html.erb +16 -16
- data/templates/web/legacy.md.erb +43 -43
- data/templates/web/partials/_navbar.html.erb +22 -22
- data/templates/web/release_notes.md.erb +5 -5
- metadata +8 -9
- data/pattern/full_reg_subr_overlay.rb +0 -26
- data/pattern/overlay_subr.rb +0 -56
data/lib/origen_jtag/driver.rb
CHANGED
|
@@ -1,708 +1,824 @@
|
|
|
1
|
-
module OrigenJTAG
|
|
2
|
-
# This driver provides methods to read and write from a JTAG instruction
|
|
3
|
-
# and data registers.
|
|
4
|
-
#
|
|
5
|
-
# Low level methods are also provided for fine control of the TAP Controller
|
|
6
|
-
# state machine via the TAPController module.
|
|
7
|
-
#
|
|
8
|
-
# To use this driver the parent model must define the following pins (an alias is fine):
|
|
9
|
-
# :tck
|
|
10
|
-
# :tdi
|
|
11
|
-
# :tdo
|
|
12
|
-
# :tms
|
|
13
|
-
class Driver
|
|
14
|
-
REQUIRED_PINS = [:tck, :tdi, :tdo, :tms]
|
|
15
|
-
|
|
16
|
-
include Origen::Model
|
|
17
|
-
include TAPController
|
|
18
|
-
# include Origen::Registers
|
|
19
|
-
|
|
20
|
-
# Returns the object that instantiated the JTAG
|
|
21
|
-
attr_reader :owner
|
|
22
|
-
|
|
23
|
-
# Returns the current value in the instruction register
|
|
24
|
-
attr_reader :ir_value
|
|
25
|
-
|
|
26
|
-
# The number of cycles for one clock pulse, assumes 50% duty cycle. Uses tester non-return format to spread TCK across multiple cycles.
|
|
27
|
-
# e.g. @tck_multiple = 2, @tck_format = :rh, means one cycle with Tck low (non-return), one with Tck high (NR)
|
|
28
|
-
# @tck_multiple = 4, @tck_format = :rl, means 2 cycles with Tck high (NR), 2 with Tck low (NR)
|
|
29
|
-
attr_accessor :tck_multiple
|
|
30
|
-
alias_method :tclk_multiple, :tck_multiple
|
|
31
|
-
alias_method :tclk_multiple=, :tck_multiple=
|
|
32
|
-
|
|
33
|
-
# Wave/timing format of the JTAG clock: :rh (ReturnHigh) or :rl (ReturnLo), :rh is the default
|
|
34
|
-
attr_accessor :tck_format
|
|
35
|
-
alias_method :tclk_format, :tck_format
|
|
36
|
-
alias_method :tclk_format=, :tck_format=
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
attr_accessor :tdo_store_cycle
|
|
40
|
-
|
|
41
|
-
# Set true to print out debug comments about all state transitions
|
|
42
|
-
attr_accessor :verbose
|
|
43
|
-
alias_method :verbose?, :verbose
|
|
44
|
-
|
|
45
|
-
# Log all state changes in pattern comments, false by default
|
|
46
|
-
attr_accessor :log_state_changes
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
#
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
#
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
#
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
#
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
#
|
|
150
|
-
#
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
#
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
#
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
@next_data_vector_to_be_stored =
|
|
333
|
-
|
|
334
|
-
if i
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
end
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
if
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
#
|
|
508
|
-
#
|
|
509
|
-
#
|
|
510
|
-
#
|
|
511
|
-
#
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
end
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
#
|
|
581
|
-
#
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
1
|
+
module OrigenJTAG
|
|
2
|
+
# This driver provides methods to read and write from a JTAG instruction
|
|
3
|
+
# and data registers.
|
|
4
|
+
#
|
|
5
|
+
# Low level methods are also provided for fine control of the TAP Controller
|
|
6
|
+
# state machine via the TAPController module.
|
|
7
|
+
#
|
|
8
|
+
# To use this driver the parent model must define the following pins (an alias is fine):
|
|
9
|
+
# :tck
|
|
10
|
+
# :tdi
|
|
11
|
+
# :tdo
|
|
12
|
+
# :tms
|
|
13
|
+
class Driver
|
|
14
|
+
REQUIRED_PINS = [:tck, :tdi, :tdo, :tms]
|
|
15
|
+
|
|
16
|
+
include Origen::Model
|
|
17
|
+
include TAPController
|
|
18
|
+
# include Origen::Registers
|
|
19
|
+
|
|
20
|
+
# Returns the object that instantiated the JTAG
|
|
21
|
+
attr_reader :owner
|
|
22
|
+
|
|
23
|
+
# Returns the current value in the instruction register
|
|
24
|
+
attr_reader :ir_value
|
|
25
|
+
|
|
26
|
+
# The number of cycles for one clock pulse, assumes 50% duty cycle. Uses tester non-return format to spread TCK across multiple cycles.
|
|
27
|
+
# e.g. @tck_multiple = 2, @tck_format = :rh, means one cycle with Tck low (non-return), one with Tck high (NR)
|
|
28
|
+
# @tck_multiple = 4, @tck_format = :rl, means 2 cycles with Tck high (NR), 2 with Tck low (NR)
|
|
29
|
+
attr_accessor :tck_multiple
|
|
30
|
+
alias_method :tclk_multiple, :tck_multiple
|
|
31
|
+
alias_method :tclk_multiple=, :tck_multiple=
|
|
32
|
+
|
|
33
|
+
# Wave/timing format of the JTAG clock: :rh (ReturnHigh) or :rl (ReturnLo), :rh is the default
|
|
34
|
+
attr_accessor :tck_format
|
|
35
|
+
alias_method :tclk_format, :tck_format
|
|
36
|
+
alias_method :tclk_format=, :tck_format=
|
|
37
|
+
|
|
38
|
+
attr_reader :tdo_strobe
|
|
39
|
+
attr_accessor :tdo_store_cycle
|
|
40
|
+
|
|
41
|
+
# Set true to print out debug comments about all state transitions
|
|
42
|
+
attr_accessor :verbose
|
|
43
|
+
alias_method :verbose?, :verbose
|
|
44
|
+
|
|
45
|
+
# Log all state changes in pattern comments, false by default
|
|
46
|
+
attr_accessor :log_state_changes
|
|
47
|
+
|
|
48
|
+
# number of additional IR bits to add when chaining multiple devices, these additional bits are added to the MSB side
|
|
49
|
+
attr_reader :chained_ir_msb_length
|
|
50
|
+
|
|
51
|
+
# by default, the chained IR data is all zeros, this value overrides
|
|
52
|
+
attr_accessor :chained_ir_msb_data
|
|
53
|
+
|
|
54
|
+
# number of additional IR bits to add when chaining multiple devices, these additional bits are added to the LSB side
|
|
55
|
+
attr_reader :chained_ir_lsb_length
|
|
56
|
+
|
|
57
|
+
# by default, the chained IR data is all zeros, this value overrides
|
|
58
|
+
attr_accessor :chained_ir_lsb_data
|
|
59
|
+
|
|
60
|
+
# number of additional DR bits to add when chaining multiple devices, these additional bits are added to the MSB side
|
|
61
|
+
attr_reader :chained_dr_msb_length
|
|
62
|
+
|
|
63
|
+
# by default, the chained DR data is all zeros, this value overrides
|
|
64
|
+
attr_accessor :chained_dr_msb_data
|
|
65
|
+
|
|
66
|
+
# number of additional DR bits to add when chaining multiple devices, these additional bits are added to the LSB side
|
|
67
|
+
attr_reader :chained_dr_lsb_length
|
|
68
|
+
|
|
69
|
+
# by default, the chained DR data is all zeros, this value overrides
|
|
70
|
+
attr_accessor :chained_dr_lsb_data
|
|
71
|
+
|
|
72
|
+
def initialize(owner, options = {})
|
|
73
|
+
if owner.is_a?(Hash)
|
|
74
|
+
@owner = parent
|
|
75
|
+
options = owner
|
|
76
|
+
else
|
|
77
|
+
@owner = owner
|
|
78
|
+
end
|
|
79
|
+
# The parent can configure JTAG settings by defining this constant
|
|
80
|
+
if defined?(owner.class::JTAG_CONFIG)
|
|
81
|
+
options = owner.class::JTAG_CONFIG.merge(options)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
@cycle_callback = options[:cycle_callback]
|
|
85
|
+
@given_options = options.dup # Save these for later use in the pins method
|
|
86
|
+
|
|
87
|
+
# Fallback defaults
|
|
88
|
+
options = {
|
|
89
|
+
verbose: false,
|
|
90
|
+
tdo_store_cycle: 0, # store vector cycle within TCK (i.e. when to indicate to tester to store vector within TCK cycle. 0 is first vector, 1 is second, etc.)
|
|
91
|
+
# NOTE: only when user indicates to store TDO, which will mean we don't care the 1 or 0 value on TDO (overriding effectively :tdo_strobe option above)
|
|
92
|
+
init_state: :unknown
|
|
93
|
+
}.merge(options)
|
|
94
|
+
|
|
95
|
+
init_tap_controller(options)
|
|
96
|
+
|
|
97
|
+
@verbose = options[:verbose]
|
|
98
|
+
@ir_value = :unknown
|
|
99
|
+
@tck_format = options[:tck_format] || options[:tclk_format] || :rh
|
|
100
|
+
@tck_multiple = options[:tck_multiple] || options[:tclk_multiple] || 1
|
|
101
|
+
self.tdo_strobe = options[:tdo_strobe] || :tck_high
|
|
102
|
+
@tdo_store_cycle = options[:tdo_store_cycle]
|
|
103
|
+
@state = options[:init_state]
|
|
104
|
+
@log_state_changes = options[:log_state_changes] || false
|
|
105
|
+
if options[:tck_vals] || options[:tclk_vals]
|
|
106
|
+
@tck_vals = options[:tck_vals] || options[:tclk_vals]
|
|
107
|
+
unless @tck_vals.is_a?(Hash) && @tck_vals.key?(:on) && @tck_vals.key?(:off)
|
|
108
|
+
fail "When specifying TCK values, you must supply a hash with both :on and :off keys, e.g. tck_vals: { on: 'P', off: 0 }"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
if @cycle_callback && @tck_multiple != 1
|
|
112
|
+
fail 'A cycle_callback can only be used with a tck_multiple setting of 1'
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
@chained_ir_msb_length = options[:chained_ir_msb_length]
|
|
116
|
+
@chained_ir_msb_data = options[:chained_ir_msb_data] || 0
|
|
117
|
+
@chained_ir_lsb_length = options[:chained_ir_lsb_length]
|
|
118
|
+
@chained_ir_lsb_data = options[:chained_ir_lsb_data] || 0
|
|
119
|
+
@chained_dr_msb_length = options[:chained_dr_msb_length]
|
|
120
|
+
@chained_dr_msb_data = options[:chained_dr_msb_data] || 0
|
|
121
|
+
@chained_dr_lsb_length = options[:chained_dr_lsb_length]
|
|
122
|
+
@chained_dr_lsb_data = options[:chained_dr_lsb_data] || 0
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# number of additional IR bits to add when chaining multiple devices, these additional bits are added to the MSB side
|
|
126
|
+
def chained_ir_msb_length=(val)
|
|
127
|
+
@chained_ir_msb_length = val.to_i
|
|
128
|
+
@chained_ir_msb_length = nil if @chained_ir_msb_length <= 0
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# number of additional IR bits to add when chaining multiple devices, these additional bits are added to the LSB side
|
|
132
|
+
def chained_ir_lsb_length=(val)
|
|
133
|
+
@chained_ir_lsb_length = val.to_i
|
|
134
|
+
@chained_ir_lsb_length = nil if @chained_ir_lsb_length <= 0
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# number of additional DR bits to add when chaining multiple devices, these additional bits are added to the MSB side
|
|
138
|
+
def chained_dr_msb_length=(val)
|
|
139
|
+
@chained_dr_msb_length = val.to_i
|
|
140
|
+
@chained_dr_msb_length = nil if @chained_dr_msb_length <= 0
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# number of additional DR bits to add when chaining multiple devices, these additional bits are added to the LSB side
|
|
144
|
+
def chained_dr_lsb_length=(val)
|
|
145
|
+
@chained_dr_lsb_length = val.to_i
|
|
146
|
+
@chained_dr_lsb_length = nil if @chained_dr_lsb_length <= 0
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# when using multiple cycles for TCK, set when to strobe for TDO, options include:
|
|
150
|
+
# :tck_high - strobe TDO only when TCK is high (Default)
|
|
151
|
+
# :tck_low - strobe TDO only when TCK is low
|
|
152
|
+
# :tck_all - strobe TDO throughout TCK cycle
|
|
153
|
+
def tdo_strobe=(val)
|
|
154
|
+
case val
|
|
155
|
+
when :tck_high, :tclk_high
|
|
156
|
+
@tdo_strobe = :tck_high
|
|
157
|
+
when :tck_low, :tclk_low
|
|
158
|
+
@tdo_strobe = :tck_low
|
|
159
|
+
when :tck_all, :tclk_all
|
|
160
|
+
@tdo_strobe = :tck_all
|
|
161
|
+
else
|
|
162
|
+
fail 'tdo_strobe must be set to one of: :tck_high, :tck_low or :tck_all'
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# When true it means that the application is dealing with how to handle the 4 JTAG signals for each JTAG cycle.
|
|
167
|
+
# In that case this driver calculates what state the 4 pins should be in each signal and then calls back to the
|
|
168
|
+
# application with that information and it is up to the application to decide what to do with that information
|
|
169
|
+
# and when/if to generate tester cycles.
|
|
170
|
+
def cycle_callback?
|
|
171
|
+
!!@cycle_callback
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Shift data into the TDI pin or out of the TDO pin.
|
|
175
|
+
#
|
|
176
|
+
# There is no TAP controller state checking or handling here, it just
|
|
177
|
+
# shifts some data directly into the pattern, so it is assumed that some
|
|
178
|
+
# higher level logic is co-ordinating the TAP Controller.
|
|
179
|
+
#
|
|
180
|
+
# Most applications should not call this method directly and should instead
|
|
181
|
+
# use the pre-packaged read/write_dr/ir methods.
|
|
182
|
+
# However it is provided as a public API for the corner cases like generating
|
|
183
|
+
# an overlay subroutine pattern where it would be necessary to generate some JTAG
|
|
184
|
+
# vectors outwith the normal state controller wrapper.
|
|
185
|
+
#
|
|
186
|
+
# @param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
|
|
187
|
+
# Value to be shifted. If a reg/bit collection is supplied this can be pre-marked for
|
|
188
|
+
# read, store or overlay and which will result in the requested action being applied to
|
|
189
|
+
# the cycles corresponding to those bits only (don't care cycles will be generated for the others).
|
|
190
|
+
# @param [Hash] options Options to customize the operation
|
|
191
|
+
# @option options [Integer] :size The number of bits to shift. This is optional
|
|
192
|
+
# when supplying a register or bit collection in which case the size will be derived from
|
|
193
|
+
# the number of bits supplied. If this option is supplied then it will override
|
|
194
|
+
# the size derived from the bits. If the size is greater than the number of bits
|
|
195
|
+
# provided then the additional space will be padded by 0s or don't cares as appropriate.
|
|
196
|
+
# @option options [Boolean] :read (false) When true the given value will be compared on the TDO pin
|
|
197
|
+
# instead of being shifted into the TDI pin. In the case of a register object being provided
|
|
198
|
+
# only those bits that are actually marked for read will be compared.
|
|
199
|
+
# @option options [Boolean] :cycle_last (false) Normally the last data bit is applied to the
|
|
200
|
+
# pins but not cycled, this is to integrate with the TAPController which usually
|
|
201
|
+
# requires that the TMS value is also changed on the last data bit. To override this
|
|
202
|
+
# default behavior and force a cycle for the last data bit set this to true.
|
|
203
|
+
# @option options [Boolean] :includes_last_bit (true) When true the TMS pin will be driven
|
|
204
|
+
# to 1 on the last cycle of the shift if :cycle_last has been specified. To override this
|
|
205
|
+
# and keep TMS low on the last cycle set this to false. One reason for doing this would be
|
|
206
|
+
# if generating some subroutine vectors which only represented a partial section of a shift
|
|
207
|
+
# operation.
|
|
208
|
+
def shift(reg_or_val, options = {})
|
|
209
|
+
options = {
|
|
210
|
+
read: false,
|
|
211
|
+
cycle_last: false,
|
|
212
|
+
includes_last_bit: true,
|
|
213
|
+
no_subr: false # do not use subroutine for any overlay
|
|
214
|
+
}.merge(options)
|
|
215
|
+
|
|
216
|
+
# save compression state for restoring afterwards
|
|
217
|
+
compression_on = !Origen.tester.dont_compress
|
|
218
|
+
|
|
219
|
+
# clean incoming data
|
|
220
|
+
size = extract_size(reg_or_val, options)
|
|
221
|
+
tdi_reg = extract_shift_in_data(reg_or_val, size, options)
|
|
222
|
+
tdo_reg = extract_shift_out_data(reg_or_val, size, options)
|
|
223
|
+
global_ovl, ovl_reg = extract_overlay_data(reg_or_val, size, options)
|
|
224
|
+
|
|
225
|
+
# let the tester handle overlay if possible
|
|
226
|
+
unless tester.respond_to?(:source_memory)
|
|
227
|
+
# tester does not support direct labels, so can't do
|
|
228
|
+
if options[:no_subr] && !$tester.respond_to?('label')
|
|
229
|
+
cc 'This tester does not support use of labels, cannot do no_subr option as requested'
|
|
230
|
+
cc ' going with subroutine overlay instead'
|
|
231
|
+
options[:no_subr] = false
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# insert global label if specified
|
|
235
|
+
if global_ovl
|
|
236
|
+
if $tester.respond_to?('label')
|
|
237
|
+
$tester.label(global_ovl, true)
|
|
238
|
+
else
|
|
239
|
+
cc "Unsupported global label: #{global_ovl}"
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end # of let tester handle overlay if possible
|
|
243
|
+
|
|
244
|
+
# loop through any LSB appended bits
|
|
245
|
+
if options[:tdi_lsb_append_size]
|
|
246
|
+
# tdo is always don't care for appended bits
|
|
247
|
+
action :tdo, :dont_care
|
|
248
|
+
cc "appending #{options[:tdi_lsb_append_size]} LSB bits"
|
|
249
|
+
options[:tdi_lsb_append_size].times do |i|
|
|
250
|
+
action :tdi, :drive, options[:tdi_lsb_append_data][i]
|
|
251
|
+
tck_cycle { cycle }
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# loop through each data bit
|
|
256
|
+
last_overlay_label = ''
|
|
257
|
+
size.times do |i|
|
|
258
|
+
store_tdo_this_tck = false
|
|
259
|
+
|
|
260
|
+
# Set up pin actions for bit transaction (tck cycle)
|
|
261
|
+
|
|
262
|
+
# TDI
|
|
263
|
+
action :tdi, :drive, tdi_reg[i]
|
|
264
|
+
|
|
265
|
+
# TDO
|
|
266
|
+
action :tdo, :dont_care # default setting
|
|
267
|
+
if tdo_reg[i]
|
|
268
|
+
if tdo_reg[i].is_to_be_stored? # store
|
|
269
|
+
store_tdo_this_tck = true
|
|
270
|
+
action :tdo, :dont_care if Origen.tester.j750?
|
|
271
|
+
elsif tdo_reg[i].is_to_be_read? # compare/assert
|
|
272
|
+
action :tdo, :assert, tdo_reg[i], meta: { position: i }
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# TMS
|
|
277
|
+
action :tms, :drive, 0
|
|
278
|
+
|
|
279
|
+
# let tester handle overlay if implemented
|
|
280
|
+
overlay_options = {}
|
|
281
|
+
if tester.respond_to?(:source_memory) && !cycle_callback?
|
|
282
|
+
if ovl_reg[i] && ovl_reg[i].has_overlay? && !Origen.mode.simulation?
|
|
283
|
+
overlay_options[:pins] = pins[:tdi]
|
|
284
|
+
if global_ovl
|
|
285
|
+
overlay_options[:overlay_str] = global_ovl
|
|
286
|
+
else
|
|
287
|
+
overlay_options[:overlay_str] = ovl_reg[i].overlay_str
|
|
288
|
+
end
|
|
289
|
+
if options[:no_subr] || global_ovl
|
|
290
|
+
if global_ovl
|
|
291
|
+
overlay_options[:overlay_style] = :global_label
|
|
292
|
+
else
|
|
293
|
+
overlay_options[:overlay_style] = :label
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
tester_subr_overlay = !(options[:no_subr] || global_ovl) && tester.overlay_style == :subroutine
|
|
297
|
+
action :tdi, :drive, 0 if tester_subr_overlay
|
|
298
|
+
action :tdo, :assert, tdo_reg[i], meta: { position: i } unless tester_subr_overlay || !options[:read]
|
|
299
|
+
# Force the last bit to be shifted from this method if overlay requested on the last bit
|
|
300
|
+
options[:cycle_last] = true if i == size - 1
|
|
301
|
+
end
|
|
302
|
+
else
|
|
303
|
+
# Overlay - reconfigure pin action for overlay if necessary
|
|
304
|
+
if ovl_reg[i] && ovl_reg[i].has_overlay? && !Origen.mode.simulation?
|
|
305
|
+
if options[:no_subr]
|
|
306
|
+
Origen.tester.dont_compress = true
|
|
307
|
+
if ovl_reg[i].overlay_str != last_overlay_label
|
|
308
|
+
$tester.label(ovl_reg[i].overlay_str)
|
|
309
|
+
last_overlay_label = ovl_reg[i].overlay_str
|
|
310
|
+
end
|
|
311
|
+
action :tdo, :assert, tdo_reg[i], meta: { position: i } if options[:read]
|
|
312
|
+
else
|
|
313
|
+
action :tdi, :drive, 0
|
|
314
|
+
call_subroutine = ovl_reg[i].overlay_str
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end # of let tester handle overlay
|
|
318
|
+
|
|
319
|
+
# With JTAG pin actions queued up, use block call to tck_cycle to
|
|
320
|
+
# execute a single TCK period. Special handling of subroutines,
|
|
321
|
+
# case of last bit in shift, and store vector (within a multi-cycle
|
|
322
|
+
# tck config).
|
|
323
|
+
if (call_subroutine || tester_subr_overlay) && !options[:tdi_msb_append_size]
|
|
324
|
+
@last_data_vector_shifted = true
|
|
325
|
+
else
|
|
326
|
+
@last_data_vector_shifted = false
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
if call_subroutine
|
|
330
|
+
Origen.tester.call_subroutine(call_subroutine)
|
|
331
|
+
else
|
|
332
|
+
@next_data_vector_to_be_stored = false
|
|
333
|
+
# Don't latch the last bit, that will be done when leaving the state.
|
|
334
|
+
if i != size - 1 || options[:cycle_last] || options[:tdi_msb_append_size]
|
|
335
|
+
if i == size - 1 && options[:includes_last_bit] && !options[:tdi_msb_append_size]
|
|
336
|
+
unless tester_subr_overlay
|
|
337
|
+
action :tms, :drive, 1
|
|
338
|
+
@last_data_vector_shifted = true
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
tck_cycle do
|
|
342
|
+
if store_tdo_this_tck && @next_data_vector_to_be_stored
|
|
343
|
+
action :store
|
|
344
|
+
end
|
|
345
|
+
if overlay_options[:pins].nil? || cycle_callback?
|
|
346
|
+
cycle
|
|
347
|
+
else
|
|
348
|
+
cycle overlay: overlay_options
|
|
349
|
+
overlay_options[:change_data] = false # data change only on first cycle if overlay
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
pins[:tdo].dont_care unless cycle_callback?
|
|
353
|
+
else
|
|
354
|
+
@deferred_compare = true
|
|
355
|
+
@deferred_store = true if store_tdo_this_tck
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# loop through any MSB append bits
|
|
361
|
+
if options[:tdi_msb_append_size]
|
|
362
|
+
# last tdi bit was left applied, so tck cycle first, then apply new tdi and leave last one for state machine driver
|
|
363
|
+
options[:tdi_msb_append_size].times do |i|
|
|
364
|
+
if i == 0
|
|
365
|
+
cc "appending #{options[:tdi_msb_append_size]} MSB bits"
|
|
366
|
+
action :tdo, :dont_care
|
|
367
|
+
end
|
|
368
|
+
action :tdi, :drive, options[:tdi_msb_append_data][i]
|
|
369
|
+
tck_cycle { cycle } unless i == options[:tdi_msb_append_size] - 1
|
|
370
|
+
end
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
# Clear read and similar flags to reflect that the request has just been fulfilled
|
|
374
|
+
reg_or_val.clear_flags if reg_or_val.respond_to?(:clear_flags)
|
|
375
|
+
|
|
376
|
+
# put back compression if turned on above
|
|
377
|
+
Origen.tester.dont_compress = false if compression_on
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# Cycles the tester through one TCK cycle
|
|
381
|
+
# Adjusts for the TCK format and cycle span
|
|
382
|
+
# Assumes caller will drive pattern to tester
|
|
383
|
+
# via .drive or similar
|
|
384
|
+
def tck_cycle
|
|
385
|
+
if cycle_callback?
|
|
386
|
+
@next_data_vector_to_be_stored = @tdo_store_cycle
|
|
387
|
+
yield
|
|
388
|
+
else
|
|
389
|
+
case @tck_format
|
|
390
|
+
when :rh
|
|
391
|
+
tck_val = 0
|
|
392
|
+
when :rl
|
|
393
|
+
tck_val = 1
|
|
394
|
+
else
|
|
395
|
+
fail 'ERROR: Invalid Tclk timing format!'
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
# determine whether to mask TDO on first half cycle
|
|
399
|
+
mask_tdo_half0 = ((@tck_format == :rl) && (@tdo_strobe == :tck_low) && (@tck_multiple > 1)) ||
|
|
400
|
+
((@tck_format == :rh) && (@tdo_strobe == :tck_high) && (@tck_multiple > 1))
|
|
401
|
+
|
|
402
|
+
# determine whether to mask TDO on second half cycle
|
|
403
|
+
mask_tdo_half1 = ((@tck_format == :rl) && (@tdo_strobe == :tck_high) && (@tck_multiple > 1)) ||
|
|
404
|
+
((@tck_format == :rh) && (@tdo_strobe == :tck_low) && (@tck_multiple > 1))
|
|
405
|
+
|
|
406
|
+
# If TDO is already suspended (by an application) then don't do the
|
|
407
|
+
# suspends below since the resume will clear the application's suspend
|
|
408
|
+
tdo_already_suspended = !cycle_callback? && pins[:tdo].suspended? && !@tdo_suspended_by_driver
|
|
409
|
+
|
|
410
|
+
@tck_multiple.times do |i|
|
|
411
|
+
# 50% duty cycle if @tck_multiple is even, otherwise slightly off
|
|
412
|
+
|
|
413
|
+
@next_data_vector_to_be_stored = @tdo_store_cycle == i ? true : false
|
|
414
|
+
|
|
415
|
+
if i < (@tck_multiple + 1) / 2
|
|
416
|
+
# first half of cycle
|
|
417
|
+
pins[:tck].drive(@tck_vals ? @tck_vals[:on] : tck_val)
|
|
418
|
+
unless tdo_already_suspended
|
|
419
|
+
if mask_tdo_half0
|
|
420
|
+
@tdo_suspended_by_driver = true
|
|
421
|
+
pins[:tdo].suspend
|
|
422
|
+
else
|
|
423
|
+
@tdo_suspended_by_driver = false
|
|
424
|
+
pins[:tdo].resume
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
else
|
|
428
|
+
# second half of cycle
|
|
429
|
+
pins[:tck].drive(@tck_vals ? @tck_vals[:off] : (1 - tck_val))
|
|
430
|
+
unless tdo_already_suspended
|
|
431
|
+
if mask_tdo_half1
|
|
432
|
+
@tdo_suspended_by_driver = true
|
|
433
|
+
pins[:tdo].suspend
|
|
434
|
+
else
|
|
435
|
+
@tdo_suspended_by_driver = false
|
|
436
|
+
pins[:tdo].resume
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
yield
|
|
441
|
+
end
|
|
442
|
+
if @tdo_suspended_by_driver
|
|
443
|
+
@tdo_suspended_by_driver = false
|
|
444
|
+
pins[:tdo].resume
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
alias_method :tclk_cycle, :tck_cycle
|
|
449
|
+
|
|
450
|
+
# Applies the given value to the TMS pin and then
|
|
451
|
+
# cycles the tester for one TCK
|
|
452
|
+
#
|
|
453
|
+
# @param [Integer] val Value to drive on the TMS pin, 0 or 1
|
|
454
|
+
def tms!(val)
|
|
455
|
+
if @deferred_compare
|
|
456
|
+
@deferred_compare = nil
|
|
457
|
+
else
|
|
458
|
+
action :tdo, :dont_care
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
if @deferred_store
|
|
462
|
+
@deferred_store = nil
|
|
463
|
+
store_tdo_this_tck = true
|
|
464
|
+
else
|
|
465
|
+
store_tdo_this_tck = false
|
|
466
|
+
end
|
|
467
|
+
@next_data_vector_to_be_stored = false
|
|
468
|
+
|
|
469
|
+
tck_cycle do
|
|
470
|
+
if store_tdo_this_tck && @next_data_vector_to_be_stored
|
|
471
|
+
action :store
|
|
472
|
+
end
|
|
473
|
+
action :tms, :drive, val
|
|
474
|
+
cycle
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
# Write the given value, register or bit collection to the data register.
|
|
479
|
+
# This is a self contained method that will take care of the TAP controller
|
|
480
|
+
# state transitions, exiting with the TAP controller in Run-Test/Idle.
|
|
481
|
+
#
|
|
482
|
+
# @param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
|
|
483
|
+
# Value to be written. If a reg/bit collection is supplied this can be pre-marked for overlay.
|
|
484
|
+
# @param [Hash] options Options to customize the operation
|
|
485
|
+
# @option options [Integer] :size The number of bits to write. This is optional
|
|
486
|
+
# when supplying a register or bit collection in which case the size will be derived from
|
|
487
|
+
# the number of bits supplied. If this option is supplied then it will override
|
|
488
|
+
# the size derived from the bits. If the size is greater than the number of bits
|
|
489
|
+
# provided then the additional space will be padded by 0s.
|
|
490
|
+
# @option options [String] :msg By default will not make any comments directly here. Can pass
|
|
491
|
+
# a msg to be written out prior to shifting data.
|
|
492
|
+
def write_dr(reg_or_val, options = {})
|
|
493
|
+
options = options.merge(get_chained_in_data(:dr))
|
|
494
|
+
if Origen.tester.respond_to?(:write_dr)
|
|
495
|
+
Origen.tester.write_dr(reg_or_val, options)
|
|
496
|
+
else
|
|
497
|
+
if options[:msg]
|
|
498
|
+
cc "#{options[:msg]}\n"
|
|
499
|
+
end
|
|
500
|
+
val = reg_or_val.respond_to?(:data) ? reg_or_val.data : reg_or_val
|
|
501
|
+
shift_dr(options.merge(write: val.to_hex)) do
|
|
502
|
+
shift(reg_or_val, options)
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
# Read the given value, register or bit collection from the data register.
|
|
508
|
+
# This is a self contained method that will take care of the TAP controller
|
|
509
|
+
# state transitions, exiting with the TAP controller in Run-Test/Idle.
|
|
510
|
+
#
|
|
511
|
+
# @param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
|
|
512
|
+
# Value to be read. If a reg/bit collection is supplied this can be pre-marked for read in which
|
|
513
|
+
# case only the marked bits will be read and the vectors corresponding to the data from the non-read
|
|
514
|
+
# bits will be set to don't care. Similarly the bits can be pre-marked for store (capture) or
|
|
515
|
+
# overlay.
|
|
516
|
+
# @param [Hash] options Options to customize the operation
|
|
517
|
+
# @option options [Integer] :size The number of bits to read. This is optional
|
|
518
|
+
# when supplying a register or bit collection in which case the size will be derived from
|
|
519
|
+
# the number of bits supplied. If the size is supplied then it will override
|
|
520
|
+
# the size derived from the bits. If the size is greater than the number of bits
|
|
521
|
+
# provided then the additional space will be padded by don't care cycles.
|
|
522
|
+
# @option options [String] :msg By default will not make any comments directly here. Can pass
|
|
523
|
+
# a msg to be written out prior to shifting data.
|
|
524
|
+
def read_dr(reg_or_val, options = {})
|
|
525
|
+
options = options.merge(get_chained_in_data(:dr))
|
|
526
|
+
if Origen.tester.respond_to?(:read_dr)
|
|
527
|
+
Origen.tester.read_dr(reg_or_val, options)
|
|
528
|
+
else
|
|
529
|
+
options = {
|
|
530
|
+
read: true
|
|
531
|
+
}.merge(options)
|
|
532
|
+
if options[:msg]
|
|
533
|
+
cc "#{options[:msg]}\n"
|
|
534
|
+
end
|
|
535
|
+
shift_dr(options.merge(read: Origen::Utility.read_hex(reg_or_val))) do
|
|
536
|
+
shift(reg_or_val, options)
|
|
537
|
+
end
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
# Write the given value, register or bit collection to the instruction register.
|
|
542
|
+
# This is a self contained method that will take care of the TAP controller
|
|
543
|
+
# state transitions, exiting with the TAP controller in Run-Test/Idle.
|
|
544
|
+
#
|
|
545
|
+
# @param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
|
|
546
|
+
# Value to be written. If a reg/bit collection is supplied this can be pre-marked for overlay.
|
|
547
|
+
# @param [Hash] options Options to customize the operation
|
|
548
|
+
# @option options [Integer] :size The number of bits to write. This is optional
|
|
549
|
+
# when supplying a register or bit collection in which case the size will be derived from
|
|
550
|
+
# the number of bits supplied. If this option is supplied then it will override
|
|
551
|
+
# the size derived from the bits. If the size is greater than the number of bits
|
|
552
|
+
# provided then the additional space will be padded by 0s.
|
|
553
|
+
# @option options [Boolean] :force By default multiple calls to this method will not generate
|
|
554
|
+
# multiple writes. This is to allow wrapper algorithms to remain efficient yet not have to
|
|
555
|
+
# manually track the IR state (and in many cases this may be impossible due to multiple
|
|
556
|
+
# protocols using the same JTAG). To force a write regardless of what the driver thinks the IR
|
|
557
|
+
# contains set this to true.
|
|
558
|
+
# @option options [String] :msg By default will not make any comments directly here. Can pass
|
|
559
|
+
# a msg to be written out prior to shifting in IR data. Will not write comment only if write
|
|
560
|
+
# occurs.
|
|
561
|
+
def write_ir(reg_or_val, options = {})
|
|
562
|
+
options = options.merge(get_chained_in_data(:ir))
|
|
563
|
+
val = reg_or_val.respond_to?(:data) ? reg_or_val.data : reg_or_val
|
|
564
|
+
if val != ir_value || options[:force]
|
|
565
|
+
if options[:msg]
|
|
566
|
+
cc "#{options[:msg]}\n"
|
|
567
|
+
end
|
|
568
|
+
if Origen.tester.respond_to?(:write_ir)
|
|
569
|
+
Origen.tester.write_ir(reg_or_val, options)
|
|
570
|
+
else
|
|
571
|
+
shift_ir(options.merge(write: val.to_hex)) do
|
|
572
|
+
shift(reg_or_val, options)
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
@ir_value = val
|
|
576
|
+
end
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
# Read the given value, register or bit collection from the instruction register.
|
|
580
|
+
# This is a self contained method that will take care of the TAP controller
|
|
581
|
+
# state transitions, exiting with the TAP controller in Run-Test/Idle.
|
|
582
|
+
#
|
|
583
|
+
# @param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
|
|
584
|
+
# Value to be read. If a reg/bit collection is supplied this can be pre-marked for read in which
|
|
585
|
+
# case only the marked bits will be read and the vectors corresponding to the data from the non-read
|
|
586
|
+
# bits will be set to don't care. Similarly the bits can be pre-marked for store (capture) or
|
|
587
|
+
# overlay.
|
|
588
|
+
# @param [Hash] options Options to customize the operation
|
|
589
|
+
# @option options [Integer] :size The number of bits to read. This is optional
|
|
590
|
+
# when supplying a register or bit collection in which case the size will be derived from
|
|
591
|
+
# the number of bits supplied. If the size is supplied then it will override
|
|
592
|
+
# the size derived from the bits. If the size is greater than the number of bits
|
|
593
|
+
# provided then the additional space will be padded by don't care cycles.
|
|
594
|
+
# @option options [String] :msg By default will not make any comments directly here. Can pass
|
|
595
|
+
# a msg to be written out prior to shifting data.
|
|
596
|
+
def read_ir(reg_or_val, options = {})
|
|
597
|
+
options = options.merge(get_chained_in_data(:ir))
|
|
598
|
+
if Origen.tester.respond_to?(:read_ir)
|
|
599
|
+
Origen.tester.read_ir(reg_or_val, options)
|
|
600
|
+
else
|
|
601
|
+
options = {
|
|
602
|
+
read: true
|
|
603
|
+
}.merge(options)
|
|
604
|
+
if options[:msg]
|
|
605
|
+
cc "#{options[:msg]}\n"
|
|
606
|
+
end
|
|
607
|
+
shift_ir(options.merge(read: Origen::Utility.read_hex(reg_or_val))) do
|
|
608
|
+
shift(reg_or_val, options)
|
|
609
|
+
end
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
def apply_action(pin, actions)
|
|
614
|
+
actions.each do |operation|
|
|
615
|
+
method = operation.shift
|
|
616
|
+
pin.send(method, *operation) if method
|
|
617
|
+
end
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
private
|
|
621
|
+
|
|
622
|
+
def action(pin_id, *operations)
|
|
623
|
+
@actions ||= clear_actions
|
|
624
|
+
if pin_id == :store
|
|
625
|
+
@actions[:store] = true
|
|
626
|
+
else
|
|
627
|
+
fail "Unkown JTAG pin ID: #{pin_id}" unless @actions[pin_id]
|
|
628
|
+
|
|
629
|
+
@actions[pin_id] << operations
|
|
630
|
+
end
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
def cycle(options = {})
|
|
634
|
+
if @actions
|
|
635
|
+
if cycle_callback?
|
|
636
|
+
@owner.send(@cycle_callback, @actions, options)
|
|
637
|
+
else
|
|
638
|
+
apply_action(pins[:tms], @actions[:tms])
|
|
639
|
+
apply_action(pins[:tdi], @actions[:tdi])
|
|
640
|
+
apply_action(pins[:tdo], @actions[:tdo])
|
|
641
|
+
tester.store_next_cycle(pins[:tdo]) if @actions[:store]
|
|
642
|
+
tester.cycle(options)
|
|
643
|
+
end
|
|
644
|
+
clear_actions
|
|
645
|
+
end
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
def clear_actions
|
|
649
|
+
@actions = { tdi: [], tms: [], tdo: [], store: false }
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
# Return size of transaction. Options[:size] has priority and need not match the
|
|
653
|
+
# register size. Any mismatch will be handled by the api.
|
|
654
|
+
def extract_size(reg_or_val, options = {})
|
|
655
|
+
size = options[:size]
|
|
656
|
+
unless size
|
|
657
|
+
if reg_or_val.is_a?(Integer) || !reg_or_val.respond_to?(:size)
|
|
658
|
+
fail 'When suppling a value to JTAG::Driver#shift you must supply a :size in the options!'
|
|
659
|
+
else
|
|
660
|
+
size = reg_or_val.size
|
|
661
|
+
end
|
|
662
|
+
end
|
|
663
|
+
size
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
# Combine any legacy options into a single global overlay and create
|
|
667
|
+
# new bit collection to track any bit-wise overlays.
|
|
668
|
+
def extract_overlay_data(reg_or_val, size, options = {})
|
|
669
|
+
if reg_or_val.respond_to?(:data)
|
|
670
|
+
ovl = reg_or_val.dup
|
|
671
|
+
else
|
|
672
|
+
ovl = Reg.dummy(size)
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
if options[:overlay]
|
|
676
|
+
global = options[:overlay_label]
|
|
677
|
+
elsif options.key?(:arm_debug_overlay) # prob don't need this anymore
|
|
678
|
+
global = options[:arm_debug_overlay] # prob don't need this anymore
|
|
679
|
+
else
|
|
680
|
+
global = nil
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
[global, ovl]
|
|
684
|
+
end
|
|
685
|
+
|
|
686
|
+
# Create data that will be shifted in on TDI prior (MSB) to target device and
|
|
687
|
+
# after (LSB) when multiple devices are chained together
|
|
688
|
+
def get_chained_in_data(shift_type)
|
|
689
|
+
tdi_msb_append_size = nil
|
|
690
|
+
tdi_msb_append_data = 0
|
|
691
|
+
tdi_lsb_append_size = nil
|
|
692
|
+
tdi_lsb_append_data = 0
|
|
693
|
+
if shift_type == :ir
|
|
694
|
+
if @chained_ir_msb_length
|
|
695
|
+
tdi_msb_append_size = @chained_ir_msb_length
|
|
696
|
+
tdi_msb_append_data = @chained_ir_msb_data
|
|
697
|
+
end
|
|
698
|
+
if @chained_ir_lsb_length
|
|
699
|
+
tdi_lsb_append_size = @chained_ir_lsb_length
|
|
700
|
+
tdi_lsb_append_data = @chained_ir_lsb_data
|
|
701
|
+
end
|
|
702
|
+
end
|
|
703
|
+
if shift_type == :dr
|
|
704
|
+
if @chained_dr_msb_length
|
|
705
|
+
tdi_msb_append_size = @chained_dr_msb_length
|
|
706
|
+
tdi_msb_append_data = @chained_dr_msb_data
|
|
707
|
+
end
|
|
708
|
+
if @chained_dr_lsb_length
|
|
709
|
+
tdi_lsb_append_size = @chained_dr_lsb_length
|
|
710
|
+
tdi_lsb_append_data = @chained_dr_lsb_data
|
|
711
|
+
end
|
|
712
|
+
end
|
|
713
|
+
{ tdi_msb_append_size: tdi_msb_append_size, tdi_msb_append_data: tdi_msb_append_data, tdi_lsb_append_size: tdi_lsb_append_size, tdi_lsb_append_data: tdi_lsb_append_data }
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
# Create data that will be shifted in on TDI, create new bit collection
|
|
717
|
+
# on the fly if reg_or_val arg is data only. Consider read operation
|
|
718
|
+
# where caller has requested (specific) shift in data to be used.
|
|
719
|
+
def extract_shift_in_data(reg_or_val, size, options = {})
|
|
720
|
+
if reg_or_val.respond_to?(:data)
|
|
721
|
+
if options[:read]
|
|
722
|
+
data = options[:shift_in_data] || 0
|
|
723
|
+
tdi = Reg.dummy(size)
|
|
724
|
+
tdi.write(data)
|
|
725
|
+
else
|
|
726
|
+
tdi = reg_or_val.dup
|
|
727
|
+
end
|
|
728
|
+
else
|
|
729
|
+
# Not a register model, so can't support bit-wise overlay
|
|
730
|
+
tdi = Reg.dummy(size)
|
|
731
|
+
if options[:read]
|
|
732
|
+
data = options[:shift_in_data] || 0
|
|
733
|
+
tdi.write(data)
|
|
734
|
+
else
|
|
735
|
+
tdi.write(reg_or_val)
|
|
736
|
+
end
|
|
737
|
+
end
|
|
738
|
+
tdi
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
# Create data that will be shifted out on TDO, create new bit collection
|
|
742
|
+
# on the fly if reg_or_val arg is data only. Consider write operation
|
|
743
|
+
# where caller has requested (specific) shift out data to be compared.
|
|
744
|
+
def extract_shift_out_data(reg_or_val, size, options = {})
|
|
745
|
+
if reg_or_val.respond_to?(:data)
|
|
746
|
+
if options[:read]
|
|
747
|
+
tdo = reg_or_val.dup
|
|
748
|
+
tdo.read(options) unless options[:mask].nil?
|
|
749
|
+
else
|
|
750
|
+
tdo = Reg.dummy(size) unless options[:shift_out_data].is_a?(Origen::Registers::Reg)
|
|
751
|
+
end
|
|
752
|
+
unless options[:read] # if this is a write operation
|
|
753
|
+
if options[:shift_out_data]
|
|
754
|
+
if options[:shift_out_data].class.to_s =~ /Origen::Registers/
|
|
755
|
+
tdo = options[:shift_out_data]
|
|
756
|
+
else
|
|
757
|
+
tdo.write(options[:shift_out_data])
|
|
758
|
+
tdo.read(options)
|
|
759
|
+
end
|
|
760
|
+
else
|
|
761
|
+
tdo.write(0)
|
|
762
|
+
end
|
|
763
|
+
end
|
|
764
|
+
else
|
|
765
|
+
tdo = Reg.dummy(size)
|
|
766
|
+
if options[:read]
|
|
767
|
+
tdo.write(reg_or_val)
|
|
768
|
+
tdo.read(options)
|
|
769
|
+
else
|
|
770
|
+
if options[:shift_out_data]
|
|
771
|
+
if options[:shift_out_data].class.to_s =~ /Origen::Registers/
|
|
772
|
+
tdo = options[:shift_out_data]
|
|
773
|
+
else
|
|
774
|
+
tdo.write(options[:shift_out_data])
|
|
775
|
+
tdo.read(options)
|
|
776
|
+
end
|
|
777
|
+
else
|
|
778
|
+
tdo.write(0)
|
|
779
|
+
end
|
|
780
|
+
end
|
|
781
|
+
end
|
|
782
|
+
tdo
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
def to_pin(pin_or_id)
|
|
786
|
+
if pin_or_id
|
|
787
|
+
if pin_or_id.is_a?(Symbol) || pin_or_id.is_a?(String)
|
|
788
|
+
@owner.pin(pin_or_id)
|
|
789
|
+
else
|
|
790
|
+
pin_or_id
|
|
791
|
+
end
|
|
792
|
+
end
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
def pins
|
|
796
|
+
@pins ||= begin
|
|
797
|
+
pins = {}
|
|
798
|
+
pins[:tck] = to_pin(@given_options[:tck_pin])
|
|
799
|
+
pins[:tdi] = to_pin(@given_options[:tdi_pin])
|
|
800
|
+
pins[:tdo] = to_pin(@given_options[:tdo_pin])
|
|
801
|
+
pins[:tms] = to_pin(@given_options[:tms_pin])
|
|
802
|
+
|
|
803
|
+
# Support legacy implementation where tck was incorrectly called tclk, in case of both being
|
|
804
|
+
# defined then :tck has priority
|
|
805
|
+
pins[:tck] ||= @owner.pin(:tck) if @owner.has_pin?(:tck)
|
|
806
|
+
pins[:tck] ||= @owner.pin(:tclk)
|
|
807
|
+
pins[:tdi] ||= @owner.pin(:tdi)
|
|
808
|
+
pins[:tdo] ||= @owner.pin(:tdo)
|
|
809
|
+
pins[:tms] ||= @owner.pin(:tms)
|
|
810
|
+
|
|
811
|
+
pins
|
|
812
|
+
end
|
|
813
|
+
rescue
|
|
814
|
+
puts 'Missing JTAG pins!'
|
|
815
|
+
puts "In order to use the JTAG driver your #{owner.class} class must either define"
|
|
816
|
+
puts 'the following pins (an alias is fine):'
|
|
817
|
+
puts REQUIRED_PINS
|
|
818
|
+
puts '-- or --'
|
|
819
|
+
puts 'Pass the pin IDs to be used instead in the initialization options:'
|
|
820
|
+
puts "sub_block :jtag, class_name: 'OrigenJTAG::Driver', tck_pin: :clk, tdi_pin: :gpio1, tdo_pin: :gpio2, tms_pin: :gpio3"
|
|
821
|
+
raise 'JTAG driver error!'
|
|
822
|
+
end
|
|
823
|
+
end
|
|
824
|
+
end
|