origen_jtag 0.19.1 → 0.20.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,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