origen_jtag 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8857b553c5de44e4b7b8d5a36bb6dc071b8d6d3b85a7bbe270b87ead73e4c537
4
- data.tar.gz: 2d09587fee678bc00d6ba8c75e38d42811a0753c1c2791dee457706c678b2f5b
3
+ metadata.gz: b15086a4ad3545ea9f62a1dfd03cbd478ba289d81cbe417ccbf6f66f0abb7741
4
+ data.tar.gz: d92e037cdc87ad03eb50cb0b480b1f2c0ea3ad658b2c5a8a607feace42f2f61a
5
5
  SHA512:
6
- metadata.gz: 5410a3a6c9c4c250341a6840979908819ad5326baf8529fef0936d92029e4f910660ac9859b8dd010832013894ea8eeba830cbbb3cd0e8e7c9ec303fa91d572b
7
- data.tar.gz: d54393fceeeb9dc965c513300c7042bd550d1c1b14962b1f523e768dafe5c0c05c6ee26dd0c98428db33e39b046af7d75af09dad7a9f1caddfbc70d52f1a4aa8
6
+ metadata.gz: 7cea430f01d68431304365ea7a47c08e76ecb12d4292828b01c9e4407570fba2ce5c4d344f6e58466258d24ae9d140441b4b3fa8e7e10db3a3436f1f19852273
7
+ data.tar.gz: fd389e11272f958e1c930ffd99a974fdad3f405ae5fb24fb8bd2da4a7d5d3f445917daca8e84e3af9f0e258cf84ec461873468faf57ff749269352071634af66
data/config/commands.rb CHANGED
@@ -93,6 +93,9 @@ when "examples", "test"
93
93
  ARGV = %w(jtag_workout -t new_P4 -e v93k -r approved)
94
94
  load "#{Origen.top}/lib/origen/commands/generate.rb"
95
95
 
96
+ ARGV = %w(jtag_workout -t serial_P1 -e v93k -r approved)
97
+ load "#{Origen.top}/lib/origen/commands/generate.rb"
98
+
96
99
  if Origen.app.stats.changed_files == 0 &&
97
100
  Origen.app.stats.new_files == 0 &&
98
101
  Origen.app.stats.changed_patterns == 0 &&
data/config/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module OrigenJTAG
2
2
  MAJOR = 0
3
- MINOR = 20
3
+ MINOR = 21
4
4
  BUGFIX = 0
5
5
  DEV = nil
6
6
 
@@ -6,12 +6,12 @@ module OrigenJTAG
6
6
  # state machine via the TAPController module.
7
7
  #
8
8
  # To use this driver the parent model must define the following pins (an alias is fine):
9
- # :tclk
9
+ # :tck
10
10
  # :tdi
11
11
  # :tdo
12
12
  # :tms
13
13
  class Driver
14
- REQUIRED_PINS = [:tclk, :tdi, :tdo, :tms]
14
+ REQUIRED_PINS = [:tck, :tdi, :tdo, :tms]
15
15
 
16
16
  include Origen::Model
17
17
  include TAPController
@@ -23,10 +23,20 @@ module OrigenJTAG
23
23
  # Returns the current value in the instruction register
24
24
  attr_reader :ir_value
25
25
 
26
- # Returns the tclk multiple
27
- attr_reader :tclk_multiple
26
+ # The number of cycles for one clock pulse, assumes 50% duty cycle. Uses tester non-return format to spread TCK across multiple cycles.
27
+ # e.g. @tck_multiple = 2, @tck_format = :rh, means one cycle with Tck low (non-return), one with Tck high (NR)
28
+ # @tck_multiple = 4, @tck_format = :rl, means 2 cycles with Tck high (NR), 2 with Tck low (NR)
29
+ attr_accessor :tck_multiple
30
+ alias_method :tclk_multiple, :tck_multiple
31
+ alias_method :tclk_multiple=, :tck_multiple=
32
+
33
+ # Wave/timing format of the JTAG clock: :rh (ReturnHigh) or :rl (ReturnLo), :rh is the default
34
+ attr_accessor :tck_format
35
+ alias_method :tclk_format, :tck_format
36
+ alias_method :tclk_format=, :tck_format=
37
+
38
+ attr_reader :tdo_strobe
28
39
 
29
- attr_accessor :tclk_format
30
40
  # Set true to print out debug comments about all state transitions
31
41
  attr_accessor :verbose
32
42
  alias_method :verbose?, :verbose
@@ -41,24 +51,17 @@ module OrigenJTAG
41
51
  else
42
52
  @owner = owner
43
53
  end
44
- validate_pins(options)
45
-
46
54
  # The parent can configure JTAG settings by defining this constant
47
55
  if defined?(owner.class::JTAG_CONFIG)
48
56
  options = owner.class::JTAG_CONFIG.merge(options)
49
57
  end
50
58
 
