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.
- checksums.yaml +5 -5
- data/config/application.rb +64 -64
- data/config/boot.rb +24 -24
- data/config/commands.rb +127 -127
- data/config/version.rb +8 -8
- data/lib/origen_jtag.rb +13 -13
- data/lib/origen_jtag/driver.rb +624 -624
- data/lib/origen_jtag/tap_controller.rb +347 -347
- data/lib/origen_jtag_dev/new_style.rb +113 -113
- data/lib/origen_jtag_dev/top_level.rb +94 -94
- data/pattern/full_reg_ovly_cap.rb +11 -11
- data/pattern/global_label_test.rb +12 -12
- data/pattern/jtag_workout.rb +221 -221
- data/pattern/rww_test.rb +25 -25
- data/pattern/two_port.rb +49 -49
- data/templates/web/index.md.erb +234 -234
- data/templates/web/layouts/_basic.html.erb +16 -16
- data/templates/web/partials/_navbar.html.erb +22 -22
- data/templates/web/release_notes.md.erb +5 -5
- metadata +3 -4
- data/config/development.rb +0 -15
data/lib/origen_jtag.rb
CHANGED
@@ -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
|
data/lib/origen_jtag/driver.rb
CHANGED
@@ -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
|