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 +4 -4
- data/config/commands.rb +3 -0
- data/config/version.rb +1 -1
- data/lib/origen_jtag/driver.rb +182 -112
- data/lib/origen_jtag_dev/new_style.rb +5 -6
- data/lib/origen_jtag_dev/serial.rb +24 -0
- data/pattern/jtag_workout.rb +10 -7
- data/templates/web/index.md.erb +99 -74
- data/templates/web/legacy.md.erb +43 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b15086a4ad3545ea9f62a1dfd03cbd478ba289d81cbe417ccbf6f66f0abb7741
|
4
|
+
data.tar.gz: d92e037cdc87ad03eb50cb0b480b1f2c0ea3ad658b2c5a8a607feace42f2f61a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
data/lib/origen_jtag/driver.rb
CHANGED
@@ -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
|
-
# :
|
9
|
+
# :tck
|
10
10
|
# :tdi
|
11
11
|
# :tdo
|
12
12
|
# :tms
|
13
13
|
class Driver
|
14
|
-
REQUIRED_PINS = [:
|
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
|
-
#
|
27
|
-
|
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
|
-
@
|
72
|
-
@
|
73
|
-
|
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
|
-
@
|
79
|
-
unless @
|
80
|
-
fail "When specifying
|
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
|
-
|
189
|
+
store_tdo_this_tck = false
|
159
190
|
|
160
|
-
# Set up pin actions for bit transaction (
|
191
|
+
# Set up pin actions for bit transaction (tck cycle)
|
161
192
|
|
162
193
|
# TDI
|
163
|
-
|
194
|
+
action :tdi, :drive, tdi_reg[i]
|
164
195
|
|
165
196
|
# TDO
|
166
|
-
|
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
|
-
|
170
|
-
|
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
|
-
|
203
|
+
action :tdo, :assert, tdo_reg[i], meta: { position: i }
|
173
204
|
end
|
174
205
|
end
|
175
206
|
|
176
207
|
# TMS
|
177
|
-
|
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] = @
|
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
|
-
|
198
|
-
|
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
|
-
|
242
|
+
action :tdo, :assert, tdo_reg[i], meta: { position: i } if options[:read]
|
212
243
|
else
|
213
|
-
|
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
|
220
|
-
# execute a single
|
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
|
-
#
|
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
|
-
|
268
|
+
action :tms, :drive, 1
|
238
269
|
@last_data_vector_shifted = true
|
239
270
|
end
|
240
271
|
end
|
241
|
-
|
242
|
-
if
|
243
|
-
|
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
|
-
|
276
|
+
if overlay_options[:pins].nil? || cycle_callback?
|
277
|
+
cycle
|
247
278
|
else
|
248
|
-
|
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
|
-
@
|
283
|
+
@pins[:tdo].dont_care unless cycle_callback?
|
253
284
|
else
|
254
285
|
@deferred_compare = true
|
255
|
-
@deferred_store = true if
|
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
|
268
|
-
# Adjusts for the
|
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
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
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
|
-
|
286
|
-
|
287
|
-
|
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
|
-
|
290
|
-
|
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
|
-
|
293
|
-
|
294
|
-
|
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
|
-
|
297
|
-
|
328
|
+
@tck_multiple.times do |i|
|
329
|
+
# 50% duty cycle if @tck_multiple is even, otherwise slightly off
|
298
330
|
|
299
|
-
|
331
|
+
@next_data_vector_to_be_stored = @tdo_store_cycle == i ? true : false
|
300
332
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
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
|
-
@
|
339
|
+
@pins[:tdo].suspend
|
309
340
|
else
|
310
341
|
@tdo_suspended_by_driver = false
|
311
|
-
@
|
342
|
+
@pins[:tdo].resume
|
312
343
|
end
|
313
344
|
end
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
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
|
-
@
|
351
|
+
@pins[:tdo].suspend
|
323
352
|
else
|
324
353
|
@tdo_suspended_by_driver = false
|
325
|
-
@
|
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
|
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
|
-
|
375
|
+
action :tdo, :dont_care
|
347
376
|
end
|
348
377
|
|
349
378
|
if @deferred_store
|
350
379
|
@deferred_store = nil
|
351
|
-
|
380
|
+
store_tdo_this_tck = true
|
352
381
|
else
|
353
|
-
|
382
|
+
store_tdo_this_tck = false
|
354
383
|
end
|
355
384
|
@next_data_vector_to_be_stored = false
|
356
385
|
|
357
|
-
|
358
|
-
if
|
359
|
-
|
386
|
+
tck_cycle do
|
387
|
+
if store_tdo_this_tck && @next_data_vector_to_be_stored
|
388
|
+
action :store
|
360
389
|
end
|
361
|
-
|
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
|
-
@
|
605
|
-
@
|
606
|
-
@
|
607
|
-
@
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
@
|
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(:
|
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
|
-
|
54
|
-
|
55
|
-
|
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
|
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
|
data/pattern/jtag_workout.rb
CHANGED
@@ -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
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
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'
|
data/templates/web/index.md.erb
CHANGED
@@ -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.
|
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
|
-
####
|
34
|
+
#### Integration
|
34
35
|
|
35
|
-
|
36
|
-
|
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
|
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
|
-
|
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
|
-
#
|
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
|
-
|
64
|
-
|
65
|
-
tdo_strobe: :
|
66
|
-
tdo_store_cycle: 3
|
67
|
-
|
68
|
-
|
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
|
-
|
76
|
-
|
77
|
-
tdo_strobe: :
|
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 (
|
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 `:
|
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
|
-
|
116
|
+
tck_vals: { on: 'P', off: 0 }
|
98
117
|
~~~
|
99
118
|
|
100
|
-
|
101
|
-
|
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.
|
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-
|
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
|