59
+ @cycle_callback = options[:cycle_callback]
60
+ validate_pins(options) unless @cycle_callback
61
+
51
62
  # Fallback defaults
52
63
  options = {
53
64
  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
65
  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
66
  # 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
67
  init_state: :unknown
@@ -68,18 +71,46 @@ module OrigenJTAG
68
71
 
69
72
  @verbose = options[:verbose]
70
73
  @ir_value = :unknown
71
- @tclk_format = options[:tclk_format]
72
- @tclk_multiple = options[:tclk_multiple]
73
- @tdo_strobe = options[:tdo_strobe]
74
+ @tck_format = options[:tck_format] || options[:tclk_format] || :rh
75
+ @tck_multiple = options[:tck_multiple] || options[:tclk_multiple] || 1
76
+ self.tdo_strobe = options[:tdo_strobe] || :tck_high
74
77
  @tdo_store_cycle = options[:tdo_store_cycle]
75
78
  @state = options[:init_state]
76
79
  @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 }"
80
+ if options[:tck_vals] || options[:tclk_vals]
81
+ @tck_vals = options[:tck_vals] || options[:tclk_vals]
82
+ unless @tck_vals.is_a?(Hash) && @tck_vals.key?(:on) && @tck_vals.key?(:off)
83
+ fail "When specifying TCK values, you must supply a hash with both :on and :off keys, e.g. tck_vals: { on: 'P', off: 0 }"
81
84
  end
82
85
  end
86
+ if @cycle_callback && @tck_multiple != 1
87
+ fail 'A cycle_callback can only be used with a tck_multiple setting of 1'
88
+ end
89
+ end
90
+
91
+ # when using multiple cycles for TCK, set when to strobe for TDO, options include:
92
+ # :tck_high - strobe TDO only when TCK is high (Default)
93
+ # :tck_low - strobe TDO only when TCK is low
94
+ # :tck_all - strobe TDO throughout TCK cycle
95
+ def tdo_strobe=(val)
96
+ case val
97
+ when :tck_high, :tclk_high
98
+ @tdo_strobe = :tck_high
99
+ when :tck_low, :tclk_low
100
+ @tdo_strobe = :tck_low
101
+ when :tck_all, :tclk_all
102
+ @tdo_strobe = :tck_all
103
+ else
104
+ fail 'tdo_strobe must be set to one of: :tck_high, :tck_low or :tck_all'
105
+ end
106
+ end
107
+
108
+ # When true it means that the application is dealing with how to handle the 4 JTAG signals for each JTAG cycle.
109
+ # In that case this driver calculates what state the 4 pins should be in each signal and then calls back to the
110
+ # application with that information and it is up to the application to decide what to do with that information
111
+ # and when/if to generate tester cycles.
112
+ def cycle_callback?
113
+ !!@cycle_callback
83
114
  end
84
115
 
85
116
  # Shift data into the TDI pin or out of the TDO pin.
@@ -155,32 +186,32 @@ module OrigenJTAG
155
186
  # loop through each data bit
156
187
  last_overlay_label = ''
157
188
  size.times do |i|
158
- store_tdo_this_tclk = false
189
+ store_tdo_this_tck = false
159
190
 
160
- # Set up pin actions for bit transaction (tclk cycle)
191
+ # Set up pin actions for bit transaction (tck cycle)
161
192
 
162
193
  # TDI
163
- @tdi_pin.drive(tdi_reg[i])
194
+ action :tdi, :drive, tdi_reg[i]
164
195
 
165
196
  # TDO
166
- @tdo_pin.dont_care # default setting
197
+ action :tdo, :dont_care # default setting
167
198
  if tdo_reg[i]
168
199
  if tdo_reg[i].is_to_be_stored? # store
169
- store_tdo_this_tclk = true
170
- @tdo_pin.dont_care if Origen.tester.j750?
200
+ store_tdo_this_tck = true
201
+ action :tdo, :dont_care if Origen.tester.j750?
171
202
  elsif tdo_reg[i].is_to_be_read? # compare/assert
172
- @tdo_pin.assert(tdo_reg[i], meta: { position: i })
203
+ action :tdo, :assert, tdo_reg[i], meta: { position: i }
173
204
  end
174
205
  end
175
206
 
176
207
  # TMS
177
- @tms_pin.drive(0)
208
+ action :tms, :drive, 0
178
209
 
179
210
  # let tester handle overlay if implemented
180
211
  overlay_options = {}
181
- if tester.respond_to?(:source_memory)
212
+ if tester.respond_to?(:source_memory) && !cycle_callback?
182
213
  if ovl_reg[i] && ovl_reg[i].has_overlay? && !Origen.mode.simulation?
183
- overlay_options[:pins] = @tdi_pin
214
+ overlay_options[:pins] = @pins[:tdi]
184
215
  if global_ovl
185
216
  overlay_options[:overlay_str] = global_ovl
186
217
  else
@@ -194,8 +225,8 @@ module OrigenJTAG
194
225
  end
