Class: OrigenJTAG::Driver
- Inherits:
-
Object
- Object
- OrigenJTAG::Driver
- Includes:
- Origen::Registers, 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.
-
#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
Returns a new instance of Driver.
33 34 35 36 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 |
# File 'lib/origen_jtag/driver.rb', line 33 def initialize(owner, = {}) @owner = owner 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 end |
Instance Attribute Details
#ir_value ⇒ Object (readonly)
Returns the current value in the instruction register
23 24 25 |
# File 'lib/origen_jtag/driver.rb', line 23 def ir_value @ir_value end |
#log_state_changes ⇒ Object
Log all state changes in pattern comments, false by default
31 32 33 |
# File 'lib/origen_jtag/driver.rb', line 31 def log_state_changes @log_state_changes end |
#owner ⇒ Object (readonly)
Returns the object that instantiated the JTAG
20 21 22 |
# File 'lib/origen_jtag/driver.rb', line 20 def owner @owner end |
#tclk_format ⇒ Object
Returns the value of attribute tclk_format.
25 26 27 |
# File 'lib/origen_jtag/driver.rb', line 25 def tclk_format @tclk_format end |
#verbose ⇒ Object Also known as: verbose?
Set true to print out debug comments about all state transitions
27 28 29 |
# File 'lib/origen_jtag/driver.rb', line 27 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.
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 |
# File 'lib/origen_jtag/driver.rb', line 374 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.
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
# File 'lib/origen_jtag/driver.rb', line 444 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.
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 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 |
# File 'lib/origen_jtag/driver.rb', line 104 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 owner.pin(:tdi).drive(tdi_reg[i]) # TDO owner.pin(:tdo).dont_care # default setting if tdo_reg[i] if tdo_reg[i].is_to_be_stored? # store store_tdo_this_tclk = true owner.pin(:tdo).dont_care if Origen.tester.j750? elsif tdo_reg[i].is_to_be_read? # compare/assert owner.pin(:tdo).assert(tdo_reg[i]) end end # TMS owner.pin(:tms).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] = owner.pin(:tdi) [:overlay_str] = ovl_reg[i]. [:overlay_style] = :label if [:no_subr] 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 owner.pin(:tdo).assert(tdo_reg[i]) if [:read] else owner.pin(: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 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 && !tester.respond_to?(:source_memory) Origen.tester.call_subroutine(call_subroutine) @last_data_vector_shifted = true else @last_data_vector_shifted = false @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] owner.pin(:tms).drive(1) end tclk_cycle do if store_tdo_this_tclk && @next_data_vector_to_be_stored Origen.tester.store_next_cycle(owner.pin(:tdo)) 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 owner.pin(:tdo).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
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 |
# File 'lib/origen_jtag/driver.rb', line 235 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 = owner.pin(:tdo).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 = owner.pin(:tdo).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 owner.pin(:tclk).drive(tclk_val) unless tdo_already_suspended unless tdo_to_be_captured if mask_tdo_half0 @tdo_suspended_by_driver = true owner.pin(:tdo).suspend else @tdo_suspended_by_driver = false owner.pin(:tdo).resume end end end else # second half of cycle owner.pin(:tclk).drive(1 - tclk_val) unless tdo_already_suspended unless tdo_to_be_captured if mask_tdo_half1 @tdo_suspended_by_driver = true owner.pin(:tdo).suspend else @tdo_suspended_by_driver = false owner.pin(:tdo).resume end end end end yield end if @tdo_suspended_by_driver owner.pin(:tdo).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
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/origen_jtag/driver.rb', line 306 def tms!(val) if @deferred_compare @deferred_compare = nil else owner.pin(:tdo).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(owner.pin(:tdo)) end owner.pin(:tms).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.
343 344 345 346 347 348 349 350 351 352 353 354 355 |
# File 'lib/origen_jtag/driver.rb', line 343 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.
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
# File 'lib/origen_jtag/driver.rb', line 410 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 |