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):
:tclk
:tdi
:tdo
:tms
Constant Summary collapse
- REQUIRED_PINS =
[:tclk, :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.
-
#tclk_format ⇒ Object
Returns the value of attribute tclk_format.
-
#tclk_multiple ⇒ Object
readonly
Returns the tclk multiple.
-
#verbose ⇒ Object
(also: #verbose?)
Set true to print out debug comments about all state transitions.
Attributes included from TAPController
Instance Method Summary collapse
-
#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.
-
#tclk_cycle ⇒ Object
Cycles the tester through one TCLK cycle Adjusts for the TCLK 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 TCLK.
-
#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
37 38 39 40 41 42 43 44 45 46 47 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 |
# File 'lib/origen_jtag/driver.rb', line 37 def initialize(owner, = {}) if owner.is_a?(Hash) @owner = parent = owner else @owner = owner end validate_pins() # The parent can configure JTAG settings by defining this constant if defined?(owner.class::JTAG_CONFIG) = owner.class::JTAG_CONFIG.merge() end # Fallback defaults = { verbose: false, tclk_format: :rh, # format of JTAG clock used: ReturnHigh (:rh), ReturnLo (:rl) 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. # e.g. @tclk_multiple = 2, @tclk_format = :rh, means one cycle with Tck low (non-return), one with Tck high (NR) # @tclk_multiple = 4, @tclk_format = :rl, means 2 cycles with Tck high (NR), 2 with Tck low (NR) tdo_strobe: :tclk_high, # when using multiple cycles for TCK, when to strobe for TDO, options include: # :tclk_high - strobe TDO only when TCK is high # :tclk_low - strobe TDO only when TCK is low # :tclk_all - strobe TDO throughout TCK cycle 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 @tclk_format = [:tclk_format] @tclk_multiple = [:tclk_multiple] @tdo_strobe = [:tdo_strobe] @tdo_store_cycle = [:tdo_store_cycle] @state = [:init_state] @log_state_changes = [:log_state_changes] || false if [:tclk_vals] @tclk_vals = [:tclk_vals] unless @tclk_vals.is_a?(Hash) && @tclk_vals.key?(:on) && @tclk_vals.key?(:off) fail "When specifying TCLK values, you must supply a hash with both :on and :off keys, e.g. tclk_vals: { on: 'P', off: 0 }" end 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
35 36 37 |
# File 'lib/origen_jtag/driver.rb', line 35 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 |
#tclk_format ⇒ Object
Returns the value of attribute tclk_format.
29 30 31 |
# File 'lib/origen_jtag/driver.rb', line 29 def tclk_format @tclk_format end |
#tclk_multiple ⇒ Object (readonly)
Returns the tclk multiple
27 28 29 |
# File 'lib/origen_jtag/driver.rb', line 27 def tclk_multiple @tclk_multiple end |
#verbose ⇒ Object Also known as: verbose?
Set true to print out debug comments about all state transitions
31 32 33 |
# File 'lib/origen_jtag/driver.rb', line 31 def verbose @verbose end |
Instance Method Details
#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.
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
# File 'lib/origen_jtag/driver.rb', line 410 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(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.
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 |
# File 'lib/origen_jtag/driver.rb', line 480 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.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 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 |
# File 'lib/origen_jtag/driver.rb', line 119 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_tclk = false # Set up pin actions for bit transaction (tclk cycle) # TDI @tdi_pin.drive(tdi_reg[i]) # TDO @tdo_pin.dont_care # default setting if tdo_reg[i] if tdo_reg[i].is_to_be_stored? # store store_tdo_this_tclk = true @tdo_pin.dont_care if Origen.tester.j750? elsif tdo_reg[i].is_to_be_read? # compare/assert @tdo_pin.assert(tdo_reg[i], meta: { position: i }) end end # TMS @tms_pin.drive(0) # let tester handle overlay if implemented = {} if tester.respond_to?(:source_memory) if ovl_reg[i] && ovl_reg[i]. && !Origen.mode.simulation? [:pins] = @tdi_pin 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 @tdi_pin.drive(0) if @tdo_pin.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 @tdo_pin.assert(tdo_reg[i], meta: { position: i }) if [:read] else @tdi_pin.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 tclk_cycle to # execute a single TCLK period. Special handling of subroutines, # case of last bit in shift, and store vector (within a multi-cycle # tclk 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 @tms_pin.drive(1) @last_data_vector_shifted = true end end tclk_cycle do if store_tdo_this_tclk && @next_data_vector_to_be_stored Origen.tester.store_next_cycle(@tdo_pin) end if [:pins].nil? Origen.tester.cycle else Origen.tester.cycle overlay: [:change_data] = false # data change only on first cycle if overlay end end @tdo_pin.dont_care else @deferred_compare = true @deferred_store = true if store_tdo_this_tclk 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 |
#tclk_cycle ⇒ Object
Cycles the tester through one TCLK cycle Adjusts for the TCLK format and cycle span Assumes caller will drive pattern to tester via .drive or similar
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 |
# File 'lib/origen_jtag/driver.rb', line 271 def tclk_cycle case @tclk_format when :rh tclk_val = 0 when :rl tclk_val = 1 else fail 'ERROR: Invalid Tclk timing format!' end # determine whether to mask TDO on first half cycle mask_tdo_half0 = ((@tclk_format == :rl) && (@tdo_strobe == :tclk_low) && (@tclk_multiple > 1)) || ((@tclk_format == :rh) && (@tdo_strobe == :tclk_high) && (@tclk_multiple > 1)) # determine whether to mask TDO on second half cycle mask_tdo_half1 = ((@tclk_format == :rl) && (@tdo_strobe == :tclk_high) && (@tclk_multiple > 1)) || ((@tclk_format == :rh) && (@tdo_strobe == :tclk_low) && (@tclk_multiple > 1)) # determine whether TDO is set to capture for this TCLK cycle tdo_to_be_captured = @tdo_pin.to_be_captured? # 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 = @tdo_pin.suspended? && !@tdo_suspended_by_driver @tclk_multiple.times do |i| # 50% duty cycle if @tclk_multiple is even, otherwise slightly off @next_data_vector_to_be_stored = @tdo_store_cycle == i ? true : false if i < (@tclk_multiple + 1) / 2 # first half of cycle @tck_pin.drive(@tclk_vals ? @tclk_vals[:on] : tclk_val) unless tdo_already_suspended unless tdo_to_be_captured if mask_tdo_half0 @tdo_suspended_by_driver = true @tdo_pin.suspend else @tdo_suspended_by_driver = false @tdo_pin.resume end end end else # second half of cycle @tck_pin.drive(@tclk_vals ? @tclk_vals[:off] : (1 - tclk_val)) unless tdo_already_suspended unless tdo_to_be_captured if mask_tdo_half1 @tdo_suspended_by_driver = true @tdo_pin.suspend else @tdo_suspended_by_driver = false @tdo_pin.resume end end end end yield end if @tdo_suspended_by_driver @tdo_pin.resume @tdo_suspended_by_driver = false end end |
#tms!(val) ⇒ Object
Applies the given value to the TMS pin and then cycles the tester for one TCLK
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
# File 'lib/origen_jtag/driver.rb', line 342 def tms!(val) if @deferred_compare @deferred_compare = nil else @tdo_pin.dont_care end if @deferred_store @deferred_store = nil store_tdo_this_tclk = true else store_tdo_this_tclk = false end @next_data_vector_to_be_stored = false tclk_cycle do if store_tdo_this_tclk && @next_data_vector_to_be_stored Origen.tester.store_next_cycle(@tdo_pin) end @tms_pin.drive!(val) 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.
379 380 381 382 383 384 385 386 387 388 389 390 391 |
# File 'lib/origen_jtag/driver.rb', line 379 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(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.
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 |
# File 'lib/origen_jtag/driver.rb', line 446 def write_ir(reg_or_val, = {}) if Origen.tester.respond_to?(:write_ir) Origen.tester.write_ir(reg_or_val, ) else 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 shift_ir(write: val.to_hex) do shift(reg_or_val, ) end @ir_value = val end end end |