195
226
  end
196
227
  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
228
+ action :tdi, :drive, 0 if tester_subr_overlay
229
+ action :tdo, :assert, tdo_reg[i], meta: { position: i } if options[:read] unless tester_subr_overlay
199
230
  # Force the last bit to be shifted from this method if overlay requested on the last bit
200
231
  options[:cycle_last] = true if i == size - 1
201
232
  end
@@ -208,18 +239,18 @@ module OrigenJTAG
208
239
  $tester.label(ovl_reg[i].overlay_str)
209
240
  last_overlay_label = ovl_reg[i].overlay_str
210
241
  end
211
- @tdo_pin.assert(tdo_reg[i], meta: { position: i }) if options[:read]
242
+ action :tdo, :assert, tdo_reg[i], meta: { position: i } if options[:read]
212
243
  else
213
- @tdi_pin.drive(0)
244
+ action :tdi, :drive, 0
214
245
  call_subroutine = ovl_reg[i].overlay_str
215
246
  end
216
247
  end
217
248
  end # of let tester handle overlay
218
249
 
219
- # With JTAG pin actions queued up, use block call to tclk_cycle to
220
- # execute a single TCLK period. Special handling of subroutines,
250
+ # With JTAG pin actions queued up, use block call to tck_cycle to
251
+ # execute a single TCK period. Special handling of subroutines,
221
252
  # case of last bit in shift, and store vector (within a multi-cycle
222
- # tclk config).
253
+ # tck config).
223
254
  if call_subroutine || tester_subr_overlay
224
255
  @last_data_vector_shifted = true
225
256
  else
@@ -234,25 +265,25 @@ module OrigenJTAG
234
265
  if i != size - 1 || options[:cycle_last]
235
266
  if i == size - 1 && options[:includes_last_bit]
236
267
  unless tester_subr_overlay
237
- @tms_pin.drive(1)
268
+ action :tms, :drive, 1
238
269
  @last_data_vector_shifted = true
239
270
  end
240
271
  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)
272
+ tck_cycle do
273
+ if store_tdo_this_tck && @next_data_vector_to_be_stored
274
+ action :store
244
275
  end
245
- if overlay_options[:pins].nil?
246
- Origen.tester.cycle
276
+ if overlay_options[:pins].nil? || cycle_callback?
277
+ cycle
247
278
  else
248
- Origen.tester.cycle overlay: overlay_options
279
+ cycle overlay: overlay_options
249
280
  overlay_options[:change_data] = false # data change only on first cycle if overlay
250
281
  end
251
282
  end
252
- @tdo_pin.dont_care
283
+ @pins[:tdo].dont_care unless cycle_callback?
253
284
  else
254
285
  @deferred_compare = true
255
- @deferred_store = true if store_tdo_this_tclk
286
+ @deferred_store = true if store_tdo_this_tck
256
287
  end
257
288
  end
258
289
  end
@@ -264,101 +295,100 @@ module OrigenJTAG
264
295
  Origen.tester.dont_compress = false if compression_on
265
296
  end
266
297
 
267
- # Cycles the tester through one TCLK cycle
268
- # Adjusts for the TCLK format and cycle span
298
+ # Cycles the tester through one TCK cycle
299
+ # Adjusts for the TCK format and cycle span
269
300
  # Assumes caller will drive pattern to tester
270
301
  # 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))
302
+ def tck_cycle
303
+ if cycle_callback?
304
+ @next_data_vector_to_be_stored = @tdo_store_cycle
305
+ yield
306
+ else
307
+ case @tck_format
308
+ when :rh
309
+ tck_val = 0
310
+ when :rl
311
+ tck_val = 1
312
+ else
313
+ fail 'ERROR: Invalid Tclk timing format!'
314
+ end
284
315
 
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))
316
+ # determine whether to mask TDO on first half cycle
317
+ mask_tdo_half0 = ((@tck_format == :rl) && (@tdo_strobe == :tck_low) && (@tck_multiple > 1)) ||
318
+ ((@tck_format == :rh) && (@tdo_strobe == :tck_high) && (@tck_multiple > 1))
288
319
 
289
- # determine whether TDO is set to capture for this TCLK cycle
290
- tdo_to_be_captured = @tdo_pin.to_be_captured?
320
+ # determine whether to mask TDO on second half cycle
321
+ mask_tdo_half1 = ((@tck_format == :rl) && (@tdo_strobe == :tck_high) && (@tck_multiple > 1)) ||
322
+ ((@tck_format == :rh) && (@tdo_strobe == :tck_low) && (@tck_multiple > 1))
291
323
 
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
324
+ # If TDO is already suspended (by an application) then don't do the
325
+ # suspends below since the resume will clear the application's suspend
326
+ tdo_already_suspended = !cycle_callback? && @pins[:tdo].suspended? && !@tdo_suspended_by_driver
295
327
 
