Class: OrigenJTAG::Driver
- Inherits:
-
Object
- Object
- OrigenJTAG::Driver
- Includes:
- Origen::Model, TAPController
- Defined in:
- lib/origen_jtag/driver.rb
Overview
This driver provides methods to read and write from a JTAG instruction and data registers.
Low level methods are also provided for fine control of the TAP Controller state machine via the TAPController module.
To use this driver the parent model must define the following pins (an alias is fine):
:tck
:tdi
:tdo
:tms
Constant Summary collapse
- REQUIRED_PINS =
[:tck, :tdi, :tdo, :tms]
Constants included from TAPController
Instance Attribute Summary collapse
-
#ir_value ⇒ Object
readonly
Returns the current value in the instruction register.
-
#log_state_changes ⇒ Object
Log all state changes in pattern comments, false by default.
-
#owner ⇒ Object
readonly
Returns the object that instantiated the JTAG.
-
#tck_format ⇒ Object
(also: #tclk_format)
Wave/timing format of the JTAG clock: :rh (ReturnHigh) or :rl (ReturnLo), :rh is the default.
-
#tck_multiple ⇒ Object
(also: #tclk_multiple)
The number of cycles for one clock pulse, assumes 50% duty cycle.
-
#tdo_store_cycle ⇒ Object
Returns the value of attribute tdo_store_cycle.
-
#tdo_strobe ⇒ Object
Returns the value of attribute tdo_strobe.
-
#verbose ⇒ Object
(also: #verbose?)
Set true to print out debug comments about all state transitions.
Attributes included from TAPController
Instance Method Summary collapse
- #apply_action(pin, actions) ⇒ Object
-
#cycle_callback? ⇒ Boolean
When true it means that the application is dealing with how to handle the 4 JTAG signals for each JTAG cycle.
-
#initialize(owner, options = {}) ⇒ Driver
constructor
A new instance of Driver.
-
#read_dr(reg_or_val, options = {}) ⇒ Object
Read the given value, register or bit collection from the data register.
-
#read_ir(reg_or_val, options = {}) ⇒ Object
Read the given value, register or bit collection from the instruction register.
-
#shift(reg_or_val, options = {}) ⇒ Object
Shift data into the TDI pin or out of the TDO pin.
-
#tck_cycle ⇒ Object
(also: #tclk_cycle)
Cycles the tester through one TCK cycle Adjusts for the TCK format and cycle span Assumes caller will drive pattern to tester via .drive or similar.
-
#tms!(val) ⇒ Object
Applies the given value to the TMS pin and then cycles the tester for one TCK.
-
#write_dr(reg_or_val, options = {}) ⇒ Object
Write the given value, register or bit collection to the data register.
-
#write_ir(reg_or_val, options = {}) ⇒ Object
Write the given value, register or bit collection to the instruction register.
Methods included from TAPController
#idle, #pause_dr, #pause_ir, #reset, #shift_dr, #shift_ir, #state_str, #update_state
Constructor Details
#initialize(owner, options = {}) ⇒ Driver
Returns a new instance of Driver.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/origen_jtag/driver.rb', line 48 def initialize(owner, = {}) if owner.is_a?(Hash) @owner = parent = owner else @owner = owner end # The parent can configure JTAG settings by defining this constant if defined?(owner.class::JTAG_CONFIG) = owner.class::JTAG_CONFIG.merge() end @cycle_callback = [:cycle_callback] @given_options = .dup # Save these for later use in the pins method # Fallback defaults = { verbose: false, 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.) # 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) init_state: :unknown }.merge() init_tap_controller() @verbose = [:verbose] @ir_value = :unknown @tck_format = [:tck_format] || [:tclk_format] || :rh @tck_multiple = [:tck_multiple] || [:tclk_multiple] || 1 self.tdo_strobe = [:tdo_strobe] || :tck_high @tdo_store_cycle = [:tdo_store_cycle] @state = [:init_state] @log_state_changes = [:log_state_changes] || false if [:tck_vals] || [:tclk_vals] @tck_vals = [:tck_vals] || [:tclk_vals] unless @tck_vals.is_a?(Hash) && @tck_vals.key?(:on) && @tck_vals.key?(:off) fail "When specifying TCK values, you must supply a hash with both :on and :off keys, e.g. tck_vals: { on: 'P', off: 0 }" end end if @cycle_callback && @tck_multiple != 1 fail 'A cycle_callback can only be used with a tck_multiple setting of 1' end end |
Instance Attribute Details
#ir_value ⇒ Object (readonly)
Returns the current value in the instruction register
24 25 26 |
# File 'lib/origen_jtag/driver.rb', line 24 def ir_value @ir_value end |
#log_state_changes ⇒ Object
Log all state changes in pattern comments, false by default
46 47 48 |
# File 'lib/origen_jtag/driver.rb', line 46 def log_state_changes @log_state_changes end |
#owner ⇒ Object (readonly)
Returns the object that instantiated the JTAG
21 22 23 |
# File 'lib/origen_jtag/driver.rb', line 21 def owner @owner end |
#tck_format ⇒ Object Also known as: tclk_format
Wave/timing format of the JTAG clock: :rh (ReturnHigh) or :rl (ReturnLo), :rh is the default
34 35 36 |
# File 'lib/origen_jtag/driver.rb', line 34 def tck_format @tck_format end |
#tck_multiple ⇒ Object Also known as: tclk_multiple
The number of cycles for one clock pulse, assumes 50% duty cycle. Uses tester non-return format to spread TCK across multiple cycles.
e.g. @tck_multiple = 2, @tck_format = :rh, means one cycle with Tck low (non-return), one with Tck high (NR)
@tck_multiple = 4, @tck_format = :rl, means 2 cycles with Tck high (NR), 2 with Tck low (NR)
29 30 31 |
# File 'lib/origen_jtag/driver.rb', line 29 def tck_multiple @tck_multiple end |
#tdo_store_cycle ⇒ Object
Returns the value of attribute tdo_store_cycle.
39 40 41 |
# File 'lib/origen_jtag/driver.rb', line 39 def tdo_store_cycle @tdo_store_cycle end |
#tdo_strobe ⇒ Object
Returns the value of attribute tdo_strobe.
38 39 40 |
# File 'lib/origen_jtag/driver.rb', line 38 def tdo_strobe @tdo_strobe end |
#verbose ⇒ Object Also known as: verbose?
Set true to print out debug comments about all state transitions
42 43 44 |
# File 'lib/origen_jtag/driver.rb', line 42 def verbose @verbose end |
Instance Method Details
#apply_action(pin, actions) ⇒ Object
528 529 530 531 532 533 |
# File 'lib/origen_jtag/driver.rb', line 528 def apply_action(pin, actions) actions.each do |operation| method = operation.shift pin.send(method, *operation) if method end end |
#cycle_callback? ⇒ Boolean
When true it means that the application is dealing with how to handle the 4 JTAG signals for each JTAG cycle. In that case this driver calculates what state the 4 pins should be in each signal and then calls back to the application with that information and it is up to the application to decide what to do with that information and when/if to generate tester cycles.
113 114 115 |
# File 'lib/origen_jtag/driver.rb', line 113 def cycle_callback? !!@cycle_callback end |
#read_dr(reg_or_val, options = {}) ⇒ Object
Read the given value, register or bit collection from the data register. This is a self contained method that will take care of the TAP controller state transitions, exiting with the TAP controller in Run-Test/Idle.
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
# File 'lib/origen_jtag/driver.rb', line 442 def read_dr(reg_or_val, = {}) if Origen.tester.respond_to?(:read_dr) Origen.tester.read_dr(reg_or_val, ) else = { read: true }.merge() if [:msg] cc "#{[:msg]}\n" end shift_dr(.merge(read: Origen::Utility.read_hex(reg_or_val))) do shift(reg_or_val, ) end end end |
#read_ir(reg_or_val, options = {}) ⇒ Object
Read the given value, register or bit collection from the instruction register. This is a self contained method that will take care of the TAP controller state transitions, exiting with the TAP controller in Run-Test/Idle.
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 |
# File 'lib/origen_jtag/driver.rb', line 512 def read_ir(reg_or_val, = {}) if Origen.tester.respond_to?(:read_ir) Origen.tester.read_ir(reg_or_val, ) else = { read: true }.merge() if [:msg] cc "#{[:msg]}\n" end shift_ir(read: Origen::Utility.read_hex(reg_or_val)) do shift(reg_or_val, ) end end end |
#shift(reg_or_val, options = {}) ⇒ Object
Shift data into the TDI pin or out of the TDO pin.
There is no TAP controller state checking or handling here, it just shifts some data directly into the pattern, so it is assumed that some higher level logic is co-ordinating the TAP Controller.
Most applications should not call this method directly and should instead use the pre-packaged read/write_dr/ir methods. However it is provided as a public API for the corner cases like generating an overlay subroutine pattern where it would be necessary to generate some JTAG vectors outwith the normal state controller wrapper.
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
# File 'lib/origen_jtag/driver.rb', line 151 def shift(reg_or_val, = {}) = { read: false, cycle_last: false, includes_last_bit: true, no_subr: false # do not use subroutine for any overlay }.merge() # save compression state for restoring afterwards compression_on = !Origen.tester.dont_compress # clean incoming data size = extract_size(reg_or_val, ) tdi_reg = extract_shift_in_data(reg_or_val, size, ) tdo_reg = extract_shift_out_data(reg_or_val, size, ) global_ovl, ovl_reg = (reg_or_val, size, ) # let the tester handle overlay if possible unless tester.respond_to?(:source_memory) # tester does not support direct labels, so can't do if [:no_subr] && !$tester.respond_to?('label') cc 'This tester does not support use of labels, cannot do no_subr option as requested' cc ' going with subroutine overlay instead' [:no_subr] = false end # insert global label if specified if global_ovl if $tester.respond_to?('label') $tester.label(global_ovl, true) else cc "Unsupported global label: #{global_ovl}" end end end # of let tester handle overlay if possible # loop through each data bit = '' size.times do |i| store_tdo_this_tck = false # Set up pin actions for bit transaction (tck cycle) # TDI action :tdi, :drive, tdi_reg[i] # TDO action :tdo, :dont_care # default setting if tdo_reg[i] if tdo_reg[i].is_to_be_stored? # store store_tdo_this_tck = true action :tdo, :dont_care if Origen.tester.j750? elsif tdo_reg[i].is_to_be_read? # compare/assert action :tdo, :assert, tdo_reg[i], meta: { position: i } end end # TMS action :tms, :drive, 0 # let tester handle overlay if implemented = {} if tester.respond_to?(:source_memory) && !cycle_callback? if ovl_reg[i] && ovl_reg[i]. && !Origen.mode.simulation? [:pins] = pins[:tdi] if global_ovl [:overlay_str] = global_ovl else [:overlay_str] = ovl_reg[i]. end if [:no_subr] || global_ovl if global_ovl [:overlay_style] = :global_label else [:overlay_style] = :label end end = !([:no_subr] || global_ovl) && tester. == :subroutine action :tdi, :drive, 0 if action :tdo, :assert, tdo_reg[i], meta: { position: i } if [:read] unless # Force the last bit to be shifted from this method if overlay requested on the last bit [:cycle_last] = true if i == size - 1 end else # Overlay - reconfigure pin action for overlay if necessary if ovl_reg[i] && ovl_reg[i]. && !Origen.mode.simulation? if [:no_subr] Origen.tester.dont_compress = true if ovl_reg[i]. != $tester.label(ovl_reg[i].) = ovl_reg[i]. end action :tdo, :assert, tdo_reg[i], meta: { position: i } if [:read] else action :tdi, :drive, 0 call_subroutine = ovl_reg[i]. end end end # of let tester handle overlay # With JTAG pin actions queued up, use block call to tck_cycle to # execute a single TCK period. Special handling of subroutines, # case of last bit in shift, and store vector (within a multi-cycle # tck config). if call_subroutine || @last_data_vector_shifted = true else @last_data_vector_shifted = false end if call_subroutine Origen.tester.call_subroutine(call_subroutine) else @next_data_vector_to_be_stored = false # Don't latch the last bit, that will be done when leaving the state. if i != size - 1 || [:cycle_last] if i == size - 1 && [:includes_last_bit] unless action :tms, :drive, 1 @last_data_vector_shifted = true end end tck_cycle do if store_tdo_this_tck && @next_data_vector_to_be_stored action :store end if [:pins].nil? || cycle_callback? cycle else cycle overlay: [:change_data] = false # data change only on first cycle if overlay end end pins[:tdo].dont_care unless cycle_callback? else @deferred_compare = true @deferred_store = true if store_tdo_this_tck end end end # Clear read and similar flags to reflect that the request has just been fulfilled reg_or_val.clear_flags if reg_or_val.respond_to?(:clear_flags) # put back compression if turned on above Origen.tester.dont_compress = false if compression_on end |
#tck_cycle ⇒ Object Also known as: tclk_cycle
Cycles the tester through one TCK cycle Adjusts for the TCK format and cycle span Assumes caller will drive pattern to tester via .drive or similar
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
# File 'lib/origen_jtag/driver.rb', line 303 def tck_cycle if cycle_callback? @next_data_vector_to_be_stored = @tdo_store_cycle yield else case @tck_format when :rh tck_val = 0 when :rl tck_val = 1 else fail 'ERROR: Invalid Tclk timing format!' end # determine whether to mask TDO on first half cycle mask_tdo_half0 = ((@tck_format == :rl) && (@tdo_strobe == :tck_low) && (@tck_multiple > 1)) || ((@tck_format == :rh) && (@tdo_strobe == :tck_high) && (@tck_multiple > 1)) # determine whether to mask TDO on second half cycle mask_tdo_half1 = ((@tck_format == :rl) && (@tdo_strobe == :tck_high) && (@tck_multiple > 1)) || ((@tck_format == :rh) && (@tdo_strobe == :tck_low) && (@tck_multiple > 1)) # If TDO is already suspended (by an application) then don't do the # suspends below since the resume will clear the application's suspend tdo_already_suspended = !cycle_callback? && pins[:tdo].suspended? && !@tdo_suspended_by_driver @tck_multiple.times do |i| # 50% duty cycle if @tck_multiple is even, otherwise slightly off @next_data_vector_to_be_stored = @tdo_store_cycle == i ? true : false if i < (@tck_multiple + 1) / 2 # first half of cycle pins[:tck].drive(@tck_vals ? @tck_vals[:on] : tck_val) unless tdo_already_suspended if mask_tdo_half0 @tdo_suspended_by_driver = true pins[:tdo].suspend else @tdo_suspended_by_driver = false pins[:tdo].resume end end else # second half of cycle pins[:tck].drive(@tck_vals ? @tck_vals[:off] : (1 - tck_val)) unless tdo_already_suspended if mask_tdo_half1 @tdo_suspended_by_driver = true pins[:tdo].suspend else @tdo_suspended_by_driver = false pins[:tdo].resume end end end yield end if @tdo_suspended_by_driver @tdo_suspended_by_driver = false pins[:tdo].resume end end end |
#tms!(val) ⇒ Object
Applies the given value to the TMS pin and then cycles the tester for one TCK
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
# File 'lib/origen_jtag/driver.rb', line 373 def tms!(val) if @deferred_compare @deferred_compare = nil else action :tdo, :dont_care end if @deferred_store @deferred_store = nil store_tdo_this_tck = true else store_tdo_this_tck = false end @next_data_vector_to_be_stored = false tck_cycle do if store_tdo_this_tck && @next_data_vector_to_be_stored action :store end action :tms, :drive, val cycle end end |
#write_dr(reg_or_val, options = {}) ⇒ Object
Write the given value, register or bit collection to the data register. This is a self contained method that will take care of the TAP controller state transitions, exiting with the TAP controller in Run-Test/Idle.
411 412 413 414 415 416 417 418 419 420 421 422 423 |
# File 'lib/origen_jtag/driver.rb', line 411 def write_dr(reg_or_val, = {}) if Origen.tester.respond_to?(:write_dr) Origen.tester.write_dr(reg_or_val, ) else if [:msg] cc "#{[:msg]}\n" end val = reg_or_val.respond_to?(:data) ? reg_or_val.data : reg_or_val shift_dr(.merge(write: val.to_hex)) do shift(reg_or_val, ) end end end |
#write_ir(reg_or_val, options = {}) ⇒ Object
Write the given value, register or bit collection to the instruction register. This is a self contained method that will take care of the TAP controller state transitions, exiting with the TAP controller in Run-Test/Idle.
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
# File 'lib/origen_jtag/driver.rb', line 478 def write_ir(reg_or_val, = {}) val = reg_or_val.respond_to?(:data) ? reg_or_val.data : reg_or_val if val != ir_value || [:force] if [:msg] cc "#{[:msg]}\n" end if Origen.tester.respond_to?(:write_ir) Origen.tester.write_ir(reg_or_val, ) else shift_ir(.merge(write: val.to_hex)) do shift(reg_or_val, ) end end @ir_value = val end end |