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
-
#chained_dr_lsb_data ⇒ Object
by default, the chained DR data is all zeros, this value overrides.
-
#chained_dr_lsb_length ⇒ Object
number of additional DR bits to add when chaining multiple devices, these additional bits are added to the LSB side.
-
#chained_dr_msb_data ⇒ Object
by default, the chained DR data is all zeros, this value overrides.
-
#chained_dr_msb_length ⇒ Object
number of additional DR bits to add when chaining multiple devices, these additional bits are added to the MSB side.
-
#chained_ir_lsb_data ⇒ Object
by default, the chained IR data is all zeros, this value overrides.
-
#chained_ir_lsb_length ⇒ Object
number of additional IR bits to add when chaining multiple devices, these additional bits are added to the LSB side.
-
#chained_ir_msb_data ⇒ Object
by default, the chained IR data is all zeros, this value overrides.
-
#chained_ir_msb_length ⇒ Object
number of additional IR bits to add when chaining multiple devices, these additional bits are added to the MSB side.
-
#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.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/origen_jtag/driver.rb', line 72 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 @chained_ir_msb_length = [:chained_ir_msb_length] @chained_ir_msb_data = [:chained_ir_msb_data] || 0 @chained_ir_lsb_length = [:chained_ir_lsb_length] @chained_ir_lsb_data = [:chained_ir_lsb_data] || 0 @chained_dr_msb_length = [:chained_dr_msb_length] @chained_dr_msb_data = [:chained_dr_msb_data] || 0 @chained_dr_lsb_length = [:chained_dr_lsb_length] @chained_dr_lsb_data = [:chained_dr_lsb_data] || 0 end |
Instance Attribute Details
#chained_dr_lsb_data ⇒ Object
by default, the chained DR data is all zeros, this value overrides
70 71 72 |
# File 'lib/origen_jtag/driver.rb', line 70 def chained_dr_lsb_data @chained_dr_lsb_data end |
#chained_dr_lsb_length ⇒ Object
number of additional DR bits to add when chaining multiple devices, these additional bits are added to the LSB side
67 68 69 |
# File 'lib/origen_jtag/driver.rb', line 67 def chained_dr_lsb_length @chained_dr_lsb_length end |
#chained_dr_msb_data ⇒ Object
by default, the chained DR data is all zeros, this value overrides
64 65 66 |
# File 'lib/origen_jtag/driver.rb', line 64 def chained_dr_msb_data @chained_dr_msb_data end |
#chained_dr_msb_length ⇒ Object
number of additional DR bits to add when chaining multiple devices, these additional bits are added to the MSB side
61 62 63 |
# File 'lib/origen_jtag/driver.rb', line 61 def chained_dr_msb_length @chained_dr_msb_length end |
#chained_ir_lsb_data ⇒ Object
by default, the chained IR data is all zeros, this value overrides
58 59 60 |
# File 'lib/origen_jtag/driver.rb', line 58 def chained_ir_lsb_data @chained_ir_lsb_data end |
#chained_ir_lsb_length ⇒ Object
number of additional IR bits to add when chaining multiple devices, these additional bits are added to the LSB side
55 56 57 |
# File 'lib/origen_jtag/driver.rb', line 55 def chained_ir_lsb_length @chained_ir_lsb_length end |
#chained_ir_msb_data ⇒ Object
by default, the chained IR data is all zeros, this value overrides
52 53 54 |
# File 'lib/origen_jtag/driver.rb', line 52 def chained_ir_msb_data @chained_ir_msb_data end |
#chained_ir_msb_length ⇒ Object
number of additional IR bits to add when chaining multiple devices, these additional bits are added to the MSB side
49 50 51 |
# File 'lib/origen_jtag/driver.rb', line 49 def chained_ir_msb_length @chained_ir_msb_length end |
#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
613 614 615 616 617 618 |
# File 'lib/origen_jtag/driver.rb', line 613 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.
170 171 172 |
# File 'lib/origen_jtag/driver.rb', line 170 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.
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 |
# File 'lib/origen_jtag/driver.rb', line 524 def read_dr(reg_or_val, = {}) = .merge(get_chained_in_data(:dr)) 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.
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 |
# File 'lib/origen_jtag/driver.rb', line 596 def read_ir(reg_or_val, = {}) = .merge(get_chained_in_data(:ir)) 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(.merge(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.
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 298 299 300 301 302 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 367 368 369 370 371 372 373 374 375 376 377 378 |
# File 'lib/origen_jtag/driver.rb', line 208 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 any LSB appended bits if [:tdi_lsb_append_size] # tdo is always don't care for appended bits action :tdo, :dont_care cc "appending #{[:tdi_lsb_append_size]} LSB bits" [:tdi_lsb_append_size].times do |i| action :tdi, :drive, [:tdi_lsb_append_data][i] tck_cycle { cycle } end end # 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 } unless || ![:read] # 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 || ) && ![:tdi_msb_append_size] @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] || [:tdi_msb_append_size] if i == size - 1 && [:includes_last_bit] && ![:tdi_msb_append_size] 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 # loop through any MSB append bits if [:tdi_msb_append_size] # last tdi bit was left applied, so tck cycle first, then apply new tdi and leave last one for state machine driver [:tdi_msb_append_size].times do |i| if i == 0 cc "appending #{[:tdi_msb_append_size]} MSB bits" action :tdo, :dont_care end action :tdi, :drive, [:tdi_msb_append_data][i] tck_cycle { cycle } unless i == [:tdi_msb_append_size] - 1 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
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 |
# File 'lib/origen_jtag/driver.rb', line 384 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
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
# File 'lib/origen_jtag/driver.rb', line 454 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.
492 493 494 495 496 497 498 499 500 501 502 503 504 505 |
# File 'lib/origen_jtag/driver.rb', line 492 def write_dr(reg_or_val, = {}) = .merge(get_chained_in_data(:dr)) 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.
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 |
# File 'lib/origen_jtag/driver.rb', line 561 def write_ir(reg_or_val, = {}) = .merge(get_chained_in_data(:ir)) 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 |