296
- @tclk_multiple.times do |i|
297
- # 50% duty cycle if @tclk_multiple is even, otherwise slightly off
328
+ @tck_multiple.times do |i|
329
+ # 50% duty cycle if @tck_multiple is even, otherwise slightly off
298
330
 
299
- @next_data_vector_to_be_stored = @tdo_store_cycle == i ? true : false
331
+ @next_data_vector_to_be_stored = @tdo_store_cycle == i ? true : false
300
332
 
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
333
+ if i < (@tck_multiple + 1) / 2
334
+ # first half of cycle
335
+ @pins[:tck].drive(@tck_vals ? @tck_vals[:on] : tck_val)
336
+ unless tdo_already_suspended
306
337
  if mask_tdo_half0
307
338
  @tdo_suspended_by_driver = true
308
- @tdo_pin.suspend
339
+ @pins[:tdo].suspend
309
340
  else
310
341
  @tdo_suspended_by_driver = false
311
- @tdo_pin.resume
342
+ @pins[:tdo].resume
312
343
  end
313
344
  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
345
+ else
346
+ # second half of cycle
347
+ @pins[:tck].drive(@tck_vals ? @tck_vals[:off] : (1 - tck_val))
348
+ unless tdo_already_suspended
320
349
  if mask_tdo_half1
321
350
  @tdo_suspended_by_driver = true
322
- @tdo_pin.suspend
351
+ @pins[:tdo].suspend
323
352
  else
324
353
  @tdo_suspended_by_driver = false
325
- @tdo_pin.resume
354
+ @pins[:tdo].resume
326
355
  end
327
356
  end
328
357
  end
358
+ yield
359
+ end
360
+ if @tdo_suspended_by_driver
361
+ @tdo_suspended_by_driver = false
362
+ @pins[:tdo].resume
329
363
  end
330
- yield
331
- end
332
- if @tdo_suspended_by_driver
333
- @tdo_pin.resume
334
- @tdo_suspended_by_driver = false
335
364
  end
336
365
  end
337
366
 
338
367
  # Applies the given value to the TMS pin and then
339
- # cycles the tester for one TCLK
368
+ # cycles the tester for one TCK
340
369
  #
341
370
  # @param [Integer] val Value to drive on the TMS pin, 0 or 1
342
371
  def tms!(val)
343
372
  if @deferred_compare
344
373
  @deferred_compare = nil
345
374
  else
346
- @tdo_pin.dont_care
375
+ action :tdo, :dont_care
347
376
  end
348
377
 
349
378
  if @deferred_store
350
379
  @deferred_store = nil
351
- store_tdo_this_tclk = true
380
+ store_tdo_this_tck = true
352
381
  else
353
- store_tdo_this_tclk = false
382
+ store_tdo_this_tck = false
354
383
  end
355
384
  @next_data_vector_to_be_stored = false
356
385
 
357
- tclk_cycle do
358
- if store_tdo_this_tclk && @next_data_vector_to_be_stored
359
- Origen.tester.store_next_cycle(@tdo_pin)
386
+ tck_cycle do
387
+ if store_tdo_this_tck && @next_data_vector_to_be_stored
388
+ action :store
360
389
  end
361
- @tms_pin.drive!(val)
390
+ action :tms, :drive, val
391
+ cycle
362
392
  end
363
393
  end
364
394
 
@@ -493,8 +523,44 @@ module OrigenJTAG
493
523
  end
494
524
  end
495
525
 
526
+ def apply_action(pin, actions)
527
+ actions.each do |operation|
528
+ method = operation.shift
529
+ pin.send(method, *operation) if method
530
+ end
531
+ end
532
+
496
533
  private
497
534
 
535
+ def action(pin_id, *operations)
536
+ @actions ||= clear_actions
537
+ if pin_id == :store
538
+ @actions[:store] = true
539
+ else
540
+ fail "Unkown JTAG pin ID: #{pin_id}" unless @actions[pin_id]
541
+ @actions[pin_id] << operations
542
+ end
543
+ end
544
+
545
+ def cycle(options = {})
546
+ if @actions
547
+ if cycle_callback?
548
+ @owner.send(@cycle_callback, @actions, options)
549
+ else
550
+ apply_action(@pins[:tms], @actions[:tms])
551
+ apply_action(@pins[:tdi], @actions[:tdi])
552
+ apply_action(@pins[:tdo], @actions[:tdo])
553
+ tester.store_next_cycle(@pins[:tdo]) if @actions[:store]
554
+ tester.cycle(options)
555
+ end
556
+ clear_actions
557
+ end
558
+ end
559
+
560
+ def clear_actions
561
+ @actions = { tdi: [], tms: [], tdo: [], store: false }
562
+ end
563
+
498
564
  # Return size of transaction. Options[:size] has priority and need not match the
499
565
  # register size. Any mismatch will be handled by the api.
500
566
  def extract_size(reg_or_val, options = {})
