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