-
1
module OrigenJTAG
-
# 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
-
1
class Driver
-
1
REQUIRED_PINS = [:tck, :tdi, :tdo, :tms]
-
-
1
include Origen::Model
-
1
include TAPController
-
# include Origen::Registers
-
-
# Returns the object that instantiated the JTAG
-
1
attr_reader :owner
-
-
# Returns the current value in the instruction register
-
1
attr_reader :ir_value
-
-
# 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)
-
1
attr_accessor :tck_multiple
-
1
alias_method :tclk_multiple, :tck_multiple
-
1
alias_method :tclk_multiple=, :tck_multiple=
-
-
# Wave/timing format of the JTAG clock: :rh (ReturnHigh) or :rl (ReturnLo), :rh is the default
-
1
attr_accessor :tck_format
-
1
alias_method :tclk_format, :tck_format
-
1
alias_method :tclk_format=, :tck_format=
-
-
1
attr_accessor :tdo_strobe
-
1
attr_accessor :tdo_store_cycle
-
-
# Set true to print out debug comments about all state transitions
-
1
attr_accessor :verbose
-
1
alias_method :verbose?, :verbose
-
-
# Log all state changes in pattern comments, false by default
-
1
attr_accessor :log_state_changes
-
-
1
def initialize(owner, options = {})
-
35
if owner.is_a?(Hash)
-
24
@owner = parent
-
24
options = owner
-
else
-
11
@owner = owner
-
end
-
# The parent can configure JTAG settings by defining this constant
-
35
if defined?(owner.class::JTAG_CONFIG)
-
11
options = owner.class::JTAG_CONFIG.merge(options)
-
end
-
-
35
@cycle_callback = options[:cycle_callback]
-
35
@given_options = options.dup # Save these for later use in the pins method
-
-
# Fallback defaults
-
options = {
-
35
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(options)
-
-
35
init_tap_controller(options)
-
-
35
@verbose = options[:verbose]
-
35
@ir_value = :unknown
-
35
@tck_format = options[:tck_format] || options[:tclk_format] || :rh
-
35
@tck_multiple = options[:tck_multiple] || options[:tclk_multiple] || 1
-
35
self.tdo_strobe = options[:tdo_strobe] || :tck_high
-
35
@tdo_store_cycle = options[:tdo_store_cycle]
-
35
@state = options[:init_state]
-
35
@log_state_changes = options[:log_state_changes] || false
-
35
if options[:tck_vals] || options[:tclk_vals]
-
3
@tck_vals = options[:tck_vals] || options[:tclk_vals]
-
3
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
-
35
if @cycle_callback && @tck_multiple != 1
-
fail 'A cycle_callback can only be used with a tck_multiple setting of 1'
-
end
-
end
-
-
# when using multiple cycles for TCK, set when to strobe for TDO, options include:
-
# :tck_high - strobe TDO only when TCK is high (Default)
-
# :tck_low - strobe TDO only when TCK is low
-
# :tck_all - strobe TDO throughout TCK cycle
-
1
def tdo_strobe=(val)
-
35
case val
-
when :tck_high, :tclk_high
-
35
@tdo_strobe = :tck_high
-
when :tck_low, :tclk_low
-
@tdo_strobe = :tck_low
-
when :tck_all, :tclk_all
-
@tdo_strobe = :tck_all
-
else
-
fail 'tdo_strobe must be set to one of: :tck_high, :tck_low or :tck_all'
-
end
-
end
-
-
# 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.
-
1
def cycle_callback?
-
111301
!!@cycle_callback
-
end
-
-
# 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.
-
#
-
# @param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
-
# Value to be shifted. If a reg/bit collection is supplied this can be pre-marked for
-
# read, store or overlay and which will result in the requested action being applied to
-
# the cycles corresponding to those bits only (don't care cycles will be generated for the others).
-
# @param [Hash] options Options to customize the operation
-
# @option options [Integer] :size The number of bits to shift. This is optional
-
# when supplying a register or bit collection in which case the size will be derived from
-
# the number of bits supplied. If this option is supplied then it will override
-
# the size derived from the bits. If the size is greater than the number of bits
-
# provided then the additional space will be padded by 0s or don't cares as appropriate.
-
# @option options [Boolean] :read (false) When true the given value will be compared on the TDO pin
-
# instead of being shifted into the TDI pin. In the case of a register object being provided
-
# only those bits that are actually marked for read will be compared.
-
# @option options [Boolean] :cycle_last (false) Normally the last data bit is applied to the
-
# pins but not cycled, this is to integrate with the TAPController which usually
-
# requires that the TMS value is also changed on the last data bit. To override this
-
# default behavior and force a cycle for the last data bit set this to true.
-
# @option options [Boolean] :includes_last_bit (true) When true the TMS pin will be driven
-
# to 1 on the last cycle of the shift if :cycle_last has been specified. To override this
-
# and keep TMS low on the last cycle set this to false. One reason for doing this would be
-
# if generating some subroutine vectors which only represented a partial section of a shift
-
# operation.
-
1
def shift(reg_or_val, options = {})
-
options = {
-
841
read: false,
-
cycle_last: false,
-
includes_last_bit: true,
-
no_subr: false # do not use subroutine for any overlay
-
}.merge(options)
-
-
# save compression state for restoring afterwards
-
841
compression_on = !Origen.tester.dont_compress
-
-
# clean incoming data
-
841
size = extract_size(reg_or_val, options)
-
841
tdi_reg = extract_shift_in_data(reg_or_val, size, options)
-
841
tdo_reg = extract_shift_out_data(reg_or_val, size, options)
-
841
global_ovl, ovl_reg = extract_overlay_data(reg_or_val, size, options)
-
-
# let the tester handle overlay if possible
-
841
unless tester.respond_to?(:source_memory)
-
# tester does not support direct labels, so can't do
-
if options[: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'
-
options[: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
-
841
last_overlay_label = ''
-
841
size.times do |i|
-
14292
store_tdo_this_tck = false
-
-
# Set up pin actions for bit transaction (tck cycle)
-
-
# TDI
-
14292
action :tdi, :drive, tdi_reg[i]
-
-
# TDO
-
14292
action :tdo, :dont_care # default setting
-
14292
if tdo_reg[i]
-
13380
if tdo_reg[i].is_to_be_stored? # store
-
1419
store_tdo_this_tck = true
-
1419
action :tdo, :dont_care if Origen.tester.j750?
-
11961
elsif tdo_reg[i].is_to_be_read? # compare/assert
-
3754
action :tdo, :assert, tdo_reg[i], meta: { position: i }
-
end
-
end
-
-
# TMS
-
14292
action :tms, :drive, 0
-
-
# let tester handle overlay if implemented
-
14292
overlay_options = {}
-
14292
if tester.respond_to?(:source_memory) && !cycle_callback?
-
13624
if ovl_reg[i] && ovl_reg[i].has_overlay? && !Origen.mode.simulation?
-
2500
overlay_options[:pins] = pins[:tdi]
-
2500
if global_ovl
-
32
overlay_options[:overlay_str] = global_ovl
-
else
-
2468
overlay_options[:overlay_str] = ovl_reg[i].overlay_str
-
end
-
2500
if options[:no_subr] || global_ovl
-
416
if global_ovl
-
32
overlay_options[:overlay_style] = :global_label
-
else
-
384
overlay_options[:overlay_style] = :label
-
end
-
end
-
2500
tester_subr_overlay = !(options[:no_subr] || global_ovl) && tester.overlay_style == :subroutine
-
2500
action :tdi, :drive, 0 if tester_subr_overlay
-
2500
action :tdo, :assert, tdo_reg[i], meta: { position: i } if options[:read] unless tester_subr_overlay
-
# Force the last bit to be shifted from this method if overlay requested on the last bit
-
2500
options[:cycle_last] = true if i == size - 1
-
end
-
else
-
# Overlay - reconfigure pin action for overlay if necessary
-
668
if ovl_reg[i] && ovl_reg[i].has_overlay? && !Origen.mode.simulation?
-
114
if options[:no_subr]
-
Origen.tester.dont_compress = true
-
if ovl_reg[i].overlay_str != last_overlay_label
-
$tester.label(ovl_reg[i].overlay_str)
-
last_overlay_label = ovl_reg[i].overlay_str
-
end
-
action :tdo, :assert, tdo_reg[i], meta: { position: i } if options[:read]
-
else
-
114
action :tdi, :drive, 0
-
114
call_subroutine = ovl_reg[i].overlay_str
-
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).
-
14292
if call_subroutine || tester_subr_overlay
-
2166
@last_data_vector_shifted = true
-
else
-
12126
@last_data_vector_shifted = false
-
end
-
-
14292
if call_subroutine
-
114
Origen.tester.call_subroutine(call_subroutine)
-
else
-
14178
@next_data_vector_to_be_stored = false
-
# Don't latch the last bit, that will be done when leaving the state.
-
14178
if i != size - 1 || options[:cycle_last]
-
13859
if i == size - 1 && options[:includes_last_bit]
-
424
unless tester_subr_overlay
-
370
action :tms, :drive, 1
-
370
@last_data_vector_shifted = true
-
end
-
end
-
13859
tck_cycle do
-
32777
if store_tdo_this_tck && @next_data_vector_to_be_stored
-
1398
action :store
-
end
-
32777
if overlay_options[:pins].nil? || cycle_callback?
-
26819
cycle
-
else
-
5958
cycle overlay: overlay_options
-
5958
overlay_options[:change_data] = false # data change only on first cycle if overlay
-
end
-
end
-
13859
pins[:tdo].dont_care unless cycle_callback?
-
else
-
319
@deferred_compare = true
-
319
@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
-
841
reg_or_val.clear_flags if reg_or_val.respond_to?(:clear_flags)
-
-
# put back compression if turned on above
-
841
Origen.tester.dont_compress = false if compression_on
-
end
-
-
# 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
-
1
def tck_cycle
-
17833
if cycle_callback?
-
723
@next_data_vector_to_be_stored = @tdo_store_cycle
-
723
yield
-
else
-
17110
case @tck_format
-
when :rh
-
11582
tck_val = 0
-
when :rl
-
5528
tck_val = 1
-
else
-
fail 'ERROR: Invalid Tclk timing format!'
-
end
-
-
# determine whether to mask TDO on first half cycle
-
17110
mask_tdo_half0 = ((@tck_format == :rl) && (@tdo_strobe == :tck_low) && (@tck_multiple > 1)) ||
-
17110
((@tck_format == :rh) && (@tdo_strobe == :tck_high) && (@tck_multiple > 1))
-
-
# determine whether to mask TDO on second half cycle
-
17110
mask_tdo_half1 = ((@tck_format == :rl) && (@tdo_strobe == :tck_high) && (@tck_multiple > 1)) ||
-
14346
((@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
-
17110
tdo_already_suspended = !cycle_callback? && pins[:tdo].suspended? && !@tdo_suspended_by_driver
-
-
17110
@tck_multiple.times do |i|
-
# 50% duty cycle if @tck_multiple is even, otherwise slightly off
-
-
41526
@next_data_vector_to_be_stored = @tdo_store_cycle == i ? true : false
-
-
41526
if i < (@tck_multiple + 1) / 2
-
# first half of cycle
-
24006
pins[:tck].drive(@tck_vals ? @tck_vals[:on] : tck_val)
-
24006
unless tdo_already_suspended
-
23481
if mask_tdo_half0
-
11740
@tdo_suspended_by_driver = true
-
11740
pins[:tdo].suspend
-
else
-
11741
@tdo_suspended_by_driver = false
-
11741
pins[:tdo].resume
-
end
-
end
-
else
-
# second half of cycle
-
17520
pins[:tck].drive(@tck_vals ? @tck_vals[:off] : (1 - tck_val))
-
17520
unless tdo_already_suspended
-
17142
if mask_tdo_half1
-
5402
@tdo_suspended_by_driver = true
-
5402
pins[:tdo].suspend
-
else
-
11740
@tdo_suspended_by_driver = false
-
11740
pins[:tdo].resume
-
end
-
end
-
end
-
41526
yield
-
end
-
17110
if @tdo_suspended_by_driver
-
2701
@tdo_suspended_by_driver = false
-
2701
pins[:tdo].resume
-
end
-
end
-
end
-
1
alias_method :tclk_cycle, :tck_cycle
-
-
# Applies the given value to the TMS pin and then
-
# cycles the tester for one TCK
-
#
-
# @param [Integer] val Value to drive on the TMS pin, 0 or 1
-
1
def tms!(val)
-
3974
if @deferred_compare
-
300
@deferred_compare = nil
-
else
-
3674
action :tdo, :dont_care
-
end
-
-
3974
if @deferred_store
-
21
@deferred_store = nil
-
21
store_tdo_this_tck = true
-
else
-
3953
store_tdo_this_tck = false
-
end
-
3974
@next_data_vector_to_be_stored = false
-
-
3974
tck_cycle do
-
9472
if store_tdo_this_tck && @next_data_vector_to_be_stored
-
21
action :store
-
end
-
9472
action :tms, :drive, val
-
9472
cycle
-
end
-
end
-
-
# 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.
-
#
-
# @param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
-
# Value to be written. If a reg/bit collection is supplied this can be pre-marked for overlay.
-
# @param [Hash] options Options to customize the operation
-
# @option options [Integer] :size The number of bits to write. This is optional
-
# when supplying a register or bit collection in which case the size will be derived from
-
# the number of bits supplied. If this option is supplied then it will override
-
# the size derived from the bits. If the size is greater than the number of bits
-
# provided then the additional space will be padded by 0s.
-
# @option options [String] :msg By default will not make any comments directly here. Can pass
-
# a msg to be written out prior to shifting data.
-
1
def write_dr(reg_or_val, options = {})
-
115
if Origen.tester.respond_to?(:write_dr)
-
Origen.tester.write_dr(reg_or_val, options)
-
else
-
115
if options[:msg]
-
57
cc "#{options[:msg]}\n"
-
end
-
115
val = reg_or_val.respond_to?(:data) ? reg_or_val.data : reg_or_val
-
115
shift_dr(options.merge(write: val.to_hex)) do
-
115
shift(reg_or_val, options)
-
end
-
end
-
end
-
-
# 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.
-
#
-
# @param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
-
# Value to be read. If a reg/bit collection is supplied this can be pre-marked for read in which
-
# case only the marked bits will be read and the vectors corresponding to the data from the non-read
-
# bits will be set to don't care. Similarly the bits can be pre-marked for store (capture) or
-
# overlay.
-
# @param [Hash] options Options to customize the operation
-
# @option options [Integer] :size The number of bits to read. This is optional
-
# when supplying a register or bit collection in which case the size will be derived from
-
# the number of bits supplied. If the size is supplied then it will override
-
# the size derived from the bits. If the size is greater than the number of bits
-
# provided then the additional space will be padded by don't care cycles.
-
# @option options [String] :msg By default will not make any comments directly here. Can pass
-
# a msg to be written out prior to shifting data.
-
1
def read_dr(reg_or_val, options = {})
-
132
if Origen.tester.respond_to?(:read_dr)
-
Origen.tester.read_dr(reg_or_val, options)
-
else
-
options = {
-
132
read: true
-
}.merge(options)
-
132
if options[:msg]
-
111
cc "#{options[:msg]}\n"
-
end
-
132
shift_dr(options.merge(read: Origen::Utility.read_hex(reg_or_val))) do
-
132
shift(reg_or_val, options)
-
end
-
end
-
end
-
-
# 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.
-
#
-
# @param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
-
# Value to be written. If a reg/bit collection is supplied this can be pre-marked for overlay.
-
# @param [Hash] options Options to customize the operation
-
# @option options [Integer] :size The number of bits to write. This is optional
-
# when supplying a register or bit collection in which case the size will be derived from
-
# the number of bits supplied. If this option is supplied then it will override
-
# the size derived from the bits. If the size is greater than the number of bits
-
# provided then the additional space will be padded by 0s.
-
# @option options [Boolean] :force By default multiple calls to this method will not generate
-
# multiple writes. This is to allow wrapper algorithms to remain efficient yet not have to
-
# manually track the IR state (and in many cases this may be impossible due to multiple
-
# protocols using the same JTAG). To force a write regardless of what the driver thinks the IR
-
# contains set this to true.
-
# @option options [String] :msg By default will not make any comments directly here. Can pass
-
# a msg to be written out prior to shifting in IR data. Will not write comment only if write
-
# occurs.
-
1
def write_ir(reg_or_val, options = {})
-
76
val = reg_or_val.respond_to?(:data) ? reg_or_val.data : reg_or_val
-
76
if val != ir_value || options[:force]
-
57
if options[:msg]
-
19
cc "#{options[:msg]}\n"
-
end
-
57
if Origen.tester.respond_to?(:write_ir)
-
Origen.tester.write_ir(reg_or_val, options)
-
else
-
57
shift_ir(options.merge(write: val.to_hex)) do
-
57
shift(reg_or_val, options)
-
end
-
end
-
57
@ir_value = val
-
end
-
end
-
-
# 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.
-
#
-
# @param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
-
# Value to be read. If a reg/bit collection is supplied this can be pre-marked for read in which
-
# case only the marked bits will be read and the vectors corresponding to the data from the non-read
-
# bits will be set to don't care. Similarly the bits can be pre-marked for store (capture) or
-
# overlay.
-
# @param [Hash] options Options to customize the operation
-
# @option options [Integer] :size The number of bits to read. This is optional
-
# when supplying a register or bit collection in which case the size will be derived from
-
# the number of bits supplied. If the size is supplied then it will override
-
# the size derived from the bits. If the size is greater than the number of bits
-
# provided then the additional space will be padded by don't care cycles.
-
# @option options [String] :msg By default will not make any comments directly here. Can pass
-
# a msg to be written out prior to shifting data.
-
1
def read_ir(reg_or_val, options = {})
-
19
if Origen.tester.respond_to?(:read_ir)
-
Origen.tester.read_ir(reg_or_val, options)
-
else
-
options = {
-
19
read: true
-
}.merge(options)
-
19
if options[:msg]
-
19
cc "#{options[:msg]}\n"
-
end
-
19
shift_ir(read: Origen::Utility.read_hex(reg_or_val)) do
-
19
shift(reg_or_val, options)
-
end
-
end
-
end
-
-
1
def apply_action(pin, actions)
-
126747
actions.each do |operation|
-
63380
method = operation.shift
-
63380
pin.send(method, *operation) if method
-
end
-
end
-
-
1
private
-
-
1
def action(pin_id, *operations)
-
64799
@actions ||= clear_actions
-
64799
if pin_id == :store
-
1419
@actions[:store] = true
-
else
-
63380
fail "Unkown JTAG pin ID: #{pin_id}" unless @actions[pin_id]
-
63380
@actions[pin_id] << operations
-
end
-
end
-
-
1
def cycle(options = {})
-
42249
if @actions
-
42249
if cycle_callback?
-
723
@owner.send(@cycle_callback, @actions, options)
-
else
-
41526
apply_action(pins[:tms], @actions[:tms])
-
41526
apply_action(pins[:tdi], @actions[:tdi])
-
41526
apply_action(pins[:tdo], @actions[:tdo])
-
41526
tester.store_next_cycle(pins[:tdo]) if @actions[:store]
-
41526
tester.cycle(options)
-
end
-
42249
clear_actions
-
end
-
end
-
-
1
def clear_actions
-
42276
@actions = { tdi: [], tms: [], tdo: [], store: false }
-
end
-
-
# Return size of transaction. Options[:size] has priority and need not match the
-
# register size. Any mismatch will be handled by the api.
-
1
def extract_size(reg_or_val, options = {})
-
841
size = options[:size]
-
841
unless size
-
300
if reg_or_val.is_a?(Integer) || !reg_or_val.respond_to?(:size)
-
fail 'When suppling a value to JTAG::Driver#shift you must supply a :size in the options!'
-
else
-
300
size = reg_or_val.size
-
end
-
end
-
841
size
-
end
-
-
# Combine any legacy options into a single global overlay and create
-
# new bit collection to track any bit-wise overlays.
-
1
def extract_overlay_data(reg_or_val, size, options = {})
-
841
if reg_or_val.respond_to?(:data)
-
494
ovl = reg_or_val.dup
-
else
-
347
ovl = Reg.dummy(size)
-
end
-
-
841
if options[:overlay]
-
2
global = options[:overlay_label]
-
839
elsif options.key?(:arm_debug_overlay) # prob don't need this anymore
-
global = options[:arm_debug_overlay] # prob don't need this anymore
-
else
-
839
global = nil
-
end
-
-
841
[global, ovl]
-
end
-
-
# Create data that will be shifted in on TDI, create new bit collection
-
# on the fly if reg_or_val arg is data only. Consider read operation
-
# where caller has requested (specific) shift in data to be used.
-
1
def extract_shift_in_data(reg_or_val, size, options = {})
-
841
if reg_or_val.respond_to?(:data)
-
494
if options[:read]
-
280
data = options[:shift_in_data] || 0
-
280
tdi = Reg.dummy(size)
-
280
tdi.write(data)
-
else
-
214
tdi = reg_or_val.dup
-
end
-
else
-
# Not a register model, so can't support bit-wise overlay
-
347
tdi = Reg.dummy(size)
-
347
if options[:read]
-
168
data = options[:shift_in_data] || 0
-
168
tdi.write(data)
-
else
-
179
tdi.write(reg_or_val)
-
end
-
end
-
841
tdi
-
end
-
-
# Create data that will be shifted out on TDO, create new bit collection
-
# on the fly if reg_or_val arg is data only. Consider write operation
-
# where caller has requested (specific) shift out data to be compared.
-
1
def extract_shift_out_data(reg_or_val, size, options = {})
-
841
if reg_or_val.respond_to?(:data)
-
494
if options[:read]
-
280
tdo = reg_or_val.dup
-
280
tdo.read(options) unless options[:mask].nil?
-
else
-
214
tdo = Reg.dummy(size) unless options[:shift_out_data].is_a?(Origen::Registers::Reg)
-
end
-
494
unless options[:read] # if this is a write operation
-
214
if options[:shift_out_data]
-
8
if options[:shift_out_data].class.to_s =~ /Origen::Registers/
-
4
tdo = options[:shift_out_data]
-
else
-
4
tdo.write(options[:shift_out_data])
-
4
tdo.read(options)
-
end
-
else
-
206
tdo.write(0)
-
end
-
end
-
else
-
347
tdo = Reg.dummy(size)
-
347
if options[:read]
-
168
tdo.write(reg_or_val)
-
168
tdo.read(options)
-
else
-
179
if options[:shift_out_data]
-
65
if options[:shift_out_data].class.to_s =~ /Origen::Registers/
-
4
tdo = options[:shift_out_data]
-
else
-
61
tdo.write(options[:shift_out_data])
-
61
tdo.read(options)
-
end
-
else
-
114
tdo.write(0)
-
end
-
end
-
end
-
841
tdo
-
end
-
-
1
def to_pin(pin_or_id)
-
104
if pin_or_id
-
4
if pin_or_id.is_a?(Symbol) || pin_or_id.is_a?(String)
-
2
@owner.pin(pin_or_id)
-
else
-
2
pin_or_id
-
end
-
end
-
end
-
-
1
def pins
-
243702
@pins ||= begin
-
26
pins = {}
-
26
pins[:tck] = to_pin(@given_options[:tck_pin])
-
26
pins[:tdi] = to_pin(@given_options[:tdi_pin])
-
26
pins[:tdo] = to_pin(@given_options[:tdo_pin])
-
26
pins[:tms] = to_pin(@given_options[:tms_pin])
-
-
# Support legacy implementation where tck was incorrectly called tclk, in case of both being
-
# defined then :tck has priority
-
26
pins[:tck] ||= @owner.pin(:tck) if @owner.has_pin?(:tck)
-
26
pins[:tck] ||= @owner.pin(:tclk)
-
26
pins[:tdi] ||= @owner.pin(:tdi)
-
26
pins[:tdo] ||= @owner.pin(:tdo)
-
26
pins[:tms] ||= @owner.pin(:tms)
-
-
26
pins
-
end
-
rescue
-
puts 'Missing JTAG pins!'
-
puts "In order to use the JTAG driver your #{owner.class} class must either define"
-
puts 'the following pins (an alias is fine):'
-
puts REQUIRED_PINS
-
puts '-- or --'
-
puts 'Pass the pin IDs to be used instead in the initialization options:'
-
puts "sub_block :jtag, class_name: 'OrigenJTAG::Driver', tck_pin: :clk, tdi_pin: :gpio1, tdo_pin: :gpio2, tms_pin: :gpio3"
-
raise 'JTAG driver error!'
-
end
-
end
-
end
-
1
module OrigenJTAG
-
# Provides methods specifically for controlling the state of the
-
# TAP Controller
-
1
module TAPController
-
# Map of internal state symbols to human readable names
-
STATES = {
-
1
reset: 'Test-Logic-Reset',
-
idle: 'Run-Test/Idle',
-
select_dr_scan: 'Select-DR-Scan',
-
capture_dr: 'Capture-DR',
-
shift_dr: 'Shift-DR',
-
exit1_dr: 'Exit1-DR',
-
pause_dr: 'Pause-DR',
-
exit2_dr: 'Exit2-DR',
-
update_dr: 'Update-DR',
-
select_ir_scan: 'Select-IR-Scan',
-
capture_ir: 'Capture-IR',
-
shift_ir: 'Shift-IR',
-
exit1_ir: 'Exit1-IR',
-
pause_ir: 'Pause-IR',
-
exit2_ir: 'Exit2-IR',
-
update_ir: 'Update-IR'
-
}
-
-
# Returns the current state of the JTAG TAP Controller
-
1
attr_reader :state
-
1
alias_method :current_state, :state
-
-
# Goto Shift-DR state then exit back to Run-Test/Idle
-
#
-
# @example Trandition into Shift-DR
-
# # State is Run-Test/Idle
-
# jtag.shift_dr do
-
# # State is Shift-DR
-
# end
-
# # State is Run-Test/Idle
-
#
-
# This method can be nested inside of a pause_dr block
-
# to transition into the Shift-DR state and then back
-
# to Pause-DR
-
#
-
# @example Switching between Pause-DR and Shift-DR
-
# # State is Run-Test/Idle
-
# jtag.pause_dr do
-
# # State is Pause-DR
-
# jtag.shift_dr do
-
# # State is Shift-DR
-
# end
-
# # State is Pause-DR
-
# end
-
# # State is Run-Test/Idle
-
1
def shift_dr(options = {})
-
options = {
-
323
start_state: :idle, # Allowed start states: :idle, :select_dr_scan, :update_ir, :update_dr
-
end_state: :idle # Allowed end states: :idle, :update_dr
-
}.merge(options)
-
-
323
if options[:start_state] == :idle # allow for pause_dr state also if called from pause_dr block
-
304
validate_state(:idle, :pause_dr)
-
19
elsif options[:state_state] == :select_dr_scan
-
validate_state(:select_dr_scan, :pause_dr)
-
19
elsif options[:state_state] == :update_dr
-
validate_state(:update_dr, :pause_dr)
-
19
elsif options[:state_state] == :update_ir
-
validate_state(:update_ir, :pause_dr)
-
end
-
323
log 'Transition to Shift-DR...'
-
323
if state == :idle || state == :select_dr_scan || state == :update_ir || state == :update_dr
-
# Non-pause states
-
285
unless state == :select_dr_scan
-
266
tms!(1) # => Select-DR-Scan
-
266
update_state :select_dr_scan
-
end
-
285
tms!(0) # => Capture-DR
-
285
update_state :capture_dr
-
285
tms!(0) # => Shift-DR
-
285
update_state :shift_dr
-
285
if options[:write]
-
115
msg = "Write DR: #{options[:write]}"
-
170
elsif options[:read]
-
132
msg = "Read DR: #{options[:read]}"
-
else
-
38
msg = 'DR Data'
-
end
-
285
log msg, always: true do
-
285
yield
-
285
log 'Transition to Run-Test/Idle...'
-
285
if @last_data_vector_shifted
-
23
@last_data_vector_shifted = false
-
else
-
262
tms!(1) # => Exit1-DR
-
262
update_state :exit1_dr
-
end
-
end
-
285
tms!(1) # => Update-DR
-
285
update_state :update_dr
-
285
if options[:end_state] == :idle
-
285
tms!(0) # => Run-Test/Idle
-
285
update_state :idle
-
end
-
else # :pause_dr
-
38
tms!(1) # => Exit2-DR
-
38
update_state :exit2_dr
-
38
tms!(0) # => Shift-DR
-
38
update_state :shift_dr
-
38
yield
-
38
log 'Transition to Pause-DR...'
-
38
tms!(1) # => Exit1-DR
-
38
update_state :exit1_dr
-
38
tms!(0) # => Pause-DR
-
38
update_state :pause_dr
-
end
-
end
-
-
# Goto Pause-DR state then exit back to Run-Test/Idle
-
#
-
# @example Trandition into Pause-DR
-
# # State is Run-Test/Idle
-
# jtag.pause_dr do
-
# # State is Pause-DR
-
# end
-
# # State is Run-Test/Idle
-
#
-
# This method can be nested inside of a shift_dr block
-
# to transition into the Pause-DR state and then back
-
# to Shift-DR
-
#
-
# @example Switching between Shift-DR and Pause-DR
-
# # State is Run-Test/Idle
-
# jtag.shift_dr do
-
# # State is Shift-DR
-
# jtag.pause_dr do
-
# # State is Pause-DR
-
# end
-
# # State is Shift-DR
-
# end
-
# # State is Run-Test/Idle
-
1
def pause_dr
-
76
validate_state(:idle, :shift_dr)
-
76
log 'Transition to Pause-DR...'
-
76
if state == :idle
-
38
tms!(1) # => Select-DR-Scan
-
38
update_state :select_dr_scan
-
38
tms!(0) # => Capture-DR
-
38
update_state :capture_dr
-
38
tms!(1) # => Exit1-DR
-
38
update_state :exit1_dr
-
38
tms!(0) # => Pause-DR
-
38
update_state :pause_dr
-
38
yield
-
38
log 'Transition to Run-Test/Idle...'
-
38
tms!(1) # => Exit2-DR
-
38
update_state :exit2_dr
-
38
tms!(1) # => Update-DR
-
38
update_state :update_dr
-
38
tms!(0) # => Run-Test/Idle
-
38
update_state :idle
-
else # shift_dr
-
38
tms!(1) # => Exit1-DR
-
38
update_state :exit1_dr
-
38
tms!(0) # => Pause-DR
-
38
update_state :pause_dr
-
38
yield
-
38
log 'Transition to Shift-DR...'
-
38
tms!(1) # => Exit2-DR
-
38
update_state :exit2_dr
-
38
tms!(0) # => Shift-DR
-
38
update_state :shift_dr
-
end
-
end
-
-
# Goto Shift-IR state then exit back to Run-Test/Idle
-
#
-
# @example Trandition into Shift-IR
-
# # State is Run-Test/Idle
-
# jtag.shift_ir do
-
# # State is Shift-IR
-
# end
-
# # State is Run-Test/Idle
-
#
-
# This method can be nested inside of a pause_ir block
-
# to transition into the Shift-IR state and then back
-
# to Pause-IR
-
#
-
# @example Switching between Pause-IR and Shift-IR
-
# # State is Run-Test/Idle
-
# jtag.pause_ir do
-
# # State is Pause-IR
-
# jtag.shift_ir do
-
# # State is Shift-IR
-
# end
-
# # State is Pause-IR
-
# end
-
# # State is Run-Test/Idle
-
1
def shift_ir(options = {})
-
options = {
-
152
start_state: :idle, # Allowed start states: :idle, :select_ir_scan
-
end_state: :idle # Allowed end states: :idle, :update_ir, :select_dr_scan
-
}.merge(options)
-
152
if options[:start_state] == :idle
-
152
validate_state(:idle, :pause_ir)
-
else
-
validate_state(:select_ir_scan, :pause_ir)
-
end
-
152
log 'Transition to Shift-IR...'
-
152
if state == :idle || state == :select_ir_scan
-
114
unless state == :select_ir_scan
-
114
tms!(1) # => Select-DR-Scan
-
114
update_state :select_dr_scan
-
114
tms!(1) # => Select-IR-Scan
-
114
update_state :select_ir_scan
-
end
-
114
tms!(0) # => Capture-IR
-
114
update_state :capture_ir
-
114
tms!(0) # => Shift-IR
-
114
update_state :shift_ir
-
114
if options[:write]
-
57
msg = "Write IR: #{options[:write]}"
-
57
elsif options[:read]
-
19
msg = "Read IR: #{options[:read]}"
-
else
-
38
msg = 'IR Data'
-
end
-
114
log msg, always: true do
-
114
yield
-
114
if options[:end_state] == :idle
-
95
log 'Transition to Run-Test/Idle...'
-
19
elsif options[:end_state] == :update_ir
-
log 'Transition to Update-IR...'
-
19
elsif options[:end_state] == :select_dr_scan
-
19
log 'Transition to Select-DR-Scan...'
-
end
-
114
if @last_data_vector_shifted
-
@last_data_vector_shifted = false
-
else
-
114
tms!(1) # => Exit1-IR
-
114
update_state :exit1_ir
-
end
-
end
-
114
tms!(1) # => Update-IR
-
114
update_state :update_ir
-
114
if options[:end_state] == :idle
-
95
tms!(0) # => Run-Test/Idle
-
95
update_state :idle
-
19
elsif options[:end_state] == :select_dr_scan
-
19
tms!(1) # => Select-DR-Scan
-
19
update_state :select_dr_scan
-
end
-
else # :pause_ir
-
38
tms!(1) # => Exit2-IR
-
38
update_state :exit2_ir
-
38
tms!(0) # => Shift-IR
-
38
update_state :shift_ir
-
38
yield
-
38
log 'Transition to Pause-IR...'
-
38
tms!(1) # => Exit1-IR
-
38
update_state :exit1_ir
-
38
tms!(0) # => Pause-IR
-
38
update_state :pause_ir
-
end
-
end
-
-
# Goto Pause-IR state then exit back to Run-Test/Idle
-
#
-
# @example Trandition into Pause-iR
-
# # State is Run-Test/Idle
-
# jtag.pause_ir do
-
# # State is Pause-IR
-
# end
-
# # State is Run-Test/Idle
-
#
-
# This method can be nested inside of a shift_ir block
-
# to transition into the Pause-IR state and then back
-
# to Shift-IR
-
#
-
# @example Switching between Shift-IR and Pause-IR
-
# # State is Run-Test/Idle
-
# jtag.shift_ir do
-
# # State is Shift-IR
-
# jtag.pause_ir do
-
# # State is Pause-IR
-
# end
-
# # State is Shift-IR
-
# end
-
# # State is Run-Test/Idle
-
1
def pause_ir
-
76
validate_state(:idle, :shift_ir)
-
76
log 'Transition to Pause-IR...'
-
76
if state == :idle
-
38
tms!(1) # => Select-DR-Scan
-
38
update_state :select_dr_scan
-
38
tms!(1) # => Select-IR-Scan
-
38
update_state :select_ir_scan
-
38
tms!(0) # => Capture-IR
-
38
update_state :capture_ir
-
38
tms!(1) # => Exit1-IR
-
38
update_state :exit1_ir
-
38
tms!(0) # => Pause-IR
-
38
update_state :pause_ir
-
38
yield
-
38
log 'Transition to Run-Test/Idle...'
-
38
tms!(1) # => Exit2-IR
-
38
update_state :exit2_ir
-
38
tms!(1) # => Update-IR
-
38
update_state :update_ir
-
38
tms!(0) # => Run-Test/Idle
-
38
update_state :idle
-
else # :shift_ir
-
38
tms!(1) # => Exit1-IR
-
38
update_state :exit1_ir
-
38
tms!(0) # => Pause-IR
-
38
update_state :pause_ir
-
38
yield
-
38
log 'Transition to Shift-IR...'
-
38
tms!(1) # => Exit2-IR
-
38
update_state :exit2_ir
-
38
tms!(0) # => Shift-IR
-
38
update_state :shift_ir
-
end
-
end
-
-
# Returns the current state as a human readable string
-
1
def state_str
-
STATES[state]
-
end
-
1
alias_method :current_state_str, :state_str
-
-
# Forces the state to Run-Test/Idle regardless of the current
-
# state.
-
1
def idle
-
27
log 'Force transition to Run-Test/Idle...'
-
# From the JTAG2IPS block guide holding TMS high for 5 cycles
-
# will force it to reset regardless of the state, let's give
-
# it 6 for luck:
-
189
6.times { tms!(1) }
-
# Now a couple of cycles low to get it into idle
-
81
2.times { tms!(0) }
-
27
update_state :idle
-
end
-
-
# Force state to Test-Logic-Reset regardless of the current
-
# state
-
1
def reset
-
19
log 'Force transition to Test-Logic-Reset...'
-
# JTAG reset
-
133
6.times { tms!(1) }
-
end
-
-
1
def update_state(state)
-
3671
@state = state
-
3671
log "Current state: #{state_str}" if log_state_changes
-
3671
@listeners ||= Origen.listeners_for(:on_jtag_state_change)
-
3671
@listeners.each { |l| l.on_jtag_state_change(@state) }
-
end
-
-
1
private
-
-
1
def init_tap_controller(options = {})
-
35
options = {
-
}.merge(options)
-
end
-
-
# Ensures that the current state matches one of the given acceptable
-
# states.
-
#
-
# Additionally if the current state is unknown and idle is acceptable
-
# then the state will be transitioned to idle.
-
1
def validate_state(*acceptable_states)
-
608
if current_state == :unknown && acceptable_states.include?(:idle)
-
27
idle
-
581
elsif acceptable_states.include?(current_state)
-
return
-
else
-
fail 'JTAG TAP Controller - An invalid state sequence has occurred!'
-
end
-
end
-
-
1
def log(msg, options = {})
-
1699
cc "[JTAG] #{msg}" if verbose? || options[:always]
-
1699
if block_given?
-
399
yield
-
399
cc "[JTAG] /#{msg}" if verbose? || options[:always]
-
end
-
end
-
end
-
end
-
1
module OrigenJTAGDev
-
# This is a dummy DUT model which is used
-
# to instantiate and test the JTAG locally
-
# during development.
-
#
-
# It is not included when this library is imported.
-
1
class NewStyle
-
1
include Origen::TopLevel
-
-
1
attr_reader :jtag_config
-
-
1
def initialize(options = {})
-
@jtag_config = {
-
23
verbose: true,
-
tclk_format: :rh,
-
tclk_multiple: 1,
-
tdo_strobe: :tclk_high,
-
tdo_store_cycle: 0,
-
init_state: :unknown
-
}
-
23
@jtag_config[:tclk_format] = options[:tclk_format] if options[:tclk_format]
-
23
@jtag_config[:tclk_multiple] = options[:tclk_multiple] if options[:tclk_multiple]
-
23
@jtag_config[:tdo_strobe] = options[:tdo_strobe] if options[:tdo_strobe]
-
23
@jtag_config[:tdo_store_cycle] = options[:tdo_store_cycle] if options[:tdo_store_cycle]
-
23
@jtag_config[:init_state] = options[:init_state] if options[:init_state]
-
23
@jtag_config[:tclk_vals] = options[:tclk_vals] if options[:tclk_vals]
-
23
@jtag_config[:cycle_callback] = options[:cycle_callback] if options[:cycle_callback]
-
-
23
instantiate_registers(options)
-
23
instantiate_pins(options)
-
23
sub_block :jtag, { class_name: 'OrigenJTAG::Driver' }.merge(@jtag_config)
-
23
if options[:extra_port]
-
# Test supplying both pin IDs (recommended) and pin objects (legacy)
-
1
sub_block :jtag2, { class_name: 'OrigenJTAG::Driver', tck_pin: :tck_2, tdi_pin: :tdi_2, tdo_pin: pin(:tdo_2), tms_pin: pin(:tms_2) }.merge(@jtag_config)
-
end
-
end
-
-
1
def instantiate_registers(options = {})
-
23
reg :test16, 0x0012, size: 16 do |reg|
-
23
reg.bit 15..8, :bus
-
23
reg.bit 0, :bit
-
end
-
-
23
reg :test32, 0x0014, size: 32 do |reg|
-
23
reg.bit 31..16, :bus
-
23
reg.bit 0, :bit
-
end
-
-
23
reg :full16, 0x0012, size: 16 do |reg|
-
23
reg.bit 15..0, :data
-
end
-
end
-
-
1
def instantiate_pins(options = {})
-
21
add_pin :tclk
-
21
unless options[:invalid_pins]
-
21
add_pin :tdi
-
end
-
21
add_pin :tdo
-
21
add_pin :tms
-
-
21
if options[:extra_port]
-
1
add_pin :tck_2
-
1
add_pin :tdi_2
-
1
add_pin :tdo_2
-
1
add_pin :tms_2
-
end
-
end
-
-
1
def startup(options = {})
-
15
tester.set_timeset('nvmbist', 40)
-
end
-
-
# Getter for top-level tclk_format setting
-
1
def tclk_format
-
11
@jtag_config[:tclk_format]
-
end
-
-
# Getter for top-level tclk_multiple setting
-
1
def tclk_multiple
-
11
@jtag_config[:tclk_multiple]
-
end
-
-
# Getter for top-level tclk_vals setting
-
1
def tclk_vals
-
11
@jtag_config[:tclk_vals]
-
end
-
-
# Getter for top-level tdo_strobe setting
-
1
def tdo_strobe
-
@jtag_config[:tdo_strobe]
-
end
-
-
# Getter for top-level tdo_store_cycle setting
-
1
def tdo_store_cycle
-
15
@jtag_config[:tdo_store_cycle]
-
end
-
-
# Getter for top-level init_state setting
-
1
def init_state
-
@jtag_config[:init_state]
-
end
-
-
# Wouldn't want to do this in reality, but allows some flexibility during gem testing
-
1
def update_jtag_config(cfg, val)
-
if @jtag_config.key?(cfg)
-
@jtag_config[cfg] = val
-
else
-
fail "#{cfg} not a part of @jtag_config"
-
end
-
end
-
end
-
end