@@ -601,15 +667,19 @@ module OrigenJTAG
601
667
  # Validates that the parent object (the owner) has defined the necessary
602
668
  # pins to implement the JTAG
603
669
  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?
670
+ @pins = {}
671
+ @pins[:tck] = options[:tck_pin]
672
+ @pins[:tdi] = options[:tdi_pin]
673
+ @pins[:tdo] = options[:tdo_pin]
674
+ @pins[:tms] = options[:tms_pin]
675
+
676
+ # Support legacy implementation where tck was incorrectly called tclk, in case of both being
677
+ # defined then :tck has priority
678
+ @pins[:tck] ||= @owner.pin(:tck) if @owner.has_pin?(:tck)
679
+ @pins[:tck] ||= @owner.pin(:tclk)
680
+ @pins[:tdi] ||= @owner.pin(:tdi)
681
+ @pins[:tdo] ||= @owner.pin(:tdo)
682
+ @pins[:tms] ||= @owner.pin(:tms)
613
683
  rescue
614
684
  puts 'Missing JTAG pins!'
615
685
  puts "In order to use the JTAG driver your #{owner.class} class must either define"
@@ -617,7 +687,7 @@ module OrigenJTAG
617
687
  puts REQUIRED_PINS
618
688
  puts '-- or --'
619
689
  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)"
690
+ puts "sub_block :jtag, class_name: 'OrigenJTAG::Driver', tck_pin: dut.pin(:tck), tdi_pin: dut.pin(:tdi), tdo_pin: dut.pin(:tdo), tms_pin: dut.pin(:tms)"
621
691
  raise 'JTAG driver error!'
622
692
  end
623
693
  end
@@ -24,6 +24,7 @@ module OrigenJTAGDev
24
24
  @jtag_config[:tdo_store_cycle] = options[:tdo_store_cycle] if options[:tdo_store_cycle]
25
25
  @jtag_config[:init_state] = options[:init_state] if options[:init_state]
26
26
  @jtag_config[:tclk_vals] = options[:tclk_vals] if options[:tclk_vals]
27
+ @jtag_config[:cycle_callback] = options[:cycle_callback] if options[:cycle_callback]
27
28
 
28
29
  instantiate_registers(options)
29
30
  instantiate_pins(options)
@@ -50,12 +51,10 @@ module OrigenJTAGDev
50
51
  end
51
52
 
52
53
  def instantiate_pins(options = {})
53
- if options[:invalid_pins]
54
- add_pin :tck
55
- else
56
- add_pin :tclk
54
+ add_pin :tclk
55
+ unless options[:invalid_pins]
56
+ add_pin :tdi
57
57
  end
58
- add_pin :tdi
59
58
  add_pin :tdo
60
59
  add_pin :tms
61
60
 
@@ -101,7 +100,7 @@ module OrigenJTAGDev
101
100
  @jtag_config[:init_state]
102
101
  end
103
102
 
104
- # Wouldn't want to do this in reality, but allows some flexibility duing gem testing
103
+ # Wouldn't want to do this in reality, but allows some flexibility during gem testing
105
104
  def update_jtag_config(cfg, val)
106
105
  if @jtag_config.key?(cfg)
107
106
  @jtag_config[cfg] = val
@@ -0,0 +1,24 @@
1
+ module OrigenJTAGDev
2
+ # This is a dummy DUT model which is used
3
+ # to instantiate and test the JTAG locally
4
+ # during development.
5
+ #
6
+ # It is not included when this library is imported.
7
+ class Serial < NewStyle
8
+ def instantiate_pins(options = {})
9
+ add_pin :tck
10
+ add_pin :tio
11
+ end
12
+
13
+ def jtag_cycle(actions, options = {})
14
+ pin(:tck).drive(1)
15
+ jtag.apply_action(pin(:tio), actions[:tdi])
16
+ tester.cycle(options)
17
+ jtag.apply_action(pin(:tio), actions[:tms])
18
+ tester.cycle(options)
19
+ jtag.apply_action(pin(:tio), actions[:tdo])
20
+ tester.store_next_cycle(pin(:tio)) if actions[:store]
21
+ tester.cycle(options)
22
+ end
23
+ end
24
+ end
@@ -1,5 +1,6 @@
1
1
  pat_name = "jtag_workout_#{$dut.tclk_format.upcase}#{$dut.tclk_multiple}"
2
2
  pat_name = pat_name + "_#{dut.tdo_store_cycle}" if dut.tdo_store_cycle != 0
3
+ pat_name += "_serial" if dut.is_a?(OrigenJTAGDev::Serial)
3
4
  pat_name += "_tclk_vals" if dut.try(:tclk_vals)
4
5
 
5
6
  Pattern.create(options = { name: pat_name }) do
@@ -196,15 +197,17 @@ Pattern.create(options = { name: pat_name }) do
196
197
  test 'Reset'
197
198
  jtag.reset
