origen_jtag 0.19.1 → 0.20.0

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