198
199
 
199
- test 'Suspend of compare on TDO works'
200
- cc 'TDO should be H'
201
- jtag.read_dr 0xFFFF, size: 16, msg: 'Read value out of DR'
202
- tester.ignore_fails($dut.pin(:tdo)) do
203
- cc 'TDO should be X'
200
+ if dut.has_pin?(:tdo)
201
+ test 'Suspend of compare on TDO works'
202
+ cc 'TDO should be H'
203
+ jtag.read_dr 0xFFFF, size: 16, msg: 'Read value out of DR'
204
+ tester.ignore_fails($dut.pin(:tdo)) do
205
+ cc 'TDO should be X'
206
+ jtag.read_dr 0xFFFF, size: 16, msg: 'Read value out of DR'
207
+ end
208
+ cc 'TDO should be H'
204
209
  jtag.read_dr 0xFFFF, size: 16, msg: 'Read value out of DR'
205
210
  end
206
- cc 'TDO should be H'
207
- jtag.read_dr 0xFFFF, size: 16, msg: 'Read value out of DR'
208
211
 
209
212
  test 'Mask option for read_dr works'
210
213
  cc 'TDO should be H'
@@ -26,24 +26,42 @@ or if your application is a plugin add this to your <code>.gemspec</code>
26
26
  spec.add_development_dependency "origen_jtag", ">= <%= Origen.app.version %>"
27
27
  ~~~
28
28
 
29
- __NOTE:__ You will also need to include <code>require 'origen_jtag'</code> somewhere in your environment. This can be done in <code>config/environment.rb</code> for example.
29
+ __NOTE:__ You will also need to include <code>require 'origen_jtag'</code> somewhere in your environment.
30
+ This can be done in <code>config/environment.rb</code> for example.
30
31
 
31
32
  ### How To Use
32
33
 
33
- #### New Style Example
34
+ #### Integration
34
35
 
35
- The driver no longer requires specific pin names (or aliases), supports sub_block instantiation and DUTs with multiple JTAG ports.
36
- You are no longer required to include "OrigenJTAG" in your DUT class.
37
-
38
- Here is an example integration:
36
+ This plugin provides a JTAG driver that should be instantiated by the top-level DUT model as shown in this
37
+ basic integration example:
39
38
 
40
39
  ~~~ruby
41
- class Pioneer
40
+ class MyApp::MyDUT
41
+ include Origen::TopLevel
42
+
43
+ def initialize(options = {})
44
+ # The JTAG driver will use these pins by default if they are defined (or aliases)
45
+ add_pin :tck
46
+ add_pin :tdi
47
+ add_pin :tdo
48
+ add_pin :tms
49
+
50
+ sub_block :jtag, class_name: 'OrigenJTAG::Driver'
51
+ end
52
+ end
53
+ ~~~
54
+
55
+ Multiple JTAG blocks can be instantiated if the DUT has multiple JTAG ports, and each one can be individually
56
+ customized as shown in this more complex example:
42
57
 
58
+ ~~~ruby
59
+ class MyApp::MyDUT
43
60
  include Origen::TopLevel
44
61
 
45
62
  def initialize
46
- add_pin :tclk
63
+ # The JTAG driver will use these pins by default if they are defined (or aliases)
64
+ add_pin :tck
47
65
  add_pin :tdi
48
66
  add_pin :tdo
49
67
  add_pin :tms
@@ -58,92 +76,48 @@ class Pioneer
58
76
  # 2 high then 2 low for each effective TCK pulse.
59
77
  # Strobe TDO only when TCK high. Only store TDO on last cycle (3)
60
78
 
61
- # several pluggins use dut.jtag, your default port driver should be named jtag for compatibility
79
+ # Several plugins use dut.jtag, your default port driver should be named jtag for compatibility
62
80
  sub_block :jtag, class_name: 'OrigenJTAG::Driver',
63
- tclk_format: :rl,
64
- tclk_multiple: 4,
65
- tdo_strobe: :tclk_high,
66
- tdo_store_cycle: 3,
67
- tck_pin: pin(:tclk),
68
- tdi_pin: pin(:tdi),
69
- tdo_pin: pin(:tdo),
70
- tms_pin: pin(:tms)
71
-
72
- # create a driver for a 2nd port like this
73
- # note different configuration settings can be used
81
+ tck_format: :rl,
82
+ tck_multiple: 4,
83
+ tdo_strobe: :tck_high,
84
+ tdo_store_cycle: 3
85
+
86
+ # Create a driver for a 2nd port like this, note different configuration settings can be used
74
87
  sub_block :jtag_port2, class_name: 'OrigenJTAG::Driver',
75
- tclk_format: :rh,
76
- tclk_multiple: 2,
77
- tdo_strobe: :tclk_high,
88
+ tck_format: :rh,
89
+ tck_multiple: 2,
90
+ tdo_strobe: :tck_high,
78
91
  tdo_store_cycle: 1,
79
92
  tck_pin: pin(:tck2),
80
93
  tdi_pin: pin(:tdi2),
81
94
  tdo_pin: pin(:tdo2),
82
95
  tms_pin: pin(:tms2)
83
96
  end
84
-
85
97
  end
86
98
 
87
- dut.jtag # => jtag driver for the first port (tclk, tdi, tdo, tms)
99
+ dut.jtag # => jtag driver for the first port (tck, tdi, tdo, tms)
88
100
  dut.jtag_port2 # => jtag driver for the second port (tck2, tdi2, tdo2, tms2)
89
101
  ~~~
90
102
 
103
+ Here are some of the most common configuration options:
104
+
105
+ * **tck_format** - TCK timing format, Return High (:rh) or Return Low (:rl). Default is :rh.
106
+ * **tck_multiple** - Number of cycles for a single TCK pulse to cover, to support cases where TCK needs to be a fraction of another clock period. Assumes 50% duty cycle, specify only even numbers if > 1. Default is :r1.
107
+ * **tdo_strobe** - When using multiple cycles for TCK, which state of TCK to strobe for TDO, :tck_high or :tck_low or :tck_all. Default :tck_high.
108
+ * **tdo_store_cycle** - When using multiple cycles for TCK, which cycle of TCK to store for TDO if store requested (0 to number of tck_multiple-1). Default 0
109
+
91
110
  By default, the driver will apply the conventional '1' and '0' drive values on the TCK pin to turn
92
111
  the clock on and off, however
93
- this can be overridden by supplying the `:tclk_vals` option as shown in the example below:
112
+ this can be overridden by supplying the `:tck_vals` option as shown in the example below:
94
113
 
95
114
  ~~~ruby
96
115
  # My V93K timing setup uses 'P' to enable a clock pulse instead of '1'
97
- tclk_vals: { on: 'P', off: 0 }
116
+ tck_vals: { on: 'P', off: 0 }
98
117
  ~~~
99
118
 
100
-
101
- #### Legacy Example
102
-
103
- Include the <code>OrigenJTAG</code> module to add a JTAG driver to your class and
104
- define the required pins.
105
- Normally the pins would be an alias to existing DUT pins and therefore the
106
- JTAG driver module cannot assume them.
107
-
108
- Including the module adds a <code>jtag</code> method which will return an instance of
109
- [<code>OrigenJTAG::Driver</code>](<%= path "api/OrigenJTAG/Driver.html" %>).
110
-
111
- The following attributes can be customized by defining a <code>JTAG_CONFIG</code>
112
- hash:
113
-
114
- * **tclk_format** - TCLK timing format, Return High (:rh) or Return Low (:rl). Default is :rh.
115
- * **tclk_multiple** - Number of cycles for a single TCLK pulse to cover, to support cases where TCLK needs to be a fraction of another clock period. Assumes 50% duty cycle, specify only even numbers if > 1. Default is :r1.
116
- * **tdo_strobe** - When using multiple cycles for TCK, which state of TCK to strobe for TDO, :tclk_high or :tclk_low or :tclk_all. Default :tclk_high.
117
- * **tdo_store_cycle** - When using multiple cycles for TCK, which cycle of TCK to store for TDO if store requested (0 to number of tclk_multiple-1). Default 0
118
-
119
- Here is an example integration:
120
-
121
- ~~~ruby
122
- class Pioneer
123
-
124
- include OrigenJTAG
125
- include Origen::Pins
126
-
127
- # TCK covers 4 tester cycles, 2 high then 2 low for each effective TCK pulse
128
- # Strobe TDO only when TCK high. Only store TDO on last cycle (3)
129
- JTAG_CONFIG = {
130
- :tclk_format => :rl,
131
- :tclk_multiple => 4,
132
- :tdo_strobe => :tclk_high,
133
- :tdo_store_cycle => 3,
134
- }
135
-
136
- def initialize
137
- add_pin :tclk
138
- add_pin :tdi
139
- add_pin :tdo
140
- add_pin :tms
141
- end
142
-
143
- end
144
-
145
- Pioneer.new.jtag # => An instance of OrigenJTAG::Driver
146
- ~~~
119
+ A [legacy integration is also supported](<%= path "legacy" %>), but not recommended for new projects
120
+ as it may be deprecated in future.
147
121
 
148
122
  #### APIs
149
123
 
@@ -203,6 +177,57 @@ def on_jtag_state_change(new_state)
203
177
  end
204
178
  ~~~
205
179
 
180
+ #### Custom JTAG Cycle Protocols
181
+
182
+ This plugin also allows applications to define how a JTAG cycle should be implemented at the
183
+ pin-level, providing the flexibility to handle hybrid JTAG protocols.
184
+ An example would be an ultra-low pincount device where the JTAG signals are multiplexed down a
185
+ single wire.
186
+
187
+ To implement a custom protocol, a `:cycle_callback` option should be supplied when instantiating the
188
+ driver to specify the name of the DUT method that will implement the cycle.
189
+ **Note that most other configuration options are meaningless in this context (and some non-default
190
+ values will raise an error) because the application
191
+ is now taking full responsibility for how a JTAG cycle is implemented.**
192
+ Similarly, there is no requirement for the conventional JTAG pins to be present or specified when this
193
+ option is given since the driver is no longer responsible for the vector generation.
194
+
195
+ The given method should accept two arguments:
196
+
197
+ * **actions** - A hash containing the actions that should be applied to the `:tdi`, `:tms` and `:tdo`,
198
+ pins and a boolean flag called `:store` which indicates if TDO should be stored/captured on this cycle
199
+ * **options** - Any options that should be passed to the tester when calling `tester.cycle`
200
+
201
+ The JTAG driver provides a method called `apply_action` which accepts a pin object and the pin-specific
202
+ actions from the actions hash, e.g.
203
+
204
+ ~~~ruby
205
+ jtag.apply_action(pin(:my_pin), actions[:tms])
206
+ ~~~
207
+
208
+ Here is a complete example which would serialize TDI, TMS and TDO on a single pin:
209
+
210
+ ~~~ruby
211
+ class MyApp::MyDUT
212
+ def initialize(options = {})
213
+ add_pin :tck
214
+ add_pin :tio
215
+
216
+ sub_block :jtag, class_name: 'OrigenJTAG::Driver', cycle_callback: :jtag_cycle
217
+ end
218
+
219
+ def jtag_cycle(actions, options = {})
220
+ pin(:tck).drive(1)
221
+ jtag.apply_action(pin(:tio), actions[:tdi])
222
+ tester.cycle(options)
223
+ jtag.apply_action(pin(:tio), actions[:tms])
224
+ tester.cycle(options)
225
+ jtag.apply_action(pin(:tio), actions[:tdo])
226
+ tester.store_next_cycle(pin(:tio)) if actions[:store]
227
+ tester.cycle(options)
228
+ end
229
+ end
230
+ ~~~
206
231
 
207
232
  ### How To Setup a Development Environment
208
233
 
@@ -0,0 +1,43 @@
1
+ % render "layouts/basic.html" do
2
+
3
+ ### Legacy Integration
4
+
5
+ The following approach to adding an JTAG driver is still supported, however new projects
6
+ should use the new style integration as described [on the home page](<%= path "/" %>).
7
+
8
+ Include the <code>OrigenJTAG</code> module to add a JTAG driver to your class and
9
+ define the required pins.
10
+ Normally the pins would be an alias to existing DUT pins and therefore the
11
+ JTAG driver module cannot assume them.
12
+
13
+ Including the module adds a <code>jtag</code> method which will return an instance of
14
+ [<code>OrigenJTAG::Driver</code>](<%= path "api/OrigenJTAG/Driver.html" %>).
15
+
16
+ Here is an example integration:
17
+
18
+ ~~~ruby
19
+ class MyApp::MyDUT
20
+ include Origen::TopLevel
21
+ include OrigenJTAG
22
+
23
+ # TCK covers 4 tester cycles, 2 high then 2 low for each effective TCK pulse
24
+ # Strobe TDO only when TCK high. Only store TDO on last cycle (3)
25
+ JTAG_CONFIG = {
26
+ :tck_format => :rl,
27
+ :tck_multiple => 4,
28
+ :tdo_strobe => :tck_high,
29
+ :tdo_store_cycle => 3,
30
+ }
31
+
32
+ def initialize
33
+ add_pin :tck
34
+ add_pin :tdi
35
+ add_pin :tdo
36
+ add_pin :tms
37
+ end
38
+ end
39
+
40
+ MyApp::MyDUT.new.jtag # => An instance of OrigenJTAG::Driver
41
+ ~~~
42
+
43
+ % end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: origen_jtag
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.20.0
4
+ version: 0.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen McGinty
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-07 00:00:00.000000000 Z
11
+ date: 2019-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: origen
@@ -59,6 +59,7 @@ files:
59
59
  - lib/origen_jtag/driver.rb
60
60
  - lib/origen_jtag/tap_controller.rb
61
61
  - lib/origen_jtag_dev/new_style.rb
62
+ - lib/origen_jtag_dev/serial.rb
62
63
  - lib/origen_jtag_dev/top_level.rb
63
64
  - pattern/full_reg_ovly_cap.rb
64
65
  - pattern/global_label_test.rb
@@ -67,6 +68,7 @@ files:
67
68
  - pattern/two_port.rb
68
69
  - templates/web/index.md.erb
69
70
  - templates/web/layouts/_basic.html.erb
71
+ - templates/web/legacy.md.erb
70
72
  - templates/web/partials/_navbar.html.erb
71
73
  - templates/web/release_notes.md.erb
72
74
  homepage: http://origen-sdk.org/jtag